Fixed alpha blending textures with the GDI renderer
authorSam Lantinga <slouken@libsdl.org>
Sat, 07 Feb 2009 17:56:08 +0000
changeset 3054 8d93bfecb9dc
parent 3053 aa34d1180d30
child 3055 cd863dd2082b
Fixed alpha blending textures with the GDI renderer
include/SDL_pixels.h
src/video/SDL_alphamult.c
src/video/SDL_alphamult.h
src/video/SDL_blit.h
src/video/win32/SDL_gdirender.c
--- a/include/SDL_pixels.h	Fri Jan 30 06:40:16 2009 +0000
+++ b/include/SDL_pixels.h	Sat Feb 07 17:56:08 2009 +0000
@@ -117,6 +117,12 @@
      (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))
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/SDL_alphamult.c	Sat Feb 07 17:56:08 2009 +0000
@@ -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: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/SDL_alphamult.h	Sat Feb 07 17:56:08 2009 +0000
@@ -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: */
--- a/src/video/SDL_blit.h	Fri Jan 30 06:40:16 2009 +0000
+++ b/src/video/SDL_blit.h	Sat Feb 07 17:56:08 2009 +0000
@@ -240,6 +240,18 @@
 {									\
 	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 @@
 	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) {							   \
--- a/src/video/win32/SDL_gdirender.c	Fri Jan 30 06:40:16 2009 +0000
+++ b/src/video/win32/SDL_gdirender.c	Sat Feb 07 17:56:08 2009 +0000
@@ -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 @@
     HBITMAP hbm;
     void *pixels;
     int pitch;
+    SDL_bool premultiplied;
 } GDI_TextureData;
 
 static void
@@ -463,10 +465,36 @@
 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 @@
                 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 @@
         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,