www.pudn.com > terrainSimple.rar > ddutil.cpp


//----------------------------------------------------------------------------- 
// File: ddutil.cpp 
// 
// Desc: DirectDraw framewark classes. Feel free to use this class as a  
//       starting point for adding extra functionality. 
// 
// 
// Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved. 
//----------------------------------------------------------------------------- 
#define STRICT 
#include  
#include  
#include  
#include  
#include "ddutil.h" 
#include "dxutil.h" 
 
 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name: CDisplay() 
// Desc: 
//----------------------------------------------------------------------------- 
CDisplay::CDisplay() 
{ 
    m_pDD                = NULL; 
    m_pddsFrontBuffer    = NULL; 
    m_pddsBackBuffer     = NULL; 
    m_pddsBackBufferLeft = NULL; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name: ~CDisplay() 
// Desc: 
//----------------------------------------------------------------------------- 
CDisplay::~CDisplay() 
{ 
    DestroyObjects(); 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name: DestroyObjects() 
// Desc: 
//----------------------------------------------------------------------------- 
HRESULT CDisplay::DestroyObjects() 
{ 
    SAFE_RELEASE( m_pddsBackBufferLeft ); 
    SAFE_RELEASE( m_pddsBackBuffer ); 
    SAFE_RELEASE( m_pddsFrontBuffer ); 
 
    if( m_pDD ) 
        m_pDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL ); 
 
    SAFE_RELEASE( m_pDD ); 
 
    return S_OK; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name: CreateFullScreenDisplay() 
// Desc: 
//----------------------------------------------------------------------------- 
HRESULT CDisplay::CreateFullScreenDisplay( HWND hWnd, DWORD dwWidth, 
                                           DWORD dwHeight, DWORD dwBPP ) 
{ 
    HRESULT hr; 
 
    // Cleanup anything from a previous call 
    DestroyObjects(); 
 
    // DDraw stuff begins here 
    if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD, 
                                         IID_IDirectDraw7, NULL ) ) ) 
        return E_FAIL; 
 
    // Set cooperative level 
    hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN ); 
    if( FAILED(hr) ) 
        return E_FAIL; 
 
    // Set the display mode 
    if( FAILED( m_pDD->SetDisplayMode( dwWidth, dwHeight, dwBPP, 0, 0 ) ) ) 
        return E_FAIL; 
 
    // Create primary surface (with backbuffer attached) 
    DDSURFACEDESC2 ddsd; 
    ZeroMemory( &ddsd, sizeof( ddsd ) ); 
    ddsd.dwSize            = sizeof( ddsd ); 
    ddsd.dwFlags           = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; 
    ddsd.ddsCaps.dwCaps    = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | 
                             DDSCAPS_COMPLEX | DDSCAPS_3DDEVICE; 
    ddsd.dwBackBufferCount = 1; 
 
    if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, 
                                           NULL ) ) ) 
        return E_FAIL; 
 
    // Get a pointer to the back buffer 
    DDSCAPS2 ddscaps; 
    ZeroMemory( &ddscaps, sizeof( ddscaps ) ); 
    ddscaps.dwCaps = DDSCAPS_BACKBUFFER; 
 
    if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps, 
                                                            &m_pddsBackBuffer ) ) ) 
        return E_FAIL; 
 
    m_pddsBackBuffer->AddRef(); 
 
    m_hWnd      = hWnd; 
    m_bWindowed = FALSE; 
    UpdateBounds(); 
 
    return S_OK; 
} 
     
 
 
 
//----------------------------------------------------------------------------- 
// Name: CreateWindowedDisplay() 
// Desc: 
//----------------------------------------------------------------------------- 
HRESULT CDisplay::CreateWindowedDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight ) 
{ 
    HRESULT hr; 
 
    // Cleanup anything from a previous call 
    DestroyObjects(); 
 
    // DDraw stuff begins here 
    if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD, 
                                         IID_IDirectDraw7, NULL ) ) ) 
        return E_FAIL; 
 
    // Set cooperative level 
    hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_NORMAL ); 
    if( FAILED(hr) ) 
        return E_FAIL; 
 
    RECT  rcWork; 
    RECT  rc; 
    DWORD dwStyle; 
 
    // If we are still a WS_POPUP window we should convert to a normal app 
    // window so we look like a windows app. 
    dwStyle  = GetWindowStyle( hWnd ); 
    dwStyle &= ~WS_POPUP; 
    dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX; 
    SetWindowLong( hWnd, GWL_STYLE, dwStyle ); 
 
    // Aet window size 
    SetRect( &rc, 0, 0, dwWidth, dwHeight ); 
 
    AdjustWindowRectEx( &rc, GetWindowStyle(hWnd), GetMenu(hWnd) != NULL, 
                        GetWindowExStyle(hWnd) ); 
 
    SetWindowPos( hWnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top, 
                  SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE ); 
 
    SetWindowPos( hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, 
                  SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE ); 
 
    //  Make sure our window does not hang outside of the work area 
    SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWork, 0 ); 
    GetWindowRect( hWnd, &rc ); 
    if( rc.left < rcWork.left ) rc.left = rcWork.left; 
    if( rc.top  < rcWork.top )  rc.top  = rcWork.top; 
    SetWindowPos( hWnd, NULL, rc.left, rc.top, 0, 0, 
                  SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE ); 
 
    LPDIRECTDRAWCLIPPER pcClipper; 
     
    // Create the primary surface 
    DDSURFACEDESC2 ddsd; 
    ZeroMemory( &ddsd, sizeof( ddsd ) ); 
    ddsd.dwSize         = sizeof( ddsd ); 
    ddsd.dwFlags        = DDSD_CAPS; 
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; 
 
    if( FAILED( m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) ) 
        return E_FAIL; 
 
    // Create the backbuffer surface 
    ddsd.dwFlags        = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;     
    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE; 
    ddsd.dwWidth        = dwWidth; 
    ddsd.dwHeight       = dwHeight; 
 
    if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL ) ) ) 
        return E_FAIL; 
 
    if( FAILED( hr = m_pDD->CreateClipper( 0, &pcClipper, NULL ) ) ) 
        return E_FAIL; 
 
    if( FAILED( hr = pcClipper->SetHWnd( 0, hWnd ) ) ) 
    { 
        pcClipper->Release(); 
        return E_FAIL; 
    } 
 
    if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pcClipper ) ) ) 
    { 
        pcClipper->Release(); 
        return E_FAIL; 
    } 
 
    // Done with clipper 
    pcClipper->Release(); 
 
    m_hWnd      = hWnd; 
    m_bWindowed = TRUE; 
    UpdateBounds(); 
 
    return S_OK; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name:  
