Mercurial > sdl-ios-xcode
diff src/video/SDL_blit_A.c @ 0:74212992fb08
Initial revision
author | Sam Lantinga <slouken@lokigames.com> |
---|---|
date | Thu, 26 Apr 2001 16:45:43 +0000 |
parents | |
children | cf2af46e9e2a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/video/SDL_blit_A.c Thu Apr 26 16:45:43 2001 +0000 @@ -0,0 +1,633 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@devolution.com +*/ + +#ifdef SAVE_RCSID +static char rcsid = + "@(#) $Id$"; +#endif + +#include <stdio.h> + +#include "SDL_types.h" +#include "SDL_video.h" +#include "SDL_blit.h" + +/* Functions to perform alpha blended blitting */ + +/* N->1 blending with per-surface alpha */ +static void BlitNto1SurfaceAlpha(SDL_BlitInfo *info) +{ + int width = info->d_width; + int height = info->d_height; + Uint8 *src = info->s_pixels; + int srcskip = info->s_skip; + Uint8 *dst = info->d_pixels; + int dstskip = info->d_skip; + Uint8 *palmap = info->table; + SDL_PixelFormat *srcfmt = info->src; + SDL_PixelFormat *dstfmt = info->dst; + int srcbpp = srcfmt->BytesPerPixel; + + const unsigned A = srcfmt->alpha; + + while ( height-- ) { + DUFFS_LOOP4( + { + Uint32 pixel; + unsigned sR; + unsigned sG; + unsigned sB; + unsigned dR; + unsigned dG; + unsigned dB; + DISEMBLE_RGB(src, srcbpp, srcfmt, pixel, sR, sG, sB); + dR = dstfmt->palette->colors[*dst].r; + dG = dstfmt->palette->colors[*dst].g; + dB = dstfmt->palette->colors[*dst].b; + ALPHA_BLEND(sR, sG, sB, A, dR, dG, dB); + dR &= 0xff; + dG &= 0xff; + dB &= 0xff; + /* Pack RGB into 8bit pixel */ + if ( palmap == NULL ) { + *dst =((dR>>5)<<(3+2))| + ((dG>>5)<<(2))| + ((dB>>6)<<(0)); + } else { + *dst = palmap[((dR>>5)<<(3+2))| + ((dG>>5)<<(2)) | + ((dB>>6)<<(0))]; + } + dst++; + src += srcbpp; + }, + width); + src += srcskip; + dst += dstskip; + } +} + +/* N->1 blending with pixel alpha */ +static void BlitNto1PixelAlpha(SDL_BlitInfo *info) +{ + int width = info->d_width; + int height = info->d_height; + Uint8 *src = info->s_pixels; + int srcskip = info->s_skip; + Uint8 *dst = info->d_pixels; + int dstskip = info->d_skip; + Uint8 *palmap = info->table; + SDL_PixelFormat *srcfmt = info->src; + SDL_PixelFormat *dstfmt = info->dst; + int srcbpp = srcfmt->BytesPerPixel; + + /* FIXME: fix alpha bit field expansion here too? */ + while ( height-- ) { + DUFFS_LOOP4( + { + Uint32 pixel; + unsigned sR; + unsigned sG; + unsigned sB; + unsigned sA; + unsigned dR; + unsigned dG; + unsigned dB; + DISEMBLE_RGBA(src,srcbpp,srcfmt,pixel,sR,sG,sB,sA); + dR = dstfmt->palette->colors[*dst].r; + dG = dstfmt->palette->colors[*dst].g; + dB = dstfmt->palette->colors[*dst].b; + ALPHA_BLEND(sR, sG, sB, sA, dR, dG, dB); + dR &= 0xff; + dG &= 0xff; + dB &= 0xff; + /* Pack RGB into 8bit pixel */ + if ( palmap == NULL ) { + *dst =((dR>>5)<<(3+2))| + ((dG>>5)<<(2))| + ((dB>>6)<<(0)); + } else { + *dst = palmap[((dR>>5)<<(3+2))| + ((dG>>5)<<(2)) | + ((dB>>6)<<(0)) ]; + } + dst++; + src += srcbpp; + }, + width); + src += srcskip; + dst += dstskip; + } +} + +/* colorkeyed N->1 blending with per-surface alpha */ +static void BlitNto1SurfaceAlphaKey(SDL_BlitInfo *info) +{ + int width = info->d_width; + int height = info->d_height; + Uint8 *src = info->s_pixels; + int srcskip = info->s_skip; + Uint8 *dst = info->d_pixels; + int dstskip = info->d_skip; + Uint8 *palmap = info->table; + SDL_PixelFormat *srcfmt = info->src; + SDL_PixelFormat *dstfmt = info->dst; + int srcbpp = srcfmt->BytesPerPixel; + Uint32 ckey = srcfmt->colorkey; + + const int A = srcfmt->alpha; + + while ( height-- ) { + DUFFS_LOOP( + { + Uint32 pixel; + unsigned sR; + unsigned sG; + unsigned sB; + unsigned dR; + unsigned dG; + unsigned dB; + DISEMBLE_RGB(src, srcbpp, srcfmt, pixel, sR, sG, sB); + if ( pixel != ckey ) { + dR = dstfmt->palette->colors[*dst].r; + dG = dstfmt->palette->colors[*dst].g; + dB = dstfmt->palette->colors[*dst].b; + ALPHA_BLEND(sR, sG, sB, A, dR, dG, dB); + dR &= 0xff; + dG &= 0xff; + dB &= 0xff; + /* Pack RGB into 8bit pixel */ + if ( palmap == NULL ) { + *dst =((dR>>5)<<(3+2))| + ((dG>>5)<<(2)) | + ((dB>>6)<<(0)); + } else { + *dst = palmap[((dR>>5)<<(3+2))| + ((dG>>5)<<(2)) | + ((dB>>6)<<(0)) ]; + } + } + dst++; + src += srcbpp; + }, + width); + src += srcskip; + dst += dstskip; + } +} + +/* fast RGB888->(A)RGB888 blending with surface alpha */ +static void BlitRGBtoRGBSurfaceAlpha(SDL_BlitInfo *info) +{ + int width = info->d_width; + int height = info->d_height; + Uint32 *srcp = (Uint32 *)info->s_pixels; + int srcskip = info->s_skip >> 2; + Uint32 *dstp = (Uint32 *)info->d_pixels; + int dstskip = info->d_skip >> 2; + SDL_PixelFormat *srcfmt = info->src; + unsigned alpha = srcfmt->alpha; + + while(height--) { + DUFFS_LOOP4({ + Uint32 s; + Uint32 d; + Uint32 s1; + Uint32 d1; + s = *srcp; + d = *dstp; + s1 = s & 0xff00ff; + d1 = d & 0xff00ff; + d1 = (d1 + ((s1 - d1) * alpha >> 8)) & 0xff00ff; + s &= 0xff00; + d &= 0xff00; + d = (d + ((s - d) * alpha >> 8)) & 0xff00; + *dstp = d1 | d | 0xff000000; + ++srcp; + ++dstp; + }, width); + srcp += srcskip; + dstp += dstskip; + } +} + +/* fast ARGB888->(A)RGB888 blending with pixel alpha */ +static void BlitRGBtoRGBPixelAlpha(SDL_BlitInfo *info) +{ + int width = info->d_width; + int height = info->d_height; + Uint32 *srcp = (Uint32 *)info->s_pixels; + int srcskip = info->s_skip >> 2; + Uint32 *dstp = (Uint32 *)info->d_pixels; + int dstskip = info->d_skip >> 2; + + while(height--) { + DUFFS_LOOP4({ + Uint32 dalpha; + Uint32 d; + Uint32 s1; + Uint32 d1; + Uint32 s = *srcp; + Uint32 alpha = s >> 24; + /* FIXME: Here we special-case opaque alpha since the + compositioning used (>>8 instead of /255) doesn't handle + it correctly. Also special-case alpha=0 for speed? + Benchmark this! */ + if(alpha == SDL_ALPHA_OPAQUE) { + *dstp = (s & 0x00ffffff) | (*dstp & 0xff000000); + } else { + /* + * take out the middle component (green), and process + * the other two in parallel. One multiply less. + */ + d = *dstp; + dalpha = d & 0xff000000; + s1 = s & 0xff00ff; + d1 = d & 0xff00ff; + d1 = (d1 + ((s1 - d1) * alpha >> 8)) & 0xff00ff; + s &= 0xff00; + d &= 0xff00; + d = (d + ((s - d) * alpha >> 8)) & 0xff00; + *dstp = d1 | d | dalpha; + } + ++srcp; + ++dstp; + }, width); + srcp += srcskip; + dstp += dstskip; + } +} + +/* fast RGB565->RGB565 blending with surface alpha */ +static void Blit565to565SurfaceAlpha(SDL_BlitInfo *info) +{ + int width = info->d_width; + int height = info->d_height; + Uint16 *srcp = (Uint16 *)info->s_pixels; + int srcskip = info->s_skip >> 1; + Uint16 *dstp = (Uint16 *)info->d_pixels; + int dstskip = info->d_skip >> 1; + unsigned alpha = info->src->alpha >> 3; /* downscale alpha to 5 bits */ + + while(height--) { + DUFFS_LOOP4({ + Uint32 s = *srcp++; + Uint32 d = *dstp; + /* + * shift out the middle component (green) to the high 16 + * bits, and process all three RGB components at the same + * time. + */ + s = (s | s << 16) & 0x07e0f81f; + d = (d | d << 16) & 0x07e0f81f; + d += (s - d) * alpha >> 5; + d &= 0x07e0f81f; + *dstp++ = d | d >> 16; + }, width); + srcp += srcskip; + dstp += dstskip; + } +} + +/* fast RGB555->RGB555 blending with surface alpha */ +static void Blit555to555SurfaceAlpha(SDL_BlitInfo *info) +{ + int width = info->d_width; + int height = info->d_height; + Uint16 *srcp = (Uint16 *)info->s_pixels; + int srcskip = info->s_skip >> 1; + Uint16 *dstp = (Uint16 *)info->d_pixels; + int dstskip = info->d_skip >> 1; + unsigned alpha = info->src->alpha >> 3; /* downscale alpha to 5 bits */ + + while(height--) { + DUFFS_LOOP4({ + Uint32 s = *srcp++; + Uint32 d = *dstp; + /* + * shift out the middle component (green) to the high 16 + * bits, and process all three RGB components at the same + * time. + */ + s = (s | s << 16) & 0x03e07c1f; + d = (d | d << 16) & 0x03e07c1f; + d += (s - d) * alpha >> 5; + d &= 0x03e07c1f; + *dstp++ = d | d >> 16; + }, width); + srcp += srcskip; + dstp += dstskip; + } +} + +/* fast ARGB8888->RGB565 blending with pixel alpha */ +static void BlitARGBto565PixelAlpha(SDL_BlitInfo *info) +{ + int width = info->d_width; + int height = info->d_height; + Uint32 *srcp = (Uint32 *)info->s_pixels; + int srcskip = info->s_skip >> 2; + Uint16 *dstp = (Uint16 *)info->d_pixels; + int dstskip = info->d_skip >> 1; + + while(height--) { + DUFFS_LOOP4({ + Uint32 s = *srcp; + unsigned alpha = s >> 27; /* downscale alpha to 5 bits */ + /* FIXME: Here we special-case opaque alpha since the + compositioning used (>>8 instead of /255) doesn't handle + it correctly. Also special-case alpha=0 for speed? + Benchmark this! */ + if(alpha == (SDL_ALPHA_OPAQUE >> 3)) { + *dstp = (s >> 8 & 0xf800) + (s >> 5 & 0x7e0) + + (s >> 3 & 0x1f); + } else { + Uint32 d = *dstp; + /* + * convert source and destination to G0RAB65565 + * and blend all components at the same time + */ + s = ((s & 0xfc00) << 11) + (s >> 8 & 0xf800) + + (s >> 3 & 0x1f); + d = (d | d << 16) & 0x07e0f81f; + d += (s - d) * alpha >> 5; + d &= 0x07e0f81f; + *dstp = d | d >> 16; + } + srcp++; + dstp++; + }, width); + srcp += srcskip; + dstp += dstskip; + } +} + +/* fast ARGB8888->RGB555 blending with pixel alpha */ +static void BlitARGBto555PixelAlpha(SDL_BlitInfo *info) +{ + int width = info->d_width; + int height = info->d_height; + Uint32 *srcp = (Uint32 *)info->s_pixels; + int srcskip = info->s_skip >> 2; + Uint16 *dstp = (Uint16 *)info->d_pixels; + int dstskip = info->d_skip >> 1; + + while(height--) { + DUFFS_LOOP4({ + unsigned alpha; + Uint32 s = *srcp; + alpha = s >> 27; /* downscale alpha to 5 bits */ + /* FIXME: Here we special-case opaque alpha since the + compositioning used (>>8 instead of /255) doesn't handle + it correctly. Also special-case alpha=0 for speed? + Benchmark this! */ + if(alpha == (SDL_ALPHA_OPAQUE >> 3)) { + *dstp = (s >> 9 & 0x7c00) + (s >> 6 & 0x3e0) + + (s >> 3 & 0x1f); + } else { + Uint32 d = *dstp; + /* + * convert source and destination to G0RAB65565 + * and blend all components at the same time + */ + s = ((s & 0xf800) << 10) + (s >> 9 & 0x7c00) + + (s >> 3 & 0x1f); + d = (d | d << 16) & 0x03e07c1f; + d += (s - d) * alpha >> 5; + d &= 0x03e07c1f; + *dstp = d | d >> 16; + } + srcp++; + dstp++; + }, width); + srcp += srcskip; + dstp += dstskip; + } +} + +/* General (slow) N->N blending with per-surface alpha */ +static void BlitNtoNSurfaceAlpha(SDL_BlitInfo *info) +{ + int width = info->d_width; + int height = info->d_height; + Uint8 *src = info->s_pixels; + int srcskip = info->s_skip; + Uint8 *dst = info->d_pixels; + int dstskip = info->d_skip; + SDL_PixelFormat *srcfmt = info->src; + SDL_PixelFormat *dstfmt = info->dst; + int srcbpp = srcfmt->BytesPerPixel; + int dstbpp = dstfmt->BytesPerPixel; + unsigned sA = srcfmt->alpha; + unsigned dA = dstfmt->Amask ? SDL_ALPHA_OPAQUE : 0; + + while ( height-- ) { + DUFFS_LOOP4( + { + Uint32 pixel; + unsigned sR; + unsigned sG; + unsigned sB; + unsigned dR; + unsigned dG; + unsigned dB; + DISEMBLE_RGB(src, srcbpp, srcfmt, pixel, sR, sG, sB); + DISEMBLE_RGB(dst, dstbpp, dstfmt, pixel, dR, dG, dB); + ALPHA_BLEND(sR, sG, sB, sA, dR, dG, dB); + ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA); + src += srcbpp; + dst += dstbpp; + }, + width); + src += srcskip; + dst += dstskip; + } +} + +/* General (slow) colorkeyed N->N blending with per-surface alpha */ +static void BlitNtoNSurfaceAlphaKey(SDL_BlitInfo *info) +{ + int width = info->d_width; + int height = info->d_height; + Uint8 *src = info->s_pixels; + int srcskip = info->s_skip; + Uint8 *dst = info->d_pixels; + int dstskip = info->d_skip; + SDL_PixelFormat *srcfmt = info->src; + SDL_PixelFormat *dstfmt = info->dst; + Uint32 ckey = srcfmt->colorkey; + int srcbpp = srcfmt->BytesPerPixel; + int dstbpp = dstfmt->BytesPerPixel; + unsigned sA = srcfmt->alpha; + unsigned dA = dstfmt->Amask ? SDL_ALPHA_OPAQUE : 0; + + while ( height-- ) { + DUFFS_LOOP4( + { + Uint32 pixel; + unsigned sR; + unsigned sG; + unsigned sB; + unsigned dR; + unsigned dG; + unsigned dB; + RETRIEVE_RGB_PIXEL(src, srcbpp, pixel); + if(pixel != ckey) { + RGB_FROM_PIXEL(pixel, srcfmt, sR, sG, sB); + DISEMBLE_RGB(dst, dstbpp, dstfmt, pixel, dR, dG, dB); + ALPHA_BLEND(sR, sG, sB, sA, dR, dG, dB); + ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA); + } + src += srcbpp; + dst += dstbpp; + }, + width); + src += srcskip; + dst += dstskip; + } +} + +/* General (slow) N->N blending with pixel alpha */ +static void BlitNtoNPixelAlpha(SDL_BlitInfo *info) +{ + int width = info->d_width; + int height = info->d_height; + Uint8 *src = info->s_pixels; + int srcskip = info->s_skip; + Uint8 *dst = info->d_pixels; + int dstskip = info->d_skip; + SDL_PixelFormat *srcfmt = info->src; + SDL_PixelFormat *dstfmt = info->dst; + + int srcbpp; + int dstbpp; + + /* Set up some basic variables */ + srcbpp = srcfmt->BytesPerPixel; + dstbpp = dstfmt->BytesPerPixel; + + /* FIXME: for 8bpp source alpha, this doesn't get opaque values + quite right. for <8bpp source alpha, it gets them very wrong + (check all macros!) + It is unclear whether there is a good general solution that doesn't + need a branch (or a divide). */ + while ( height-- ) { + DUFFS_LOOP4( + { + Uint32 pixel; + unsigned sR; + unsigned sG; + unsigned sB; + unsigned dR; + unsigned dG; + unsigned dB; + unsigned sA; + unsigned dA; + DISEMBLE_RGBA(src, srcbpp, srcfmt, pixel, sR, sG, sB, sA); + DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixel, dR, dG, dB, dA); + ALPHA_BLEND(sR, sG, sB, sA, dR, dG, dB); + ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA); + src += srcbpp; + dst += dstbpp; + }, + width); + src += srcskip; + dst += dstskip; + } +} + + +SDL_loblit SDL_CalculateAlphaBlit(SDL_Surface *surface, int blit_index) +{ + SDL_PixelFormat *sf = surface->format; + SDL_PixelFormat *df = surface->map->dst->format; + + if(sf->Amask == 0) { + if((surface->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY) { + if(df->BytesPerPixel == 1) + return BlitNto1SurfaceAlphaKey; + else + return BlitNtoNSurfaceAlphaKey; + } else { + /* Per-surface alpha blits */ + switch(df->BytesPerPixel) { + case 1: + return BlitNto1SurfaceAlpha; + + case 2: + if(surface->map->identity) { + if(df->Gmask == 0x7e0) + return Blit565to565SurfaceAlpha; + else if(df->Gmask == 0x3e0) + return Blit555to555SurfaceAlpha; + } + return BlitNtoNSurfaceAlpha; + + case 4: + if(sf->Rmask == df->Rmask + && sf->Gmask == df->Gmask + && sf->Bmask == df->Bmask + && (sf->Rmask | sf->Gmask | sf->Bmask) == 0xffffff + && sf->BytesPerPixel == 4) + return BlitRGBtoRGBSurfaceAlpha; + else + return BlitNtoNSurfaceAlpha; + + case 3: + default: + return BlitNtoNSurfaceAlpha; + } + } + } else { + /* Per-pixel alpha blits */ + switch(df->BytesPerPixel) { + case 1: + return BlitNto1PixelAlpha; + + case 2: + if(sf->BytesPerPixel == 4 && sf->Amask == 0xff000000 + && sf->Gmask == 0xff00 + && ((sf->Rmask == 0xff && df->Rmask == 0x1f) + || (sf->Bmask == 0xff && df->Bmask == 0x1f))) { + if(df->Gmask == 0x7e0) + return BlitARGBto565PixelAlpha; + else if(df->Gmask == 0x3e0) + return BlitARGBto555PixelAlpha; + } + return BlitNtoNPixelAlpha; + + case 4: + if(sf->Amask == 0xff000000 + && sf->Rmask == df->Rmask + && sf->Gmask == df->Gmask + && sf->Bmask == df->Bmask + && sf->BytesPerPixel == 4) + return BlitRGBtoRGBPixelAlpha; + return BlitNtoNPixelAlpha; + + case 3: + default: + return BlitNtoNPixelAlpha; + } + } +} +