#include <windows.h>
#include <crtdbg.h>
#define WND_WIDTH 300
#define WND_HEIGHT 300
#define WND_CLASSNAME "MainWnd"
#define WND_TITLENAME "Test"
struct SBmpInfo
{
BITMAPINFO m_BitmapInfo;
RGBQUAD m_bmiColors[2]; // 为BITMAPINFO的m_bmiColors补充两个元素空间
};
struct SGDI
{
HWND m_hWnd;
HDC m_hMainDC;
HDC m_hMemoryDC;
HBITMAP m_hMainSurface;
HBITMAP m_hOldBitmap;
int m_Width;
int m_Height;
UINT* m_pBackBuffer;
SBmpInfo m_BmpInfo;
};
SGDI g_GDI;
extern UINT g_Bmp32[268*268];
int g_bmpWidth = 268;
int g_bmpHeight = 268;
void AlphaBlend32(UINT* pDstBmp, int dst_width, UINT* pSrcBmp, int src_width, int blend_width, int blend_height)
{
// C实现
// {
// const int nextLineOffset_src = (src_width - blend_width) * 4; // 混合完一行像素后,通过加上该值,便可直接定位到下行起始像素
// const int nextLineOffset_dst = (dst_width - blend_width) * 4;
// BYTE* pSrc = (BYTE*)pSrcBmp;
// BYTE* pDst = (BYTE*)pDstBmp;
// int below_A, below_R, below_G, below_B;
// int above_A, above_R, above_G, above_B;
//
// for (int h=0, w=0; h<blend_height; h++)
// {
// for (w=0; w<blend_width; w++)
// {
// above_B = *pSrc++;
// above_G = *pSrc++;
// above_R = *pSrc++;
// above_A = *pSrc++;
//
// if (above_A == 0)
// {
// pDst += 4;
// continue;
// }
//
// below_B = *pDst;
// below_G = *(pDst+1);
// below_R = *(pDst+2);
// below_A = *(pDst+3);
//
// *pDst++ = below_B - (below_B-above_B)*above_A/255;
// *pDst++ = below_G - (below_G-above_G)*above_A/255;
// *pDst++ = below_R - (below_R-above_R)*above_A/255;
//
// if (below_A == 255)
// *pDst++ = 255;
// else
// *pDst++ = below_A - (below_A-above_A)*above_A/255;
// }
//
// pSrc += nextLineOffset_src;
// pDst += nextLineOffset_dst;
// }
// return;
// }
const int nextLineOffset_src = (src_width - blend_width) * 4; // 混合完一行像素后,通过加上该值,便可直接定位到下行起始像素
const int nextLineOffset_dst = (dst_width - blend_width) * 4;
__asm
{
mov edi, pDstBmp ; 目的像素
mov esi, pSrcBmp ; 源像素
xor ebx, ebx ; 已混合的高度
mov ecx, blend_width ; 要混合的宽度
BLEND_BEGIN:
cmp dword ptr[esi], 0x00FFFFFF ; 如果alpha为0,则跳过混合部分
jna BLEND_END
movd mm0, [edi] ; 把目的像素值移入mm0寄存器的低32位
movd mm1, [esi] ; 把源像素值移入mm1寄存器的低32位
; Core Begin:result = b - (b-a)*a_alpha/255 (a为源像素分量,b为目的像素分量)
pxor mm2, mm2 ; ① 把MM2清0
punpcklbw mm0, mm2 ; 将mm0与mm2按字节交叉组合,存入mm0,mm0 = 0x00AA00BB00GG00RR
punpcklbw mm1, mm2 ; 将mm1与mm2按字节交叉组合,存入mm1,mm1 = 0x00AA00BB00GG00RR
movq mm3, mm1 ; ② mm3 = 0x00AA00BB00GG00RR
punpckhwd mm3, mm3 ; 将高32位按16位交错排列,mm3 = 0x00AA00AA00BB00BB
punpckhdq mm3, mm3 ; 将高32位按32位交错排列,mm3 = 0x00AA00AA00AA00AA
movq mm4, mm0 ; ③ mm4 = 目的像素 = 0x00AA00BB00GG00RR
movq mm5, mm1 ; mm5 = 源像素 = 0x00AA00BB00GG00RR
psubusw mm4, mm1 ; ④ dst-src,按字饱和减,小于0为0
psubusw mm5, mm0 ; src-dst,按字饱和减,小于0为0
pmullw mm4, mm3 ; (dst-src) * alpha,若dst-src为0,则mm4为0
pmullw mm5, mm3 ; (src-dst) * alpha,若src-dst为0,则mm5为0
psrlw mm4, 8 ; 按字右移8位,即除以256
psrlw mm5, 8 ; 按字右移8位,即除以256
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 ; 按16位有符号数压缩为8位无符号数
; Core End
movd [edi], mm0 ; 混合结果写进目的像素
BLEND_END:
add edi, 4
add esi, 4
loop BLEND_BEGIN ; 循环
add esi, nextLineOffset_src ; 加上偏移量,使定位到下行起始处
add edi, nextLineOffset_dst
inc ebx
mov ecx, blend_width
cmp ebx, blend_height ; 若ebx小于blend_height,则转移到上面继续混合
jb BLEND_BEGIN
EMMS ; 因为从mm0到mm7,这些寄存器是“借用”浮点寄存器的低64位,所以每次在用完MMX指令后一定要用EMMS指令将寄存器清空
}
}
void DrawBmp(UINT* pBmp, int width, int height, int x, int y)
{
RECT srcRect = { 0, 0, width-1, height-1 };
RECT dstRect = { x, y, 0, 0 };
// 边界校正
{
if (srcRect.right >= width)
srcRect.right = width - 1;
if (srcRect.bottom >= height)
srcRect.bottom = height - 1;
// 超出左边界
if (dstRect.left < 0)
{
srcRect.left += -dstRect.left;
dstRect.left = 0;
}
// 超出上边界
if (dstRect.top < 0)
{
srcRect.top += -dstRect.top;
dstRect.top = 0;
}
int visibleW = srcRect.right - srcRect.left + 1;
int visibleH = srcRect.bottom - srcRect.top + 1;
// 超出右边界
if (dstRect.left+visibleW > g_GDI.m_Width)
{
visibleW = g_GDI.m_Width - dstRect.left;
srcRect.right = srcRect.left + visibleW-1;
}
// 超出下边界
if (dstRect.top+visibleH > g_GDI.m_Height)
{
visibleH = g_GDI.m_Height - dstRect.top;
srcRect.bottom = srcRect.top + visibleH-1;
}
dstRect.right = dstRect.left + (srcRect.right-srcRect.left);
dstRect.bottom = dstRect.top + (srcRect.bottom-srcRect.top);
if (visibleW<=0 || visibleH<=0) return;
}
UINT* pSrc = pBmp + srcRect.top*width+srcRect.left;
UINT* pDst = g_GDI.m_pBackBuffer + dstRect.top*g_GDI.m_Width+dstRect.left;
AlphaBlend32(pDst, g_GDI.m_Width, pSrc, width, srcRect.right-srcRect.left+1, srcRect.bottom-srcRect.top+1);
}
bool Init(HWND hWnd)
{
// 初始化g_GDI
{
memset(&g_GDI, 0, sizeof(g_GDI));
g_GDI.m_hWnd = hWnd;
g_GDI.m_Width = WND_WIDTH;
g_GDI.m_Height = WND_HEIGHT;
g_GDI.m_hMainDC = ::GetDC(hWnd);
g_GDI.m_hMemoryDC = ::CreateCompatibleDC(NULL);
g_GDI.m_hMainSurface = ::CreateCompatibleBitmap(g_GDI.m_hMainDC, g_GDI.m_Width, g_GDI.m_Height);
g_GDI.m_pBackBuffer = (UINT*)malloc(g_GDI.m_Width*g_GDI.m_Height*4);
BITMAPINFO& bmpInfo = g_GDI.m_BmpInfo.m_BitmapInfo;
bmpInfo.bmiHeader.biSize = sizeof(bmpInfo.bmiHeader);
bmpInfo.bmiHeader.biWidth = g_GDI.m_Width;
bmpInfo.bmiHeader.biHeight = -g_GDI.m_Height;
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biBitCount = 32;
bmpInfo.bmiHeader.biCompression = BI_BITFIELDS;
*(UINT*)(bmpInfo.bmiColors+0) = 0xFF0000; // red分量
*(UINT*)(bmpInfo.bmiColors+1) = 0x00FF00; // green分量
*(UINT*)(bmpInfo.bmiColors+2) = 0x0000FF; // blue分量
// 将主表面选入内存DC
g_GDI.m_hOldBitmap = (HBITMAP)::SelectObject(g_GDI.m_hMemoryDC, g_GDI.m_hMainSurface);
}
DWORD dwExStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE);
if (!(dwExStyle & WS_EX_LAYERED))
::SetWindowLong(hWnd, GWL_EXSTYLE, dwExStyle|WS_EX_LAYERED);
return true;
}
void End()
{
if (g_GDI.m_pBackBuffer != NULL)
{
free(g_GDI.m_pBackBuffer);
g_GDI.m_pBackBuffer = NULL;
}
if (g_GDI.m_hMainSurface != NULL)
{
if (g_GDI.m_hOldBitmap != NULL)
{
::SelectObject(g_GDI.m_hMemoryDC, g_GDI.m_hOldBitmap);
g_GDI.m_hOldBitmap = NULL;
}
::DeleteObject(g_GDI.m_hMainSurface);
g_GDI.m_hMainSurface = NULL;
}
if (g_GDI.m_hMemoryDC != NULL)
{
::DeleteDC(g_GDI.m_hMemoryDC);
g_GDI.m_hMemoryDC = NULL;
}
if (g_GDI.m_hMainDC != NULL)
{
ReleaseDC(g_GDI.m_hWnd, g_GDI.m_hMainDC);
g_GDI.m_hMainDC = NULL;
}
}
void MainLoop()
{
// 清空后台像素
memset(g_GDI.m_pBackBuffer, 0, g_GDI.m_Width*g_GDI.m_Height*4);
DrawBmp(g_Bmp32, g_bmpWidth, g_bmpHeight, 0, 0);
// Flip
{
::SetDIBitsToDevice(g_GDI.m_hMemoryDC,
0, 0, g_GDI.m_Width, g_GDI.m_Height,
0, 0, 0, g_GDI.m_Height,
g_GDI.m_pBackBuffer, &g_GDI.m_BmpInfo.m_BitmapInfo, DIB_RGB_COLORS);
{
RECT rcWnd;
::GetWindowRect(g_GDI.m_hWnd, &rcWnd);
POINT srcPos = { 0, 0 };
POINT dstPos = { rcWnd.left, rcWnd.top };
SIZE dstSize = { rcWnd.right-rcWnd.left, rcWnd.bottom-rcWnd.top };
BLENDFUNCTION blend;
blend.BlendO
- 1
- 2
- 3
- 4
- 5
- 6
前往页