home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectDraw / DirectSurfaceWrite / directsurfacewrite.cpp next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  17.9 KB  |  552 lines

  1. //-----------------------------------------------------------------------------
  2. // File: DirectSurfaceWrite.cpp
  3. //
  4. // Desc: This sample demonstrates how to animate sprites using
  5. //       DirectDraw.  The samples runs in full-screen mode.  Pressing any
  6. //       key will exit the sample.
  7. //
  8. // Copyright (c) 1999-2001 Microsoft Corporation. All rights reserved.
  9. //-----------------------------------------------------------------------------
  10. #define STRICT
  11. #include <windows.h>
  12. #include <ddraw.h>
  13. #include <mmsystem.h>
  14. #include "resource.h"
  15. #include "ddutil.h"
  16.  
  17.  
  18.  
  19.  
  20. //-----------------------------------------------------------------------------
  21. // Defines, constants, and global variables
  22. //-----------------------------------------------------------------------------
  23. #define SAFE_DELETE(p)  { if(p) { delete (p);     (p)=NULL; } }
  24. #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
  25.  
  26. #define SCREEN_WIDTH        640
  27. #define SCREEN_HEIGHT       480
  28. #define SCREEN_BPP          16
  29.  
  30. #define SPRITE_DIAMETER     250
  31. #define NUM_SPRITES         5
  32.  
  33. #define HELPTEXT TEXT("Press Escape to quit.")
  34.  
  35. struct SPRITE_STRUCT
  36. {
  37.     FLOAT fPosX; 
  38.     FLOAT fPosY;
  39.     FLOAT fVelX; 
  40.     FLOAT fVelY;
  41. };
  42.  
  43. CDisplay*            g_pDisplay           = NULL;
  44. CSurface*            g_pSpriteSurface     = NULL;  
  45. CSurface*            g_pTextSurface       = NULL;  
  46. RECT                 g_rcViewport;          
  47. RECT                 g_rcScreen;            
  48. BOOL                 g_bActive            = FALSE; 
  49. DWORD                g_dwLastTick;
  50. SPRITE_STRUCT        g_Sprite[NUM_SPRITES]; 
  51.  
  52.  
  53.  
  54.  
  55. //-----------------------------------------------------------------------------
  56. // Function-prototypes
  57. //-----------------------------------------------------------------------------
  58. LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
  59. HRESULT WinInit( HINSTANCE hInst, int nCmdShow, HWND* phWnd, HACCEL* phAccel );
  60. HRESULT InitDirectDraw( HWND hWnd );
  61. HRESULT DrawSprite();
  62. VOID    FreeDirectDraw();
  63. HRESULT ProcessNextFrame();
  64. VOID    UpdateSprite( SPRITE_STRUCT* pSprite, FLOAT fTimeDelta );
  65. HRESULT DisplayFrame();
  66. HRESULT RestoreSurfaces();
  67.  
  68.  
  69.  
  70.  
  71. //-----------------------------------------------------------------------------
  72. // Name: WinMain()
  73. // Desc: Entry point to the program. Initializes everything and calls
  74. //       UpdateFrame() when idle from the message pump.
  75. //-----------------------------------------------------------------------------
  76. int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int nCmdShow )
  77. {
  78.     MSG         msg;
  79.     HWND     hWnd;
  80.     HACCEL   hAccel;
  81.  
  82.     ZeroMemory( &g_Sprite, sizeof(SPRITE_STRUCT) * NUM_SPRITES );
  83.     srand( GetTickCount() );
  84.  
  85.     if( FAILED( WinInit( hInst, nCmdShow, &hWnd, &hAccel ) ) )
  86.         return FALSE;
  87.  
  88.     if( FAILED( InitDirectDraw( hWnd ) ) )
  89.     {
  90.         SAFE_DELETE( g_pDisplay );
  91.  
  92.         MessageBox( hWnd, TEXT("DirectDraw init failed. ")
  93.                     TEXT("The sample will now exit. "), TEXT("DirectDraw Sample"), 
  94.                     MB_ICONERROR | MB_OK );
  95.         return FALSE;
  96.     }
  97.  
  98.     g_dwLastTick = timeGetTime();
  99.  
  100.     while( TRUE )
  101.     {
  102.         // Look for messages, if none are found then 
  103.         // update the state and display it
  104.         if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
  105.         {
  106.             if( 0 == GetMessage(&msg, NULL, 0, 0 ) )
  107.             {
  108.                 // WM_QUIT was posted, so exit
  109.                 return (int)msg.wParam;
  110.             }
  111.  
  112.             // Translate and dispatch the message
  113.             if( 0 == TranslateAccelerator( hWnd, hAccel, &msg ) )
  114.             {
  115.                 TranslateMessage( &msg ); 
  116.                 DispatchMessage( &msg );
  117.             }
  118.         }
  119.         else
  120.         {
  121.             if( g_bActive )
  122.             {
  123.                 // Move the sprites, blt them to the back buffer, then 
  124.                 // flip or blt the back buffer to the primary buffer
  125.                 if( FAILED( ProcessNextFrame() ) )
  126.                 {
  127.                     SAFE_DELETE( g_pDisplay );
  128.  
  129.                     MessageBox( hWnd, TEXT("Displaying the next frame failed. ")
  130.                                 TEXT("The sample will now exit. "), TEXT("DirectDraw Sample"), 
  131.                                 MB_ICONERROR | MB_OK );
  132.                     return FALSE;
  133.                 }
  134.             }
  135.             else
  136.             {
  137.                 // Make sure we go to sleep if we have nothing else to do
  138.                 WaitMessage();
  139.  
  140.                 // Ignore time spent inactive 
  141.                 g_dwLastTick = timeGetTime();
  142.             }
  143.         }
  144.     }
  145. }
  146.  
  147.  
  148.  
  149.  
  150. //-----------------------------------------------------------------------------
  151. // Name: WinInit()
  152. // Desc: Init the window
  153. //-----------------------------------------------------------------------------
  154. HRESULT WinInit( HINSTANCE hInst, int nCmdShow, HWND* phWnd, HACCEL* phAccel )
  155. {
  156.     WNDCLASS wc;
  157.     HWND     hWnd;
  158.     HACCEL   hAccel;
  159.  
  160.     // Register the Window Class
  161.     wc.lpszClassName = TEXT("DirectSurfaceWrite");
  162.     wc.lpfnWndProc   = MainWndProc;
  163.     wc.style         = CS_VREDRAW | CS_HREDRAW;
  164.     wc.hInstance     = hInst;
  165.     wc.hIcon         = LoadIcon( hInst, MAKEINTRESOURCE(IDI_MAIN) );
  166.     wc.hCursor       = LoadCursor( NULL, IDC_ARROW );
  167.     wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  168.     wc.lpszMenuName  = NULL;
  169.     wc.cbClsExtra    = 0;
  170.     wc.cbWndExtra    = 0;
  171.  
  172.     if( RegisterClass( &wc ) == 0 )
  173.         return E_FAIL;
  174.  
  175.     // Load keyboard accelerators
  176.     hAccel = LoadAccelerators( hInst, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
  177.  
  178.     // Create and show the main window
  179.     hWnd = CreateWindowEx( 0, TEXT("DirectSurfaceWrite"), TEXT("DirectDraw DirectSurfaceWrite Sample"),
  180.                            WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,
  181.                              CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL );
  182.     if( hWnd == NULL )
  183.         return E_FAIL;
  184.  
  185.     ShowWindow( hWnd, nCmdShow );
  186.     UpdateWindow( hWnd );
  187.  
  188.     *phWnd   = hWnd;
  189.     *phAccel = hAccel;
  190.  
  191.     return S_OK;
  192. }
  193.  
  194.  
  195.  
  196.  
  197. //-----------------------------------------------------------------------------
  198. // Name: InitDirectDraw()
  199. // Desc: Create the DirectDraw object, and init the surfaces
  200. //-----------------------------------------------------------------------------
  201. HRESULT InitDirectDraw( HWND hWnd )
  202. {
  203.     HRESULT        hr;
  204.  
  205.     g_pDisplay = new CDisplay();
  206.     if( FAILED( hr = g_pDisplay->CreateFullScreenDisplay( hWnd, SCREEN_WIDTH, 
  207.                                                           SCREEN_HEIGHT, SCREEN_BPP ) ) )
  208.     {
  209.         MessageBox( hWnd, TEXT("This display card does not support 640x480x8. "),
  210.                     TEXT("DirectDraw Sample"), MB_ICONERROR | MB_OK );
  211.         return hr;
  212.     }
  213.  
  214.     // Create a DirectDrawSurface for this bitmap
  215.     if( FAILED( hr = g_pDisplay->CreateSurface( &g_pSpriteSurface, SPRITE_DIAMETER, SPRITE_DIAMETER ) ) )
  216.         return hr;
  217.  
  218.     if( FAILED( hr = DrawSprite() ) )
  219.         return hr;
  220.     
  221.     // Create a surface, and draw text to it.  
  222.     if( FAILED( hr = g_pDisplay->CreateSurfaceFromText( &g_pTextSurface, NULL, HELPTEXT, 
  223.                                                         RGB(0,0,0), RGB(255, 255, 0) ) ) )
  224.         return hr;
  225.  
  226.     // Init all the sprites.  All of these sprites using the 
  227.     // same g_pDDSAnimationSheet surface, but depending on the
  228.     // sprite's lFrame value, it indexes a different rect on the 
  229.     // surface.
  230.     for( int iSprite = 0; iSprite < NUM_SPRITES; iSprite++ )
  231.     {
  232.         // Set the sprite's position and velocity
  233.         g_Sprite[iSprite].fPosX = (float) (rand() % SCREEN_WIDTH);
  234.         g_Sprite[iSprite].fPosY = (float) (rand() % SCREEN_HEIGHT); 
  235.  
  236.         g_Sprite[iSprite].fVelX = 500.0f * rand() / RAND_MAX - 250.0f;
  237.         g_Sprite[iSprite].fVelY = 500.0f * rand() / RAND_MAX - 250.0f;
  238.     }
  239.  
  240.     return S_OK;
  241. }
  242.  
  243.  
  244.  
  245.  
  246. //-----------------------------------------------------------------------------
  247. // Name: DrawSprite()
  248. // Desc: Draws a pattern of colors to a DirectDraw surface by directly writing
  249. //       to the surface memory.  This function was designed to work only in 
  250. //       16-bit color.
  251. //-----------------------------------------------------------------------------
  252. HRESULT DrawSprite()
  253. {
  254.     DDSURFACEDESC2 ddsd;
  255.     HRESULT        hr;
  256.     DWORD dwShift;
  257.     DWORD dwBits;
  258.     DWORD dwRed;
  259.     DWORD dwGreen;
  260.     DWORD dwBlue;
  261.     FLOAT fPercentX;
  262.     FLOAT fPercentY;
  263.     FLOAT fPercentXY;
  264.  
  265.     LPDIRECTDRAWSURFACE7 pDDS = g_pSpriteSurface->GetDDrawSurface();
  266.  
  267.     ZeroMemory( &ddsd,sizeof(ddsd) );
  268.     ddsd.dwSize = sizeof(ddsd);
  269.  
  270.     // Lock the surface to directly write to the surface memory 
  271.     if( FAILED( hr = pDDS->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL ) ) )
  272.         return hr;
  273.  
  274.     // Get a pointer into the memory starting at ddsd.lpSurface.  Cast this pointer to a 
  275.     // 16-bit WORD since we are in 16 bit color, so each pixel has 16 bits of color information.  
  276.     WORD* pDDSColor = (WORD*) ddsd.lpSurface;
  277.  
  278.     for( DWORD iY = 0; iY < ddsd.dwHeight; iY++ )
  279.     {
  280.         for( DWORD iX = 0; iX < ddsd.dwWidth; iX++ )
  281.         {
  282.             // Figure out the red component as a function of the Y location of the pixel
  283.             CSurface::GetBitMaskInfo( ddsd.ddpfPixelFormat.dwRBitMask, &dwShift, &dwBits );
  284.             fPercentY = (float) abs( ddsd.dwHeight / 2 - iY ) / (float) ( ddsd.dwHeight / 2 ) + 0.25f;
  285.             if( fPercentY > 1.00f )
  286.                 fPercentY = 1.00f;
  287.             dwRed = (DWORD) ( (ddsd.ddpfPixelFormat.dwRBitMask >> dwShift) * fPercentY) << dwShift;
  288.  
  289.             // Figure out the green component as a function of the X location of the pixel
  290.             CSurface::GetBitMaskInfo( ddsd.ddpfPixelFormat.dwGBitMask, &dwShift, &dwBits );
  291.             fPercentX = (float) abs( ddsd.dwWidth / 2 - iX ) / (float) ( ddsd.dwWidth / 2 ) + 0.25f;
  292.             if( fPercentX > 1.00f )
  293.                 fPercentX = 1.00f;
  294.             dwGreen = (DWORD) ( (ddsd.ddpfPixelFormat.dwGBitMask >> dwShift) * fPercentX) << dwShift;
  295.  
  296.             // Figure out the blue component as a function of the X and Y location of the pixel
  297.             CSurface::GetBitMaskInfo( ddsd.ddpfPixelFormat.dwBBitMask, &dwShift, &dwBits );
  298.             fPercentX = (float) abs( ddsd.dwWidth / 2 - iX ) / (float) ( ddsd.dwWidth / 4 );
  299.             fPercentX = 1.0f - fPercentX * fPercentX;
  300.             fPercentY = (float) abs( ddsd.dwHeight / 2 - iY ) / (float) ( ddsd.dwHeight / 4 );
  301.             fPercentY = 1.0f - fPercentY * fPercentY;
  302.             fPercentXY = fPercentX + fPercentY;
  303.             if( fPercentXY > 1.0f )
  304.                 fPercentXY = 1.0f;
  305.             if( fPercentXY < 0.0f )
  306.                 fPercentXY = 0.0f;
  307.             dwBlue = (DWORD) ( (ddsd.ddpfPixelFormat.dwBBitMask >> dwShift) * fPercentXY ) << dwShift;
  308.  
  309.             // Make the dwDDSColor by combining all the color components
  310.             *pDDSColor = (WORD) ( dwRed | dwGreen | dwBlue );
  311.  
  312.             // Advance the surface pointer by 16 bits (one pixel) 
  313.             pDDSColor++;
  314.         }
  315.  
  316.         // Multiply ddsd.lPitch by iY to figure out offset needed to access 
  317.         // the next scan line on the surface. 
  318.         pDDSColor = (WORD*) ( (BYTE*) ddsd.lpSurface + ( iY + 1 ) * ddsd.lPitch );
  319.     }
  320.     
  321.     // Unlock the surface
  322.     pDDS->Unlock(NULL); 
  323.  
  324.     return S_OK;
  325. }
  326.  
  327.  
  328.  
  329.  
  330. //-----------------------------------------------------------------------------
  331. // Name: FreeDirectDraw()
  332. // Desc: Release all the DirectDraw objects
  333. //-----------------------------------------------------------------------------
  334. VOID FreeDirectDraw()
  335. {
  336.     SAFE_DELETE( g_pSpriteSurface );
  337.     SAFE_DELETE( g_pTextSurface );
  338.     SAFE_DELETE( g_pDisplay );
  339. }
  340.  
  341.  
  342.  
  343.  
  344. //-----------------------------------------------------------------------------
  345. // Name: MainWndProc()
  346. // Desc: The main window procedure
  347. //-----------------------------------------------------------------------------
  348. LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
  349. {
  350.     switch (msg)
  351.     {
  352.         case WM_COMMAND:
  353.             switch( LOWORD(wParam) )
  354.             {
  355.                 case IDM_EXIT:
  356.                     // Received key/menu command to exit app
  357.                     PostMessage( hWnd, WM_CLOSE, 0, 0 );
  358.                     return 0L;
  359.             }
  360.             break; // Continue with default processing
  361.  
  362.         case WM_SETCURSOR:
  363.             // Hide the cursor in fullscreen 
  364.             SetCursor( NULL );
  365.             return TRUE;
  366.  
  367.         case WM_SIZE:
  368.             // Check to see if we are losing our window...
  369.             if( SIZE_MAXHIDE==wParam || SIZE_MINIMIZED==wParam )
  370.                 g_bActive = FALSE;
  371.             else
  372.                 g_bActive = TRUE;
  373.             break;
  374.  
  375.         case WM_EXITMENULOOP:
  376.             // Ignore time spent in menu
  377.             g_dwLastTick = timeGetTime();
  378.             break;
  379.  
  380.         case WM_EXITSIZEMOVE:
  381.             // Ignore time spent resizing
  382.             g_dwLastTick = timeGetTime();
  383.             break;
  384.         
  385.         case WM_SYSCOMMAND:
  386.             // Prevent moving/sizing and power loss in fullscreen mode
  387.             switch( wParam )
  388.             {
  389.                 case SC_MOVE:
  390.                 case SC_SIZE:
  391.                 case SC_MAXIMIZE:
  392.                 case SC_MONITORPOWER:
  393.                     return TRUE;
  394.             }
  395.             break;
  396.             
  397.         case WM_DESTROY:
  398.             // Cleanup and close the app
  399.             FreeDirectDraw();
  400.             PostQuitMessage( 0 );
  401.             return 0L;
  402.     }
  403.  
  404.     return DefWindowProc(hWnd, msg, wParam, lParam);
  405. }
  406.  
  407.  
  408.  
  409.  
  410. //-----------------------------------------------------------------------------
  411. // Name: ProcessNextFrame()
  412. // Desc: Move the sprites, blt them to the back buffer, then 
  413. //       flips the back buffer to the primary buffer
  414. //-----------------------------------------------------------------------------
  415. HRESULT ProcessNextFrame()
  416. {
  417.     HRESULT hr;
  418.  
  419.     // Figure how much time has passed since the last time
  420.     DWORD dwCurrTick = timeGetTime();
  421.     DWORD dwTickDiff = dwCurrTick - g_dwLastTick;
  422.  
  423.     // Don't update if no time has passed 
  424.     if( dwTickDiff == 0 )
  425.         return S_OK; 
  426.  
  427.     g_dwLastTick = dwCurrTick;
  428.  
  429.     // Update the sprites according to how much time has passed
  430.     for( int iSprite = 0; iSprite < NUM_SPRITES; iSprite++ )
  431.         UpdateSprite( &g_Sprite[ iSprite ], dwTickDiff / 1000.0f );
  432.  
  433.     // Display the sprites on the screen
  434.     if( FAILED( hr = DisplayFrame() ) )
  435.     {
  436.         if( hr != DDERR_SURFACELOST )
  437.             return hr;
  438.  
  439.         // The surfaces were lost so restore them 
  440.         RestoreSurfaces();
  441.     }
  442.  
  443.     return S_OK;
  444. }
  445.  
  446.  
  447.  
  448.  
  449. //-----------------------------------------------------------------------------
  450. // Name: UpdateSprite()
  451. // Desc: Moves and bounces the sprite based on how much time has passed.  
  452. //       It also changes the sprite state based on random values it gets 
  453. //       from the array g_lRandTable
  454. //-----------------------------------------------------------------------------
  455. VOID UpdateSprite( SPRITE_STRUCT* pSprite, FLOAT fTimeDelta )
  456. {    
  457.     // Update the sprite position
  458.     pSprite->fPosX += pSprite->fVelX * fTimeDelta;
  459.     pSprite->fPosY += pSprite->fVelY * fTimeDelta;
  460.  
  461.     // Clip the position, and bounce if it hits the edge
  462.     if( pSprite->fPosX < 0.0f )
  463.     {
  464.         pSprite->fPosX  = 0;
  465.         pSprite->fVelX = -pSprite->fVelX;
  466.     }
  467.  
  468.     if( pSprite->fPosX >= SCREEN_WIDTH - SPRITE_DIAMETER )
  469.     {
  470.         pSprite->fPosX = SCREEN_WIDTH - 1 - SPRITE_DIAMETER;
  471.         pSprite->fVelX = -pSprite->fVelX;
  472.     }
  473.  
  474.     if( pSprite->fPosY < 0 )
  475.     {
  476.         pSprite->fPosY = 0;
  477.         pSprite->fVelY = -pSprite->fVelY;
  478.     }
  479.  
  480.     if( pSprite->fPosY > SCREEN_HEIGHT - SPRITE_DIAMETER )
  481.     {
  482.         pSprite->fPosY = SCREEN_HEIGHT - 1 - SPRITE_DIAMETER;
  483.         pSprite->fVelY = -pSprite->fVelY;
  484.     }   
  485. }
  486.  
  487.  
  488.  
  489.  
  490. //-----------------------------------------------------------------------------
  491. // Name: DisplayFrame()
  492. // Desc: Blts a the sprites to the back buffer, then flips the 
  493. //       back buffer onto the primary buffer.
  494. //-----------------------------------------------------------------------------
  495. HRESULT DisplayFrame()
  496. {
  497.     HRESULT hr;
  498.  
  499.     // Fill the back buffer with black, ignoring errors until the flip
  500.     g_pDisplay->Clear( 0 );
  501.  
  502.     // Blt the help text on the backbuffer, ignoring errors until the flip
  503.     g_pDisplay->Blt( 10, 10, g_pTextSurface, NULL );
  504.  
  505.     // Blt all the sprites onto the back buffer using color keying,
  506.     // ignoring errors until the flip. Note that all of these sprites 
  507.     // use the same DirectDraw surface.
  508.     for( int iSprite = 0; iSprite < NUM_SPRITES; iSprite++ )
  509.     {
  510.         g_pDisplay->Blt( (DWORD)g_Sprite[iSprite].fPosX, 
  511.                          (DWORD)g_Sprite[iSprite].fPosY, 
  512.                          g_pSpriteSurface, NULL );
  513.     }
  514.  
  515.     // We are in fullscreen mode, so perform a flip and return 
  516.     // any errors like DDERR_SURFACELOST
  517.     if( FAILED( hr = g_pDisplay->Present() ) )
  518.         return hr;
  519.  
  520.     return S_OK;
  521. }
  522.  
  523.  
  524.  
  525.  
  526. //-----------------------------------------------------------------------------
  527. // Name: RestoreSurfaces()
  528. // Desc: Restore all the surfaces, and redraw the sprite surfaces.
  529. //-----------------------------------------------------------------------------
  530. HRESULT RestoreSurfaces()
  531. {
  532.     HRESULT hr;
  533.  
  534.     if( FAILED( hr = g_pDisplay->GetDirectDraw()->RestoreAllSurfaces() ) )
  535.         return hr;
  536.  
  537.     // No need to re-create the surface, just re-draw it.
  538.     if( FAILED( hr = g_pTextSurface->DrawText( NULL, HELPTEXT, 
  539.                                                0, 0, RGB(0,0,0), RGB(255, 255, 0) ) ) )
  540.         return hr;
  541.  
  542.     // No need to re-create the surface, just re-draw it.
  543.     if( FAILED( hr = DrawSprite() ) )
  544.         return hr;
  545.  
  546.     return S_OK;
  547. }
  548.  
  549.  
  550.  
  551.  
  552.