DirectDraw Tutorial 2

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混合的主題
 
 
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章