src/video/SDL_RLEaccel.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 19 Jun 2015 23:12:13 -0700
changeset 9761 fd7fe355f173
parent 9619 b94b6d0bff0f
child 10000 acd714e378f4
permissions -rw-r--r--
Fixed bug 3023 - setting a white and then non-white texture color mod breaks the texture with software renderer

Adam M.

Okay, here is the problem, I think.

During the first blit, RLEAlphaSurface is called to do RLE conversion of the RGBA source into a format allowing it "to be quickly alpha-blittable onto dest". Since the destination is the screen, it has no alpha channel. RLEAlphaSurface calls copy_opaque(dst, src + runstart, len, sf, df) (where copy_opaque is copy_32), which has this code:

SDL_RLEaccel.c:984:
RGBA_FROM_8888(*src, sfmt, r, g, b, a);
PIXEL_FROM_RGBA(*d, dfmt, r, g, b, a);

On the first line, it reads the source pixel 0xFFFFFFFF. The second line drops the alpha value (because dfmt for the screen has no alpha channel) and writes 0x00FFFFFF. Later, when the RLE conversion is being undone, uncopy_32 is called, which has the following code:

SDL_RLEaccel.c:1001:
Uint32 pixel = *s++;
RGB_FROM_PIXEL(pixel, sfmt, r, g, b);
a = pixel >> 24;
PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, a);

However, the the alpha channel has already been dropped by copy_opaque (= copy_32), so pixel = 0x00FFFFFF and 'a' becomes 0. Thus, all opaque pixels lose their alpha channel when being unRLE'd. (I don't know what happens to pixels with alpha from 1-254, but they should be checked too.)

So, that seems to be the problem, but I'm not sure what the solution should be. Since opaque pixels have alpha == 255, I'm thinking to create another uncopy function for opaque pixels that simply uses 255 for alpha.

However, there may be other problems here. For translucent pixels, uncopy_32 assumes the alpha channel is stored in the upper 8 bits, but copy_32 doesn't store it there. Instead, it stores it in whatever location is appropriate for the destination surface. Isn't one of their behaviors incorrect, given the other? I'm not sure which to change, however.

For translucent pixels, it seems that the blit function uses do_blend, which is the BLIT_TRANSL_888 macro, which also assumes alpha is in top 8 bits. It has the comment "we have made sure the alpha is stored in the top 8 bits...", but it seems that's not true (copy_32 doesn't make sure the alpha goes there).

Perhaps the correct fix is to make copy_32 put the alpha there, but then that seems to require that RLE conversion be limited to destination surfaces that don't use the upper 8 bits. However, looking further, it seems that has already been done: if (masksum != 0x00ffffff) return -1; /* requires unused high byte */
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@9619
     3
  Copyright (C) 1997-2015 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
/*
slouken@0
    24
 * RLE encoding for software colorkey and alpha-channel acceleration
slouken@0
    25
 *
slouken@0
    26
 * Original version by Sam Lantinga
slouken@0
    27
 *
slouken@0
    28
 * Mattias Engdegård (Yorick): Rewrite. New encoding format, encoder and
slouken@0
    29
 * decoder. Added per-surface alpha blitter. Added per-pixel alpha
slouken@0
    30
 * format, encoder and blitter.
slouken@0
    31
 *
slouken@0
    32
 * Many thanks to Xark and johns for hints, benchmarks and useful comments
slouken@0
    33
 * leading to this code.
slouken@0
    34
 *
slouken@0
    35
 * Welcome to Macro Mayhem.
slouken@0
    36
 */
slouken@0
    37
slouken@0
    38
/*
slouken@0
    39
 * The encoding translates the image data to a stream of segments of the form
slouken@0
    40
 *
slouken@0
    41
 * <skip> <run> <data>
slouken@0
    42
 *
slouken@0
    43
 * where <skip> is the number of transparent pixels to skip,
slouken@0
    44
 *       <run>  is the number of opaque pixels to blit,
slouken@0
    45
 * and   <data> are the pixels themselves.
slouken@0
    46
 *
slouken@0
    47
 * This basic structure is used both for colorkeyed surfaces, used for simple
slouken@0
    48
 * binary transparency and for per-surface alpha blending, and for surfaces
slouken@0
    49
 * with per-pixel alpha. The details differ, however:
slouken@0
    50
 *
slouken@0
    51
 * Encoding of colorkeyed surfaces:
slouken@0
    52
 *
slouken@0
    53
 *   Encoded pixels always have the same format as the target surface.
slouken@0
    54
 *   <skip> and <run> are unsigned 8 bit integers, except for 32 bit depth
slouken@0
    55
 *   where they are 16 bit. This makes the pixel data aligned at all times.
slouken@0
    56
 *   Segments never wrap around from one scan line to the next.
slouken@0
    57
 *
slouken@0
    58
 *   The end of the sequence is marked by a zero <skip>,<run> pair at the *
slouken@0
    59
 *   beginning of a line.
slouken@0
    60
 *
slouken@0
    61
 * Encoding of surfaces with per-pixel alpha:
slouken@0
    62
 *
slouken@0
    63
 *   The sequence begins with a struct RLEDestFormat describing the target
slouken@0
    64
 *   pixel format, to provide reliable un-encoding.
slouken@0
    65
 *
slouken@0
    66
 *   Each scan line is encoded twice: First all completely opaque pixels,
slouken@0
    67
 *   encoded in the target format as described above, and then all
slouken@0
    68
 *   partially transparent (translucent) pixels (where 1 <= alpha <= 254),
slouken@0
    69
 *   in the following 32-bit format:
slouken@0
    70
 *
slouken@0
    71
 *   For 32-bit targets, each pixel has the target RGB format but with
slouken@0
    72
 *   the alpha value occupying the highest 8 bits. The <skip> and <run>
slouken@0
    73
 *   counts are 16 bit.
slouken@7191
    74
 *
slouken@0
    75
 *   For 16-bit targets, each pixel has the target RGB format, but with
slouken@0
    76
 *   the middle component (usually green) shifted 16 steps to the left,
slouken@0
    77
 *   and the hole filled with the 5 most significant bits of the alpha value.
slouken@0
    78
 *   i.e. if the target has the format         rrrrrggggggbbbbb,
slouken@0
    79
 *   the encoded pixel will be 00000gggggg00000rrrrr0aaaaabbbbb.
slouken@0
    80
 *   The <skip> and <run> counts are 8 bit for the opaque lines, 16 bit
slouken@0
    81
 *   for the translucent lines. Two padding bytes may be inserted
slouken@0
    82
 *   before each translucent line to keep them 32-bit aligned.
slouken@0
    83
 *
slouken@0
    84
 *   The end of the sequence is marked by a zero <skip>,<run> pair at the
slouken@0
    85
 *   beginning of an opaque line.
slouken@0
    86
 */
slouken@0
    87
slouken@0
    88
#include "SDL_video.h"
slouken@0
    89
#include "SDL_sysvideo.h"
slouken@0
    90
#include "SDL_blit.h"
slouken@0
    91
#include "SDL_RLEaccel_c.h"
slouken@0
    92
slouken@0
    93
#ifndef MAX
slouken@0
    94
#define MAX(a, b) ((a) > (b) ? (a) : (b))
slouken@0
    95
#endif
slouken@0
    96
#ifndef MIN
slouken@0
    97
#define MIN(a, b) ((a) < (b) ? (a) : (b))
slouken@0
    98
#endif
slouken@0
    99
slouken@7191
   100
#define PIXEL_COPY(to, from, len, bpp)          \
slouken@7351
   101
    SDL_memcpy(to, from, (size_t)(len) * (bpp))
slouken@1
   102
slouken@0
   103
/*
slouken@0
   104
 * Various colorkey blit methods, for opaque and per-surface alpha
slouken@0
   105
 */
slouken@0
   106
slouken@7191
   107
#define OPAQUE_BLIT(to, from, length, bpp, alpha)   \
slouken@1
   108
    PIXEL_COPY(to, from, length, bpp)
slouken@0
   109
slouken@0
   110
/*
slouken@0
   111
 * For 32bpp pixels on the form 0x00rrggbb:
slouken@0
   112
 * If we treat the middle component separately, we can process the two
slouken@0
   113
 * remaining in parallel. This is safe to do because of the gap to the left
slouken@0
   114
 * of each component, so the bits from the multiplication don't collide.
slouken@0
   115
 * This can be used for any RGB permutation of course.
slouken@0
   116
 */
slouken@7191
   117
#define ALPHA_BLIT32_888(to, from, length, bpp, alpha)      \
slouken@8924
   118
    do {                                                    \
slouken@8924
   119
        int i;                                              \
slouken@8924
   120
        Uint32 *src = (Uint32 *)(from);                     \
slouken@8924
   121
        Uint32 *dst = (Uint32 *)(to);                       \
slouken@8924
   122
        for (i = 0; i < (int)(length); i++) {               \
slouken@8924
   123
            Uint32 s = *src++;                              \
slouken@8924
   124
            Uint32 d = *dst;                                \
slouken@8924
   125
            Uint32 s1 = s & 0xff00ff;                       \
slouken@8924
   126
            Uint32 d1 = d & 0xff00ff;                       \
slouken@8924
   127
            d1 = (d1 + ((s1 - d1) * alpha >> 8)) & 0xff00ff; \
slouken@8924
   128
            s &= 0xff00;                                    \
slouken@8924
   129
            d &= 0xff00;                                    \
slouken@8924
   130
            d = (d + ((s - d) * alpha >> 8)) & 0xff00;      \
slouken@8924
   131
            *dst++ = d1 | d;                                \
slouken@8924
   132
        }                                                   \
slouken@8924
   133
    } while (0)
slouken@0
   134
slouken@0
   135
/*
slouken@0
   136
 * For 16bpp pixels we can go a step further: put the middle component
slouken@0
   137
 * in the high 16 bits of a 32 bit word, and process all three RGB
slouken@0
   138
 * components at the same time. Since the smallest gap is here just
slouken@0
   139
 * 5 bits, we have to scale alpha down to 5 bits as well.
slouken@0
   140
 */
slouken@7191
   141
#define ALPHA_BLIT16_565(to, from, length, bpp, alpha)  \
slouken@8924
   142
    do {                                                \
slouken@8924
   143
        int i;                                          \
slouken@8924
   144
        Uint16 *src = (Uint16 *)(from);                 \
slouken@8924
   145
        Uint16 *dst = (Uint16 *)(to);                   \
slouken@8924
   146
        Uint32 ALPHA = alpha >> 3;                      \
slouken@8924
   147
        for(i = 0; i < (int)(length); i++) {            \
slouken@8924
   148
            Uint32 s = *src++;                          \
slouken@8924
   149
            Uint32 d = *dst;                            \
slouken@8924
   150
            s = (s | s << 16) & 0x07e0f81f;             \
slouken@8924
   151
            d = (d | d << 16) & 0x07e0f81f;             \
slouken@8924
   152
            d += (s - d) * ALPHA >> 5;                  \
slouken@8924
   153
            d &= 0x07e0f81f;                            \
slouken@8924
   154
            *dst++ = (Uint16)(d | d >> 16);             \
slouken@8924
   155
        }                                               \
slouken@0
   156
    } while(0)
slouken@0
   157
slouken@7191
   158
#define ALPHA_BLIT16_555(to, from, length, bpp, alpha)  \
slouken@8924
   159
    do {                                                \
slouken@8924
   160
        int i;                                          \
slouken@8924
   161
        Uint16 *src = (Uint16 *)(from);                 \
slouken@8924
   162
        Uint16 *dst = (Uint16 *)(to);                   \
slouken@8924
   163
        Uint32 ALPHA = alpha >> 3;                      \
slouken@8924
   164
        for(i = 0; i < (int)(length); i++) {            \
slouken@8924
   165
            Uint32 s = *src++;                          \
slouken@8924
   166
            Uint32 d = *dst;                            \
slouken@8924
   167
            s = (s | s << 16) & 0x03e07c1f;             \
slouken@8924
   168
            d = (d | d << 16) & 0x03e07c1f;             \
slouken@8924
   169
            d += (s - d) * ALPHA >> 5;                  \
slouken@8924
   170
            d &= 0x03e07c1f;                            \
slouken@8924
   171
            *dst++ = (Uint16)(d | d >> 16);             \
slouken@8924
   172
        }                                               \
slouken@0
   173
    } while(0)