// Desc:  
//----------------------------------------------------------------------------- 
HRESULT CDisplay::CreateSurface( CSurface** ppSurface, 
                                 DWORD dwWidth, DWORD dwHeight ) 
{ 
    if( NULL == m_pDD ) 
        return E_POINTER; 
    if( NULL == ppSurface ) 
        return E_INVALIDARG; 
 
    HRESULT        hr; 
    DDSURFACEDESC2 ddsd; 
    ZeroMemory( &ddsd, sizeof( ddsd ) ); 
    ddsd.dwSize         = sizeof( ddsd ); 
    ddsd.dwFlags        = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;  
    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; 
    ddsd.dwWidth        = dwWidth; 
    ddsd.dwHeight       = dwHeight; 
 
    (*ppSurface) = new CSurface(); 
    if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) ) 
    { 
        delete (*ppSurface); 
        return hr; 
    } 
 
    return S_OK; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name: CDisplay::CreateSurfaceFromBitmap() 
// Desc: Create a DirectDrawSurface from a bitmap resource or bitmap file. 
//       Use MAKEINTRESOURCE() to pass a constant into strBMP. 
//----------------------------------------------------------------------------- 
HRESULT CDisplay::CreateSurfaceFromBitmap( CSurface** ppSurface, 
                                           TCHAR* strBMP,                                             
                                           DWORD dwDesiredWidth,  
                                           DWORD dwDesiredHeight ) 
{ 
    HRESULT        hr; 
    HBITMAP        hBMP = NULL; 
    BITMAP         bmp; 
    DDSURFACEDESC2 ddsd; 
 
    if( m_pDD == NULL || strBMP == NULL || ppSurface == NULL )  
        return E_INVALIDARG; 
 
    *ppSurface = NULL; 
 
    //  Try to load the bitmap as a resource, if that fails, try it as a file 
    hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,  
                                IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,  
                                LR_CREATEDIBSECTION ); 
    if( hBMP == NULL ) 
    { 
        hBMP = (HBITMAP) LoadImage( NULL, strBMP,  
                                    IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,  
                                    LR_LOADFROMFILE | LR_CREATEDIBSECTION ); 
        if( hBMP == NULL ) 
            return E_FAIL; 
    } 
 
    // Get size of the bitmap 
    GetObject( hBMP, sizeof(bmp), &bmp ); 
 
    // Create a DirectDrawSurface for this bitmap 
    ZeroMemory( &ddsd, sizeof(ddsd) ); 
    ddsd.dwSize         = sizeof(ddsd); 
    ddsd.dwFlags        = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; 
    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; 
    ddsd.dwWidth        = bmp.bmWidth; 
    ddsd.dwHeight       = bmp.bmHeight; 
 
    (*ppSurface) = new CSurface(); 
    if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) ) 
    { 
        delete (*ppSurface); 
        return hr; 
    } 
 
    // Draw the bitmap on this surface 
    if( FAILED( hr = (*ppSurface)->DrawBitmap( hBMP, 0, 0, 0, 0 ) ) ) 
    { 
        DeleteObject( hBMP ); 
        return hr; 
    } 
 
    DeleteObject( hBMP ); 
 
    return S_OK; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name: CDisplay::CreateSurfaceFromText() 
