Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
Added slow but complete blit fallback
Don't try to RLE encode surfaces that have alpha channel and alpha modulation
Don't turn on blending when converting an RGB surface to RGBA format
Do turn on blending when converting colorkey to alpha channel
  • Loading branch information
slouken committed Dec 2, 2008
1 parent 84ecbe4 commit 4f5944b
Show file tree
Hide file tree
Showing 6 changed files with 227 additions and 34 deletions.
1 change: 1 addition & 0 deletions src/video/SDL_RLEaccel.c
Expand Up @@ -1819,6 +1819,7 @@ SDL_RLESurface(SDL_Surface * surface)

/* Pass on combinations not supported */
if ((flags & SDL_COPY_MODULATE_COLOR) ||
((flags & SDL_COPY_MODULATE_ALPHA) && surface->format->Amask) ||
(flags & (SDL_COPY_ADD | SDL_COPY_MOD)) ||
(flags & SDL_COPY_NEAREST)) {
return -1;
Expand Down
10 changes: 10 additions & 0 deletions src/video/SDL_blit.c
Expand Up @@ -26,6 +26,7 @@
#include "SDL_blit.h"
#include "SDL_blit_auto.h"
#include "SDL_blit_copy.h"
#include "SDL_blit_slow.h"
#include "SDL_RLEaccel_c.h"
#include "SDL_pixels_c.h"

Expand Down Expand Up @@ -269,6 +270,15 @@ SDL_CalculateBlit(SDL_Surface * surface)
SDL_ChooseBlitFunc(src_format, dst_format, map->info.flags,
SDL_GeneratedBlitFuncTable);
}
#ifndef TEST_SLOW_BLIT
if (blit == NULL)
#endif
{
if (surface->format->BytesPerPixel > 1
&& dst->format->BytesPerPixel > 1) {
blit = SDL_Blit_Slow;
}
}
map->data = blit;