slouken@0
   174
slouken@0
   175
/*
slouken@0
   176
 * The general slow catch-all function, for remaining depths and formats
slouken@0
   177
 */
slouken@7191
   178
#define ALPHA_BLIT_ANY(to, from, length, bpp, alpha)            \
slouken@8924
   179
    do {                                                        \
slouken@8924
   180
        int i;                                                  \
slouken@8924
   181
        Uint8 *src = from;                                      \
slouken@8924
   182
        Uint8 *dst = to;                                        \
slouken@8924
   183
        for (i = 0; i < (int)(length); i++) {                   \
slouken@8924
   184
            Uint32 s, d;                                        \
slouken@8924
   185
            unsigned rs, gs, bs, rd, gd, bd;                    \
slouken@8924
   186
            switch (bpp) {                                      \
slouken@8924
   187
            case 2:                                             \
slouken@8924
   188
                s = *(Uint16 *)src;                             \
slouken@8924
   189
                d = *(Uint16 *)dst;                             \
slouken@8924
   190
                break;                                          \
slouken@8924
   191
            case 3:                                             \
slouken@8924
   192
                if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {          \
slouken@8924
   193
                    s = (src[0] << 16) | (src[1] << 8) | src[2]; \
slouken@8924
   194
                    d = (dst[0] << 16) | (dst[1] << 8) | dst[2]; \
slouken@8924
   195
                } else {                                        \
slouken@8924
   196
                    s = (src[2] << 16) | (src[1] << 8) | src[0]; \
slouken@8924
   197
                    d = (dst[2] << 16) | (dst[1] << 8) | dst[0]; \
slouken@8924
   198
                }                                               \
slouken@8924
   199
                break;                                          \
slouken@8924
   200
            case 4:                                             \
slouken@8924
   201
                s = *(Uint32 *)src;                             \
slouken@8924
   202
                d = *(Uint32 *)dst;                             \
slouken@8924
   203
                break;                                          \
slouken@8924
   204
            }                                                   \
slouken@8924
   205
            RGB_FROM_PIXEL(s, fmt, rs, gs, bs);                 \
slouken@8924
   206
            RGB_FROM_PIXEL(d, fmt, rd, gd, bd);                 \
slouken@8924
   207
            rd += (rs - rd) * alpha >> 8;                       \
slouken@8924
   208
            gd += (gs - gd) * alpha >> 8;                       \
slouken@8924
   209
            bd += (bs - bd) * alpha >> 8;                       \
slouken@8924
   210
            PIXEL_FROM_RGB(d, fmt, rd, gd, bd);                 \
slouken@8924
   211
            switch (bpp) {                                      \
slouken@8924
   212
            case 2:                                             \
slouken@8924
   213
                *(Uint16 *)dst = (Uint16)d;                     \
slouken@8924
   214
                break;                                          \
slouken@8924
   215
            case 3:                                             \
slouken@8924
   216
                if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {          \
slouken@8924
   217
                    dst[0] = (Uint8)(d >> 16);                  \
slouken@8924
   218
                    dst[1] = (Uint8)(d >> 8);                   \
slouken@8924
   219
                    dst[2] = (Uint8)(d);                        \
slouken@8924
   220
                } else {                                        \
slouken@8924
   221
                    dst[0] = (Uint8)d;                          \
slouken@8924
   222
                    dst[1] = (Uint8)(d >> 8);                   \
slouken@8924
   223
                    dst[2] = (Uint8)(d >> 16);                  \
slouken@8924
   224
                }                                               \
slouken@8924
   225
                break;                                          \
slouken@8924
   226
            case 4:                                             \
slouken@8924
   227
                *(Uint32 *)dst = d;                             \
slouken@8924
   228
                break;                                          \
slouken@8924
   229
            }                                                   \
slouken@8924
   230
            src += bpp;                                         \
slouken@8924
   231
            dst += bpp;                                         \
slouken@8924
   232
        }                                                       \
slouken@0
   233
    } while(0)
slouken@0
   234
slouken@0
   235
/*
slouken@0
   236
 * Special case: 50% alpha (alpha=128)
slouken@0
   237
 * This is treated specially because it can be optimized very well, and
slouken@0
   238
 * since it is good for many cases of semi-translucency.
slouken@0
   239
 * The theory is to do all three components at the same time:
slouken@0
   240
 * First zero the lowest bit of each component, which gives us room to
slouken@0
   241
 * add them. Then shift right and add the sum of the lowest bits.
slouken@0
   242
 */
slouken@7191
   243
#define ALPHA_BLIT32_888_50(to, from, length, bpp, alpha)       \
slouken@8924
   244
    do {                                                        \
slouken@8924
   245
        int i;                                                  \
slouken@8924
   246
        Uint32 *src = (Uint32 *)(from);                         \
slouken@8924
   247
        Uint32 *dst = (Uint32 *)(to);                           \
slouken@8924
   248
        for(i = 0; i < (int)(length); i++) {                    \
slouken@8924
   249
            Uint32 s = *src++;                                  \
slouken@8924
   250
            Uint32 d = *dst;                                    \
slouken@8924
   251
            *dst++ = (((s & 0x00fefefe) + (d & 0x00fefefe)) >> 1) \
slouken@8924
   252
                 + (s & d & 0x00010101);                        \
slouken@8924
   253
        }                                                       \
slouken@0
   254
    } while(0)
slouken@0
   255
slouken@0
   256
/*
slouken@0
   257
 * For 16bpp, we can actually blend two pixels in parallel, if we take
slouken@0
   258
 * care to shift before we add, not after.
slouken@0
   259
 */
slouken@0
   260
slouken@0
   261
/* helper: blend a single 16 bit pixel at 50% */
slouken@8924
   262
#define BLEND16_50(dst, src, mask)                              \
slouken@8924
   263
    do {                                                        \
slouken@8924
   264
        Uint32 s = *src++;                                      \
slouken@8924
   265
        Uint32 d = *dst;                                        \
slouken@8924
   266
        *dst++ = (Uint16)((((s & mask) + (d & mask)) >> 1) +    \
slouken@8924
   267
                          (s & d & (~mask & 0xffff)));          \
slouken@0
   268
    } while(0)
slouken@0
   269
slouken@0
   270
/* basic 16bpp blender. mask is the pixels to keep when adding. */
slouken@7191
   271
#define ALPHA_BLIT16_50(to, from, length, bpp, alpha, mask)     \
slouken@8924
   272
    do {                                                        \
slouken@8924
   273
        unsigned n = (length);                                  \
slouken@8924
   274
        Uint16 *src = (Uint16 *)(from);                         \
slouken@8924
   275
        Uint16 *dst = (Uint16 *)(to);                           \
slouken@8924
   276
        if (((uintptr_t)src ^ (uintptr_t)dst) & 3) {            \
slouken@8924
   277
            /* source and destination not in phase, blit one by one */ \
slouken@8924
   278
            while (n--)                                         \
slouken@8924
   279
                BLEND16_50(dst, src, mask);                     \
slouken@8924
   280
        } else {                                                \
slouken@8924
   281
            if ((uintptr_t)src & 3) {                           \
slouken@8924
   282
                /* first odd pixel */                           \
slouken@8924
   283
                BLEND16_50(dst, src, mask);                     \
slouken@8924
   284
                n--;                                            \
slouken@8924
   285
            }                                                   \
slouken@8924
   286
            for (; n > 1; n -= 2) {                             \
slouken@8924
   287
                Uint32 s = *(Uint32 *)src;                      \
slouken@8924
   288
                Uint32 d = *(Uint32 *)dst;                      \
slouken@8924
   289
                *(Uint32 *)dst = ((s & (mask | mask << 16)) >> 1) \
slouken@8924
   290
                    + ((d & (mask | mask << 16)) >> 1)          \
slouken@8924
   291
                    + (s & d & (~(mask | mask << 16)));         \
slouken@8924
   292
                src += 2;                                       \
slouken@8924
   293
                dst += 2;                                       \
slouken@8924
   294
            }                                                   \
slouken@8924
   295
            if (n)                                              \
slouken@8924
   296
                BLEND16_50(dst, src, mask); /* last odd pixel */ \
slouken@8924
   297
        }                                                       \
slouken@0
   298
    } while(0)
slouken@0
   299
slouken@8924
   300
#define ALPHA_BLIT16_565_50(to, from, length, bpp, alpha)       \
slouken@0
   301
    ALPHA_BLIT16_50(to, from, length, bpp, alpha, 0xf7de)
slouken@0
   302
slouken@8924
   303
#define ALPHA_BLIT16_555_50(to, from, length, bpp, alpha)       \
slouken@0
   304
    ALPHA_BLIT16_50(to, from, length, bpp, alpha, 0xfbde)
slouken@0
   305
slouken@8924
   306
#define CHOOSE_BLIT(blitter, alpha, fmt)                        \
slouken@8924
   307
    do {                                                        \
slouken@8924
   308
        if (alpha == 255) {                                     \
slouken@8924
   309
            switch (fmt->BytesPerPixel) {                       \
slouken@8924
   310
            case 1: blitter(1, Uint8, OPAQUE_BLIT); break;      \
slouken@8924
   311
            case 2: blitter(2, Uint8, OPAQUE_BLIT); break;      \
slouken@8924
   312
            case 3: blitter(3, Uint8, OPAQUE_BLIT); break;      \
slouken@8924
   313
            case 4: blitter(4, Uint16, OPAQUE_BLIT); break;     \
slouken@8924
   314
            }                                                   \
slouken@8924
   315
        } else {                                                \
slouken@8924
   316
            switch (fmt->BytesPerPixel) {                       \
slouken@8924
   317
            case 1:                                             \
slouken@8924
   318
                /* No 8bpp alpha blitting */                    \
slouken@8924
   319
                break;                                          \
slouken@8924
   320
                                                                \
slouken@8924
   321
            case 2:                                             \
slouken@8924
   322
                switch (fmt->Rmask | fmt->Gmask | fmt->Bmask) { \
slouken@8924
   323
                case 0xffff:                                    \
slouken@8924
   324
                    if (fmt->Gmask == 0x07e0                    \
slouken@8924
   325
                        || fmt->Rmask == 0x07e0                 \
slouken@8924
   326
                        || fmt->Bmask == 0x07e0) {              \
slouken@8924
   327
                        if (alpha == 128) {                     \
slouken@8924
   328
                            blitter(2, Uint8, ALPHA_BLIT16_565_50); \
slouken@8924
   329
                        } else {                                \
slouken@8924
   330
                            blitter(2, Uint8, ALPHA_BLIT16_565); \
slouken@8924
   331
                        }                                       \
slouken@8924
   332
                    } else                                      \
slouken@8924
   333
                        goto general16;                         \
slouken@8924
   334
                    break;                                      \
slouken@8924
   335
                                                                \
slouken@8924
   336
                case 0x7fff:                                    \
slouken@8924
   337
                    if (fmt->Gmask == 0x03e0                    \
slouken@8924
   338
                        || fmt->Rmask == 0x03e0                 \
slouken@8924
   339
                        || fmt->Bmask == 0x03e0) {              \
slouken@8924
   340
                        if (alpha == 128) {                     \
slouken@8924
   341
                            blitter(2, Uint8, ALPHA_BLIT16_555_50); \
slouken@8924
   342
                        } else {                                \
slouken@8924
   343
                            blitter(2, Uint8, ALPHA_BLIT16_555); \
slouken@8924
   344
                        }                                       \
slouken@8924
   345
                        break;                                  \
slouken@8924
   346
                    } else                                      \
slouken@8924
   347
                        goto general16;                         \
slouken@8924
   348
                    break;                                      \
slouken@8924
   349
                                                                \
slouken@8924
   350
                default:                                        \
slouken@8924
   351
    general16:                                                  \
slouken@8924
   352
                    blitter(2, Uint8, ALPHA_BLIT_ANY);          \
slouken@8924
   353
                }                                               \
slouken@8924
   354
                break;                                          \
slouken@8924
   355
                                                                \
slouken@8924
   356
            case 3:                                             \
slouken@8924
   357
                blitter(3, Uint8, ALPHA_BLIT_ANY);              \
slouken@8924
   358
                break;                                          \
slouken@8924
   359
                                                                \
slouken@8924
   360
            case 4:                                             \
slouken@8924
   361
                if ((fmt->Rmask | fmt->Gmask | fmt->Bmask) == 0x00ffffff \
slouken@8924
   362
                    && (fmt->Gmask == 0xff00 || fmt->Rmask == 0xff00 \
slouken@8924
   363
                    || fmt->Bmask == 0xff00)) {                 \
slouken@8924
   364
                    if (alpha == 128) {                         \
slouken@8924
   365
                        blitter(4, Uint16, ALPHA_BLIT32_888_50); \
slouken@8924
   366
                    } else {                                    \
slouken@8924
   367
                        blitter(4, Uint16, ALPHA_BLIT32_888);   \
slouken@8924
   368
                    }                                           \
slouken@8924
   369
                } else                                          \
slouken@8924
   370
                    blitter(4, Uint16, ALPHA_BLIT_ANY);         \
slouken@8924
   371
                break;                                          \
slouken@8924
   372
            }                                                   \
slouken@8924
   373
        }                                                       \
slouken@0
   374
    } while(0)