// Desc: Creates a DirectDrawSurface from a text string using hFont or the default  
//       GDI font if hFont is NULL. 
//----------------------------------------------------------------------------- 
HRESULT CDisplay::CreateSurfaceFromText( CSurface** ppSurface, 
                                         HFONT hFont, TCHAR* strText,  
                                         COLORREF crBackground, COLORREF crForeground ) 
{ 
    HDC                  hDC  = NULL; 
    LPDIRECTDRAWSURFACE7 pDDS = NULL; 
    HRESULT              hr; 
    DDSURFACEDESC2       ddsd; 
    SIZE                 sizeText; 
 
    if( m_pDD == NULL || strText == NULL || ppSurface == NULL ) 
        return E_INVALIDARG; 
 
    *ppSurface = NULL; 
 
    hDC = GetDC( NULL ); 
 
    if( hFont ) 
        SelectObject( hDC, hFont ); 
 
    GetTextExtentPoint32( hDC, strText, _tcslen(strText), &sizeText ); 
    ReleaseDC( NULL, hDC ); 
 
    // Create a DirectDrawSurface for this bitmap 
    ZeroMemory( &ddsd, sizeof(ddsd) ); 
    ddsd.dwSize         = sizeof(ddsd); 
    ddsd.dwFlags        = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; 
    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; 
    ddsd.dwWidth        = sizeText.cx; 
    ddsd.dwHeight       = sizeText.cy; 
 
    (*ppSurface) = new CSurface(); 
    if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) ) 
    { 
        delete (*ppSurface); 
        return hr; 
    } 
 
    if( FAILED( hr = (*ppSurface)->DrawText( hFont, strText, 0, 0,  
                                             crBackground, crForeground ) ) ) 
        return hr; 
 
    return S_OK; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name:  
