alphablend的问题
图片太大。。。截一部分贴上来桌面widget,自己写alphablend(MMX的),好吧,其实是粘贴别人的,关于mmx的alphablend网上一抓一大把。。我自己呢,MMX还没有完全搞懂。
来吧,代码。。
void Widget_HTC_Weather::AlphaBlend32(UINT* pDstBmp, UINT* pSrcBmp, int bit_w, int bit_h, int rc_x, int rc_y, int rc_w, int rc_h, int x, int y, int sw, int sh, int blendalpha)
{
// alpha异常
if (blendalpha < 0 || blendalpha > 255) return;
// rect尺寸为0或负
if (rc_w <= 0) return;
if (rc_h <= 0) return;
// 越界
if (x >= sw) return;
if (y >= sh) return;
if (rc_w + rc_x - 1 < 0) return;
if (rc_h + rc_y - 1 < 0) return;
if (x < 0)
{
rc_x -= x;
rc_w += x;
x = 0;
}
if (y < 0)
{
rc_y -= y;
rc_h += y;
y = 0;
}
if (rc_x >= bit_w) return;
if (rc_y >= bit_h) return;
// 修正边界
if (rc_x < 0)
{
rc_w += rc_x;
rc_x = 0;
}
if (rc_y < 0)
{
rc_h += rc_y;
rc_y = 0;
}
if (rc_x + rc_w > bit_w) rc_w = bit_w - rc_x;
if (rc_y + rc_h > bit_h) rc_h = bit_h - rc_y;
if (x + rc_w > sw) rc_w = sw - x;
if (y + rc_h > sh) rc_h = sh - y;
const int nextLineOffset_src = (bit_w - rc_w) * 4; // 混合完一行像素后,通过加上该值,便可直接定位到下行起始像素
const int nextLineOffset_dst = (sw - rc_w) * 4;
pDstBmp += y * sw + x;
pSrcBmp += rc_y * bit_w + rc_x;
const int ff = 0xff;
__asm
{
mov edi, pDstBmp ; 目的像素
mov esi, pSrcBmp ; 源像素
xor ebx, ebx ; 已混合的高度
mov ecx, rc_w ; 要混合的宽度
BLEND_BEGIN:
cmp dword ptr, 0x00FFFFFF; 如果alpha为0,则跳过混合部分
jna BLEND_END
mov eax, blendalpha ; 获取blend alpha
mov edx, dword ptr
shr edx, 24 ; edx 获取源像素 alpha
imul eax, edx
;cwd
mov edx, 0
idiv ff
shl eax, 24
mov edx, eax
mov eax, dword ptr
and eax, 0x00ffffff
or eax, edx
movd mm0, ; 把目的像素值移入mm0寄存器的低32位
;movd mm1, ; 把源像素值移入mm1寄存器的低32位
movd mm1, eax
; Core Begin
pxor mm2, mm2 ; 把MM2清0
punpcklbw mm0, mm2 ; src:8 bit到16 bit以容纳结果,32bit expand to 64 bit
punpcklbw mm1, mm2 ; dst:8 bit到16 bit以容纳结果.32bit expand to 64 bit
movq mm3, mm1 ; 因为要用dst的Alpha值
punpckhwd mm3, mm3 ; 高字移动到双字
punpckhdq mm3, mm3 ; 双字移动到四字,现在有八个像素的Alpha了!
movq mm4, mm0 ; mm4 = dst
movq mm5, mm1 ; mm5 = src
psubusw mm4, mm1 ; dst-src,饱和减,小于0为0
psubusw mm5, mm0 ; src-dst,饱和减,小于0为0
pmullw mm4, mm3 ; Alpha * (src-dst)
pmullw mm5, mm3 ; Alpha * (dst-src)
psrlw mm4, 8 ; 除以256,now mm4 get the result,(src-dst)<0 部分
psrlw mm5, 8 ; 除以256,now mm5 get the result,(dst-src)>0 部分
paddusw mm0, mm5 ; 饱和加到原图象:D=Alpha*(O-S)+S,(src-dst)<0 部分
psubusw mm0, mm4 ; 饱和加到原图象D=S-Alpha*(S-O),(dst-src)>0 部分
packuswb mm0, mm0 ; 紧缩到低32bit
; Core End
;movd eax, mm0
;and eax, 0x00ffffff
;mov edx, dword ptr
;and edx, 0xff000000
;or eax, edx
movd , mm0 ; 混合结果写进目的像素
;mov dword ptr, eax
BLEND_END:
add edi, 4
add esi, 4
;loop BLEND_BEGIN ; 循环
dec ecx
cmp ecx, 0 ; rc_w <= 0 跳出循环
jg BLEND_BEGIN
add esi, nextLineOffset_src ; 加上偏移量,使定位到下行起始处
add edi, nextLineOffset_dst
inc ebx
mov ecx, rc_w
cmp ebx, rc_h ; 若ebx小于rc_h,则转移到上面继续混合
jb BLEND_BEGIN
EMMS ; 因为从mm0到mm7,这些寄存器是“借用”浮点寄存器的低64位,所以每次在用完MMX指令后一定要用EMMS指令将寄存器清空
}
}
问题。。。在图片上。。。原本不贴 太阳那幅图,正常。但是贴上太阳,图像整体变成半透明了,咋办哇?
我看到 颜色 dst,src的混合计算公式
结果色 = dst * (1-src.alpha) + src * src.alpha
那么,其实我有个疑问。。 结果色.alpha怎么算。。
上面的公式 通常默认 dst.alpha = 1.0 (255)的,但是我想混两个不透明色,而不是把透明色混到不透明色上,怎么办?
问题叙述完毕,上图中。。。。 会用__asm的大触手你好~~~ D为底色,S为覆盖到上面的颜色
Dr = Sr + ((Dr - Sr) * Sa / 255)
Dg = Sg + ((Dg - Sg) * Sa / 255)
Db = Sb + ((Db - Sb) * Sa / 255)
Da = 255 两个半透明色混合的结果会被强制转换成不透明的 桌面应用我不太懂。
不过由于游戏背景本身是黑色的,所以第一个半透明与黑色做AlphaBlend,得到图像A
第二个半透明图像再与图像A做Alphablend,得到图像B
桌面应用的话大概就是:以第一个半透明图像的大小的桌面截图作为背景,然后用第一个半透明图像和这个桌面截图进行AlphaBlend,得到图像A。
然后再用图像A与第二个半透明图像进行AlphaBlend,得到图像B。
这么说你能听懂吧? 那刷新就需要不停的截图。就是麻烦点。
页:
[1]