slouken@0
   375
slouken@0
   376
/*
slouken@9761
   377
 * Set a pixel value using the given format, except that the alpha value is
slouken@9761
   378
 * placed in the top byte. This is the format used for RLE with alpha.
slouken@9761
   379
 */
slouken@9761
   380
#define RLEPIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a)                      \
slouken@9761
   381
{                                                                       \
slouken@9761
   382
    Pixel = ((r>>fmt->Rloss)<<fmt->Rshift)|                             \
slouken@9761
   383
        ((g>>fmt->Gloss)<<fmt->Gshift)|                                 \
slouken@9761
   384
        ((b>>fmt->Bloss)<<fmt->Bshift)|                                 \
slouken@9761
   385
        (a<<24);                                                        \
slouken@9761
   386
}
slouken@9761
   387
slouken@9761
   388
/*
slouken@0
   389
 * This takes care of the case when the surface is clipped on the left and/or
slouken@0
   390
 * right. Top clipping has already been taken care of.
slouken@0
   391
 */
slouken@1895
   392
static void
slouken@8922
   393
RLEClipBlit(int w, Uint8 * srcbuf, SDL_Surface * surf_dst,
slouken@1895
   394
            Uint8 * dstbuf, SDL_Rect * srcrect, unsigned alpha)
slouken@0
   395
{
slouken@8922
   396
    SDL_PixelFormat *fmt = surf_dst->format;
slouken@0
   397
slouken@8924
   398
#define RLECLIPBLIT(bpp, Type, do_blit)                         \
slouken@8924
   399
    do {                                                        \
slouken@8924
   400
        int linecount = srcrect->h;                             \
slouken@8924
   401
        int ofs = 0;                                            \
slouken@8924
   402
        int left = srcrect->x;                                  \
slouken@8924
   403
        int right = left + srcrect->w;                          \
slouken@8924
   404
        dstbuf -= left * bpp;                                   \
slouken@8924
   405
        for (;;) {                                              \
slouken@8924
   406
            int run;                                            \
slouken@8924
   407
            ofs += *(Type *)srcbuf;                             \
slouken@8924
   408
            run = ((Type *)srcbuf)[1];                          \
slouken@8924
   409
            srcbuf += 2 * sizeof(Type);                         \
slouken@8924
   410
            if (run) {                                          \
slouken@8924
   411
                /* clip to left and right borders */            \
slouken@8924
   412
                if (ofs < right) {                              \
slouken@8924
   413
                    int start = 0;                              \
slouken@8924
   414
                    int len = run;                              \
slouken@8924
   415
                    int startcol;                               \
slouken@8924
   416
                    if (left - ofs > 0) {                       \
slouken@8924
   417
                        start = left - ofs;                     \
slouken@8924
   418
                        len -= start;                           \
slouken@8924
   419
                        if (len <= 0)                           \
slouken@8924
   420
                            goto nocopy ## bpp ## do_blit;      \
slouken@8924
   421
                    }                                           \
slouken@8924
   422
                    startcol = ofs + start;                     \
slouken@8924
   423
                    if (len > right - startcol)                 \
slouken@8924
   424
                        len = right - startcol;                 \
slouken@8924
   425
                    do_blit(dstbuf + startcol * bpp, srcbuf + start * bpp, \
slouken@8924
   426
                        len, bpp, alpha);                       \
slouken@8924
   427
                }                                               \
slouken@8924
   428
    nocopy ## bpp ## do_blit:                                   \
slouken@8924
   429
                srcbuf += run * bpp;                            \
slouken@8924
   430
                ofs += run;                                     \
slouken@8924
   431
            } else if (!ofs)                                    \
slouken@8924
   432
                break;                                          \
slouken@8924
   433
                                                                \
slouken@8924
   434
            if (ofs == w) {                                     \
slouken@8924
   435
                ofs = 0;                                        \
slouken@8924
   436
                dstbuf += surf_dst->pitch;                      \
slouken@8924
   437
                if (!--linecount)                               \
slouken@8924
   438
                    break;                                      \
slouken@8924
   439
            }                                                   \
slouken@8924
   440
        }                                                       \
slouken@0
   441
    } while(0)
slouken@0
   442
slouken@0
   443
    CHOOSE_BLIT(RLECLIPBLIT, alpha, fmt);
slouken@0
   444
slouken@0
   445
#undef RLECLIPBLIT
slouken@0
   446
slouken@0
   447
}
slouken@0
   448
slouken@0
   449
slouken@0
   450
/* blit a colorkeyed RLE surface */
slouken@1895
   451
int
slouken@8922
   452
SDL_RLEBlit(SDL_Surface * surf_src, SDL_Rect * srcrect,
slouken@8922
   453
            SDL_Surface * surf_dst, SDL_Rect * dstrect)
slouken@0
   454
{
slouken@1895
   455
    Uint8 *dstbuf;
slouken@1895
   456
    Uint8 *srcbuf;
slouken@1895
   457
    int x, y;
slouken@8922
   458
    int w = surf_src->w;
slouken@1895
   459
    unsigned alpha;
slouken@0
   460
slouken@1895
   461
    /* Lock the destination if necessary */
slouken@8922
   462
    if (SDL_MUSTLOCK(surf_dst)) {
slouken@8922
   463
        if (SDL_LockSurface(surf_dst) < 0) {
slouken@1895
   464
            return (-1);
slouken@1895
   465
        }
slouken@1895
   466
    }
slouken@0
   467
slouken@1895
   468
    /* Set up the source and destination pointers */
slouken@1895
   469
    x = dstrect->x;
slouken@1895
   470
    y = dstrect->y;
slouken@8922
   471
    dstbuf = (Uint8 *) surf_dst->pixels
slouken@8922
   472
        + y * surf_dst->pitch + x * surf_src->format->BytesPerPixel;
slouken@8922
   473
    srcbuf = (Uint8 *) surf_src->map->data;
slouken@0
   474
slouken@1895
   475
    {
philipp@7128
   476
        /* skip lines at the top if necessary */
slouken@1895
   477
        int vskip = srcrect->y;
slouken@1895
   478
        int ofs = 0;
slouken@1895
   479
        if (vskip) {
slouken@0
   480
slouken@7191
   481
#define RLESKIP(bpp, Type)          \
slouken@7191
   482
        for(;;) {           \
slouken@7191
   483
            int run;            \
slouken@7191
   484
            ofs += *(Type *)srcbuf; \
slouken@7191
   485
            run = ((Type *)srcbuf)[1];  \
slouken@7191
   486
            srcbuf += sizeof(Type) * 2; \
slouken@7191
   487
            if(run) {           \
slouken@7191
   488
            srcbuf += run * bpp;    \
slouken@7191
   489
            ofs += run;     \
slouken@7191
   490
            } else if(!ofs)     \
slouken@7191
   491
            goto done;      \
slouken@7191
   492
            if(ofs == w) {      \
slouken@7191
   493
            ofs = 0;        \
slouken@7191
   494
            if(!--vskip)        \
slouken@7191
   495
                break;      \
slouken@7191
   496
            }               \
slouken@7191
   497
        }
slouken@0
   498
slouken@8922
   499
            switch (surf_src->format->BytesPerPixel) {
slouken@1895
   500
            case 1:
slouken@1895
   501
                RLESKIP(1, Uint8);
slouken@1895
   502
                break;
slouken@1895
   503
            case 2:
slouken@1895
   504
                RLESKIP(2, Uint8);
slouken@1895
   505
                break;
slouken@1895
   506
            case 3:
slouken@1895
   507
                RLESKIP(3, Uint8);
slouken@1895
   508
                break;
slouken@1895
   509
            case 4:
slouken@1895
   510
                RLESKIP(4, Uint16);
slouken@1895
   511
                break;
slouken@1895
   512
            }
slouken@0
   513
slouken@0
   514
#undef RLESKIP
slouken@0
   515
slouken@1895
   516
        }
slouken@1895
   517
    }
slouken@0
   518
slouken@8922
   519
    alpha = surf_src->map->info.a;
slouken@1895
   520
    /* if left or right edge clipping needed, call clip blit */
slouken@8922
   521
    if (srcrect->x || srcrect->w != surf_src->w) {
slouken@8922
   522
        RLEClipBlit(w, srcbuf, surf_dst, dstbuf, srcrect, alpha);
slouken@1895
   523
    } else {
slouken@8922
   524
        SDL_PixelFormat *fmt = surf_src->format;
slouken@0
   525
slouken@7191
   526
#define RLEBLIT(bpp, Type, do_blit)                       \
slouken@7191
   527
        do {                                  \
slouken@7191
   528
        int linecount = srcrect->h;                   \
slouken@7191
   529
        int ofs = 0;                              \
slouken@7191
   530
        for(;;) {                             \
slouken@7191
   531
            unsigned run;                         \
slouken@7191
   532
            ofs += *(Type *)srcbuf;                   \
slouken@7191
   533
            run = ((Type *)srcbuf)[1];                    \
slouken@7191
   534
            srcbuf += 2 * sizeof(Type);                   \
slouken@7191
   535
            if(run) {                             \
slouken@7191
   536
            do_blit(dstbuf + ofs * bpp, srcbuf, run, bpp, alpha); \
slouken@7191
   537
            srcbuf += run * bpp;                      \
slouken@7191
   538
            ofs += run;                       \
slouken@7191
   539
            } else if(!ofs)                       \
slouken@7191
   540
            break;                            \
slouken@7191
   541
            if(ofs == w) {                        \
slouken@7191
   542
            ofs = 0;                          \
slouken@8922
   543
            dstbuf += surf_dst->pitch;                     \
slouken@7191
   544
            if(!--linecount)                      \
slouken@7191
   545
                break;                        \
slouken@7191
   546
            }                                 \
slouken@7191
   547
        }                                 \
slouken@7191
   548
        } while(0)
slouken@0
   549
slouken@1895
   550
        CHOOSE_BLIT(RLEBLIT, alpha, fmt);
slouken@0
   551
slouken@0
   552
#undef RLEBLIT
slouken@1895
   553
    }
slouken@0
   554
slouken@1895
   555
  done:
slouken@1895
   556
    /* Unlock the destination if necessary */
slouken@8922
   557
    if (SDL_MUSTLOCK(surf_dst)) {
slouken@8922
   558
        SDL_UnlockSurface(surf_dst);
slouken@1895
   559
    }
slouken@1895
   560
    return (0);
slouken@0
   561
}
slouken@0
   562
