From: Massimo Del Fedele Date: Sun, 18 Jul 2010 10:26:10 +0000 (+0200) Subject: DIB Engine: implement AlphaBlend X-Git-Url: https://repo.or.cz/w/wine/hacks.git/commitdiff_plain/44b4072b16220065961a7a953160842cd47949d9 DIB Engine: implement AlphaBlend --- diff --git a/dlls/winedib.drv/bitblt.c b/dlls/winedib.drv/bitblt.c index 20cdcaa6cdd..c0227a03846 100644 --- a/dlls/winedib.drv/bitblt.c +++ b/dlls/winedib.drv/bitblt.c @@ -150,34 +150,84 @@ BOOL DIBDRV_AlphaBlend( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst, INT width xDst, yDst, widthDst, heightDst, physDevSrc, physDevSrc->hasDIB ? "DIB-" : "DDB", physDevSrc->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevSrc->physBitmap) : "", xSrc, ySrc, widthSrc, heightSrc)); + - if(physDevDst->hasDIB && physDevSrc->hasDIB) + /* if sizes are null or negative, returns false */ + if(widthSrc <= 0 || heightSrc <= 0 || widthDst <= 0 || heightDst <= 0) { - /* DIB section selected in both source and dest DC, use DIB Engine */ - ONCE(FIXME("STUB\n")); - res = TRUE; + res = FALSE; + goto fin; } - else if(!physDevDst->hasDIB && !physDevSrc->hasDIB) + + /* source sould be a 32 bit DIB */ + if(!physDevSrc) { - /* DDB selected in noth source and dest DC, use X11 driver */ - res = _DIBDRV_GetDisplayDriver()->pAlphaBlend(physDevDst->X11PhysDev, xDst, yDst, widthDst, heightDst, - physDevSrc->X11PhysDev, xSrc, ySrc, widthSrc, heightSrc, - blendfn); + FIXME("Null source bitmap -- shouldn't happen\n"); + res = FALSE; + goto fin; } - else if(physDevSrc->hasDIB) + else if(!physDevSrc->hasDIB) { - /* DIB on source, DDB on dest -- must convert source DIB to DDB and use X11 driver for blit */ - ONCE(FIXME("TEMPORARY - fallback to X11 driver\n")); - res = _DIBDRV_GetDisplayDriver()->pAlphaBlend(physDevDst->X11PhysDev, xDst, yDst, widthDst, heightDst, - physDevSrc->X11PhysDev, xSrc, ySrc, widthSrc, heightSrc, - blendfn); + FIXME("DDB source bitmap -- shouldn't happen\n"); + res = FALSE; + goto fin; } - else /* if(physDevDst->hasDIB) */ + + if(physDevDst->hasDIB) { - /* DDB on source, DIB on dest -- must convert source DDB to DIB and use the engine for blit */ - ONCE(FIXME("STUB\n")); - res = TRUE; + /* DIB section selected in dest DC, use DIB Engine */ + MAYBE(TRACE("Blending DIB->DIB\n")); + res = physDevDst->physBitmap.funcs->AlphaBlend(physDevDst, xDst, yDst, widthDst, heightDst, + physDevSrc, xSrc, ySrc, widthSrc, heightSrc, blendfn); + } + else + { + /* DDB selected on dest DC -- must double-convert */ + HBITMAP tmpDIB, stock; + HDC tmpDC; + MAYBE(TRACE("Blending DIB->DDB\n")); + + /* converts dest DDB onto a temporary DIB -- just the needed part */ + tmpDIB = _DIBDRV_ConvertDevDDBtoDIB(physDevDst->hdc, physDevSrc->hdc, xDst, yDst, widthDst, heightDst); + if(!tmpDIB) + { + ERR("Couldn't convert dest DDB to DIB\n"); + res = FALSE; + goto fin; + } + + /* selects the temporary DIB into a temporary DC */ + tmpDC = CreateCompatibleDC(physDevDst->hdc); + if(!tmpDC) + { + ERR("Couldn't create temporary DC\n"); + DeleteObject(tmpDIB); + res = FALSE; + goto fin; + } + stock = SelectObject(tmpDC, tmpDIB); + if(!stock) + { + ERR("Couldn't select temporary DIB into temporary DC\n"); + DeleteDC(tmpDC); + DeleteObject(tmpDIB); + res = FALSE; + goto fin; + } + + /* blends source DIB onto temp DIB and re-blits onto dest DC */ + res = GdiAlphaBlend(tmpDC, 0, 0, widthDst, heightDst, physDevSrc->hdc, xSrc, ySrc, widthSrc, heightSrc, blendfn); + if(!res) + MAYBE(TRACE("AlphaBlend failed\n")); + else + res = BitBlt(physDevDst->hdc, xDst, yDst, widthDst, heightDst, tmpDC, 0, 0, SRCCOPY); + + /* frees resources */ + SelectObject(tmpDC, stock); + DeleteDC(tmpDC); + DeleteObject(tmpDIB); } +fin: return res; } diff --git a/dlls/winedib.drv/dibdrv.h b/dlls/winedib.drv/dibdrv.h index 773941ece8f..c801d96f2d0 100644 --- a/dlls/winedib.drv/dibdrv.h +++ b/dlls/winedib.drv/dibdrv.h @@ -94,6 +94,8 @@ typedef struct _DIBDRV_PRIMITIVE_FUNCS BOOL (* PutLine) ( struct _DIBDRVBITMAP *bmp, int line, int startx, int width, void *buf); /* BitBlt primitives */ + BOOL (* AlphaBlend) ( struct _DIBDRVPHYSDEV *physDevDst, int xDst, int yDst, int widthDst, int heightDst, + const struct _DIBDRVPHYSDEV *physDevSrc, int xSrc, int ySrc, int widthSrc, int heightSrc, BLENDFUNCTION blendFn ); BOOL (* BitBlt) ( struct _DIBDRVPHYSDEV *physDevDst, int xDst, int yDst, int width, int height, const struct _DIBDRVPHYSDEV *physDevSrc, int xSrc, int ySrc, DWORD rop ); BOOL (* StretchBlt) ( struct _DIBDRVPHYSDEV *physDevDst, int xDst, int yDst, int widthDst, int heightDst, diff --git a/dlls/winedib.drv/primitives.c b/dlls/winedib.drv/primitives.c index cbad239f674..a2fa04a93a3 100644 --- a/dlls/winedib.drv/primitives.c +++ b/dlls/winedib.drv/primitives.c @@ -133,6 +133,10 @@ BOOL _DIBDRV_StretchBlt_generic(DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst, const DIBDRVPHYSDEV *physDevSrc, INT xSrc, INT ySrc, int widthSrc, int heightSrc, DWORD rop); +BOOL _DIBDRV_AlphaBlend_generic(DIBDRVPHYSDEV *physDevDst, int xDst, int yDst, + int widthDst, int heightDst, const DIBDRVPHYSDEV *physDevSrc, + int xSrc, int ySrc, int widthSrc, int heightSrc, BLENDFUNCTION blendFn ); + /* ------------------------------------------------------------*/ /* FREETYPE FONT BITMAP BLITTING */ void _DIBDRV_freetype_blit_8888 (DIBDRVPHYSDEV *dib, int x, int y, FT_Bitmap *bmp); @@ -156,6 +160,7 @@ DIBDRV_PRIMITIVE_FUNCS DIBDRV_funcs_DIB32_RGB = _DIBDRV_SolidVLine32, _DIBDRV_GetLine32_RGB, _DIBDRV_PutLine32_RGB, + _DIBDRV_AlphaBlend_generic, _DIBDRV_BitBlt_generic, _DIBDRV_StretchBlt_generic, _DIBDRV_freetype_blit_32_RGB @@ -172,6 +177,7 @@ DIBDRV_PRIMITIVE_FUNCS DIBDRV_funcs_DIB32_BITFIELDS = _DIBDRV_SolidVLine32, _DIBDRV_GetLine32_BITFIELDS, _DIBDRV_PutLine32_BITFIELDS, + _DIBDRV_AlphaBlend_generic, _DIBDRV_BitBlt_generic, _DIBDRV_StretchBlt_generic, _DIBDRV_freetype_blit_32_BITFIELDS @@ -188,6 +194,7 @@ DIBDRV_PRIMITIVE_FUNCS DIBDRV_funcs_DIB24 = _DIBDRV_SolidVLine24, _DIBDRV_GetLine24, _DIBDRV_PutLine24, + _DIBDRV_AlphaBlend_generic, _DIBDRV_BitBlt_generic, _DIBDRV_StretchBlt_generic, _DIBDRV_freetype_blit_24 @@ -204,6 +211,7 @@ DIBDRV_PRIMITIVE_FUNCS DIBDRV_funcs_DIB16_RGB = _DIBDRV_SolidVLine16, _DIBDRV_GetLine16_RGB, _DIBDRV_PutLine16_RGB, + _DIBDRV_AlphaBlend_generic, _DIBDRV_BitBlt_generic, _DIBDRV_StretchBlt_generic, _DIBDRV_freetype_blit_16_RGB @@ -220,6 +228,7 @@ DIBDRV_PRIMITIVE_FUNCS DIBDRV_funcs_DIB16_BITFIELDS = _DIBDRV_SolidVLine16, _DIBDRV_GetLine16_BITFIELDS, _DIBDRV_PutLine16_BITFIELDS, + _DIBDRV_AlphaBlend_generic, _DIBDRV_BitBlt_generic, _DIBDRV_StretchBlt_generic, _DIBDRV_freetype_blit_16_BITFIELDS @@ -236,6 +245,7 @@ DIBDRV_PRIMITIVE_FUNCS DIBDRV_funcs_DIB8 = _DIBDRV_SolidVLine8, _DIBDRV_GetLine8, _DIBDRV_PutLine8, + _DIBDRV_AlphaBlend_generic, _DIBDRV_BitBlt_generic, _DIBDRV_StretchBlt_generic, _DIBDRV_freetype_blit_8 @@ -252,6 +262,7 @@ DIBDRV_PRIMITIVE_FUNCS DIBDRV_funcs_DIB4 = _DIBDRV_SolidVLine4, _DIBDRV_GetLine4, _DIBDRV_PutLine4, + _DIBDRV_AlphaBlend_generic, _DIBDRV_BitBlt_generic, _DIBDRV_StretchBlt_generic, _DIBDRV_freetype_blit_4 @@ -268,6 +279,7 @@ DIBDRV_PRIMITIVE_FUNCS DIBDRV_funcs_DIB1 = _DIBDRV_SolidVLine1, _DIBDRV_GetLine1, _DIBDRV_PutLine1, + _DIBDRV_AlphaBlend_generic, _DIBDRV_BitBlt_generic, _DIBDRV_StretchBlt_generic, _DIBDRV_freetype_blit_1 diff --git a/dlls/winedib.drv/primitives_bitblt.c b/dlls/winedib.drv/primitives_bitblt.c index da4835298ae..7540dad8190 100644 --- a/dlls/winedib.drv/primitives_bitblt.c +++ b/dlls/winedib.drv/primitives_bitblt.c @@ -80,6 +80,293 @@ static void StretchLine(DWORD *dst, int dstWidth, DWORD *src, int srcWidth) memcpy(dst, src, 4 * srcWidth); } +/* premultiply alpha channel on a line by a constant alpha + note : it seems that pixels are already premultiplied + by alpha channel content */ +static void PemultiplyLine(DWORD *dst, int width, BYTE constAlpha) +{ + int i = width; + BYTE *alphaPnt = (BYTE *)dst + 3; + + /* small optimization for 0 and 255 values of constAlpha */ + + /* fully transparent -- just sets all pix to 0 */ + if(constAlpha == 0) + { + while(i--) + *dst++ = 0; + return; + } + + /* fully opaque, just do nothing */ + if(constAlpha == 255) + return; + + /* intermediate -- premultiply alpha values */ + while(i--) + { + *alphaPnt = MulDiv(*alphaPnt, constAlpha, 255); + alphaPnt += 4; + } + return; + +} + +/* alpha blends a source line onto a destination line + preconditions : + 1) source and dest widths must be the same + 2) source line should be already premultiplied by constant alpha */ +static void BlendLine(DWORD *dst, DWORD *src, int width) +{ + int i = width; + BYTE *blueDst = (BYTE *)dst; + BYTE *greenDst = blueDst + 1; + BYTE *redDst = greenDst + 1; + BYTE *blueSrc = (BYTE *)src; + BYTE *greenSrc = blueSrc + 1; + BYTE *redSrc = greenSrc + 1; + BYTE *alphaSrc = redSrc + 1; + BYTE alpha; + + /* still don't know if it must take in account an eventual dest + alpha channel..... */ + while(i--) + { + alpha = 255 - *alphaSrc; + + *blueDst = *blueSrc + MulDiv(*blueDst, alpha, 255); + *greenDst = *greenSrc + MulDiv(*greenDst, alpha, 255); + *redDst = *redSrc + MulDiv(*redDst, alpha, 255); + + blueSrc += 4; + greenSrc += 4; + redSrc += 4; + alphaSrc += 4; + blueDst += 4; + greenDst += 4; + redDst += 4; + } + +} + +/* ------------------------------------------------------------*/ +/* ALPHABLEND PRIMITIVES */ +BOOL _DIBDRV_AlphaBlend_generic(DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst, + INT widthDst, INT heightDst, const DIBDRVPHYSDEV *physDevSrc, + INT xSrc, INT ySrc, int widthSrc, int heightSrc, BLENDFUNCTION blendFn) +{ + /* flags indicating wether source should be stretched */ + BOOL horStretch = (widthSrc != widthDst); + BOOL verStretch = (heightSrc != heightDst); + + /* constant alpha value */ + BYTE constAlpha = blendFn.SourceConstantAlpha; + + /* source and dest bitmaps */ + const DIBDRVBITMAP *srcBmp = &physDevSrc->physBitmap; + DIBDRVBITMAP *dstBmp = &physDevDst->physBitmap; + + /* source and destination line buffers */ + DWORD *sBuf = HeapAlloc(GetProcessHeap(), 0, abs(srcBmp->stride)); + DWORD *dBuf = HeapAlloc(GetProcessHeap(), 0, abs(dstBmp->stride)); + + int ys = ySrc; + int yd = yDst; + int iLine; + int delta; + + /* in order to optimize a bit, we divide the routine in 4 parts, + depending on stretching modes */ + if(!horStretch && !verStretch) + { + /* simplest case, no stretching needed */ + MAYBE(TRACE("No stretching\n")); + for(iLine = 0; iLine < heightSrc; iLine++, ys++, yd++) + { + /* load source and dest lines */ + srcBmp->funcs->GetLine(srcBmp, ys, xSrc, widthSrc, sBuf); + dstBmp->funcs->GetLine(dstBmp, yd, xDst, widthDst, dBuf); + + /* premultiply source by constant and pixel alpha */ + PemultiplyLine(sBuf, widthSrc, constAlpha); + + /* blends source on dest */ + BlendLine(dBuf, sBuf, widthSrc); + + /* puts dest line back */ + dstBmp->funcs->PutLine(dstBmp, yd, xDst, widthDst, dBuf); + } + } + else if (horStretch && !verStretch) + { + /* just horizontal stretching needed */ + DWORD *strBuf = HeapAlloc(GetProcessHeap(), 0, abs(dstBmp->stride)); + MAYBE(TRACE("Horizontal stretching\n")); + + for(iLine = 0; iLine < heightSrc; iLine++, ys++, yd++) + { + /* load source and dest lines */ + srcBmp->funcs->GetLine(srcBmp, ys, xSrc, widthSrc, sBuf); + dstBmp->funcs->GetLine(dstBmp, yd, xDst, widthDst, dBuf); + + /* stretch source line to match dest one */ + StretchLine(strBuf, widthDst, sBuf, widthSrc); + + /* premultiply source by constant and pixel alpha */ + PemultiplyLine(strBuf, widthDst, constAlpha); + + /* blends source on dest */ + BlendLine(dBuf, sBuf, widthDst); + + /* puts dest line back */ + dstBmp->funcs->PutLine(dstBmp, yd, xDst, widthDst, dBuf); + } + HeapFree(GetProcessHeap(), 0, strBuf); + } + else if (!horStretch && verStretch) + { + /* just vertical stretching needed */ + MAYBE(TRACE("Vertical stretching\n")); + + if(heightSrc > heightDst) + { + iLine = 0; + delta = 0; + while(iLine < heightDst) + { + /* load source and dest lines */ + srcBmp->funcs->GetLine(srcBmp, ys, xSrc, widthSrc, sBuf); + dstBmp->funcs->GetLine(dstBmp, yd, xDst, widthDst, dBuf); + + /* premultiply source by constant and pixel alpha */ + PemultiplyLine(sBuf, widthSrc, constAlpha); + + /* blends source on dest */ + BlendLine(dBuf, sBuf, widthDst); + + /* puts dest line back */ + dstBmp->funcs->PutLine(dstBmp, yd, xDst, widthDst, dBuf); + + while(delta < heightSrc) + { + ys++; + delta += heightDst; + } + delta -= heightSrc; + yd++; + iLine++; + } + } + else if(heightSrc < heightDst) + { + iLine = 0; + delta = 0; + while(iLine < heightSrc) + { + /* load source line */ + srcBmp->funcs->GetLine(srcBmp, ys, xSrc, widthSrc, sBuf); + + /* premultiply source by constant and pixel alpha */ + PemultiplyLine(sBuf, widthSrc, constAlpha); + + while(delta < heightDst) + { + /* load dest line */ + dstBmp->funcs->GetLine(dstBmp, yd, xDst, widthDst, dBuf); + + /* blends source on dest */ + BlendLine(dBuf, sBuf, widthDst); + + /* puts dest line back */ + dstBmp->funcs->PutLine(dstBmp, yd, xDst, widthDst, dBuf); + yd++; + delta += heightSrc; + } + delta -= heightDst; + ys++; + iLine++; + } + } + } + else + { + DWORD *strBuf = HeapAlloc(GetProcessHeap(), 0, abs(dstBmp->stride)); + /* both stretching needed -- generic case */ + MAYBE(TRACE("Horizontal and vertical stretching\n")); + + if(heightSrc > heightDst) + { + iLine = 0; + delta = 0; + while(iLine < heightDst) + { + /* load source and dest lines */ + srcBmp->funcs->GetLine(srcBmp, ys, xSrc, widthSrc, sBuf); + dstBmp->funcs->GetLine(dstBmp, yd, xDst, widthDst, dBuf); + + /* stretch source line to match dest one */ + StretchLine(strBuf, widthDst, sBuf, widthSrc); + + /* premultiply source by constant and pixel alpha */ + PemultiplyLine(strBuf, widthDst, constAlpha); + + /* blends source on dest */ + BlendLine(dBuf, strBuf, widthDst); + + /* puts dest line back */ + dstBmp->funcs->PutLine(dstBmp, yd, xDst, widthDst, dBuf); + + while(delta < heightSrc) + { + ys++; + delta += heightDst; + } + delta -= heightSrc; + yd++; + iLine++; + } + } + else if(heightSrc < heightDst) + { + iLine = 0; + delta = 0; + while(iLine < heightSrc) + { + /* load source line */ + srcBmp->funcs->GetLine(srcBmp, ys, xSrc, widthSrc, sBuf); + + /* stretch source line to match dest one */ + StretchLine(strBuf, widthDst, sBuf, widthSrc); + + /* premultiply source by constant and pixel alpha */ + PemultiplyLine(strBuf, widthDst, constAlpha); + + while(delta < heightDst) + { + /* load dest line */ + dstBmp->funcs->GetLine(dstBmp, yd, xDst, widthDst, dBuf); + + /* blends source on dest */ + BlendLine(dBuf, strBuf, widthDst); + + /* puts dest line back */ + dstBmp->funcs->PutLine(dstBmp, yd, xDst, widthDst, dBuf); + yd++; + delta += heightSrc; + } + delta -= heightDst; + ys++; + iLine++; + } + } + HeapFree(GetProcessHeap(), 0, strBuf); + } + + HeapFree(GetProcessHeap(), 0, sBuf); + HeapFree(GetProcessHeap(), 0, dBuf); + return TRUE; +} + /* ------------------------------------------------------------*/ /* BLITTING PRIMITIVES */ BOOL _DIBDRV_BitBlt_generic(DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,