home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / Common / src / ddutil.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  29.2 KB  |  1,032 lines

  1. //-----------------------------------------------------------------------------
  2. // File: ddutil.cpp
  3. //
  4. // Desc: DirectDraw framewark classes. Feel free to use this class as a 
  5. //       starting point for adding extra functionality.
  6. //
  7. //
  8. // Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved.
  9. //-----------------------------------------------------------------------------
  10. #define STRICT
  11. #include <tchar.h>
  12. #include <windows.h>
  13. #include <windowsx.h>
  14. #include <ddraw.h>
  15. #include "ddutil.h"
  16. #include "dxutil.h"
  17.  
  18.  
  19.  
  20.  
  21.  
  22.  
  23. //-----------------------------------------------------------------------------
  24. // Name: CDisplay()
  25. // Desc:
  26. //-----------------------------------------------------------------------------
  27. CDisplay::CDisplay()
  28. {
  29.     m_pDD                = NULL;
  30.     m_pddsFrontBuffer    = NULL;
  31.     m_pddsBackBuffer     = NULL;
  32.     m_pddsBackBufferLeft = NULL;
  33. }
  34.  
  35.  
  36.  
  37.  
  38. //-----------------------------------------------------------------------------
  39. // Name: ~CDisplay()
  40. // Desc:
  41. //-----------------------------------------------------------------------------
  42. CDisplay::~CDisplay()
  43. {
  44.     DestroyObjects();
  45. }
  46.  
  47.  
  48.  
  49.  
  50. //-----------------------------------------------------------------------------
  51. // Name: DestroyObjects()
  52. // Desc:
  53. //-----------------------------------------------------------------------------
  54. HRESULT CDisplay::DestroyObjects()
  55. {
  56.     SAFE_RELEASE( m_pddsBackBufferLeft );
  57.     SAFE_RELEASE( m_pddsBackBuffer );
  58.     SAFE_RELEASE( m_pddsFrontBuffer );
  59.  
  60.     if( m_pDD )
  61.         m_pDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL );
  62.  
  63.     SAFE_RELEASE( m_pDD );
  64.  
  65.     return S_OK;
  66. }
  67.  
  68.  
  69.  
  70.  
  71. //-----------------------------------------------------------------------------
  72. // Name: CreateFullScreenDisplay()
  73. // Desc:
  74. //-----------------------------------------------------------------------------
  75. HRESULT CDisplay::CreateFullScreenDisplay( HWND hWnd, DWORD dwWidth,
  76.                                            DWORD dwHeight, DWORD dwBPP )
  77. {
  78.     HRESULT hr;
  79.  
  80.     // Cleanup anything from a previous call
  81.     DestroyObjects();
  82.  
  83.     // DDraw stuff begins here
  84.     if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
  85.                                          IID_IDirectDraw7, NULL ) ) )
  86.         return E_FAIL;
  87.  
  88.     // Set cooperative level
  89.     hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN );
  90.     if( FAILED(hr) )
  91.         return E_FAIL;
  92.  
  93.     // Set the display mode
  94.     if( FAILED( m_pDD->SetDisplayMode( dwWidth, dwHeight, dwBPP, 0, 0 ) ) )
  95.         return E_FAIL;
  96.  
  97.     // Create primary surface (with backbuffer attached)
  98.     DDSURFACEDESC2 ddsd;
  99.     ZeroMemory( &ddsd, sizeof( ddsd ) );
  100.     ddsd.dwSize            = sizeof( ddsd );
  101.     ddsd.dwFlags           = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
  102.     ddsd.ddsCaps.dwCaps    = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
  103.                              DDSCAPS_COMPLEX | DDSCAPS_3DDEVICE;
  104.     ddsd.dwBackBufferCount = 1;
  105.  
  106.     if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer,
  107.                                            NULL ) ) )
  108.         return E_FAIL;
  109.  
  110.     // Get a pointer to the back buffer
  111.     DDSCAPS2 ddscaps;
  112.     ZeroMemory( &ddscaps, sizeof( ddscaps ) );
  113.     ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
  114.  
  115.     if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps,
  116.                                                             &m_pddsBackBuffer ) ) )
  117.         return E_FAIL;
  118.  
  119.     m_pddsBackBuffer->AddRef();
  120.  
  121.     m_hWnd      = hWnd;
  122.     m_bWindowed = FALSE;
  123.     UpdateBounds();
  124.  
  125.     return S_OK;
  126. }
  127.     
  128.  
  129.  
  130.  
  131. //-----------------------------------------------------------------------------
  132. // Name: CreateWindowedDisplay()
  133. // Desc:
  134. //-----------------------------------------------------------------------------
  135. HRESULT CDisplay::CreateWindowedDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight )
  136. {
  137.     HRESULT hr;
  138.  
  139.     // Cleanup anything from a previous call
  140.     DestroyObjects();
  141.  
  142.     // DDraw stuff begins here
  143.     if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
  144.                                          IID_IDirectDraw7, NULL ) ) )
  145.         return E_FAIL;
  146.  
  147.     // Set cooperative level
  148.     hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_NORMAL );
  149.     if( FAILED(hr) )
  150.         return E_FAIL;
  151.  
  152.     RECT  rcWork;
  153.     RECT  rc;
  154.     DWORD dwStyle;
  155.  
  156.     // If we are still a WS_POPUP window we should convert to a normal app
  157.     // window so we look like a windows app.
  158.     dwStyle  = GetWindowStyle( hWnd );
  159.     dwStyle &= ~WS_POPUP;
  160.     dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX;
  161.     SetWindowLong( hWnd, GWL_STYLE, dwStyle );
  162.  
  163.     // Aet window size
  164.     SetRect( &rc, 0, 0, dwWidth, dwHeight );
  165.  
  166.     AdjustWindowRectEx( &rc, GetWindowStyle(hWnd), GetMenu(hWnd) != NULL,
  167.                         GetWindowExStyle(hWnd) );
  168.  
  169.     SetWindowPos( hWnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
  170.                   SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
  171.  
  172.     SetWindowPos( hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
  173.                   SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
  174.  
  175.     //  Make sure our window does not hang outside of the work area
  176.     SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWork, 0 );
  177.     GetWindowRect( hWnd, &rc );
  178.     if( rc.left < rcWork.left ) rc.left = rcWork.left;
  179.     if( rc.top  < rcWork.top )  rc.top  = rcWork.top;
  180.     SetWindowPos( hWnd, NULL, rc.left, rc.top, 0, 0,
  181.                   SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
  182.  
  183.     LPDIRECTDRAWCLIPPER pcClipper;
  184.     
  185.     // Create the primary surface
  186.     DDSURFACEDESC2 ddsd;
  187.     ZeroMemory( &ddsd, sizeof( ddsd ) );
  188.     ddsd.dwSize         = sizeof( ddsd );
  189.     ddsd.dwFlags        = DDSD_CAPS;
  190.     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  191.  
  192.     if( FAILED( m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) )
  193.         return E_FAIL;
  194.  
  195.     // Create the backbuffer surface
  196.     ddsd.dwFlags        = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;    
  197.     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
  198.     ddsd.dwWidth        = dwWidth;
  199.     ddsd.dwHeight       = dwHeight;
  200.  
  201.     if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL ) ) )
  202.         return E_FAIL;
  203.  
  204.     if( FAILED( hr = m_pDD->CreateClipper( 0, &pcClipper, NULL ) ) )
  205.         return E_FAIL;
  206.  
  207.     if( FAILED( hr = pcClipper->SetHWnd( 0, hWnd ) ) )
  208.     {
  209.         pcClipper->Release();
  210.         return E_FAIL;
  211.     }
  212.  
  213.     if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pcClipper ) ) )
  214.     {
  215.         pcClipper->Release();
  216.         return E_FAIL;
  217.     }
  218.  
  219.     // Done with clipper
  220.     pcClipper->Release();
  221.  
  222.     m_hWnd      = hWnd;
  223.     m_bWindowed = TRUE;
  224.     UpdateBounds();
  225.  
  226.     return S_OK;
  227. }
  228.  
  229.  
  230.  
  231.  
  232. //-----------------------------------------------------------------------------
  233. // Name: 
  234. // Desc: 
  235. //-----------------------------------------------------------------------------
  236. HRESULT CDisplay::CreateSurface( CSurface** ppSurface,
  237.                                  DWORD dwWidth, DWORD dwHeight )
  238. {
  239.     if( NULL == m_pDD )
  240.         return E_POINTER;
  241.     if( NULL == ppSurface )
  242.         return E_INVALIDARG;
  243.  
  244.     HRESULT        hr;
  245.     DDSURFACEDESC2 ddsd;
  246.     ZeroMemory( &ddsd, sizeof( ddsd ) );
  247.     ddsd.dwSize         = sizeof( ddsd );
  248.     ddsd.dwFlags        = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; 
  249.     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  250.     ddsd.dwWidth        = dwWidth;
  251.     ddsd.dwHeight       = dwHeight;
  252.  
  253.     (*ppSurface) = new CSurface();
  254.     if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
  255.     {
  256.         delete (*ppSurface);
  257.         return hr;
  258.     }
  259.  
  260.     return S_OK;
  261. }
  262.  
  263.  
  264.  
  265.  
  266. //-----------------------------------------------------------------------------
  267. // Name: CDisplay::CreateSurfaceFromBitmap()
  268. // Desc: Create a DirectDrawSurface from a bitmap resource or bitmap file.
  269. //       Use MAKEINTRESOURCE() to pass a constant into strBMP.
  270. //-----------------------------------------------------------------------------
  271. HRESULT CDisplay::CreateSurfaceFromBitmap( CSurface** ppSurface,
  272.                                            TCHAR* strBMP,                                            
  273.                                            DWORD dwDesiredWidth, 
  274.                                            DWORD dwDesiredHeight )
  275. {
  276.     HRESULT        hr;
  277.     HBITMAP        hBMP = NULL;
  278.     BITMAP         bmp;
  279.     DDSURFACEDESC2 ddsd;
  280.  
  281.     if( m_pDD == NULL || strBMP == NULL || ppSurface == NULL ) 
  282.         return E_INVALIDARG;
  283.  
  284.     *ppSurface = NULL;
  285.  
  286.     //  Try to load the bitmap as a resource, if that fails, try it as a file
  287.     hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP, 
  288.                                 IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight, 
  289.                                 LR_CREATEDIBSECTION );
  290.     if( hBMP == NULL )
  291.     {
  292.         hBMP = (HBITMAP) LoadImage( NULL, strBMP, 
  293.                                     IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight, 
  294.                                     LR_LOADFROMFILE | LR_CREATEDIBSECTION );
  295.         if( hBMP == NULL )
  296.             return E_FAIL;
  297.     }
  298.  
  299.     // Get size of the bitmap
  300.     GetObject( hBMP, sizeof(bmp), &bmp );
  301.  
  302.     // Create a DirectDrawSurface for this bitmap
  303.     ZeroMemory( &ddsd, sizeof(ddsd) );
  304.     ddsd.dwSize         = sizeof(ddsd);
  305.     ddsd.dwFlags        = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
  306.     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  307.     ddsd.dwWidth        = bmp.bmWidth;
  308.     ddsd.dwHeight       = bmp.bmHeight;
  309.  
  310.     (*ppSurface) = new CSurface();
  311.     if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
  312.     {
  313.         delete (*ppSurface);
  314.         return hr;
  315.     }
  316.  
  317.     // Draw the bitmap on this surface
  318.     if( FAILED( hr = (*ppSurface)->DrawBitmap( hBMP, 0, 0, 0, 0 ) ) )
  319.     {
  320.         DeleteObject( hBMP );
  321.         return hr;
  322.     }
  323.  
  324.     DeleteObject( hBMP );
  325.  
  326.     return S_OK;
  327. }
  328.  
  329.  
  330.  
  331.  
  332. //-----------------------------------------------------------------------------
  333. // Name: CDisplay::CreateSurfaceFromText()
  334. // Desc: Creates a DirectDrawSurface from a text string using hFont or the default 
  335. //       GDI font if hFont is NULL.
  336. //-----------------------------------------------------------------------------
  337. HRESULT CDisplay::CreateSurfaceFromText( CSurface** ppSurface,
  338.                                          HFONT hFont, TCHAR* strText, 
  339.                                          COLORREF crBackground, COLORREF crForeground )
  340. {
  341.     HDC                  hDC  = NULL;
  342.     LPDIRECTDRAWSURFACE7 pDDS = NULL;
  343.     HRESULT              hr;
  344.     DDSURFACEDESC2       ddsd;
  345.     SIZE                 sizeText;
  346.  
  347.     if( m_pDD == NULL || strText == NULL || ppSurface == NULL )
  348.         return E_INVALIDARG;
  349.  
  350.     *ppSurface = NULL;
  351.  
  352.     hDC = GetDC( NULL );
  353.  
  354.     if( hFont )
  355.         SelectObject( hDC, hFont );
  356.  
  357.     GetTextExtentPoint32( hDC, strText, _tcslen(strText), &sizeText );
  358.     ReleaseDC( NULL, hDC );
  359.  
  360.     // Create a DirectDrawSurface for this bitmap
  361.     ZeroMemory( &ddsd, sizeof(ddsd) );
  362.     ddsd.dwSize         = sizeof(ddsd);
  363.     ddsd.dwFlags        = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
  364.     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  365.     ddsd.dwWidth        = sizeText.cx;
  366.     ddsd.dwHeight       = sizeText.cy;
  367.  
  368.     (*ppSurface) = new CSurface();
  369.     if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
  370.     {
  371.         delete (*ppSurface);
  372.         return hr;
  373.     }
  374.  
  375.     if( FAILED( hr = (*ppSurface)->DrawText( hFont, strText, 0, 0, 
  376.                                              crBackground, crForeground ) ) )
  377.         return hr;
  378.  
  379.     return S_OK;
  380. }
  381.  
  382.  
  383.  
  384.  
  385. //-----------------------------------------------------------------------------
  386. // Name: 
  387. // Desc: 
  388. //-----------------------------------------------------------------------------
  389. HRESULT CDisplay::Present()
  390. {
  391.     HRESULT hr;
  392.  
  393.     if( NULL == m_pddsFrontBuffer && NULL == m_pddsBackBuffer )
  394.         return E_POINTER;
  395.  
  396.     while( 1 )
  397.     {
  398.         if( m_bWindowed )
  399.             hr = m_pddsFrontBuffer->Blt( &m_rcWindow, m_pddsBackBuffer,
  400.                                          NULL, DDBLT_WAIT, NULL );
  401.         else
  402.             hr = m_pddsFrontBuffer->Flip( NULL, 0 );
  403.  
  404.         if( hr == DDERR_SURFACELOST )
  405.         {
  406.             m_pddsFrontBuffer->Restore();
  407.             m_pddsBackBuffer->Restore();
  408.         }
  409.  
  410.         if( hr != DDERR_WASSTILLDRAWING )
  411.             return hr;
  412.     }
  413. }
  414.  
  415.  
  416.  
  417.  
  418. //-----------------------------------------------------------------------------
  419. // Name: 
  420. // Desc: 
  421. //-----------------------------------------------------------------------------
  422. HRESULT CDisplay::ShowBitmap( HBITMAP hbm, LPDIRECTDRAWPALETTE pPalette )
  423. {
  424.     if( NULL == m_pddsFrontBuffer ||  NULL == m_pddsBackBuffer )
  425.         return E_POINTER;
  426.  
  427.     // Set the palette before loading the bitmap
  428.     if( pPalette )
  429.         m_pddsFrontBuffer->SetPalette( pPalette );
  430.  
  431.     CSurface backBuffer;
  432.     backBuffer.Create( m_pddsBackBuffer );
  433.  
  434.     if( FAILED( backBuffer.DrawBitmap( hbm, 0, 0, 0, 0 ) ) )
  435.         return E_FAIL;
  436.  
  437.     return Present();
  438. }
  439.  
  440.  
  441.  
  442.  
  443. //-----------------------------------------------------------------------------
  444. // Name: 
  445. // Desc: 
  446. //-----------------------------------------------------------------------------
  447. HRESULT CDisplay::ColorKeyBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
  448.                                RECT* prc )
  449. {
  450.     if( NULL == m_pddsBackBuffer )
  451.         return E_POINTER;
  452.  
  453.     return m_pddsBackBuffer->BltFast( x, y, pdds, prc, DDBLTFAST_SRCCOLORKEY );
  454. }
  455.  
  456.  
  457.  
  458.  
  459. //-----------------------------------------------------------------------------
  460. // Name: 
  461. // Desc: 
  462. //-----------------------------------------------------------------------------
  463. HRESULT CDisplay::Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds, RECT* prc,
  464.                        DWORD dwFlags )
  465. {
  466.     if( NULL == m_pddsBackBuffer )
  467.         return E_POINTER;
  468.  
  469.     return m_pddsBackBuffer->BltFast( x, y, pdds, prc, dwFlags );
  470. }
  471.  
  472.  
  473.  
  474.  
  475. //-----------------------------------------------------------------------------
  476. // Name: 
  477. // Desc: 
  478. //-----------------------------------------------------------------------------
  479. HRESULT CDisplay::Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc )
  480. {
  481.     if( NULL == pSurface )
  482.         return E_INVALIDARG;
  483.  
  484.     if( pSurface->IsColorKeyed() )
  485.         return Blt( x, y, pSurface->GetDDrawSurface(), prc, DDBLTFAST_SRCCOLORKEY );
  486.     else
  487.         return Blt( x, y, pSurface->GetDDrawSurface(), prc, 0L );
  488. }
  489.  
  490.  
  491.  
  492.  
  493. //-----------------------------------------------------------------------------
  494. // Name: 
  495. // Desc: 
  496. //-----------------------------------------------------------------------------
  497. HRESULT CDisplay::Clear( DWORD dwColor )
  498. {
  499.     if( NULL == m_pddsBackBuffer )
  500.         return E_POINTER;
  501.  
  502.     // Erase the background
  503.     DDBLTFX ddbltfx;
  504.     ZeroMemory( &ddbltfx, sizeof(ddbltfx) );
  505.     ddbltfx.dwSize      = sizeof(ddbltfx);
  506.     ddbltfx.dwFillColor = dwColor;
  507.  
  508.     return m_pddsBackBuffer->Blt( NULL, NULL, NULL, DDBLT_COLORFILL, &ddbltfx );
  509. }
  510.  
  511.  
  512.  
  513.  
  514. //-----------------------------------------------------------------------------
  515. // Name: 
  516. // Desc: 
  517. //-----------------------------------------------------------------------------
  518. HRESULT CDisplay::SetPalette( LPDIRECTDRAWPALETTE pPalette )
  519. {
  520.     if( NULL == m_pddsFrontBuffer )
  521.         return E_POINTER;
  522.  
  523.     return m_pddsFrontBuffer->SetPalette( pPalette );
  524. }
  525.  
  526.  
  527.  
  528.  
  529. //-----------------------------------------------------------------------------
  530. // Name: 
  531. // Desc: 
  532. //-----------------------------------------------------------------------------
  533. HRESULT CDisplay::CreatePaletteFromBitmap( LPDIRECTDRAWPALETTE* ppPalette,
  534.                                            const TCHAR* strBMP )
  535. {
  536.     HRSRC             hResource      = NULL;
  537.     RGBQUAD*          pRGB           = NULL;
  538.     BITMAPINFOHEADER* pbi = NULL;
  539.     PALETTEENTRY      aPalette[256];
  540.     HANDLE            hFile = NULL;
  541.     DWORD             iColor;
  542.     DWORD             dwColors;
  543.     BITMAPFILEHEADER  bf;
  544.     BITMAPINFOHEADER  bi;
  545.     DWORD             dwBytesRead;
  546.  
  547.     if( m_pDD == NULL || strBMP == NULL || ppPalette == NULL )
  548.         return E_INVALIDARG;
  549.  
  550.     *ppPalette = NULL;
  551.  
  552.     //  Try to load the bitmap as a resource, if that fails, try it as a file
  553.     hResource = FindResource( NULL, strBMP, RT_BITMAP );
  554.     if( hResource )
  555.     {
  556.         pbi = (LPBITMAPINFOHEADER) LockResource( LoadResource( NULL, hResource ) );       
  557.         if( NULL == pbi )
  558.             return E_FAIL;
  559.  
  560.         pRGB = (RGBQUAD*) ( (BYTE*) pbi + pbi->biSize );
  561.  
  562.         // Figure out how many colors there are
  563.         if( pbi == NULL || pbi->biSize < sizeof(BITMAPINFOHEADER) )
  564.             dwColors = 0;
  565.         else if( pbi->biBitCount > 8 )
  566.             dwColors = 0;
  567.         else if( pbi->biClrUsed == 0 )
  568.             dwColors = 1 << pbi->biBitCount;
  569.         else
  570.             dwColors = pbi->biClrUsed;
  571.  
  572.         //  A DIB color table has its colors stored BGR not RGB
  573.         //  so flip them around.
  574.         for( iColor = 0; iColor < dwColors; iColor++ )
  575.         {
  576.             aPalette[iColor].peRed   = pRGB[iColor].rgbRed;
  577.             aPalette[iColor].peGreen = pRGB[iColor].rgbGreen;
  578.             aPalette[iColor].peBlue  = pRGB[iColor].rgbBlue;
  579.             aPalette[iColor].peFlags = 0;
  580.         }
  581.  
  582.         return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL );
  583.     }
  584.  
  585.     // Attempt to load bitmap as a file
  586.     hFile = CreateFile( strBMP, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
  587.     if( NULL == hFile )
  588.         return E_FAIL;
  589.  
  590.     // Read the BITMAPFILEHEADER
  591.     ReadFile( hFile, &bf, sizeof(bf), &dwBytesRead, NULL );
  592.     if( dwBytesRead != sizeof(bf) )
  593.     {
  594.         CloseHandle( hFile );
  595.         return E_FAIL;
  596.     }
  597.  
  598.     // Read the BITMAPINFOHEADER
  599.     ReadFile( hFile, &bi, sizeof(bi), &dwBytesRead, NULL );
  600.     if( dwBytesRead != sizeof(bi) )
  601.     {
  602.         CloseHandle( hFile );
  603.         return E_FAIL;
  604.     }
  605.  
  606.     // Read the PALETTEENTRY 
  607.     ReadFile( hFile, aPalette, sizeof(aPalette), &dwBytesRead, NULL );
  608.     if( dwBytesRead != sizeof(aPalette) )
  609.     {
  610.         CloseHandle( hFile );
  611.         return E_FAIL;
  612.     }
  613.  
  614.     CloseHandle( hFile );
  615.  
  616.     // Figure out how many colors there are
  617.     if( bi.biSize != sizeof(BITMAPINFOHEADER) )
  618.         dwColors = 0;
  619.     else if (bi.biBitCount > 8)
  620.         dwColors = 0;
  621.     else if (bi.biClrUsed == 0)
  622.         dwColors = 1 << bi.biBitCount;
  623.     else
  624.         dwColors = bi.biClrUsed;
  625.  
  626.     //  A DIB color table has its colors stored BGR not RGB
  627.     //  so flip them around since DirectDraw uses RGB
  628.     for( iColor = 0; iColor < dwColors; iColor++ )
  629.     {
  630.         BYTE r = aPalette[iColor].peRed;
  631.         aPalette[iColor].peRed  = aPalette[iColor].peBlue;
  632.         aPalette[iColor].peBlue = r;
  633.     }
  634.  
  635.     return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL );
  636. }
  637.  
  638.  
  639.  
  640.  
  641. //-----------------------------------------------------------------------------
  642. // Name: 
  643. // Desc: 
  644. //-----------------------------------------------------------------------------
  645. HRESULT CDisplay::UpdateBounds()
  646. {
  647.     if( m_bWindowed )
  648.     {
  649.         GetClientRect( m_hWnd, &m_rcWindow );
  650.         ClientToScreen( m_hWnd, (POINT*)&m_rcWindow );
  651.         ClientToScreen( m_hWnd, (POINT*)&m_rcWindow+1 );
  652.     }
  653.     else
  654.     {
  655.         SetRect( &m_rcWindow, 0, 0, GetSystemMetrics(SM_CXSCREEN),
  656.                  GetSystemMetrics(SM_CYSCREEN) );
  657.     }
  658.  
  659.     return S_OK;
  660. }
  661.  
  662.  
  663.  
  664.  
  665.  
  666. //-----------------------------------------------------------------------------
  667. // Name: CDisplay::InitClipper
  668. // Desc: 
  669. //-----------------------------------------------------------------------------
  670. HRESULT CDisplay::InitClipper()
  671. {
  672.     LPDIRECTDRAWCLIPPER pClipper;
  673.     HRESULT hr;
  674.  
  675.     // Create a clipper when using GDI to draw on the primary surface 
  676.     if( FAILED( hr = m_pDD->CreateClipper( 0, &pClipper, NULL ) ) )
  677.         return hr;
  678.  
  679.     pClipper->SetHWnd( 0, m_hWnd );
  680.  
  681.     if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pClipper ) ) )
  682.         return hr;
  683.  
  684.     // We can release the clipper now since g_pDDSPrimary 
  685.     // now maintains a ref count on the clipper
  686.     SAFE_RELEASE( pClipper );
  687.  
  688.     return S_OK;
  689. }
  690.  
  691.  
  692.  
  693.  
  694.  
  695. //-----------------------------------------------------------------------------
  696. // Name: 
  697. // Desc: 
  698. //-----------------------------------------------------------------------------
  699. CSurface::CSurface()
  700. {
  701.     m_pdds = NULL;
  702.     m_bColorKeyed = NULL;
  703. }
  704.  
  705.  
  706.  
  707.  
  708. //-----------------------------------------------------------------------------
  709. // Name: 
  710. // Desc: 
  711. //-----------------------------------------------------------------------------
  712. CSurface::~CSurface()
  713. {
  714.     SAFE_RELEASE( m_pdds );
  715. }
  716.  
  717.  
  718.  
  719.  
  720. //-----------------------------------------------------------------------------
  721. // Name: 
  722. // Desc: 
  723. //-----------------------------------------------------------------------------
  724. HRESULT CSurface::Create( LPDIRECTDRAWSURFACE7 pdds )
  725. {
  726.     m_pdds = pdds;
  727.  
  728.     if( m_pdds )
  729.     {
  730.         m_pdds->AddRef();
  731.  
  732.         // Get the DDSURFACEDESC structure for this surface
  733.         m_ddsd.dwSize = sizeof(m_ddsd);
  734.         m_pdds->GetSurfaceDesc( &m_ddsd );
  735.     }
  736.  
  737.     return S_OK;
  738. }
  739.  
  740.  
  741.  
  742.  
  743. //-----------------------------------------------------------------------------
  744. // Name: 
  745. // Desc: 
  746. //-----------------------------------------------------------------------------
  747. HRESULT CSurface::Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd )
  748. {
  749.     HRESULT hr;
  750.  
  751.     // Create the DDraw surface
  752.     if( FAILED( hr = pDD->CreateSurface( pddsd, &m_pdds, NULL ) ) )
  753.         return hr;
  754.  
  755.     // Prepare the DDSURFACEDESC structure
  756.     m_ddsd.dwSize = sizeof(m_ddsd);
  757.  
  758.     // Get the DDSURFACEDESC structure for this surface
  759.     m_pdds->GetSurfaceDesc( &m_ddsd );
  760.  
  761.     return S_OK;
  762. }
  763.  
  764.  
  765.  
  766.  
  767. //-----------------------------------------------------------------------------
  768. // Name: 
  769. // Desc: 
  770. //-----------------------------------------------------------------------------
  771. HRESULT CSurface::Destroy()
  772. {
  773.     SAFE_RELEASE( m_pdds );
  774.     return S_OK;
  775. }
  776.  
  777.  
  778.  
  779.  
  780. //-----------------------------------------------------------------------------
  781. // Name: CSurface::DrawBitmap()
  782. // Desc: Draws a bitmap over an entire DirectDrawSurface, stretching the 
  783. //       bitmap if nessasary
  784. //-----------------------------------------------------------------------------
  785. HRESULT CSurface::DrawBitmap( HBITMAP hBMP, 
  786.                               DWORD dwBMPOriginX, DWORD dwBMPOriginY, 
  787.                               DWORD dwBMPWidth, DWORD dwBMPHeight )
  788. {
  789.     HDC            hDCImage;
  790.     HDC            hDC;
  791.     BITMAP         bmp;
  792.     DDSURFACEDESC2 ddsd;
  793.     HRESULT        hr;
  794.  
  795.     if( hBMP == NULL || m_pdds == NULL )
  796.         return E_INVALIDARG;
  797.  
  798.     // Make sure this surface is restored.
  799.     if( FAILED( hr = m_pdds->Restore() ) )
  800.         return hr;
  801.  
  802.     // Get the surface.description
  803.     ddsd.dwSize  = sizeof(ddsd);
  804.     m_pdds->GetSurfaceDesc( &ddsd );
  805.  
  806.     if( ddsd.ddpfPixelFormat.dwFlags == DDPF_FOURCC )
  807.         return E_NOTIMPL;
  808.  
  809.     // Select bitmap into a memoryDC so we can use it.
  810.     hDCImage = CreateCompatibleDC( NULL );
  811.     if( NULL == hDCImage )
  812.         return E_FAIL;
  813.  
  814.     SelectObject( hDCImage, hBMP );
  815.  
  816.     // Get size of the bitmap
  817.     GetObject( hBMP, sizeof(bmp), &bmp );
  818.  
  819.     // Use the passed size, unless zero
  820.     dwBMPWidth  = ( dwBMPWidth  == 0 ) ? bmp.bmWidth  : dwBMPWidth;     
  821.     dwBMPHeight = ( dwBMPHeight == 0 ) ? bmp.bmHeight : dwBMPHeight;
  822.  
  823.     // Stretch the bitmap to cover this surface
  824.     if( FAILED( hr = m_pdds->GetDC( &hDC ) ) )
  825.         return hr;
  826.  
  827.     StretchBlt( hDC, 0, 0, 
  828.                 ddsd.dwWidth, ddsd.dwHeight, 
  829.                 hDCImage, dwBMPOriginX, dwBMPOriginY,
  830.                 dwBMPWidth, dwBMPHeight, SRCCOPY );
  831.  
  832.     if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
  833.         return hr;
  834.  
  835.     DeleteDC( hDCImage );
  836.  
  837.     return S_OK;
  838. }
  839.  
  840.  
  841.  
  842.  
  843. //-----------------------------------------------------------------------------
  844. // Name: CSurface::DrawText()
  845. // Desc: Draws a text string on a DirectDraw surface using hFont or the default
  846. //       GDI font if hFont is NULL.  
  847. //-----------------------------------------------------------------------------
  848. HRESULT CSurface::DrawText( HFONT hFont, TCHAR* strText, 
  849.                             DWORD dwOriginX, DWORD dwOriginY,
  850.                             COLORREF crBackground, COLORREF crForeground )
  851. {
  852.     HDC     hDC = NULL;
  853.     HRESULT hr;
  854.  
  855.     if( m_pdds == NULL || strText == NULL )
  856.         return E_INVALIDARG;
  857.  
  858.     // Make sure this surface is restored.
  859.     if( FAILED( hr = m_pdds->Restore() ) )
  860.         return hr;
  861.  
  862.     if( FAILED( hr = m_pdds->GetDC( &hDC ) ) )
  863.         return hr;
  864.  
  865.     // Set the background and foreground color
  866.     SetBkColor( hDC, crBackground );
  867.     SetTextColor( hDC, crForeground );
  868.  
  869.     if( hFont )
  870.         SelectObject( hDC, hFont );
  871.  
  872.     // Use GDI to draw the text on the surface
  873.     TextOut( hDC, dwOriginX, dwOriginY, strText, _tcslen(strText) );
  874.  
  875.     if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
  876.         return hr;
  877.  
  878.     return S_OK;
  879. }
  880.  
  881.  
  882.  
  883.  
  884. //-----------------------------------------------------------------------------
  885. // Name: CSurface::ReDrawBitmapOnSurface()
  886. // Desc: Load a bitmap from a file or resource into a DirectDraw surface.
  887. //       normaly used to re-load a surface after a restore.
  888. //-----------------------------------------------------------------------------
  889. HRESULT CSurface::DrawBitmap( TCHAR* strBMP, 
  890.                               DWORD dwDesiredWidth, DWORD dwDesiredHeight  )
  891. {
  892.     HBITMAP hBMP;
  893.     HRESULT hr;
  894.  
  895.     if( m_pdds == NULL || strBMP == NULL )
  896.         return E_INVALIDARG;
  897.  
  898.     //  Try to load the bitmap as a resource, if that fails, try it as a file
  899.     hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP, 
  900.                                 IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight, 
  901.                                 LR_CREATEDIBSECTION );
  902.     if( hBMP == NULL )
  903.     {
  904.         hBMP = (HBITMAP) LoadImage( NULL, strBMP, IMAGE_BITMAP, 
  905.                                     dwDesiredWidth, dwDesiredHeight, 
  906.                                     LR_LOADFROMFILE | LR_CREATEDIBSECTION );
  907.         if( hBMP == NULL )
  908.             return E_FAIL;
  909.     }
  910.  
  911.     // Draw the bitmap on this surface
  912.     if( FAILED( hr = DrawBitmap( hBMP, 0, 0, 0, 0 ) ) )
  913.     {
  914.         DeleteObject( hBMP );
  915.         return hr;
  916.     }
  917.  
  918.     DeleteObject( hBMP );
  919.  
  920.     return S_OK;
  921. }
  922.  
  923.  
  924.  
  925.  
  926. //-----------------------------------------------------------------------------
  927. // Name: 
  928. // Desc: 
  929. //-----------------------------------------------------------------------------
  930. HRESULT CSurface::SetColorKey( DWORD dwColorKey )
  931. {
  932.     if( NULL == m_pdds )
  933.         return E_POINTER;
  934.  
  935.     m_bColorKeyed = TRUE;
  936.  
  937.     DDCOLORKEY ddck;
  938.     ddck.dwColorSpaceLowValue  = ConvertGDIColor( dwColorKey );
  939.     ddck.dwColorSpaceHighValue = ConvertGDIColor( dwColorKey );
  940.     
  941.     return m_pdds->SetColorKey( DDCKEY_SRCBLT, &ddck );
  942. }
  943.  
  944.  
  945.  
  946.  
  947.  
  948. //-----------------------------------------------------------------------------
  949. // Name: CSurface::ConvertGDIColor()
  950. // Desc: Converts a GDI color (0x00bbggrr) into the equivalent color on a 
  951. //       DirectDrawSurface using its pixel format.  
  952. //-----------------------------------------------------------------------------
  953. DWORD CSurface::ConvertGDIColor( COLORREF dwGDIColor )
  954. {
  955.     if( m_pdds == NULL )
  956.         return 0x00000000;
  957.  
  958.     COLORREF       rgbT;
  959.     HDC            hdc;
  960.     DWORD          dw = CLR_INVALID;
  961.     DDSURFACEDESC2 ddsd;
  962.     HRESULT        hr;
  963.  
  964.     //  Use GDI SetPixel to color match for us
  965.     if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK)
  966.     {
  967.         rgbT = GetPixel(hdc, 0, 0);     // Save current pixel value
  968.         SetPixel(hdc, 0, 0, dwGDIColor);       // Set our value
  969.         m_pdds->ReleaseDC(hdc);
  970.     }
  971.  
  972.     // Now lock the surface so we can read back the converted color
  973.     ddsd.dwSize = sizeof(ddsd);
  974.     hr = m_pdds->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
  975.     if( hr == DD_OK)
  976.     {
  977.         dw = *(DWORD *) ddsd.lpSurface; 
  978.         if( ddsd.ddpfPixelFormat.dwRGBBitCount < 32 ) // Mask it to bpp
  979.             dw &= ( 1 << ddsd.ddpfPixelFormat.dwRGBBitCount ) - 1;  
  980.         m_pdds->Unlock(NULL);
  981.     }
  982.  
  983.     //  Now put the color that was there back.
  984.     if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK )
  985.     {
  986.         SetPixel( hdc, 0, 0, rgbT );
  987.         m_pdds->ReleaseDC(hdc);
  988.     }
  989.     
  990.     return dw;    
  991. }
  992.  
  993.  
  994.  
  995.  
  996. //-----------------------------------------------------------------------------
  997. // Name: CSurface::GetBitMaskInfo()
  998. // Desc: Returns the number of bits and the shift in the bit mask
  999. //-----------------------------------------------------------------------------
  1000. HRESULT CSurface::GetBitMaskInfo( DWORD dwBitMask, DWORD* pdwShift, DWORD* pdwBits )
  1001. {
  1002.     DWORD dwShift = 0;
  1003.     DWORD dwBits  = 0; 
  1004.  
  1005.     if( pdwShift == NULL || pdwBits == NULL )
  1006.         return E_INVALIDARG;
  1007.  
  1008.     if( dwBitMask )
  1009.     {
  1010.         while( (dwBitMask & 1) == 0 )
  1011.         {
  1012.             dwShift++;
  1013.             dwBitMask >>= 1;
  1014.         }
  1015.     }
  1016.  
  1017.     while( (dwBitMask & 1) != 0 )
  1018.     {
  1019.         dwBits++;
  1020.         dwBitMask >>= 1;
  1021.     }
  1022.  
  1023.     *pdwShift = dwShift;
  1024.     *pdwBits  = dwBits;
  1025.  
  1026.     return S_OK;
  1027. }
  1028.  
  1029.  
  1030.  
  1031.  
  1032.