slouken@0
   563
#undef OPAQUE_BLIT
slouken@0
   564
slouken@0
   565
/*
slouken@0
   566
 * Per-pixel blitting macros for translucent pixels:
slouken@0
   567
 * These use the same techniques as the per-surface blitting macros
slouken@0
   568
 */
slouken@0
   569
slouken@0
   570
/*
slouken@0
   571
 * For 32bpp pixels, we have made sure the alpha is stored in the top
slouken@0
   572
 * 8 bits, so proceed as usual
slouken@0
   573
 */
slouken@7191
   574
#define BLIT_TRANSL_888(src, dst)               \
slouken@7191
   575
    do {                            \
slouken@7191
   576
        Uint32 s = src;                     \
slouken@7191
   577
    Uint32 d = dst;                     \
slouken@7191
   578
    unsigned alpha = s >> 24;               \
slouken@7191
   579
    Uint32 s1 = s & 0xff00ff;               \
slouken@7191
   580
    Uint32 d1 = d & 0xff00ff;               \
slouken@7191
   581
    d1 = (d1 + ((s1 - d1) * alpha >> 8)) & 0xff00ff;    \
slouken@7191
   582
    s &= 0xff00;                        \
slouken@7191
   583
    d &= 0xff00;                        \
slouken@7191
   584
    d = (d + ((s - d) * alpha >> 8)) & 0xff00;      \
slouken@7191
   585
    dst = d1 | d | 0xff000000;              \
slouken@0
   586
    } while(0)
slouken@0
   587
slouken@0
   588
/*
slouken@0
   589
 * For 16bpp pixels, we have stored the 5 most significant alpha bits in
slouken@0
   590
 * bits 5-10. As before, we can process all 3 RGB components at the same time.
slouken@0
   591
 */
slouken@7191
   592
#define BLIT_TRANSL_565(src, dst)       \
slouken@7191
   593
    do {                    \
slouken@7191
   594
    Uint32 s = src;             \
slouken@7191
   595
    Uint32 d = dst;             \
slouken@7191
   596
    unsigned alpha = (s & 0x3e0) >> 5;  \
slouken@7191
   597
    s &= 0x07e0f81f;            \
slouken@7191
   598
    d = (d | d << 16) & 0x07e0f81f;     \
slouken@7191
   599
    d += (s - d) * alpha >> 5;      \
slouken@7191
   600
    d &= 0x07e0f81f;            \
slouken@7191
   601
    dst = (Uint16)(d | d >> 16);            \
slouken@0
   602
    } while(0)
slouken@0
   603
slouken@7191
   604
#define BLIT_TRANSL_555(src, dst)       \
slouken@7191
   605
    do {                    \
slouken@7191
   606
    Uint32 s = src;             \
slouken@7191
   607
    Uint32 d = dst;             \
slouken@7191
   608
    unsigned alpha = (s & 0x3e0) >> 5;  \
slouken@7191
   609
    s &= 0x03e07c1f;            \
slouken@7191
   610
    d = (d | d << 16) & 0x03e07c1f;     \
slouken@7191
   611
    d += (s - d) * alpha >> 5;      \
slouken@7191
   612
    d &= 0x03e07c1f;            \
slouken@7191
   613
    dst = (Uint16)(d | d >> 16);            \
slouken@0
   614
    } while(0)
slouken@0
   615
slouken@0
   616
/* used to save the destination format in the encoding. Designed to be
slouken@0
   617
   macro-compatible with SDL_PixelFormat but without the unneeded fields */
slouken@1895
   618
typedef struct
slouken@1895
   619
{
slouken@1895
   620
    Uint8 BytesPerPixel;
slouken@5435
   621
    Uint8 padding[3];
slouken@5435
   622
    Uint32 Rmask;
slouken@5435
   623
    Uint32 Gmask;
slouken@5435
   624
    Uint32 Bmask;
slouken@5435
   625
    Uint32 Amask;
slouken@1895
   626
    Uint8 Rloss;
slouken@1895
   627
    Uint8 Gloss;
slouken@1895
   628
    Uint8 Bloss;
slouken@5435
   629
    Uint8 Aloss;
slouken@1895
   630
    Uint8 Rshift;
slouken@1895
   631
    Uint8 Gshift;
slouken@1895
   632
    Uint8 Bshift;
slouken@1895
   633
    Uint8 Ashift;
slouken@0
   634
} RLEDestFormat;
slouken@0
   635
slouken@0
   636
/* blit a pixel-alpha RLE surface clipped at the right and/or left edges */
slouken@1895
   637
static void
slouken@8922
   638
RLEAlphaClipBlit(int w, Uint8 * srcbuf, SDL_Surface * surf_dst,
slouken@1895
   639
                 Uint8 * dstbuf, SDL_Rect * srcrect)
slouken@0
   640
{
slouken@8922
   641
    SDL_PixelFormat *df = surf_dst->format;
slouken@0
   642
    /*
slouken@0
   643
     * clipped blitter: Ptype is the destination pixel type,
slouken@0
   644
     * Ctype the translucent count type, and do_blend the macro
slouken@0
   645
     * to blend one pixel.
slouken@0
   646
     */
slouken@7191
   647
#define RLEALPHACLIPBLIT(Ptype, Ctype, do_blend)              \
slouken@7191
   648
    do {                                  \
slouken@7191
   649
    int linecount = srcrect->h;                   \
slouken@7191
   650
    int left = srcrect->x;                        \
slouken@7191
   651
    int right = left + srcrect->w;                    \
slouken@7191
   652
    dstbuf -= left * sizeof(Ptype);                   \
slouken@7191
   653
    do {                                  \
slouken@7191
   654
        int ofs = 0;                          \
slouken@7191
   655
        /* blit opaque pixels on one line */              \
slouken@7191
   656
        do {                              \
slouken@7191
   657
        unsigned run;                         \
slouken@7191
   658
        ofs += ((Ctype *)srcbuf)[0];                  \
slouken@7191
   659
        run = ((Ctype *)srcbuf)[1];               \
slouken@7191
   660
        srcbuf += 2 * sizeof(Ctype);                  \
slouken@7191
   661
        if(run) {                         \
slouken@7191
   662
            /* clip to left and right borders */          \
slouken@7191
   663
            int cofs = ofs;                   \
slouken@7191
   664
            int crun = run;                   \
slouken@7191
   665
            if(left - cofs > 0) {                 \
slouken@7191
   666
            crun -= left - cofs;                  \
slouken@7191
   667
            cofs = left;                      \
slouken@7191
   668
            }                             \
slouken@7191
   669
            if(crun > right - cofs)               \
slouken@7191
   670
            crun = right - cofs;                  \
slouken@7191
   671
            if(crun > 0)                      \
slouken@7191
   672
            PIXEL_COPY(dstbuf + cofs * sizeof(Ptype),     \
slouken@7191
   673
                   srcbuf + (cofs - ofs) * sizeof(Ptype), \
slouken@7191
   674
                   (unsigned)crun, sizeof(Ptype));    \
slouken@7191
   675
            srcbuf += run * sizeof(Ptype);            \
slouken@7191
   676
            ofs += run;                       \
slouken@7191
   677
        } else if(!ofs)                       \
slouken@7191
   678
            return;                       \
slouken@7191
   679
        } while(ofs < w);                         \
slouken@7191
   680
        /* skip padding if necessary */               \
slouken@7191
   681
        if(sizeof(Ptype) == 2)                    \
slouken@7191
   682
        srcbuf += (uintptr_t)srcbuf & 2;              \
slouken@7191
   683
        /* blit translucent pixels on the same line */        \
slouken@7191
   684
        ofs = 0;                              \
slouken@7191
   685
        do {                              \
slouken@7191
   686
        unsigned run;                         \
slouken@7191
   687
        ofs += ((Uint16 *)srcbuf)[0];                 \
slouken@7191
   688
        run = ((Uint16 *)srcbuf)[1];                  \
slouken@7191
   689
        srcbuf += 4;                          \
slouken@7191
   690
        if(run) {                         \
slouken@7191
   691
            /* clip to left and right borders */          \
slouken@7191
   692
            int cofs = ofs;                   \
slouken@7191
   693
            int crun = run;                   \
slouken@7191
   694
            if(left - cofs > 0) {                 \
slouken@7191
   695
            crun -= left - cofs;                  \
slouken@7191
   696
            cofs = left;                      \
slouken@7191
   697
            }                             \
slouken@7191
   698
            if(crun > right - cofs)               \
slouken@7191
   699
            crun = right - cofs;                  \
slouken@7191
   700
            if(crun > 0) {                    \
slouken@7191
   701
            Ptype *dst = (Ptype *)dstbuf + cofs;          \
slouken@7191
   702
            Uint32 *src = (Uint32 *)srcbuf + (cofs - ofs);    \
slouken@7191
   703
            int i;                        \
slouken@7191
   704
            for(i = 0; i < crun; i++)             \
slouken@7191
   705
                do_blend(src[i], dst[i]);             \
slouken@7191
   706
            }                             \
slouken@7191
   707
            srcbuf += run * 4;                    \
slouken@7191
   708
            ofs += run;                       \
slouken@7191
   709
        }                             \
slouken@7191
   710
        } while(ofs < w);                         \
slouken@8922
   711
        dstbuf += surf_dst->pitch;                     \
slouken@7191
   712
    } while(--linecount);                         \
slouken@0
   713
    } while(0)
slouken@0
   714
slouken@1895
   715
    switch (df->BytesPerPixel) {
slouken@0
   716
    case 2:
slouken@1895
   717
        if (df->Gmask == 0x07e0 || df->Rmask == 0x07e0 || df->Bmask == 0x07e0)
slouken@1895
   718
            RLEALPHACLIPBLIT(Uint16, Uint8, BLIT_TRANSL_565);
slouken@1895
   719
        else
slouken@1895
   720
            RLEALPHACLIPBLIT(Uint16, Uint8, BLIT_TRANSL_555);
slouken@1895
   721
        break;
slouken@0
   722
    case 4:
slouken@1895
   723
        RLEALPHACLIPBLIT(Uint32, Uint16, BLIT_TRANSL_888);
slouken@1895
   724
        break;
slouken@0
   725
    }
slouken@0
   726
}
slouken@0
   727
slouken@0
   728
/* blit a pixel-alpha RLE surface */
slouken@1895
   729
int
slouken@8922
   730
SDL_RLEAlphaBlit(SDL_Surface * surf_src, SDL_Rect * srcrect,
slouken@8922
   731
                 SDL_Surface * surf_dst, SDL_Rect * dstrect)