// Desc:  
//----------------------------------------------------------------------------- 
HRESULT CDisplay::Present() 
{ 
    HRESULT hr; 
 
    if( NULL == m_pddsFrontBuffer && NULL == m_pddsBackBuffer ) 
        return E_POINTER; 
 
    while( 1 ) 
    { 
        if( m_bWindowed ) 
            hr = m_pddsFrontBuffer->Blt( &m_rcWindow, m_pddsBackBuffer, 
                                         NULL, DDBLT_WAIT, NULL ); 
        else 
            hr = m_pddsFrontBuffer->Flip( NULL, 0 ); 
 
        if( hr == DDERR_SURFACELOST ) 
        { 
            m_pddsFrontBuffer->Restore(); 
            m_pddsBackBuffer->Restore(); 
        } 
 
        if( hr != DDERR_WASSTILLDRAWING ) 
            return hr; 
    } 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name:  
// Desc:  
//----------------------------------------------------------------------------- 
HRESULT CDisplay::ShowBitmap( HBITMAP hbm, LPDIRECTDRAWPALETTE pPalette ) 
{ 
    if( NULL == m_pddsFrontBuffer ||  NULL == m_pddsBackBuffer ) 
        return E_POINTER; 
 
    // Set the palette before loading the bitmap 
    if( pPalette ) 
        m_pddsFrontBuffer->SetPalette( pPalette ); 
 
    CSurface backBuffer; 
    backBuffer.Create( m_pddsBackBuffer ); 
 
    if( FAILED( backBuffer.DrawBitmap( hbm, 0, 0, 0, 0 ) ) ) 
        return E_FAIL; 
 
    return Present(); 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name:  
// Desc:  
//----------------------------------------------------------------------------- 
HRESULT CDisplay::ColorKeyBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds, 
                               RECT* prc ) 
{ 
    if( NULL == m_pddsBackBuffer ) 
        return E_POINTER; 
 
    return m_pddsBackBuffer->BltFast( x, y, pdds, prc, DDBLTFAST_SRCCOLORKEY ); 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name:  
// Desc:  
//----------------------------------------------------------------------------- 
HRESULT CDisplay::Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds, RECT* prc, 
                       DWORD dwFlags ) 
{ 
    if( NULL == m_pddsBackBuffer ) 
        return E_POINTER; 
 
    return m_pddsBackBuffer->BltFast( x, y, pdds, prc, dwFlags ); 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name:  
// Desc:  
//----------------------------------------------------------------------------- 
HRESULT CDisplay::Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc ) 
{ 
    if( NULL == pSurface ) 
        return E_INVALIDARG; 
 
    if( pSurface->IsColorKeyed() ) 
        return Blt( x, y, pSurface->GetDDrawSurface(), prc, DDBLTFAST_SRCCOLORKEY ); 
    else 
        return Blt( x, y, pSurface->GetDDrawSurface(), prc, 0L ); 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name:  
// Desc:  
//----------------------------------------------------------------------------- 
HRESULT CDisplay::Clear( DWORD dwColor ) 
{ 
    if( NULL == m_pddsBackBuffer ) 
        return E_POINTER; 
 
    // Erase the background 
    DDBLTFX ddbltfx; 
    ZeroMemory( &ddbltfx, sizeof(ddbltfx) ); 
    ddbltfx.dwSize      = sizeof(ddbltfx); 
    ddbltfx.dwFillColor = dwColor; 
 
    return m_pddsBackBuffer->Blt( NULL, NULL, NULL, DDBLT_COLORFILL, &ddbltfx ); 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name:  
// Desc:  
//----------------------------------------------------------------------------- 
HRESULT CDisplay::SetPalette( LPDIRECTDRAWPALETTE pPalette ) 
{ 
    if( NULL == m_pddsFrontBuffer ) 
        return E_POINTER; 
 
    return m_pddsFrontBuffer->SetPalette( pPalette ); 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name:  
// Desc:  
//----------------------------------------------------------------------------- 
HRESULT CDisplay::CreatePaletteFromBitmap( LPDIRECTDRAWPALETTE* ppPalette, 
                                           const TCHAR* strBMP ) 
{ 
    HRSRC             hResource      = NULL; 
    RGBQUAD*          pRGB           = NULL; 
    BITMAPINFOHEADER* pbi = NULL; 
    PALETTEENTRY      aPalette[256]; 
    HANDLE            hFile = NULL; 
    DWORD             iColor; 
    DWORD             dwColors; 
    BITMAPFILEHEADER  bf; 
    BITMAPINFOHEADER  bi; 
    DWORD             dwBytesRead; 
 
    if( m_pDD == NULL || strBMP == NULL || ppPalette == NULL ) 
        return E_INVALIDARG; 
 
    *ppPalette = NULL; 
 
    //  Try to load the bitmap as a resource, if that fails, try it as a file 
    hResource = FindResource( NULL, strBMP, RT_BITMAP ); 
    if( hResource ) 
    { 
        pbi = (LPBITMAPINFOHEADER) LockResource( LoadResource( NULL, hResource ) );        
        if( NULL == pbi ) 
            return E_FAIL; 
 
        pRGB = (RGBQUAD*) ( (BYTE*) pbi + pbi->biSize ); 
 
        // Figure out how many colors there are 
        if( pbi == NULL || pbi->biSize < sizeof(BITMAPINFOHEADER) ) 
            dwColors = 0; 
        else if( pbi->biBitCount > 8 ) 
            dwColors = 0; 
        else if( pbi->biClrUsed == 0 ) 
            dwColors = 1 << pbi->biBitCount; 
        else 
            dwColors = pbi->biClrUsed; 
 
        //  A DIB color table has its colors stored BGR not RGB 
        //  so flip them around. 
        for( iColor = 0; iColor < dwColors; iColor++ ) 
        { 
            aPalette[iColor].peRed   = pRGB[iColor].rgbRed; 
            aPalette[iColor].peGreen = pRGB[iColor].rgbGreen; 
            aPalette[iColor].peBlue  = pRGB[iColor].rgbBlue; 
            aPalette[iColor].peFlags = 0; 
        } 
 
        return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL ); 
    } 
 
    // Attempt to load bitmap as a file 
    hFile = CreateFile( strBMP, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL ); 
    if( INVALID_HANDLE_VALUE == hFile ) 
        return E_FAIL; 
 
    // Read the BITMAPFILEHEADER 
    ReadFile( hFile, &bf, sizeof(bf), &dwBytesRead, NULL ); 
    if( dwBytesRead != sizeof(bf) ) 
    { 
        CloseHandle( hFile ); 
        return E_FAIL; 
    } 
 
    // Read the BITMAPINFOHEADER 
    ReadFile( hFile, &bi, sizeof(bi), &dwBytesRead, NULL ); 
    if( dwBytesRead != sizeof(bi) ) 
    { 
        CloseHandle( hFile ); 
        return E_FAIL; 
    } 
 
    // Read the PALETTEENTRY  
    ReadFile( hFile, aPalette, sizeof(aPalette), &dwBytesRead, NULL ); 
    if( dwBytesRead != sizeof(aPalette) ) 
    { 
        CloseHandle( hFile ); 
        return E_FAIL; 
    } 
 
    CloseHandle( hFile ); 
 
    // Figure out how many colors there are 
    if( bi.biSize != sizeof(BITMAPINFOHEADER) ) 
        dwColors = 0; 
    else if (bi.biBitCount > 8) 
        dwColors = 0; 
    else if (bi.biClrUsed == 0) 
        dwColors = 1 << bi.biBitCount; 
    else 
        dwColors = bi.biClrUsed; 
 
    //  A DIB color table has its colors stored BGR not RGB 
    //  so flip them around since DirectDraw uses RGB 
    for( iColor = 0; iColor < dwColors; iColor++ ) 
    { 
        BYTE r = aPalette[iColor].peRed; 
        aPalette[iColor].peRed  = aPalette[iColor].peBlue; 
        aPalette[iColor].peBlue = r; 
    } 
 
    return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL ); 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name:  
// Desc:  
//----------------------------------------------------------------------------- 
HRESULT CDisplay::UpdateBounds() 
{ 
    if( m_bWindowed ) 
    { 
        GetClientRect( m_hWnd, &m_rcWindow ); 
        ClientToScreen( m_hWnd, (POINT*)&m_rcWindow ); 
        ClientToScreen( m_hWnd, (POINT*)&m_rcWindow+1 ); 
    } 
    else 
    { 
        SetRect( &m_rcWindow, 0, 0, GetSystemMetrics(SM_CXSCREEN), 
                 GetSystemMetrics(SM_CYSCREEN) ); 
    } 
 
    return S_OK; 
} 
 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name: CDisplay::InitClipper 
// Desc:  
//----------------------------------------------------------------------------- 
HRESULT CDisplay::InitClipper() 
{ 
    LPDIRECTDRAWCLIPPER pClipper; 
    HRESULT hr; 
 
    // Create a clipper when using GDI to draw on the primary surface  
    if( FAILED( hr = m_pDD->CreateClipper( 0, &pClipper, NULL ) ) ) 
        return hr; 
 
    pClipper->SetHWnd( 0, m_hWnd ); 
 
    if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pClipper ) ) ) 
        return hr; 
 
    // We can release the clipper now since g_pDDSPrimary  
    // now maintains a ref count on the clipper 
    SAFE_RELEASE( pClipper ); 
 
    return S_OK; 
} 
 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name:  
