|
是这样
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)
{
// 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;
UINT** pptmp = &pDstBmp;
__asm
{
mov edi, pDstBmp ; 目的像素
mov esi, pSrcBmp ; 源像素
xor ebx, ebx ; 已混合的高度
mov ecx, rc_w ; 要混合的宽度
BLEND_BEGIN:
cmp dword ptr[esi], 0x00FFFFFF ; 如果alpha为0,则跳过混合部分
jna BLEND_END
movd mm0, [edi] ; 把目的像素值移入mm0寄存器的低32位
movd mm1, [esi] ; 把源像素值移入mm1寄存器的低32位
; 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 ; 饱和加到原图象=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 [edi], mm0 ; 混合结果写进目的像素
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指令将寄存器清空
}
} |
|