slouken@0
   732
{
slouken@0
   733
    int x, y;
slouken@8922
   734
    int w = surf_src->w;
slouken@0
   735
    Uint8 *srcbuf, *dstbuf;
slouken@8922
   736
    SDL_PixelFormat *df = surf_dst->format;
slouken@0
   737
slouken@0
   738
    /* Lock the destination if necessary */
slouken@8922
   739
    if (SDL_MUSTLOCK(surf_dst)) {
slouken@8922
   740
        if (SDL_LockSurface(surf_dst) < 0) {
slouken@1895
   741
            return -1;
slouken@1895
   742
        }
slouken@0
   743
    }
slouken@0
   744
slouken@0
   745
    x = dstrect->x;
slouken@0
   746
    y = dstrect->y;
slouken@8922
   747
    dstbuf = (Uint8 *) surf_dst->pixels + y * surf_dst->pitch + x * df->BytesPerPixel;
slouken@8922
   748
    srcbuf = (Uint8 *) surf_src->map->data + sizeof(RLEDestFormat);
slouken@0
   749
slouken@0
   750
    {
slouken@1895
   751
        /* skip lines at the top if necessary */
slouken@1895
   752
        int vskip = srcrect->y;
slouken@1895
   753
        if (vskip) {
slouken@1895
   754
            int ofs;
slouken@1895
   755
            if (df->BytesPerPixel == 2) {
slouken@1895
   756
                /* the 16/32 interleaved format */
slouken@1895
   757
                do {
slouken@1895
   758
                    /* skip opaque line */
slouken@1895
   759
                    ofs = 0;
slouken@1895
   760
                    do {
slouken@1895
   761
                        int run;
slouken@1895
   762
                        ofs += srcbuf[0];
slouken@1895
   763
                        run = srcbuf[1];
slouken@1895
   764
                        srcbuf += 2;
slouken@1895
   765
                        if (run) {
slouken@1895
   766
                            srcbuf += 2 * run;
slouken@1895
   767
                            ofs += run;
slouken@1895
   768
                        } else if (!ofs)
slouken@1895
   769
                            goto done;
slouken@2735
   770
                    } while (ofs < w);
slouken@0
   771
slouken@1895
   772
                    /* skip padding */
slouken@1895
   773
                    srcbuf += (uintptr_t) srcbuf & 2;
slouken@0
   774
slouken@1895
   775
                    /* skip translucent line */
slouken@1895
   776
                    ofs = 0;
slouken@1895
   777
                    do {
slouken@1895
   778
                        int run;
slouken@1895
   779
                        ofs += ((Uint16 *) srcbuf)[0];
slouken@1895
   780
                        run = ((Uint16 *) srcbuf)[1];
slouken@1895
   781
                        srcbuf += 4 * (run + 1);
slouken@1895
   782
                        ofs += run;
slouken@2735
   783
                    } while (ofs < w);
slouken@2735
   784
                } while (--vskip);
slouken@1895
   785
            } else {
slouken@1895
   786
                /* the 32/32 interleaved format */
slouken@1895
   787
                vskip <<= 1;    /* opaque and translucent have same format */
slouken@1895
   788
                do {
slouken@1895
   789
                    ofs = 0;
slouken@1895
   790
                    do {
slouken@1895
   791
                        int run;
slouken@1895
   792
                        ofs += ((Uint16 *) srcbuf)[0];
slouken@1895
   793
                        run = ((Uint16 *) srcbuf)[1];
slouken@1895
   794
                        srcbuf += 4;
slouken@1895
   795
                        if (run) {
slouken@1895
   796
                            srcbuf += 4 * run;
slouken@1895
   797
                            ofs += run;
slouken@1895
   798
                        } else if (!ofs)
slouken@1895
   799
                            goto done;
slouken@2735
   800
                    } while (ofs < w);
slouken@2735
   801
                } while (--vskip);
slouken@1895
   802
            }
slouken@1895
   803
        }
slouken@0
   804
    }
slouken@0
   805
slouken@0
   806
    /* if left or right edge clipping needed, call clip blit */
slouken@8922
   807
    if (srcrect->x || srcrect->w != surf_src->w) {
slouken@8922
   808
        RLEAlphaClipBlit(w, srcbuf, surf_dst, dstbuf, srcrect);
slouken@0
   809
    } else {
slouken@0
   810
slouken@1895
   811
        /*
slouken@1895
   812
         * non-clipped blitter. Ptype is the destination pixel type,
slouken@1895
   813
         * Ctype the translucent count type, and do_blend the
slouken@1895
   814
         * macro to blend one pixel.
slouken@1895
   815
         */
slouken@7191
   816
#define RLEALPHABLIT(Ptype, Ctype, do_blend)                 \
slouken@7191
   817
    do {                                 \
slouken@7191
   818
        int linecount = srcrect->h;                  \
slouken@7191
   819
        do {                             \
slouken@7191
   820
        int ofs = 0;                         \
slouken@7191
   821
        /* blit opaque pixels on one line */             \
slouken@7191
   822
        do {                             \
slouken@7191
   823
            unsigned run;                    \
slouken@7191
   824
            ofs += ((Ctype *)srcbuf)[0];             \
slouken@7191
   825
            run = ((Ctype *)srcbuf)[1];              \
slouken@7191
   826
            srcbuf += 2 * sizeof(Ctype);             \
slouken@7191
   827
            if(run) {                        \
slouken@7191
   828
            PIXEL_COPY(dstbuf + ofs * sizeof(Ptype), srcbuf, \
slouken@7191
   829
                   run, sizeof(Ptype));          \
slouken@7191
   830
            srcbuf += run * sizeof(Ptype);           \
slouken@7191
   831
            ofs += run;                  \
slouken@7191
   832
            } else if(!ofs)                  \
slouken@7191
   833
            goto done;                   \
slouken@7191
   834
        } while(ofs < w);                    \
slouken@7191
   835
        /* skip padding if necessary */              \
slouken@7191
   836
        if(sizeof(Ptype) == 2)                   \
slouken@7191
   837
            srcbuf += (uintptr_t)srcbuf & 2;             \
slouken@7191
   838
        /* blit translucent pixels on the same line */       \
slouken@7191
   839
        ofs = 0;                         \
slouken@7191
   840
        do {                             \
slouken@7191
   841
            unsigned run;                    \
slouken@7191
   842
            ofs += ((Uint16 *)srcbuf)[0];            \
slouken@7191
   843
            run = ((Uint16 *)srcbuf)[1];             \
slouken@7191
   844
            srcbuf += 4;                     \
slouken@7191
   845
            if(run) {                        \
slouken@7191
   846
            Ptype *dst = (Ptype *)dstbuf + ofs;      \
slouken@7191
   847
            unsigned i;                  \
slouken@7191
   848
            for(i = 0; i < run; i++) {           \
slouken@7191
   849
                Uint32 src = *(Uint32 *)srcbuf;      \
slouken@7191
   850
                do_blend(src, *dst);             \
slouken@7191
   851
                srcbuf += 4;                 \
slouken@7191
   852
                dst++;                   \
slouken@7191
   853
            }                        \
slouken@7191
   854
            ofs += run;                  \
slouken@7191
   855
            }                            \
slouken@7191
   856
        } while(ofs < w);                    \
slouken@8922
   857
        dstbuf += surf_dst->pitch;                    \
slouken@7191
   858
        } while(--linecount);                    \
slouken@7191
   859
    } while(0)
slouken@0
   860
slouken@1895
   861
        switch (df->BytesPerPixel) {
slouken@1895
   862
        case 2:
slouken@1895
   863
            if (df->Gmask == 0x07e0 || df->Rmask == 0x07e0
slouken@1895
   864
                || df->Bmask == 0x07e0)
slouken@1895
   865
                RLEALPHABLIT(Uint16, Uint8, BLIT_TRANSL_565);
slouken@1895
   866
            else
slouken@1895
   867
                RLEALPHABLIT(Uint16, Uint8, BLIT_TRANSL_555);
slouken@1895
   868
            break;
slouken@1895
   869
        case 4:
slouken@1895
   870
            RLEALPHABLIT(Uint32, Uint16, BLIT_TRANSL_888);
slouken@1895
   871
            break;
slouken@1895
   872
        }
slouken@0
   873
    }
slouken@0
   874
slouken@1895
   875
  done:
slouken@0
   876
    /* Unlock the destination if necessary */
slouken@8922
   877
    if (SDL_MUSTLOCK(surf_dst)) {
slouken@8922
   878
        SDL_UnlockSurface(surf_dst);
slouken@0
   879
    }
slouken@0
   880
    return 0;
slouken@0
   881
}
slouken@0
   882
slouken@0
   883
/*
slouken@0
   884
 * Auxiliary functions:
slouken@0
   885
 * The encoding functions take 32bpp rgb + a, and
slouken@0
   886
 * return the number of bytes copied to the destination.
slouken@0
   887
 * The decoding functions copy to 32bpp rgb + a, and
slouken@0
   888
 * return the number of bytes copied from the source.
slouken@0
   889
 * These are only used in the encoder and un-RLE code and are therefore not
slouken@0
   890
 * highly optimised.
slouken@0
   891
 */
slouken@0
   892
slouken@0
   893
/* encode 32bpp rgb + a into 16bpp rgb, losing alpha */
slouken@1895
   894
static int
slouken@1895
   895
copy_opaque_16(void *dst, Uint32 * src, int n,
slouken@1895
   896
               SDL_PixelFormat * sfmt, SDL_PixelFormat * dfmt)
slouken@0
   897
{
slouken@0
   898
    int i;
slouken@0
   899
    Uint16 *d = dst;
slouken@1895
   900
    for (i = 0; i < n; i++) {
slouken@1895
   901
        unsigned r, g, b;
slouken@1895
   902
        RGB_FROM_PIXEL(*src, sfmt, r, g, b);
slouken@1895
   903
        PIXEL_FROM_RGB(*d, dfmt, r, g, b);
slouken@1895
   904
        src++;
slouken@1895
   905
        d++;
slouken@0
   906
    }
slouken@0
   907
    return n * 2;
slouken@0
   908
}
slouken@0
   909
slouken@0
   910
/* decode opaque pixels from 16bpp to 32bpp rgb + a */
slouken@1895
   911
static int
slouken@1895
   912
uncopy_opaque_16(Uint32 * dst, void *src, int n,
slouken@1895
   913
                 RLEDestFormat * sfmt, SDL_PixelFormat * dfmt)
slouken@0
   914
{
slouken@0
   915
    int i;
slouken@0
   916
    Uint16 *s = src;
slouken@0
   917
    unsigned alpha = dfmt->Amask ? 255 : 0;
slouken@1895
   918
    for (i = 0; i < n; i++) {
slouken@1895
   919
        unsigned r, g, b;
slouken@1895
   920
        RGB_FROM_PIXEL(*s, sfmt, r, g, b);
slouken@1895
   921
        PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, alpha);
slouken@1895
   922
        s++;
slouken@1895
   923
        dst++;
slouken@0
   924
    }
slouken@0
   925
    return n * 2;
slouken@0
   926
}
slouken@0
   927
slouken@0
   928
slouken@0
   929
slouken@0
   930
/* encode 32bpp rgb + a into 32bpp G0RAB format for blitting into 565 */
slouken@1895
   931
static int
slouken@1895
   932
copy_transl_565(void *dst, Uint32 * src, int n,
slouken@1895
   933
                SDL_PixelFormat * sfmt, SDL_PixelFormat * dfmt)
slouken@0
   934
{
slouken@0
   935
    int i;
slouken@0
   936
    Uint32 *d = dst;
slouken@1895
   937
    for (i = 0; i < n; i++) {
slouken@1895
   938
        unsigned r, g, b, a;
slouken@1895
   939
        Uint16 pix;
slouken@1895
   940
        RGBA_FROM_8888(*src, sfmt, r, g, b, a);
slouken@1895
   941
        PIXEL_FROM_RGB(pix, dfmt, r, g, b);
slouken@1895
   942
        *d = ((pix & 0x7e0) << 16) | (pix & 0xf81f) | ((a << 2) & 0x7e0);
slouken@1895
   943
        src++;
slouken@1895
   944
        d++;
slouken@0
   945
    }
slouken@0
   946
    return n * 4;
slouken@0
   947
}
slouken@0
   948
slouken@0
   949
/* encode 32bpp rgb + a into 32bpp G0RAB format for blitting into 555 */
slouken@1895
   950
static int
slouken@1895
   951
copy_transl_555(void *dst, Uint32 * src, int n,
slouken@1895
   952
                SDL_PixelFormat * sfmt, SDL_PixelFormat * dfmt)
slouken@0
   953
{
slouken@0
   954
    int i;
slouken@0
   955
    Uint32 *d = dst;
slouken@1895
   956
    for (i = 0; i < n; i++) {
slouken@1895
   957
        unsigned r, g, b, a;
slouken@1895
   958
        Uint16 pix;
slouken@1895
   959
        RGBA_FROM_8888(*src, sfmt, r, g, b, a);
slouken@1895
   960
        PIXEL_FROM_RGB(pix, dfmt, r, g, b);
slouken@5439
   961
        *d = ((pix & 0x3e0) << 16) | (pix & 0xfc1f) | ((a << 2) & 0x3e0);
slouken@1895
   962
        src++;
slouken@1895
   963
        d++;
slouken@0
   964
    }
slouken@0
   965
    return n * 4;
slouken@0
   966
}
slouken@0
   967
