DirectDraw Tutorial 2
Alpha
混合
一、
基本alpha混合
Alhpa混合有多种算法,基本的计算公式如下:
result = ALPHA * srcPixel + ( 1 - ALPHA ) * destPixel
其中ALHPA的范围从0.0到1.0,result为混合后的颜色,srcPixel为前景色,destPixel为背景色。也就是说较大的ALPHA值意味着更多得源颜色。
上述公式中出现了两个乘法,可以通过合并来优化它:
result = ALPHA * ( srcPixel - destPixel ) + destPixel
现在ALPHA是一个浮点数,因此可以将它转化为整数:
result = ( ALPHA * ( srcPixel - destPixel ) ) / 256 + destPixel
现在ALPHA
的取值范围为0
到256
,对于除法可以通过右移来代替:
result = ( ALPHA * ( srcPixel - destPixel ) ) >>8+ destPixel
根据上面的公式,可以得到ALHPHA
混合的代码:
//DESC:Blt a surface pdds to (x,y) of backbuffer
//This function just can be used to blt a 32bit bitmap,if you want to blt a 8bit,16bit or 24bit
//you should rewrite this function, and int this version the parameter RECT* prc is not be used
//you should pass a NULL as value, alpha from 0 to 255, pdds is the source surface
HRESULT CDisplay::AlphaBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
RECT* prc, USHORT alpha )
{
HRESULT hr;
//Get the desc
DDSURFACEDESC2 ddsdSrc;
DDSURFACEDESC2 ddsdDest;
ZeroMemory( &ddsdSrc, sizeof( ddsdSrc ) );
ddsdSrc.dwSize = sizeof(ddsdSrc);
ZeroMemory( &ddsdDest, sizeof( ddsdDest ) );
ddsdDest.dwSize = sizeof(ddsdDest);
//Get the mask info
DDPIXELFORMAT ddpf;
ZeroMemory( &ddpf, sizeof(ddpf) );
ddpf.dwSize = sizeof(ddpf);
pdds->GetPixelFormat(&ddpf);
DWORD rMask = ddpf.dwRBitMask;
DWORD bMask = ddpf.dwBBitMask;
DWORD gMask = ddpf.dwGBitMask;
if( FAILED( hr = pdds->Lock( NULL, &ddsdSrc, DDLOCK_WAIT, NULL )))
return hr;
//the target area
RECT rect = {x, y, x+ddsdSrc.dwWidth, y+ddsdSrc.dwHeight} ;
if( FAILED( hr = m_pddsBackBuffer->Lock( &rect, &ddsdDest, DDLOCK_WAIT, NULL )))
return hr;
BYTE* srcPt = (BYTE*)ddsdSrc.lpSurface;
DWORD srcPitch = ddsdSrc.lPitch;
BYTE* destPt = (BYTE*)ddsdDest.lpSurface;
DWORD destPitch = ddsdDest.lPitch;
//the width and height of area need to process
int iWidth = ddsdSrc.dwWidth;
int iHeight = ddsdSrc.dwHeight;
DWORD dwDestPad = ddsdDest.lPitch - ( iWidth * 4 );
DWORD dwSrcPad = ddsdSrc.lPitch - ( iWidth * 4 );
for( int i = 0; i < ddsdSrc.dwHeight; i++ )
{
for( int j = 0; j < ddsdSrc.dwWidth; j++ )
{
DWORD dwSourceTemp = *((DWORD*)srcPt);
//if the source pixel is not black
if(( dwSourceTemp & 0xffffff ) != 0 )
{
DWORD dwTargetTemp = *((DWORD*)destPt);
// Extract the red channels.
DWORD dwTgtRed = dwTargetTemp & rMask;
DWORD dwSrcRed = dwSourceTemp & rMask;
// Extract the green channels.
DWORD dwTgtGreen = dwTargetTemp & gMask;
DWORD dwSrcGreen = dwSourceTemp & gMask;
// Extract the blue channel.
DWORD dwTgtBlue = dwTargetTemp & bMask;
DWORD dwSrcBlue = dwSourceTemp & bMask;
// Calculate the destination pixel.
dwTargetTemp =
( ( ( ( alpha * ( dwSrcRed - dwTgtRed ) >> 8 ) + dwTgtRed ) & rMask ) |
( ( ( alpha * ( dwSrcGreen - dwTgtGreen ) >> 8 ) + dwTgtGreen ) & gMask ) |
( ( alpha * ( dwSrcBlue - dwTgtBlue ) >> 8 ) + dwTgtBlue ) );
*((DWORD*)destPt) = dwTargetTemp;
}
//move to next pixel
srcPt += 4;
destPt += 4;
}
//move to next line
srcPt += dwSrcPad;
destPt += dwDestPad;
}
pdds->Unlock(NULL);
m_pddsBackBuffer->Unlock(&rect);
return hr;
}
二、
代码优化
可以使用MMX、SSE来优化上述代码,下面给出一些网上关于alpha混合的主题