社区应用 最新帖子 精华区 社区服务 会员列表 统计排行 道具中心
主题 : alphablend的问题
secondsen 离线
级别: 总版主
显示用户信息 
0  发表于: 2012-11-12   
来源于 通用编程 分类

alphablend的问题

图片太大。。。截一部分贴上来

桌面widget,自己写alphablend(MMX的),好吧,其实是粘贴别人的,关于mmx的alphablend网上一抓一大把。。我自己呢,MMX还没有完全搞懂。

来吧,代码。。

复制代码
  1. 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)
  2. {
  3.     // alpha异常
  4.     if (blendalpha < 0 || blendalpha > 255) return;
  5.     // rect尺寸为0或负
  6.     if (rc_w <= 0) return;
  7.     if (rc_h <= 0) return;
  8.     // 越界
  9.     if (x >= sw) return;
  10.     if (y >= sh) return;
  11.     if (rc_w + rc_x - 1 < 0) return;
  12.     if (rc_h + rc_y - 1 < 0) return;
  13.     if (x < 0)
  14.     {
  15.         rc_x -= x;
  16.         rc_w += x;
  17.         x = 0;
  18.     }
  19.     if (y < 0)
  20.     {
  21.         rc_y -= y;
  22.         rc_h += y;
  23.         y = 0;
  24.     }
  25.     if (rc_x >= bit_w) return;
  26.     if (rc_y >= bit_h) return;
  27.     // 修正边界
  28.     if (rc_x < 0)
  29.     {
  30.         rc_w += rc_x;
  31.         rc_x = 0;
  32.     }
  33.     if (rc_y < 0)
  34.     {
  35.         rc_h += rc_y;
  36.         rc_y = 0;
  37.     }
  38.     if (rc_x + rc_w > bit_w) rc_w = bit_w - rc_x;
  39.     if (rc_y + rc_h > bit_h) rc_h = bit_h - rc_y;
  40.     if (x + rc_w > sw) rc_w = sw - x;
  41.     if (y + rc_h > sh) rc_h = sh - y;
  42.     const int nextLineOffset_src = (bit_w - rc_w) * 4;    // 混合完一行像素后,通过加上该值,便可直接定位到下行起始像素
  43.     const int nextLineOffset_dst = (sw - rc_w) * 4;
  44.     pDstBmp += y * sw + x;
  45.     pSrcBmp += rc_y * bit_w + rc_x;
  46.     const int ff = 0xff;
  47.     __asm
  48.     {
  49.         mov            edi, pDstBmp        ; 目的像素
  50.             mov            esi, pSrcBmp        ; 源像素
  51.             xor            ebx, ebx            ; 已混合的高度
  52.             mov            ecx, rc_w            ; 要混合的宽度
  53. BLEND_BEGIN:
  54.         cmp            dword ptr[esi], 0x00FFFFFF; 如果alpha为0,则跳过混合部分
  55.             jna            BLEND_END
  56.             mov            eax, blendalpha        ; 获取blend alpha
  57.             mov            edx, dword ptr[esi]
  58.             shr            edx, 24                ; edx 获取源像素 alpha
  59.             imul        eax, edx
  60.             ;cwd
  61.             mov            edx, 0
  62.             idiv        ff
  63.             shl            eax, 24
  64.             mov            edx, eax
  65.             mov            eax, dword ptr[esi]
  66.             and            eax, 0x00ffffff
  67.             or            eax, edx
  68.             movd        mm0, [edi]            ; 把目的像素值移入mm0寄存器的低32位
  69.             ;movd        mm1, [esi]            ; 把源像素值移入mm1寄存器的低32位
  70.             movd        mm1, eax
  71.             ; Core Begin
  72.             pxor        mm2, mm2            ; 把MM2清0
  73.             punpcklbw    mm0, mm2            ; src:8 bit到16 bit以容纳结果,32bit expand to 64 bit
  74.             punpcklbw    mm1, mm2            ; dst:8 bit到16 bit以容纳结果.32bit expand to 64 bit
  75.             movq        mm3, mm1            ; 因为要用dst的Alpha值
  76.             punpckhwd    mm3, mm3            ; 高字移动到双字
  77.             punpckhdq    mm3, mm3            ; 双字移动到四字,现在有八个像素的Alpha了!
  78.             movq        mm4, mm0            ; mm4 = dst
  79.             movq        mm5, mm1            ; mm5 = src
  80.             psubusw        mm4, mm1            ; dst-src,饱和减,小于0为0
  81.             psubusw        mm5, mm0            ; src-dst,饱和减,小于0为0
  82.             pmullw        mm4, mm3            ; Alpha * (src-dst)
  83.             pmullw        mm5, mm3            ; Alpha * (dst-src)
  84.             psrlw        mm4, 8                ; 除以256,now mm4 get the result,(src-dst)<0 部分
  85.             psrlw        mm5, 8                ; 除以256,now mm5 get the result,(dst-src)>0 部分
  86.             paddusw        mm0, mm5            ; 饱和加到原图象:D=Alpha*(O-S)+S,(src-dst)<0 部分
  87.             psubusw        mm0, mm4            ; 饱和加到原图象D=S-Alpha*(S-O),(dst-src)>0 部分
  88.             packuswb    mm0, mm0            ; 紧缩到低32bit
  89.             ; Core End
  90.             ;movd        eax, mm0
  91.             ;and            eax, 0x00ffffff
  92.             ;mov            edx, dword ptr[edi]
  93.             ;and            edx, 0xff000000
  94.             ;or            eax, edx
  95.             movd        [edi], mm0            ; 混合结果写进目的像素
  96.             ;mov            dword ptr[edi], eax
  97. BLEND_END:
  98.         add            edi, 4
  99.             add            esi, 4
  100.             ;loop        BLEND_BEGIN                ; 循环
  101.             dec            ecx
  102.             cmp            ecx, 0                ; rc_w <= 0 跳出循环
  103.             jg            BLEND_BEGIN
  104.             add            esi, nextLineOffset_src    ; 加上偏移量,使定位到下行起始处
  105.             add            edi, nextLineOffset_dst
  106.             inc            ebx
  107.             mov            ecx, rc_w
  108.             cmp            ebx, rc_h                ; 若ebx小于rc_h,则转移到上面继续混合
  109.             jb            BLEND_BEGIN
  110.             EMMS                                ; 因为从mm0到mm7,这些寄存器是“借用”浮点寄存器的低64位,所以每次在用完MMX指令后一定要用EMMS指令将寄存器清空
  111.     }
  112. }