slouken@0
   968
/* decode translucent pixels from 32bpp GORAB to 32bpp rgb + a */
slouken@1895
   969
static int
slouken@1895
   970
uncopy_transl_16(Uint32 * dst, void *src, int n,
slouken@1895
   971
                 RLEDestFormat * sfmt, SDL_PixelFormat * dfmt)
slouken@0
   972
{
slouken@0
   973
    int i;
slouken@0
   974
    Uint32 *s = src;
slouken@1895
   975
    for (i = 0; i < n; i++) {
slouken@1895
   976
        unsigned r, g, b, a;
slouken@1895
   977
        Uint32 pix = *s++;
slouken@1895
   978
        a = (pix & 0x3e0) >> 2;
slouken@1895
   979
        pix = (pix & ~0x3e0) | pix >> 16;
slouken@1895
   980
        RGB_FROM_PIXEL(pix, sfmt, r, g, b);
slouken@1895
   981
        PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, a);
slouken@1895
   982
        dst++;
slouken@0
   983
    }
slouken@0
   984
    return n * 4;
slouken@0
   985
}
slouken@0
   986
slouken@0
   987
/* encode 32bpp rgba into 32bpp rgba, keeping alpha (dual purpose) */
slouken@1895
   988
static int
slouken@1895
   989
copy_32(void *dst, Uint32 * src, int n,
slouken@1895
   990
        SDL_PixelFormat * sfmt, SDL_PixelFormat * dfmt)
slouken@0
   991
{
slouken@0
   992
    int i;
slouken@0
   993
    Uint32 *d = dst;
slouken@1895
   994
    for (i = 0; i < n; i++) {
slouken@1895
   995
        unsigned r, g, b, a;
slouken@1895
   996
        RGBA_FROM_8888(*src, sfmt, r, g, b, a);
slouken@9761
   997
        RLEPIXEL_FROM_RGBA(*d, dfmt, r, g, b, a);
icculus@5631
   998
        d++;
slouken@1895
   999
        src++;
slouken@0
  1000
    }
slouken@0
  1001
    return n * 4;
slouken@0
  1002
}
slouken@0
  1003
slouken@0
  1004
/* decode 32bpp rgba into 32bpp rgba, keeping alpha (dual purpose) */
slouken@1895
  1005
static int
slouken@1895
  1006
uncopy_32(Uint32 * dst, void *src, int n,
slouken@1895
  1007
          RLEDestFormat * sfmt, SDL_PixelFormat * dfmt)
slouken@0
  1008
{
slouken@0
  1009
    int i;
slouken@0
  1010
    Uint32 *s = src;
slouken@1895
  1011
    for (i = 0; i < n; i++) {
slouken@1895
  1012
        unsigned r, g, b, a;
slouken@1895
  1013
        Uint32 pixel = *s++;
slouken@1895
  1014
        RGB_FROM_PIXEL(pixel, sfmt, r, g, b);
slouken@1895
  1015
        a = pixel >> 24;
slouken@1895
  1016
        PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, a);
slouken@1895
  1017
        dst++;
slouken@0
  1018
    }
slouken@0
  1019
    return n * 4;
slouken@0
  1020
}
slouken@0
  1021
slouken@0
  1022
#define ISOPAQUE(pixel, fmt) ((((pixel) & fmt->Amask) >> fmt->Ashift) == 255)
slouken@0
  1023
slouken@7191
  1024
#define ISTRANSL(pixel, fmt)    \
slouken@0
  1025
    ((unsigned)((((pixel) & fmt->Amask) >> fmt->Ashift) - 1U) < 254U)
slouken@0
  1026
slouken@0
  1027
/* convert surface to be quickly alpha-blittable onto dest, if possible */
slouken@1895
  1028
static int
slouken@1895
  1029
RLEAlphaSurface(SDL_Surface * surface)
slouken@0
  1030
{
slouken@0
  1031
    SDL_Surface *dest;
slouken@0
  1032
    SDL_PixelFormat *df;
slouken@0
  1033
    int maxsize = 0;
slouken@0
  1034
    int max_opaque_run;
slouken@0
  1035
    int max_transl_run = 65535;
slouken@0
  1036
    unsigned masksum;
slouken@0
  1037
    Uint8 *rlebuf, *dst;
slouken@1895
  1038
    int (*copy_opaque) (void *, Uint32 *, int,
slouken@1895
  1039
                        SDL_PixelFormat *, SDL_PixelFormat *);
slouken@1895
  1040
    int (*copy_transl) (void *, Uint32 *, int,
slouken@1895
  1041
                        SDL_PixelFormat *, SDL_PixelFormat *);
slouken@0
  1042
slouken@0
  1043
    dest = surface->map->dst;
slouken@1895
  1044
    if (!dest)
slouken@1895
  1045
        return -1;
slouken@0
  1046
    df = dest->format;
slouken@1895
  1047
    if (surface->format->BitsPerPixel != 32)
slouken@1895
  1048
        return -1;              /* only 32bpp source supported */
slouken@0
  1049
slouken@0
  1050
    /* find out whether the destination is one we support,
slouken@0
  1051
       and determine the max size of the encoded result */
slouken@0
  1052
    masksum = df->Rmask | df->Gmask | df->Bmask;
slouken@1895
  1053
    switch (df->BytesPerPixel) {
slouken@0
  1054
    case 2:
slouken@1895
  1055
        /* 16bpp: only support 565 and 555 formats */
slouken@1895
  1056
        switch (masksum) {
slouken@1895
  1057
        case 0xffff:
slouken@1895
  1058
            if (df->Gmask == 0x07e0
slouken@1895
  1059
                || df->Rmask == 0x07e0 || df->Bmask == 0x07e0) {
slouken@1895
  1060
                copy_opaque = copy_opaque_16;
slouken@1895
  1061
                copy_transl = copy_transl_565;
slouken@1895
  1062
            } else
slouken@1895
  1063
                return -1;
slouken@1895
  1064
            break;
slouken@1895
  1065
        case 0x7fff:
slouken@1895
  1066
            if (df->Gmask == 0x03e0
slouken@1895
  1067
                || df->Rmask == 0x03e0 || df->Bmask == 0x03e0) {
slouken@1895
  1068
                copy_opaque = copy_opaque_16;
slouken@1895
  1069
                copy_transl = copy_transl_555;
slouken@1895
  1070
            } else
slouken@1895
  1071
                return -1;
slouken@1895
  1072
            break;
slouken@1895
  1073
        default:
slouken@1895
  1074
            return -1;
slouken@1895
  1075
        }
slouken@1895
  1076
        max_opaque_run = 255;   /* runs stored as bytes */
slouken@0
  1077
slouken@1895
  1078
        /* worst case is alternating opaque and translucent pixels,
slouken@1895
  1079
           with room for alignment padding between lines */
slouken@1895
  1080
        maxsize = surface->h * (2 + (4 + 2) * (surface->w + 1)) + 2;
slouken@1895
  1081
        break;
slouken@0
  1082
    case 4:
slouken@1895
  1083
        if (masksum != 0x00ffffff)
slouken@1895
  1084
            return -1;          /* requires unused high byte */
slouken@1895
  1085
        copy_opaque = copy_32;
slouken@1895
  1086
        copy_transl = copy_32;
slouken@1895
  1087
        max_opaque_run = 255;   /* runs stored as short ints */
slouken@0
  1088
slouken@1895
  1089
        /* worst case is alternating opaque and translucent pixels */
slouken@1895
  1090
        maxsize = surface->h * 2 * 4 * (surface->w + 1) + 4;
slouken@1895
  1091
        break;
slouken@0
  1092
    default:
slouken@1895
  1093
        return -1;              /* anything else unsupported right now */
slouken@0
  1094
    }
slouken@0
  1095
slouken@0
  1096
    maxsize += sizeof(RLEDestFormat);
slouken@1895
  1097
    rlebuf = (Uint8 *) SDL_malloc(maxsize);
slouken@1895
  1098
    if (!rlebuf) {
icculus@7037
  1099
        return SDL_OutOfMemory();
slouken@0
  1100
    }
slouken@0
  1101
    {
slouken@1895
  1102
        /* save the destination format so we can undo the encoding later */
slouken@1895
  1103
        RLEDestFormat *r = (RLEDestFormat *) rlebuf;
slouken@1895
  1104
        r->BytesPerPixel = df->BytesPerPixel;
slouken@5435
  1105
        r->Rmask = df->Rmask;
slouken@5435
  1106
        r->Gmask = df->Gmask;
slouken@5435
  1107
        r->Bmask = df->Bmask;
slouken@5435
  1108
        r->Amask = df->Amask;
slouken@1895
  1109
        r->Rloss = df->Rloss;
slouken@1895
  1110
        r->Gloss = df->Gloss;
slouken@1895
  1111
        r->Bloss = df->Bloss;
slouken@5435
  1112
        r->Aloss = df->Aloss;
slouken@1895
  1113
        r->Rshift = df->Rshift;
slouken@1895
  1114
        r->Gshift = df->Gshift;
slouken@1895
  1115
        r->Bshift = df->Bshift;
slouken@1895
  1116
        r->Ashift = df->Ashift;
slouken@0
  1117
    }
slouken@0
  1118
    dst = rlebuf + sizeof(RLEDestFormat);
slouken@0
  1119
slouken@0
  1120
    /* Do the actual encoding */
slouken@0
  1121
    {
slouken@1895
  1122
        int x, y;
slouken@1895
  1123
        int h = surface->h, w = surface->w;
slouken@1895
  1124
        SDL_PixelFormat *sf = surface->format;
slouken@1895
  1125
        Uint32 *src = (Uint32 *) surface->pixels;
slouken@1895
  1126
        Uint8 *lastline = dst;  /* end of last non-blank line */
slouken@0
  1127
slouken@1895
  1128
        /* opaque counts are 8 or 16 bits, depending on target depth */
slouken@7191
  1129
#define ADD_OPAQUE_COUNTS(n, m)         \
slouken@7191
  1130
    if(df->BytesPerPixel == 4) {        \
slouken@7191
  1131
        ((Uint16 *)dst)[0] = n;     \
slouken@7191
  1132
        ((Uint16 *)dst)[1] = m;     \
slouken@7191
  1133
        dst += 4;               \
slouken@7191
  1134
    } else {                \
slouken@7191
  1135
        dst[0] = n;             \
slouken@7191
  1136
        dst[1] = m;             \
slouken@7191
  1137
        dst += 2;               \
slouken@7191
  1138
    }
slouken@0
  1139
slouken@1895
  1140
        /* translucent counts are always 16 bit */
slouken@7191
  1141
#define ADD_TRANSL_COUNTS(n, m)     \
slouken@7191
  1142
    (((Uint16 *)dst)[0] = n, ((Uint16 *)dst)[1] = m, dst += 4)
slouken@0
  1143
slouken@1895
  1144
        for (y = 0; y < h; y++) {
slouken@1895
  1145
            int runstart, skipstart;
slouken@1895
  1146
            int blankline = 0;
slouken@1895
  1147
            /* First encode all opaque pixels of a scan line */
slouken@1895
  1148
            x = 0;
slouken@1895
  1149
            do {
slouken@1895
  1150
                int run, skip, len;
slouken@1895
  1151
                skipstart = x;
slouken@1895
  1152
                while (x < w && !ISOPAQUE(src[x], sf))
slouken@1895
  1153
                    x++;
slouken@1895
  1154
                runstart = x;
slouken@1895
  1155
                while (x < w && ISOPAQUE(src[x], sf))
slouken@1895
  1156
                    x++;
slouken@1895
  1157
                skip = runstart - skipstart;
slouken@1895
  1158
                if (skip == w)
slouken@1895
  1159
                    blankline = 1;
slouken@1895
  1160
                run = x - runstart;
slouken@1895
  1161
                while (skip > max_opaque_run) {
slouken@1895
  1162
                    ADD_OPAQUE_COUNTS(max_opaque_run, 0);
slouken@1895
  1163
                    skip -= max_opaque_run;
slouken@1895
  1164
                }
slouken@1895
  1165
                len = MIN(run, max_opaque_run);
slouken@1895
  1166
                ADD_OPAQUE_COUNTS(skip, len);
slouken@1895
  1167
                dst += copy_opaque(dst, src + runstart, len, sf, df);
slouken@1895
  1168
                runstart += len;
slouken@1895
  1169
                run -= len;
slouken@1895
  1170
                while (run) {
slouken@1895
  1171
                    len = MIN(run, max_opaque_run);
slouken@1895
  1172
                    ADD_OPAQUE_COUNTS(0, len);
slouken@1895
  1173
                    dst += copy_opaque(dst, src + runstart, len, sf, df);
slouken@1895
  1174
                    runstart += len;
slouken@1895
  1175
                    run -= len;
slouken@1895
  1176
                }
slouken@2735
  1177
            } while (x < w);
slouken@0
  1178
slouken@1895
  1179
            /* Make sure the next output address is 32-bit aligned */
slouken@1895
  1180
            dst += (uintptr_t) dst & 2;
slouken@0
  1181
slouken@1895
  1182
            /* Next, encode all translucent pixels of the same scan line */
slouken@1895
  1183
            x = 0;
slouken@1895
  1184
            do {
slouken@1895
  1185
                int run, skip, len;
slouken@1895
  1186
                skipstart = x;
slouken@1895
  1187
                while (x < w && !ISTRANSL(src[x], sf))
slouken@1895
  1188
                    x++;
slouken@1895
  1189
                runstart = x;
slouken@1895
  1190
                while (x < w && ISTRANSL(src[x], sf))
slouken@1895
  1191
                    x++;
slouken@1895
  1192
                skip = runstart - skipstart;
slouken@1895
  1193
                blankline &= (skip == w);
slouken@1895
  1194
                run = x - runstart;
slouken@1895
  1195
                while (skip > max_transl_run) {
slouken@1895
  1196
                    ADD_TRANSL_COUNTS(max_transl_run, 0);
slouken@1895
  1197
                    skip -= max_transl_run;
slouken@1895
  1198
                }
slouken@1895
  1199
                len = MIN(run, max_transl_run);
slouken@1895
  1200
                ADD_TRANSL_COUNTS(skip, len);
slouken@1895
  1201
                dst += copy_transl(dst, src + runstart, len, sf, df);
slouken@1895
  1202
                runstart += len;
slouken@1895
  1203
                run -= len;
slouken@1895
  1204
                while (run) {
slouken@1895
  1205
                    len = MIN(run, max_transl_run);
slouken@1895
  1206
                    ADD_TRANSL_COUNTS(0, len);
slouken@1895
  1207
                    dst += copy_transl(dst, src + runstart, len, sf, df);
slouken@1895
  1208
                    runstart += len;
slouken@1895
  1209
                    run -= len;
slouken@1895
  1210
                }
slouken@1895
  1211
                if (!blankline)
slouken@1895
  1212
                    lastline = dst;
slouken@2735
  1213
            } while (x < w);
slouken@0
  1214
slouken@1895
  1215
            src += surface->pitch >> 2;
slouken@1895
  1216
        }
slouken@1895
  1217
        dst = lastline;         /* back up past trailing blank lines */
slouken@1895
  1218
        ADD_OPAQUE_COUNTS(0, 0);
slouken@0
  1219
    }
slouken@0
  1220
slouken@0
  1221
#undef ADD_OPAQUE_COUNTS
slouken@0
  1222
#undef ADD_TRANSL_COUNTS
slouken@0
  1223
slouken@0
  1224
    /* Now that we have it encoded, release the original pixels */
slouken@2222
  1225
    if (!(surface->flags & SDL_PREALLOC)) {
slouken@1895
  1226
        SDL_free(surface->pixels);
slouken@1895
  1227
        surface->pixels = NULL;
slouken@0
  1228
    }
slouken@0
  1229
slouken@0
  1230
    /* realloc the buffer to release unused memory */
slouken@0
  1231
    {
slouken@1895
  1232
        Uint8 *p = SDL_realloc(rlebuf, dst - rlebuf);
slouken@1895
  1233
        if (!p)
slouken@1895
  1234
            p = rlebuf;
slouken@2257
  1235
        surface->map->data = p;
slouken@0
  1236
    }
slouken@0
  1237
slouken@0
  1238
    return 0;
slouken@0
  1239
}
slouken@0
  1240