/* Make sure we have a blit function */
Expand Down
58 changes: 33 additions & 25 deletions src/video/SDL_blit.h
Expand Up @@ -165,7 +165,7 @@ do { \
\
case 3: { \
Uint8 *B = (Uint8 *)(buf); \
if(SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
if (SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
Pixel = B[0] + (B[1] << 8) + (B[2] << 16); \
} else { \
Pixel = (B[0] << 16) + (B[1] << 8) + B[2]; \
Expand All @@ -178,38 +178,42 @@ do { \
break; \
\
default: \
Pixel = 0; /* appease gcc */ \
Pixel; /* stop gcc complaints */ \
break; \
} \
} while(0)
} while (0)

#define DISEMBLE_RGB(buf, bpp, fmt, Pixel, r, g, b) \
do { \
switch (bpp) { \
case 2: \
Pixel = *((Uint16 *)(buf)); \
RGB_FROM_PIXEL(Pixel, fmt, r, g, b); \
break; \
\
case 3: { \
Uint8 *B = (Uint8 *)buf; \
if(SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
Pixel = B[0] + (B[1] << 8) + (B[2] << 16); \
case 3: { \
if (SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
r = *((buf)+fmt->Rshift/8); \
g = *((buf)+fmt->Gshift/8); \
b = *((buf)+fmt->Bshift/8); \
} else { \
Pixel = (B[0] << 16) + (B[1] << 8) + B[2]; \
r = *((buf)+2-fmt->Rshift/8); \
g = *((buf)+2-fmt->Gshift/8); \
b = *((buf)+2-fmt->Bshift/8); \
} \
} \
break; \
\
case 4: \
Pixel = *((Uint32 *)(buf)); \
RGB_FROM_PIXEL(Pixel, fmt, r, g, b); \
break; \
\
default: \
Pixel = 0; /* prevent gcc from complaining */ \
default: \
Pixel; /* stop gcc complaints */ \
break; \
} \
RGB_FROM_PIXEL(Pixel, fmt, r, g, b); \
} while(0)
} while (0)

/* Assemble R-G-B values into a specified pixel format and store them */
#define PIXEL_FROM_RGB(Pixel, fmt, r, g, b) \
Expand Down Expand Up @@ -242,7 +246,7 @@ do { \
break; \
\
case 3: { \
if(SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
if (SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
*((buf)+fmt->Rshift/8) = r; \
*((buf)+fmt->Gshift/8) = g; \
*((buf)+fmt->Bshift/8) = b; \
Expand Down Expand Up @@ -277,7 +281,7 @@ do { \
break; \
\
case 3: { \
if(SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
if (SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
*((buf)+fmt->Rshift/8) = r; \
*((buf)+fmt->Gshift/8) = g; \
*((buf)+fmt->Bshift/8) = b; \
Expand Down Expand Up @@ -342,29 +346,33 @@ do { \
switch (bpp) { \
case 2: \
Pixel = *((Uint16 *)(buf)); \
RGBA_FROM_PIXEL(Pixel, fmt, r, g, b, a); \
break; \
\
case 3: {/* FIXME: broken code (no alpha) */ \
Uint8 *b = (Uint8 *)buf; \
if(SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
Pixel = b[0] + (b[1] << 8) + (b[2] << 16); \
case 3: { \
if (SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
r = *((buf)+fmt->Rshift/8); \
g = *((buf)+fmt->Gshift/8); \
b = *((buf)+fmt->Bshift/8); \
} else { \
Pixel = (b[0] << 16) + (b[1] << 8) + b[2]; \
r = *((buf)+2-fmt->Rshift/8); \
g = *((buf)+2-fmt->Gshift/8); \
b = *((buf)+2-fmt->Bshift/8); \
} \
a = 0xFF; \
} \
break; \
\
case 4: \
Pixel = *((Uint32 *)(buf)); \
RGBA_FROM_PIXEL(Pixel, fmt, r, g, b, a); \
break; \
\
default: \
Pixel = 0; /* stop gcc complaints */ \
Pixel; /* stop gcc complaints */ \
break; \
} \
RGBA_FROM_PIXEL(Pixel, fmt, r, g, b, a); \
Pixel &= ~fmt->Amask; \
} while(0)
} while (0)

/* FIXME: this isn't correct, especially for Alpha (maximum != 255) */
#define PIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a) \
Expand All @@ -385,8 +393,8 @@ do { \
} \
break; \
\
case 3: { /* FIXME: broken code (no alpha) */ \
if(SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
case 3: { \
if (SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
*((buf)+fmt->Rshift/8) = r; \
*((buf)+fmt->Gshift/8) = g; \
*((buf)+fmt->Bshift/8) = b; \
Expand Down
139 changes: 139 additions & 0 deletions src/video/SDL_blit_slow.c
Expand Up @@ -27,5 +27,144 @@
/* The ONE TRUE BLITTER
* This puppy has to handle all the unoptimized cases - yes, it's slow.
*/
void
SDL_Blit_Slow(SDL_BlitInfo * info)
{
const int flags = info->flags;
const Uint32 modulateR = info->r;
const Uint32 modulateG = info->g;
const Uint32 modulateB = info->b;
const Uint32 modulateA = info->a;
Uint32 srcpixel;
Uint32 srcR, srcG, srcB, srcA;
Uint32 dstpixel;
Uint32 dstR, dstG, dstB, dstA;
int srcy, srcx;
int posy, posx;
int incy, incx;
SDL_PixelFormat *src_fmt = info->src_fmt;
SDL_PixelFormat *dst_fmt = info->dst_fmt;
int srcbpp = src_fmt->BytesPerPixel;
int dstbpp = dst_fmt->BytesPerPixel;

srcy = 0;
posy = 0;
incy = (info->src_h << 16) / info->dst_h;
incx = (info->src_w << 16) / info->dst_w;

while (info->dst_h--) {
Uint8 *src;
Uint8 *dst = (Uint8 *) info->dst;
int n = info->dst_w;
srcx = -1;
posx = 0x10000L;
while (posy >= 0x10000L) {
++srcy;
posy -= 0x10000L;
}
while (n--) {
if (posx >= 0x10000L) {
while (posx >= 0x10000L) {
++srcx;
posx -= 0x10000L;
}
src =
(info->src + (srcy * info->src_pitch) + (srcx * srcbpp));
}
if (src_fmt->Amask) {
DISEMBLE_RGBA(src, srcbpp, src_fmt, srcpixel, srcR, srcG,
srcB, srcA);
} else {
DISEMBLE_RGB(src, srcbpp, src_fmt, srcpixel, srcR, srcG,
srcB);
srcA = 0xFF;
}
if (flags & SDL_COPY_COLORKEY) {
/* srcpixel isn't set for 24 bpp */
if (srcbpp == 24) {
srcpixel = (srcR << src_fmt->Rshift) |
(srcG << src_fmt->Gshift) | (srcB << src_fmt->Bshift);
}
if (srcpixel == info->colorkey) {
posx += incx;
dst += dstbpp;
continue;
}
}
if (dst_fmt->Amask) {
DISEMBLE_RGBA(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG,
dstB, dstA);
} else {
DISEMBLE_RGB(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG,
dstB);
dstA = 0xFF;
}

if (flags & SDL_COPY_MODULATE_COLOR) {
srcR = (srcR * modulateR) / 255;
srcG = (srcG * modulateG) / 255;
srcB = (srcB * modulateB) / 255;
}
if (flags & SDL_COPY_MODULATE_ALPHA) {
srcA = (srcA * modulateA) / 255;
}
if (flags & (SDL_COPY_BLEND | SDL_COPY_ADD)) {
/* This goes away if we ever use premultiplied alpha */
if (srcA < 255) {
srcR = (srcR * srcA) / 255;
srcG = (srcG * srcA) / 255;
srcB = (srcB * srcA) / 255;
}
}
switch (flags &
(SDL_COPY_MASK | SDL_COPY_BLEND | SDL_COPY_ADD |
SDL_COPY_MOD)) {
case 0:
dstR = srcR;
dstG = srcG;
dstB = srcB;
dstA = srcA;
break;
case SDL_COPY_MASK:
if (srcA) {
dstR = srcR;
dstG = srcG;
dstB = srcB;
}
break;
case SDL_COPY_BLEND:
dstR = srcR + ((255 - srcA) * dstR) / 255;
dstG = srcG + ((255 - srcA) * dstG) / 255;
dstB = srcB + ((255 - srcA) * dstB) / 255;
break;
case SDL_COPY_ADD:
dstR = srcR + dstR;
if (dstR > 255)
dstR = 255;
dstG = srcG + dstG;
if (dstG > 255)
dstG = 255;
dstB = srcB + dstB;
if (dstB > 255)
dstB = 255;
break;
case SDL_COPY_MOD:
dstR = (srcR * dstR) / 255;
dstG = (srcG * dstG) / 255;
dstB = (srcB * dstB) / 255;
break;
}
if (dst_fmt->Amask) {
ASSEMBLE_RGBA(dst, dstbpp, dst_fmt, dstR, dstG, dstB, dstA);
} else {
ASSEMBLE_RGB(dst, dstbpp, dst_fmt, dstR, dstG, dstB);
}
posx += incx;
dst += dstbpp;
}
posy += incy;
info->dst += info->dst_pitch;
}
}

/* vi: set ts=4 sw=4 expandtab: */
26 changes: 26 additions & 0 deletions src/video/SDL_blit_slow.h
@@ -0,0 +1,26 @@
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"

extern void SDL_Blit_Slow(SDL_BlitInfo * info);

/* vi: set ts=4 sw=4 expandtab: */
27 changes: 18 additions & 9 deletions src/video/SDL_surface.c
Expand Up @@ -336,6 +336,7 @@ SDL_ConvertColorkeyToAlpha(SDL_Surface * surface)
SDL_UnlockSurface(surface);

SDL_SetColorKey(surface, 0, 0);
SDL_SetSurfaceBlendMode(surface, SDL_TEXTUREBLENDMODE_BLEND);
}

int
Expand Down Expand Up @@ -808,29 +809,37 @@ SDL_ConvertSurface(SDL_Surface * surface, SDL_PixelFormat * format,
SDL_LowerBlit(surface, &bounds, convert, &bounds);

/* Clean up the original surface, and update converted surface */
SDL_SetClipRect(convert, &surface->clip_rect);
convert->map->info.r = surface->map->info.r;
convert->map->info.g = surface->map->info.g;
convert->map->info.b = surface->map->info.b;
convert->map->info.a = surface->map->info.a;
convert->map->info.flags =
(copy_flags &
~(SDL_COPY_COLORKEY | SDL_COPY_BLEND
| SDL_COPY_RLE_DESIRED | SDL_COPY_RLE_COLORKEY |
SDL_COPY_RLE_ALPHAKEY));
surface->map->info.flags = copy_flags;
if (copy_flags & SDL_COPY_COLORKEY) {
Uint8 keyR, keyG, keyB, keyA;

SDL_GetRGBA(surface->map->info.colorkey, surface->format, &keyR,
&keyG, &keyB, &keyA);
SDL_SetColorKey(convert, 1,
SDL_MapRGBA(convert->format, keyR, keyG, keyB, keyA));
/* This is needed when converting for 3D texture upload */
SDL_ConvertColorkeyToAlpha(convert);
}
convert->map->info.r = surface->map->info.r;
convert->map->info.g = surface->map->info.g;
convert->map->info.b = surface->map->info.b;
convert->map->info.a = surface->map->info.a;
convert->map->info.flags = copy_flags;
surface->map->info.flags = copy_flags;
SDL_SetClipRect(convert, &surface->clip_rect);

/* Enable alpha blending by default if the new surface has an
* alpha channel or alpha modulation */
if (format->Amask || (copy_flags & SDL_COPY_MODULATE_ALPHA)) {
if ((surface->format->Amask && format->Amask) ||
(copy_flags & SDL_COPY_MODULATE_ALPHA)) {
SDL_SetSurfaceBlendMode(convert, SDL_TEXTUREBLENDMODE_BLEND);
}
SDL_SetSurfaceRLE(convert, (flags & SDL_RLEACCEL));
if ((copy_flags & SDL_COPY_RLE_DESIRED) || (flags & SDL_RLEACCEL)) {
SDL_SetSurfaceRLE(convert, SDL_RLEACCEL);
}

/* We're ready to go! */
return (convert);
Expand Down

0 comments on commit 4f5944b

Please sign in to comment.