问题。。。在图片上。。。原本不贴 太阳那幅图,正常。但是贴上太阳,图像整体变成半透明了,咋办哇?

我看到 颜色 dst,src的混合计算公式

结果色 = dst * (1-src.alpha) + src * src.alpha
那么,其实我有个疑问。。 结果色.alpha怎么算。。

上面的公式 通常默认 dst.alpha = 1.0 (255)的,但是我想混两个不透明色,而不是把透明色混到不透明色上,怎么办?

问题叙述完毕,上图中。。。。
图片:1.png
图片:2.png
图片:3.png
评价一下你浏览此帖子的感受

精彩

感动

搞笑

开心

愤怒

无聊

灌水
相关话题
我就是你们的神,庶民们,追随我吧!跟着我一起拖后腿!
拖后腿的人发勋章!
tamashii 离线
级别: ③业余
显示用户信息 
1  发表于: 2013-02-04   
会用__asm的大触手你好~~~
Tamashii是啥意思?
魂!
=======================
我真是败给C++的面向对象了啊……
tamashii 离线
级别: ③业余
显示用户信息 
2  发表于: 2013-02-04   
D为底色,S为覆盖到上面的颜色
Dr = Sr + ((Dr - Sr) * Sa / 255)
Dg = Sg + ((Dg - Sg) * Sa / 255)
Db = Sb + ((Db - Sb) * Sa / 255)
Da = 255
Tamashii是啥意思?
魂!
=======================
我真是败给C++的面向对象了啊……
secondsen 离线
级别: 总版主
显示用户信息 
3  发表于: 2013-02-04   
两个半透明色混合的结果会被强制转换成不透明的
我就是你们的神,庶民们,追随我吧!跟着我一起拖后腿!
拖后腿的人发勋章!
tamashii 离线
级别: ③业余
显示用户信息 
4  发表于: 2013-02-04   
桌面应用我不太懂。
不过由于游戏背景本身是黑色的,所以第一个半透明与黑色做AlphaBlend,得到图像A
第二个半透明图像再与图像A做Alphablend,得到图像B

桌面应用的话大概就是:以第一个半透明图像的大小的桌面截图作为背景,然后用第一个半透明图像和这个桌面截图进行AlphaBlend,得到图像A。
然后再用图像A与第二个半透明图像进行AlphaBlend,得到图像B。

这么说你能听懂吧?
Tamashii是啥意思?
魂!
=======================
我真是败给C++的面向对象了啊……
secondsen 离线
级别: 总版主
显示用户信息 
5  发表于: 2013-02-04   
那刷新就需要不停的截图。就是麻烦点。
我就是你们的神,庶民们,追随我吧!跟着我一起拖后腿!
拖后腿的人发勋章!
描述
快速回复

认证码:

验证问题:
12-5=?,答案:7 正确答案:7
按"Ctrl+Enter"直接提交