slouken@1895
  1241
static Uint32
slouken@1895
  1242
getpix_8(Uint8 * srcbuf)
slouken@0
  1243
{
slouken@0
  1244
    return *srcbuf;
slouken@0
  1245
}
slouken@0
  1246
slouken@1895
  1247
static Uint32
slouken@1895
  1248
getpix_16(Uint8 * srcbuf)
slouken@0
  1249
{
slouken@1895
  1250
    return *(Uint16 *) srcbuf;
slouken@0
  1251
}
slouken@0
  1252
slouken@1895
  1253
static Uint32
slouken@1895
  1254
getpix_24(Uint8 * srcbuf)
slouken@0
  1255
{
icculus@1155
  1256
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
icculus@1155
  1257
    return srcbuf[0] + (srcbuf[1] << 8) + (srcbuf[2] << 16);
icculus@1155
  1258
#else
icculus@1155
  1259
    return (srcbuf[0] << 16) + (srcbuf[1] << 8) + srcbuf[2];
icculus@1155
  1260
#endif
slouken@0
  1261
}
slouken@0
  1262
slouken@1895
  1263
static Uint32
slouken@1895
  1264
getpix_32(Uint8 * srcbuf)
slouken@0
  1265
{
slouken@1895
  1266
    return *(Uint32 *) srcbuf;
slouken@0
  1267
}
slouken@0
  1268
slouken@1895
  1269
typedef Uint32(*getpix_func) (Uint8 *);
slouken@0
  1270
slouken@3162
  1271
static const getpix_func getpixes[4] = {
slouken@0
  1272
    getpix_8, getpix_16, getpix_24, getpix_32
slouken@0
  1273
};
slouken@0
  1274
slouken@1895
  1275
static int
slouken@1895
  1276
RLEColorkeySurface(SDL_Surface * surface)
slouken@0
  1277
{
slouken@1895
  1278
    Uint8 *rlebuf, *dst;
slouken@1895
  1279
    int maxn;
slouken@1895
  1280
    int y;
icculus@6389
  1281
    Uint8 *srcbuf, *lastline;
slouken@1895
  1282
    int maxsize = 0;
slouken@1895
  1283
    int bpp = surface->format->BytesPerPixel;
slouken@1895
  1284
    getpix_func getpix;
slouken@1895
  1285
    Uint32 ckey, rgbmask;
slouken@1895
  1286
    int w, h;
slouken@0
  1287
slouken@1895
  1288
    /* calculate the worst case size for the compressed surface */
slouken@1895
  1289
    switch (bpp) {
slouken@1895
  1290
    case 1:
slouken@1895
  1291
        /* worst case is alternating opaque and transparent pixels,
slouken@1895
  1292
           starting with an opaque pixel */
slouken@1895
  1293
        maxsize = surface->h * 3 * (surface->w / 2 + 1) + 2;
slouken@1895
  1294
        break;
slouken@1895
  1295
    case 2:
slouken@1895
  1296
    case 3:
slouken@1895
  1297
        /* worst case is solid runs, at most 255 pixels wide */
slouken@1895
  1298
        maxsize = surface->h * (2 * (surface->w / 255 + 1)
slouken@1895
  1299
                                + surface->w * bpp) + 2;
slouken@1895
  1300
        break;
slouken@1895
  1301
    case 4:
slouken@1895
  1302
        /* worst case is solid runs, at most 65535 pixels wide */
slouken@1895
  1303
        maxsize = surface->h * (4 * (surface->w / 65535 + 1)
slouken@1895
  1304
                                + surface->w * 4) + 4;
slouken@1895
  1305
        break;
slouken@1895
  1306
    }
slouken@0
  1307
slouken@1895
  1308
    rlebuf = (Uint8 *) SDL_malloc(maxsize);
slouken@1895
  1309
    if (rlebuf == NULL) {
icculus@7037
  1310
        return SDL_OutOfMemory();
slouken@1895
  1311
    }
slouken@0
  1312
slouken@1895
  1313
    /* Set up the conversion */
slouken@1895
  1314
    srcbuf = (Uint8 *) surface->pixels;
slouken@1895
  1315
    maxn = bpp == 4 ? 65535 : 255;
slouken@1895
  1316
    dst = rlebuf;
slouken@1895
  1317
    rgbmask = ~surface->format->Amask;
slouken@2262
  1318
    ckey = surface->map->info.colorkey & rgbmask;
slouken@1895
  1319
    lastline = dst;
slouken@1895
  1320
    getpix = getpixes[bpp - 1];
slouken@1895
  1321
    w = surface->w;
slouken@1895
  1322
    h = surface->h;
slouken@0
  1323
slouken@7191
  1324
#define ADD_COUNTS(n, m)            \
slouken@7191
  1325
    if(bpp == 4) {              \
slouken@7191
  1326
        ((Uint16 *)dst)[0] = n;     \
slouken@7191
  1327
        ((Uint16 *)dst)[1] = m;     \
slouken@7191
  1328
        dst += 4;               \
slouken@7191
  1329
    } else {                \
slouken@7191
  1330
        dst[0] = n;             \
slouken@7191
  1331
        dst[1] = m;             \
slouken@7191
  1332
        dst += 2;               \
slouken@7191
  1333
    }
slouken@0
  1334
slouken@1895
  1335
    for (y = 0; y < h; y++) {
slouken@1895
  1336
        int x = 0;
slouken@1895
  1337
        int blankline = 0;
slouken@1895
  1338
        do {
slouken@1895
  1339
            int run, skip, len;
slouken@1895
  1340
            int runstart;
slouken@1895
  1341
            int skipstart = x;
slouken@0
  1342
slouken@1895
  1343
            /* find run of transparent, then opaque pixels */
slouken@1895
  1344
            while (x < w && (getpix(srcbuf + x * bpp) & rgbmask) == ckey)
slouken@1895
  1345
                x++;
slouken@1895
  1346
            runstart = x;
slouken@1895
  1347
            while (x < w && (getpix(srcbuf + x * bpp) & rgbmask) != ckey)
slouken@1895
  1348
                x++;
slouken@1895
  1349
            skip = runstart - skipstart;
slouken@1895
  1350
            if (skip == w)
slouken@1895
  1351
                blankline = 1;
slouken@1895
  1352
            run = x - runstart;
slouken@0
  1353
slouken@1895
  1354
            /* encode segment */
slouken@1895
  1355
            while (skip > maxn) {
slouken@1895
  1356
                ADD_COUNTS(maxn, 0);
slouken@1895
  1357
                skip -= maxn;
slouken@1895
  1358
            }
slouken@1895
  1359
            len = MIN(run, maxn);
slouken@1895
  1360
            ADD_COUNTS(skip, len);
slouken@1895
  1361
            SDL_memcpy(dst, srcbuf + runstart * bpp, len * bpp);
slouken@1895
  1362
            dst += len * bpp;
slouken@1895
  1363
            run -= len;
slouken@1895
  1364
            runstart += len;
slouken@1895
  1365
            while (run) {
slouken@1895
  1366
                len = MIN(run, maxn);
slouken@1895
  1367
                ADD_COUNTS(0, len);
slouken@1895
  1368
                SDL_memcpy(dst, srcbuf + runstart * bpp, len * bpp);
slouken@1895
  1369
                dst += len * bpp;
slouken@1895
  1370
                runstart += len;
slouken@1895
  1371
                run -= len;
slouken@1895
  1372
            }
slouken@1895
  1373
            if (!blankline)
slouken@1895
  1374
                lastline = dst;
slouken@2735
  1375
        } while (x < w);
slouken@0
  1376
slouken@1895
  1377
        srcbuf += surface->pitch;
slouken@1895
  1378
    }
slouken@1895
  1379
    dst = lastline;             /* back up bast trailing blank lines */
slouken@1895
  1380
    ADD_COUNTS(0, 0);
slouken@0
  1381
slouken@0
  1382
#undef ADD_COUNTS
slouken@0
  1383
slouken@1895
  1384
    /* Now that we have it encoded, release the original pixels */
slouken@2222
  1385
    if (!(surface->flags & SDL_PREALLOC)) {
slouken@1895
  1386
        SDL_free(surface->pixels);
slouken@1895
  1387
        surface->pixels = NULL;
slouken@1895
  1388
    }
slouken@0
  1389
slouken@1895
  1390
    /* realloc the buffer to release unused memory */
slouken@1895
  1391
    {
slouken@1895
  1392
        /* If realloc returns NULL, the original block is left intact */
slouken@1895
  1393
        Uint8 *p = SDL_realloc(rlebuf, dst - rlebuf);
slouken@1895
  1394
        if (!p)
slouken@1895
  1395
            p = rlebuf;
slouken@2257
  1396
        surface->map->data = p;
slouken@1895
  1397
    }
slouken@0
  1398
slouken@1895
  1399
    return (0);
slouken@0
  1400
}
slouken@0
  1401
