From 4730035cf348d99a0d26b9eacc0eb6defab13583 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sat, 7 Feb 2009 17:56:08 +0000 Subject: [PATCH] Fixed alpha blending textures with the GDI renderer --- include/SDL_pixels.h | 6 ++++ src/video/SDL_alphamult.c | 58 +++++++++++++++++++++++++++++++++ src/video/SDL_alphamult.h | 36 ++++++++++++++++++++ src/video/SDL_blit.h | 19 +++++++++++ src/video/win32/SDL_gdirender.c | 50 +++++++++++++++++++++++++--- 5 files changed, 165 insertions(+), 4 deletions(-) create mode 100644 src/video/SDL_alphamult.c create mode 100644 src/video/SDL_alphamult.h diff --git a/include/SDL_pixels.h b/include/SDL_pixels.h index f4523fa8e..cc800a9fd 100644 --- a/include/SDL_pixels.h +++ b/include/SDL_pixels.h @@ -117,6 +117,12 @@ enum (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_INDEX4) || \ (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_INDEX8)) +#define SDL_ISPIXELFORMAT_ALPHA(format) \ + ((SDL_PIXELORDER(format) == SDL_PACKEDORDER_ARGB) || \ + (SDL_PIXELORDER(format) == SDL_PACKEDORDER_RGBA) || \ + (SDL_PIXELORDER(format) == SDL_PACKEDORDER_ABGR) || \ + (SDL_PIXELORDER(format) == SDL_PACKEDORDER_BGRA)) + #define SDL_ISPIXELFORMAT_FOURCC(format) \ ((format) && !((format) & 0x80000000)) diff --git a/src/video/SDL_alphamult.c b/src/video/SDL_alphamult.c new file mode 100644 index 000000000..ea7ee83fe --- /dev/null +++ b/src/video/SDL_alphamult.c @@ -0,0 +1,58 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2009 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" + +#include "SDL_blit.h" +#include "SDL_alphamult.h" + +/* Functions to pre-multiply the alpha channel into the color channels */ + +#define DEFINE_PREMULTIPLY_FUNC(fmt) \ +void \ +SDL_PreMultiplyAlpha##fmt(int w, int h, Uint32 *pixels, int pitch) \ +{ \ + pitch /= 4; \ + while (h--) { \ + int n; \ + Uint32 *row = pixels; \ + Uint32 pixel; \ + unsigned r, g, b, a; \ + \ + for (n = w; n--; ) { \ + pixel = *row; \ + RGBA_FROM_##fmt(pixel, r, g, b, a); \ + r = (r * a) / 255; \ + g = (g * a) / 255; \ + b = (b * a) / 255; \ + fmt##_FROM_RGBA(*row, r, g, b, a); \ + ++row; \ + } \ + pixels += pitch; \ + } \ +} + +DEFINE_PREMULTIPLY_FUNC(ARGB8888) +DEFINE_PREMULTIPLY_FUNC(RGBA8888) +DEFINE_PREMULTIPLY_FUNC(ABGR8888) +DEFINE_PREMULTIPLY_FUNC(BGRA8888) + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/SDL_alphamult.h b/src/video/SDL_alphamult.h new file mode 100644 index 000000000..0c24c53e1 --- /dev/null +++ b/src/video/SDL_alphamult.h @@ -0,0 +1,36 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2009 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 +*/ + +/* Functions to pre-multiply the alpha channel into the color channels */ + +#define DEFINE_PREMULTIPLY_FUNC(fmt) \ +void \ +SDL_PreMultiplyAlpha##fmt(int w, int h, Uint32 *pixels, int pitch); + +DEFINE_PREMULTIPLY_FUNC(ARGB8888) +DEFINE_PREMULTIPLY_FUNC(RGBA8888) +DEFINE_PREMULTIPLY_FUNC(ABGR8888) +DEFINE_PREMULTIPLY_FUNC(BGRA8888) + +#undef DEFINE_PREMULTIPLY_FUNC + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/SDL_blit.h b/src/video/SDL_blit.h index bd62ceb68..798b93e95 100644 --- a/src/video/SDL_blit.h +++ b/src/video/SDL_blit.h @@ -240,6 +240,18 @@ do { \ { \ Pixel = (a<<24)|(r<<16)|(g<<8)|b; \ } +#define RGBA8888_FROM_RGBA(Pixel, r, g, b, a) \ +{ \ + Pixel = (r<<24)|(g<<16)|(b<<8)|a; \ +} +#define ABGR8888_FROM_RGBA(Pixel, r, g, b, a) \ +{ \ + Pixel = (a<<24)|(b<<16)|(g<<8)|r; \ +} +#define BGRA8888_FROM_RGBA(Pixel, r, g, b, a) \ +{ \ + Pixel = (b<<24)|(g<<16)|(r<<8)|a; \ +} #define ASSEMBLE_RGB(buf, bpp, fmt, r, g, b) \ { \ switch (bpp) { \ @@ -347,6 +359,13 @@ do { \ b = ((Pixel>>16)&0xFF); \ a = (Pixel>>24); \ } +#define RGBA_FROM_BGRA8888(Pixel, r, g, b, a) \ +{ \ + r = ((Pixel>>8)&0xFF); \ + g = ((Pixel>>16)&0xFF); \ + b = (Pixel>>24); \ + a = (Pixel&0xFF); \ +} #define DISEMBLE_RGBA(buf, bpp, fmt, Pixel, r, g, b, a) \ do { \ switch (bpp) { \ diff --git a/src/video/win32/SDL_gdirender.c b/src/video/win32/SDL_gdirender.c index 3519764f6..9a9c90f1e 100644 --- a/src/video/win32/SDL_gdirender.c +++ b/src/video/win32/SDL_gdirender.c @@ -26,6 +26,7 @@ #include "SDL_win32video.h" #include "../SDL_rect_c.h" #include "../SDL_yuv_sw_c.h" +#include "../SDL_alphamult.h" /* GDI renderer implementation */ @@ -120,6 +121,7 @@ typedef struct HBITMAP hbm; void *pixels; int pitch; + SDL_bool premultiplied; } GDI_TextureData; static void @@ -463,10 +465,36 @@ GDI_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture) static int GDI_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture) { + GDI_TextureData *data = (GDI_TextureData *) texture->driverdata; + switch (texture->blendMode) { case SDL_BLENDMODE_NONE: + if (data->premultiplied) { + /* Crap, we've lost the original pixel data... *sigh* */ + } + return 0; case SDL_BLENDMODE_MASK: case SDL_BLENDMODE_BLEND: + if (!data->premultiplied && data->pixels) { + switch (texture->format) { + case SDL_PIXELFORMAT_ARGB8888: + SDL_PreMultiplyAlphaARGB8888(texture->w, texture->h, (Uint32 *)data->pixels, data->pitch); + data->premultiplied = SDL_TRUE; + break; + case SDL_PIXELFORMAT_RGBA8888: + SDL_PreMultiplyAlphaRGBA8888(texture->w, texture->h, (Uint32 *)data->pixels, data->pitch); + data->premultiplied = SDL_TRUE; + break; + case SDL_PIXELFORMAT_ABGR8888: + SDL_PreMultiplyAlphaABGR8888(texture->w, texture->h, (Uint32 *)data->pixels, data->pitch); + data->premultiplied = SDL_TRUE; + break; + case SDL_PIXELFORMAT_BGRA8888: + SDL_PreMultiplyAlphaBGRA8888(texture->w, texture->h, (Uint32 *)data->pixels, data->pitch); + data->premultiplied = SDL_TRUE; + break; + } + } return 0; default: SDL_Unsupported(); @@ -525,6 +553,23 @@ GDI_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, src += pitch; dst += data->pitch; } + if (data->premultiplied) { + Uint32 *pixels = (Uint32 *) data->pixels + rect->y * (data->pitch / 4) + rect->x; + switch (texture->format) { + case SDL_PIXELFORMAT_ARGB8888: + SDL_PreMultiplyAlphaARGB8888(rect->w, rect->h, pixels, data->pitch); + break; + case SDL_PIXELFORMAT_RGBA8888: + SDL_PreMultiplyAlphaRGBA8888(rect->w, rect->h, pixels, data->pitch); + break; + case SDL_PIXELFORMAT_ABGR8888: + SDL_PreMultiplyAlphaABGR8888(rect->w, rect->h, pixels, data->pitch); + break; + case SDL_PIXELFORMAT_BGRA8888: + SDL_PreMultiplyAlphaBGRA8888(rect->w, rect->h, pixels, data->pitch); + break; + } + } } else if (rect->w == texture->w && pitch == data->pitch) { if (!SetDIBits (renderdata->window_hdc, data->hbm, rect->y, rect->h, pixels, @@ -700,16 +745,13 @@ GDI_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, SelectPalette(data->memory_hdc, texturedata->hpal, TRUE); RealizePalette(data->memory_hdc); } - if (texture->blendMode & SDL_BLENDMODE_MASK) { + if (texture->blendMode & (SDL_BLENDMODE_MASK|SDL_BLENDMODE_BLEND)) { BLENDFUNCTION blendFunc = { AC_SRC_OVER, 0, texture->a, AC_SRC_ALPHA }; - /* FIXME: GDI uses premultiplied alpha! - * Once we solve this and somehow support blended drawing we can enable SDL_BLENDMODE_BLEND - */ if (!AlphaBlend (data->current_hdc, dstrect->x, dstrect->y, dstrect->w, dstrect->h, data->memory_hdc, srcrect->x, srcrect->y, srcrect->w,