// Desc:  
//----------------------------------------------------------------------------- 
CSurface::CSurface() 
{ 
    m_pdds = NULL; 
    m_bColorKeyed = NULL; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name:  
// Desc:  
//----------------------------------------------------------------------------- 
CSurface::~CSurface() 
{ 
    SAFE_RELEASE( m_pdds ); 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name:  
// Desc:  
//----------------------------------------------------------------------------- 
HRESULT CSurface::Create( LPDIRECTDRAWSURFACE7 pdds ) 
{ 
    m_pdds = pdds; 
 
    if( m_pdds ) 
    { 
        m_pdds->AddRef(); 
 
        // Get the DDSURFACEDESC structure for this surface 
        m_ddsd.dwSize = sizeof(m_ddsd); 
        m_pdds->GetSurfaceDesc( &m_ddsd ); 
    } 
 
    return S_OK; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name:  
// Desc:  
//----------------------------------------------------------------------------- 
HRESULT CSurface::Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd ) 
{ 
    HRESULT hr; 
 
    // Create the DDraw surface 
    if( FAILED( hr = pDD->CreateSurface( pddsd, &m_pdds, NULL ) ) ) 
        return hr; 
 
    // Prepare the DDSURFACEDESC structure 
    m_ddsd.dwSize = sizeof(m_ddsd); 
 
    // Get the DDSURFACEDESC structure for this surface 
    m_pdds->GetSurfaceDesc( &m_ddsd ); 
 
    return S_OK; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name:  
// Desc:  
//----------------------------------------------------------------------------- 
HRESULT CSurface::Destroy() 
{ 
    SAFE_RELEASE( m_pdds ); 
    return S_OK; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name: CSurface::DrawBitmap() 
// Desc: Draws a bitmap over an entire DirectDrawSurface, stretching the  
//       bitmap if nessasary 
//----------------------------------------------------------------------------- 
HRESULT CSurface::DrawBitmap( HBITMAP hBMP,  
                              DWORD dwBMPOriginX, DWORD dwBMPOriginY,  
                              DWORD dwBMPWidth, DWORD dwBMPHeight ) 
{ 
    HDC            hDCImage; 
    HDC            hDC; 
    BITMAP         bmp; 
    DDSURFACEDESC2 ddsd; 
    HRESULT        hr; 
 
    if( hBMP == NULL || m_pdds == NULL ) 
        return E_INVALIDARG; 
 
    // Make sure this surface is restored. 
    if( FAILED( hr = m_pdds->Restore() ) ) 
        return hr; 
 
    // Get the surface.description 
    ddsd.dwSize  = sizeof(ddsd); 
    m_pdds->GetSurfaceDesc( &ddsd ); 
 
    if( ddsd.ddpfPixelFormat.dwFlags == DDPF_FOURCC ) 
        return E_NOTIMPL; 
 
    // Select bitmap into a memoryDC so we can use it. 
    hDCImage = CreateCompatibleDC( NULL ); 
    if( NULL == hDCImage ) 
        return E_FAIL; 
 
    SelectObject( hDCImage, hBMP ); 
 
    // Get size of the bitmap 
    GetObject( hBMP, sizeof(bmp), &bmp ); 
 
    // Use the passed size, unless zero 
    dwBMPWidth  = ( dwBMPWidth  == 0 ) ? bmp.bmWidth  : dwBMPWidth;      
    dwBMPHeight = ( dwBMPHeight == 0 ) ? bmp.bmHeight : dwBMPHeight; 
 
    // Stretch the bitmap to cover this surface 
    if( FAILED( hr = m_pdds->GetDC( &hDC ) ) ) 
        return hr; 
 
    StretchBlt( hDC, 0, 0,  
                ddsd.dwWidth, ddsd.dwHeight,  
                hDCImage, dwBMPOriginX, dwBMPOriginY, 
                dwBMPWidth, dwBMPHeight, SRCCOPY ); 
 
    if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) ) 
        return hr; 
 
    DeleteDC( hDCImage ); 
 
    return S_OK; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name: CSurface::DrawText() 
// Desc: Draws a text string on a DirectDraw surface using hFont or the default 
//       GDI font if hFont is NULL.   
//----------------------------------------------------------------------------- 
HRESULT CSurface::DrawText( HFONT hFont, TCHAR* strText,  
                            DWORD dwOriginX, DWORD dwOriginY, 
                            COLORREF crBackground, COLORREF crForeground ) 
{ 
    HDC     hDC = NULL; 
    HRESULT hr; 
 
    if( m_pdds == NULL || strText == NULL ) 
        return E_INVALIDARG; 
 
    // Make sure this surface is restored. 
    if( FAILED( hr = m_pdds->Restore() ) ) 
        return hr; 
 
    if( FAILED( hr = m_pdds->GetDC( &hDC ) ) ) 
        return hr; 
 
    // Set the background and foreground color 
    SetBkColor( hDC, crBackground ); 
    SetTextColor( hDC, crForeground ); 
 
    if( hFont ) 
        SelectObject( hDC, hFont ); 
 
    // Use GDI to draw the text on the surface 
    TextOut( hDC, dwOriginX, dwOriginY, strText, _tcslen(strText) ); 
 
    if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) ) 
        return hr; 
 
    return S_OK; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name: CSurface::ReDrawBitmapOnSurface() 
// Desc: Load a bitmap from a file or resource into a DirectDraw surface. 
//       normaly used to re-load a surface after a restore. 
//----------------------------------------------------------------------------- 
HRESULT CSurface::DrawBitmap( TCHAR* strBMP,  
                              DWORD dwDesiredWidth, DWORD dwDesiredHeight  ) 
{ 
    HBITMAP hBMP; 
    HRESULT hr; 
 
    if( m_pdds == NULL || strBMP == NULL ) 
        return E_INVALIDARG; 
 
    //  Try to load the bitmap as a resource, if that fails, try it as a file 
    hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,  
                                IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,  
                                LR_CREATEDIBSECTION ); 
    if( hBMP == NULL ) 
    { 
        hBMP = (HBITMAP) LoadImage( NULL, strBMP, IMAGE_BITMAP,  
                                    dwDesiredWidth, dwDesiredHeight,  
                                    LR_LOADFROMFILE | LR_CREATEDIBSECTION ); 
        if( hBMP == NULL ) 
            return E_FAIL; 
    } 
 
    // Draw the bitmap on this surface 
    if( FAILED( hr = DrawBitmap( hBMP, 0, 0, 0, 0 ) ) ) 
    { 
        DeleteObject( hBMP ); 
        return hr; 
    } 
 
    DeleteObject( hBMP ); 
 
    return S_OK; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name:  
// Desc:  
//----------------------------------------------------------------------------- 
HRESULT CSurface::SetColorKey( DWORD dwColorKey ) 
{ 
    if( NULL == m_pdds ) 
        return E_POINTER; 
 
    m_bColorKeyed = TRUE; 
 
    DDCOLORKEY ddck; 
    ddck.dwColorSpaceLowValue  = ConvertGDIColor( dwColorKey ); 
    ddck.dwColorSpaceHighValue = ConvertGDIColor( dwColorKey ); 
     
    return m_pdds->SetColorKey( DDCKEY_SRCBLT, &ddck ); 
} 
 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name: CSurface::ConvertGDIColor() 
// Desc: Converts a GDI color (0x00bbggrr) into the equivalent color on a  
//       DirectDrawSurface using its pixel format.   
//----------------------------------------------------------------------------- 
DWORD CSurface::ConvertGDIColor( COLORREF dwGDIColor ) 
{ 
    if( m_pdds == NULL ) 
	    return 0x00000000; 
 
    COLORREF       rgbT; 
    HDC            hdc; 
    DWORD          dw = CLR_INVALID; 
    DDSURFACEDESC2 ddsd; 
    HRESULT        hr; 
 
    //  Use GDI SetPixel to color match for us 
    if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK) 
    { 
        rgbT = GetPixel(hdc, 0, 0);     // Save current pixel value 
        SetPixel(hdc, 0, 0, dwGDIColor);       // Set our value 
        m_pdds->ReleaseDC(hdc); 
    } 
 
    // Now lock the surface so we can read back the converted color 
    ddsd.dwSize = sizeof(ddsd); 
    hr = m_pdds->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL ); 
    if( hr == DD_OK) 
    { 
        dw = *(DWORD *) ddsd.lpSurface;  
        if( ddsd.ddpfPixelFormat.dwRGBBitCount < 32 ) // Mask it to bpp 
            dw &= ( 1 << ddsd.ddpfPixelFormat.dwRGBBitCount ) - 1;   
        m_pdds->Unlock(NULL); 
    } 
 
    //  Now put the color that was there back. 
    if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK ) 
    { 
        SetPixel( hdc, 0, 0, rgbT ); 
        m_pdds->ReleaseDC(hdc); 
    } 
     
    return dw;     
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name: CSurface::GetBitMaskInfo() 
// Desc: Returns the number of bits and the shift in the bit mask 
//----------------------------------------------------------------------------- 
HRESULT CSurface::GetBitMaskInfo( DWORD dwBitMask, DWORD* pdwShift, DWORD* pdwBits ) 
{ 
    DWORD dwShift = 0; 
    DWORD dwBits  = 0;  
 
    if( pdwShift == NULL || pdwBits == NULL ) 
        return E_INVALIDARG; 
 
    if( dwBitMask ) 
    { 
        while( (dwBitMask & 1) == 0 ) 
        { 
            dwShift++; 
            dwBitMask >>= 1; 
        } 
    } 
 
    while( (dwBitMask & 1) != 0 ) 
    { 
        dwBits++; 
        dwBitMask >>= 1; 
    } 
 
    *pdwShift = dwShift; 
    *pdwBits  = dwBits; 
 
    return S_OK; 
}