slouken@1895
  1402
int
slouken@1895
  1403
SDL_RLESurface(SDL_Surface * surface)
slouken@0
  1404
{
slouken@2266
  1405
    int flags;
slouken@0
  1406
slouken@1895
  1407
    /* Clear any previous RLE conversion */
slouken@1895
  1408
    if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
slouken@1895
  1409
        SDL_UnRLESurface(surface, 1);
slouken@1895
  1410
    }
slouken@0
  1411
slouken@1895
  1412
    /* We don't support RLE encoding of bitmaps */
slouken@1895
  1413
    if (surface->format->BitsPerPixel < 8) {
slouken@2266
  1414
        return -1;
slouken@1895
  1415
    }
slouken@0
  1416
slouken@2266
  1417
    /* Make sure the pixels are available */
slouken@2266
  1418
    if (!surface->pixels) {
slouken@2266
  1419
        return -1;
slouken@1895
  1420
    }
slouken@0
  1421
slouken@2266
  1422
    /* If we don't have colorkey or blending, nothing to do... */
slouken@2266
  1423
    flags = surface->map->info.flags;
slouken@2267
  1424
    if (!(flags & (SDL_COPY_COLORKEY | SDL_COPY_BLEND))) {
slouken@2266
  1425
        return -1;
slouken@1895
  1426
    }
slouken@0
  1427
slouken@2266
  1428
    /* Pass on combinations not supported */
slouken@2266
  1429
    if ((flags & SDL_COPY_MODULATE_COLOR) ||
slouken@2824
  1430
        ((flags & SDL_COPY_MODULATE_ALPHA) && surface->format->Amask) ||
slouken@5184
  1431
        (flags & (SDL_COPY_ADD | SDL_COPY_MOD)) ||
slouken@2266
  1432
        (flags & SDL_COPY_NEAREST)) {
slouken@2266
  1433
        return -1;
slouken@1895
  1434
    }
slouken@0
  1435
slouken@2266
  1436
    /* Encode and set up the blit */
slouken@2266
  1437
    if (!surface->format->Amask || !(flags & SDL_COPY_BLEND)) {
slouken@2266
  1438
        if (!surface->map->identity) {
slouken@2266
  1439
            return -1;
slouken@2266
  1440
        }
slouken@2266
  1441
        if (RLEColorkeySurface(surface) < 0) {
slouken@2266
  1442
            return -1;
slouken@2266
  1443
        }
slouken@2266
  1444
        surface->map->blit = SDL_RLEBlit;
slouken@2266
  1445
        surface->map->info.flags |= SDL_COPY_RLE_COLORKEY;
slouken@2266
  1446
    } else {
slouken@2266
  1447
        if (RLEAlphaSurface(surface) < 0) {
slouken@2266
  1448
            return -1;
slouken@2266
  1449
        }
slouken@2266
  1450
        surface->map->blit = SDL_RLEAlphaBlit;
slouken@2266
  1451
        surface->map->info.flags |= SDL_COPY_RLE_ALPHAKEY;
slouken@2266
  1452
    }
slouken@0
  1453
slouken@1895
  1454
    /* The surface is now accelerated */
slouken@1895
  1455
    surface->flags |= SDL_RLEACCEL;
slouken@0
  1456
slouken@1895
  1457
    return (0);
slouken@0
  1458
}
slouken@0
  1459
slouken@0
  1460
/*
slouken@0
  1461
 * Un-RLE a surface with pixel alpha
slouken@0
  1462
 * This may not give back exactly the image before RLE-encoding; all
philipp@7128
  1463
 * completely transparent pixels will be lost, and color and alpha depth
slouken@0
  1464
 * may have been reduced (when encoding for 16bpp targets).
slouken@0
  1465
 */
slouken@1895
  1466
static SDL_bool
slouken@1895
  1467
UnRLEAlpha(SDL_Surface * surface)
slouken@0
  1468
{
slouken@0
  1469
    Uint8 *srcbuf;
slouken@0
  1470
    Uint32 *dst;
slouken@0
  1471
    SDL_PixelFormat *sf = surface->format;
slouken@2257
  1472
    RLEDestFormat *df = surface->map->data;
slouken@1895
  1473
    int (*uncopy_opaque) (Uint32 *, void *, int,
slouken@1895
  1474
                          RLEDestFormat *, SDL_PixelFormat *);
slouken@1895
  1475
    int (*uncopy_transl) (Uint32 *, void *, int,
slouken@1895
  1476
                          RLEDestFormat *, SDL_PixelFormat *);
slouken@0
  1477
    int w = surface->w;
slouken@0
  1478
    int bpp = df->BytesPerPixel;
slouken@0
  1479
slouken@1895
  1480
    if (bpp == 2) {
slouken@1895
  1481
        uncopy_opaque = uncopy_opaque_16;
slouken@1895
  1482
        uncopy_transl = uncopy_transl_16;
slouken@0
  1483
    } else {
slouken@1895
  1484
        uncopy_opaque = uncopy_transl = uncopy_32;
slouken@0
  1485
    }
slouken@0
  1486
slouken@1336
  1487
    surface->pixels = SDL_malloc(surface->h * surface->pitch);
slouken@1895
  1488
    if (!surface->pixels) {
slouken@1895
  1489
        return (SDL_FALSE);
slouken@944
  1490
    }
slouken@0
  1491
    /* fill background with transparent pixels */
slouken@1336
  1492
    SDL_memset(surface->pixels, 0, surface->h * surface->pitch);
slouken@0
  1493
slouken@0
  1494
    dst = surface->pixels;
slouken@1895
  1495
    srcbuf = (Uint8 *) (df + 1);
slouken@1895
  1496
    for (;;) {
slouken@1895
  1497
        /* copy opaque pixels */
slouken@1895
  1498
        int ofs = 0;
slouken@1895
  1499
        do {
slouken@1895
  1500
            unsigned run;
slouken@1895
  1501
            if (bpp == 2) {
slouken@1895
  1502
                ofs += srcbuf[0];
slouken@1895
  1503
                run = srcbuf[1];
slouken@1895
  1504
                srcbuf += 2;
slouken@1895
  1505
            } else {
slouken@1895
  1506
                ofs += ((Uint16 *) srcbuf)[0];
slouken@1895
  1507
                run = ((Uint16 *) srcbuf)[1];
slouken@1895
  1508
                srcbuf += 4;
slouken@1895
  1509
            }
slouken@1895
  1510
            if (run) {
slouken@1895
  1511
                srcbuf += uncopy_opaque(dst + ofs, srcbuf, run, df, sf);
slouken@1895
  1512
                ofs += run;
slouken@1895
  1513
            } else if (!ofs)
slouken@1895
  1514
                return (SDL_TRUE);
slouken@2735
  1515
        } while (ofs < w);
slouken@0
  1516
slouken@1895
  1517
        /* skip padding if needed */
slouken@1895
  1518
        if (bpp == 2)
slouken@1895
  1519
            srcbuf += (uintptr_t) srcbuf & 2;
slouken@1895
  1520
slouken@1895
  1521
        /* copy translucent pixels */
slouken@1895
  1522
        ofs = 0;
slouken@1895
  1523
        do {
slouken@1895
  1524
            unsigned run;
slouken@1895
  1525
            ofs += ((Uint16 *) srcbuf)[0];
slouken@1895
  1526
            run = ((Uint16 *) srcbuf)[1];
slouken@1895
  1527
            srcbuf += 4;
slouken@1895
  1528
            if (run) {
slouken@1895
  1529
                srcbuf += uncopy_transl(dst + ofs, srcbuf, run, df, sf);
slouken@1895
  1530
                ofs += run;
slouken@1895
  1531
            }
slouken@2735
  1532
        } while (ofs < w);
slouken@1895
  1533
        dst += surface->pitch >> 2;
slouken@0
  1534
    }
slouken@944
  1535
    /* Make the compiler happy */
slouken@1895
  1536
    return (SDL_TRUE);
slouken@0
  1537
}
slouken@0
  1538
slouken@1895
  1539
void
slouken@1895
  1540
SDL_UnRLESurface(SDL_Surface * surface, int recode)
slouken@0
  1541
{
slouken@2266
  1542
    if (surface->flags & SDL_RLEACCEL) {
slouken@1895
  1543
        surface->flags &= ~SDL_RLEACCEL;
slouken@0
  1544
slouken@2222
  1545
        if (recode && !(surface->flags & SDL_PREALLOC)) {
slouken@2266
  1546
            if (surface->map->info.flags & SDL_COPY_RLE_COLORKEY) {
slouken@1895
  1547
                SDL_Rect full;
slouken@0
  1548
slouken@1895
  1549
                /* re-create the original surface */
slouken@1895
  1550
                surface->pixels = SDL_malloc(surface->h * surface->pitch);
slouken@1895
  1551
                if (!surface->pixels) {
slouken@1895
  1552
                    /* Oh crap... */
slouken@1895
  1553
                    surface->flags |= SDL_RLEACCEL;
slouken@1895
  1554
                    return;
slouken@1895
  1555
                }
slouken@0
  1556
philipp@7128
  1557
                /* fill it with the background color */
slouken@2262
  1558
                SDL_FillRect(surface, NULL, surface->map->info.colorkey);
slouken@0
  1559
slouken@1895
  1560
                /* now render the encoded surface */
slouken@1895
  1561
                full.x = full.y = 0;
slouken@1895
  1562
                full.w = surface->w;
slouken@1895
  1563
                full.h = surface->h;
slouken@1895
  1564
                SDL_RLEBlit(surface, &full, surface, &full);
slouken@1895
  1565
            } else {
slouken@1895
  1566
                if (!UnRLEAlpha(surface)) {
slouken@1895
  1567
                    /* Oh crap... */
slouken@1895
  1568
                    surface->flags |= SDL_RLEACCEL;
slouken@1895
  1569
                    return;
slouken@1895
  1570
                }
slouken@1895
  1571
            }
slouken@1895
  1572
        }
slouken@2267
  1573
        surface->map->info.flags &=
slouken@2798
  1574
            ~(SDL_COPY_RLE_COLORKEY | SDL_COPY_RLE_ALPHAKEY);
slouken@0
  1575
slouken@7719
  1576
        SDL_free(surface->map->data);
slouken@7719
  1577
        surface->map->data = NULL;
slouken@0
  1578
    }
slouken@0
  1579
}
slouken@0
  1580
slouken@1895
  1581
/* vi: set ts=4 sw=4 expandtab: */