Click here to Skip to main content
15,867,308 members
Articles / Multimedia / DirectX

Falling Blocks

Rate me:
Please Sign up or sign in to vote.
4.95/5 (11 votes)
17 Apr 2008CPOL 269.7K   9.2K   72  
A game written using Visual C++ and DirectX.
//-----------------------------------------------------------------------------
// File: FallingBlocks.cpp
//-----------------------------------------------------------------------------
#define STRICT
#include <windows.h>
#include <ddraw.h>
#include <mmsystem.h>
#include "resource.h"
#include "ddutil.h"
#include "BlockList.h"
#include "FlooredBlocks.h"
#include "Shape.h"



//-----------------------------------------------------------------------------
// Defines, constants, and global variables
//-----------------------------------------------------------------------------
#define SAFE_DELETE(p)  { if(p) { delete (p);     (p)=NULL; } }
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }

#define WINDOW_WIDTH    320
#define WINDOW_HEIGHT   375


#define BITMAP_WIDTH     329
#define BITMAP_HEIGHT    400 

#define BLOCK_START   379
#define BLOCK_DIAMETER 21

#define CURR_SHAPE_X 3
#define CURR_SHAPE_Y -3
#define NEXT_SHAPE_X 10
#define NEXT_SHAPE_Y 6

#define SCORE_X   230
#define SCORE_Y   105

#define DELAY_TO_MOVE_DOWN_LEVEL1  10
#define DELAY_TO_MOVE_DOWN_LEVEL2  6
#define DELAY_TO_MOVE_DOWN_LEVEL3  3
#define DELAY_TO_MOVE_DOWN_LEVEL4  1

#define ROWS   15
#define COLS    9

#define NORMAL_GAME  7
#define CRAZY_GAME   11

#define GAMEOVERTEXT TEXT("G A M E   O V E R")

CDisplay*            g_pDisplay           = NULL;
CSurface*            g_pSecondarySurface  = NULL;  
CSurface*            g_pGameOverSurface   = NULL;  
CSurface*            g_pScoreSurface      = NULL;
CSurface*            g_pPauseSurface      = NULL;
RECT                 g_rcViewport;          
RECT                 g_rcScreen;            
RECT                 g_rcBackground = { 0 , 0, WINDOW_WIDTH, WINDOW_HEIGHT };
RECT                 g_rcBlock = {0, BLOCK_START, BLOCK_DIAMETER, BLOCK_START+BLOCK_DIAMETER};
RECT                 g_rcBoundary = { 1,-5, 9,16 }; 
CFlooredBlocks       g_FlooredBlocks(g_rcBoundary);
BOOL                 g_bActive     = FALSE; 
DWORD                g_dwLastTick;
CShape*              g_pCurrShape;
CShape*              g_pNextShape;
bool                 g_bIsGameOver=false;
bool                 g_bIsPaused = false;
long                 g_nScore =0;
long                 g_nPulse=0;
long                 g_nDelayToMoveDown = 10;
HINSTANCE            g_hInstance =0;

//-----------------------------------------------------------------------------
// Function-prototypes
//-----------------------------------------------------------------------------
LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
HRESULT WinInit( HINSTANCE hInst, int nCmdShow, HWND* phWnd, HACCEL* phAccel );
HRESULT InitDirectDraw( HWND hWnd );
VOID    FreeDirectDraw();
HRESULT ProcessNextFrame( HWND hWnd );
HRESULT DisplayFrame();
HRESULT RestoreSurfaces();

BOOL CALLBACK AboutDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    switch (message) 
    { 
        case WM_COMMAND: 
            switch (LOWORD(wParam)) 
            { 
                case IDOK: 
                case IDCANCEL: 
                    EndDialog(hwndDlg, wParam); 
                    return TRUE; 
            } 
    } 
    return FALSE; 
} 


//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: Entry point to the program. Initializes everything and calls
//       UpdateFrame() when idle from the message pump.
//-----------------------------------------------------------------------------
int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int nCmdShow )
{
    MSG		 msg;
    HWND     hWnd;
    HACCEL   hAccel;

    srand( GetTickCount() );

    if( FAILED( WinInit( hInst, nCmdShow, &hWnd, &hAccel ) ) )
        return FALSE;

    if( FAILED( InitDirectDraw( hWnd ) ) )
    {
        MessageBox( hWnd, TEXT("DirectDraw init failed. ")
                    TEXT("The sample will now exit. "), TEXT("DirectDraw Sample"), 
                    MB_ICONERROR | MB_OK );
        return FALSE;
    }

    g_dwLastTick = timeGetTime();

	
	while( TRUE )
    {
        // Look for messages, if none are found then 
        // update the state and display it
        if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
        {
            if( 0 == GetMessage(&msg, NULL, 0, 0 ) )
            {
                // WM_QUIT was posted, so exit
                return (int)msg.wParam;
            }

            // Translate and dispatch the message
            if( 0 == TranslateAccelerator( hWnd, hAccel, &msg ) )
            {
                TranslateMessage( &msg ); 
                DispatchMessage( &msg );
            }
        }
        else
        {
            if( g_bActive )
            {
                // Move the sprites, blt them to the back buffer, then 
                // flip or blt the back buffer to the primary buffer
                if( FAILED( ProcessNextFrame( hWnd ) ) )
                {
                    SAFE_DELETE( g_pDisplay );

                    MessageBox( hWnd, TEXT("Displaying the next frame failed. ")
                                TEXT("The sample will now exit. "), TEXT("DirectDraw Sample"), 
                                MB_ICONERROR | MB_OK );
                    return FALSE;
                }
            }
            else
            {
                // Make sure we go to sleep if we have nothing else to do
                WaitMessage();

                // Ignore time spent inactive 
                g_dwLastTick = timeGetTime();
            }
        }
    }
}




//-----------------------------------------------------------------------------
// Name: WinInit()
// Desc: Init the window
//-----------------------------------------------------------------------------
HRESULT WinInit( HINSTANCE hInst, int nCmdShow, HWND* phWnd, HACCEL* phAccel )
{
    WNDCLASSEX wc;
    HWND       hWnd;
    HACCEL     hAccel;
	
	g_hInstance = hInst;

    // Register the Window Class
    wc.cbSize        = sizeof(wc);
    wc.lpszClassName = TEXT("WindowedMode");
    wc.lpfnWndProc   = MainWndProc;
    wc.style         = CS_VREDRAW | CS_HREDRAW;
    wc.hInstance     = hInst;
    wc.hIcon         = LoadIcon( hInst, MAKEINTRESOURCE(IDI_MAIN) );
    wc.hIconSm       = LoadIcon( hInst, MAKEINTRESOURCE(IDI_MAIN) );
    wc.hCursor       = LoadCursor( NULL, IDC_ARROW );
    wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
    wc.lpszMenuName  = MAKEINTRESOURCE(IDR_MENU);
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;

    if( RegisterClassEx( &wc ) == 0 )
        return E_FAIL;

    // Load keyboard accelerators
    hAccel = LoadAccelerators( hInst, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );

    // Calculate the proper size for the window given a client of 640x480
    DWORD dwFrameWidth    = GetSystemMetrics( SM_CXSIZEFRAME );
    DWORD dwFrameHeight   = GetSystemMetrics( SM_CYSIZEFRAME );
    DWORD dwMenuHeight    = GetSystemMetrics( SM_CYMENU );
    DWORD dwCaptionHeight = GetSystemMetrics( SM_CYCAPTION );
    DWORD dwWindowWidth   = WINDOW_WIDTH  + dwFrameWidth * 2;
    DWORD dwWindowHeight  = WINDOW_HEIGHT + dwFrameHeight * 2 + 
                            dwMenuHeight + dwCaptionHeight;

    // Create and show the main window
    DWORD dwStyle = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX;
    hWnd = CreateWindowEx( 0, TEXT("WindowedMode"), TEXT("Falling Blocks"),
                           dwStyle, CW_USEDEFAULT, CW_USEDEFAULT,
  	                       dwWindowWidth, dwWindowHeight, NULL, NULL, hInst, NULL );
    if( hWnd == NULL )
    	return E_FAIL;

    ShowWindow( hWnd, nCmdShow );
    UpdateWindow( hWnd );

    *phWnd   = hWnd;
    *phAccel = hAccel;
	::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_1, MF_CHECKED);
	::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_NORMAL, MF_CHECKED);
    return S_OK;
}

void NewGame()
{
	g_FlooredBlocks.Destroy();
	g_nScore = 0;
	g_bIsGameOver= false;
	if (g_pCurrShape)
		delete g_pCurrShape;
	g_pCurrShape = new CShape(&g_FlooredBlocks);
	g_pCurrShape->CreateRandShape();
	g_pCurrShape->MoveTo(CURR_SHAPE_X,CURR_SHAPE_Y);

	if (g_pNextShape)
		delete g_pNextShape;
	g_pNextShape = new CShape(&g_FlooredBlocks);
	g_pNextShape->CreateRandShape();
	g_pNextShape->MoveTo(NEXT_SHAPE_X, NEXT_SHAPE_Y );

}


//-----------------------------------------------------------------------------
// Name: InitDirectDraw()
// Desc: Create the DirectDraw object, and init the surfaces
//-----------------------------------------------------------------------------
HRESULT InitDirectDraw( HWND hWnd )
{
    LPDIRECTDRAWPALETTE pDDPal = NULL; 
    HRESULT	hr;

    g_pDisplay = new CDisplay();
    if( FAILED( hr = g_pDisplay->CreateWindowedDisplay( hWnd, WINDOW_WIDTH, WINDOW_HEIGHT ) ) )
    {
        MessageBox( hWnd, TEXT("Failed initializing DirectDraw."),
                    TEXT("DirectDraw Sample"), MB_ICONERROR | MB_OK );
        return hr;
    }

    // Create and set the palette when in palettized color
    if( FAILED( hr = g_pDisplay->CreatePaletteFromBitmap( &pDDPal, "IDB_Graphics" ) ) )
        return hr;

    g_pDisplay->SetPalette( pDDPal );

    SAFE_RELEASE( pDDPal );

    // Create a surface, and draw a bitmap resource on it.  
    if( FAILED( hr = g_pDisplay->CreateSurfaceFromBitmap( &g_pSecondarySurface, "IDB_Graphics", 
                                                          BITMAP_WIDTH, BITMAP_HEIGHT ) ) )
        return hr;

    // Create a surface, and draw text to it.  
    if( FAILED( hr = g_pDisplay->CreateSurfaceFromText( &g_pGameOverSurface, NULL, GAMEOVERTEXT, 
                                                        RGB(0,0,0), RGB(255, 255, 0) ) ) )
        return hr;

    if( FAILED( hr = g_pDisplay->CreateSurfaceFromText( &g_pScoreSurface, NULL, "xxxxxx", 
                                                        RGB(0,0,0), RGB(255, 255, 0) ) ) )
        return hr;

    if( FAILED( hr = g_pDisplay->CreateSurfaceFromText( &g_pPauseSurface, NULL, "Paused...", 
                                                        RGB(0,0,0), RGB(255, 255, 0) ) ) )
        return hr;

	CShape::SetMaxNoOfShapesAllowed(NORMAL_GAME);
	NewGame();

    return S_OK;
}




//-----------------------------------------------------------------------------
// Name: FreeDirectDraw()
// Desc: Release all the DirectDraw objects
//-----------------------------------------------------------------------------
VOID FreeDirectDraw()
{
    SAFE_DELETE( g_pSecondarySurface );
    SAFE_DELETE( g_pGameOverSurface );
	SAFE_DELETE( g_pScoreSurface );
	SAFE_DELETE( g_pPauseSurface);
    SAFE_DELETE( g_pDisplay );
	SAFE_DELETE( g_pCurrShape);
    SAFE_DELETE( g_pNextShape);
}

void MoveDownShape()
{
	if (g_bIsGameOver)
		return;
	if (g_pCurrShape->MoveDown() == false) {
	                  g_pCurrShape->ConvertToSpaceCoord();
//	::PlaySound(MAKEINTRESOURCE( IDR_SOUNDPLACED), g_hInstance, SND_RESOURCE | SND_ASYNC);
	                   g_FlooredBlocks.Insert(*g_pCurrShape);
					   delete g_pCurrShape;
					   g_pCurrShape = g_pNextShape;
					   g_pCurrShape->MoveTo(CURR_SHAPE_X,CURR_SHAPE_Y);
					   g_pNextShape = new CShape(&g_FlooredBlocks);
					   if (g_pNextShape->CreateRandShape(3,-4) == false) {
						   OutputDebugString("Creation of New Shape Failed\n");
					   }
					   g_pNextShape->MoveTo(NEXT_SHAPE_X, NEXT_SHAPE_Y);
	}
	if (g_FlooredBlocks.IsGameOver()) {
					   g_bIsGameOver=true;
					   ::PlaySound(MAKEINTRESOURCE( IDR_SOUNDGAMEOVER), g_hInstance, SND_RESOURCE | SND_ASYNC);
					   
	}
				   short nRows;
	nRows = g_FlooredBlocks.CheckAndRemoveContinuousBlocks();
	g_nScore += 10 * nRows * nRows * ( 11 - g_nDelayToMoveDown);

}


//-----------------------------------------------------------------------------
// Name: MainWndProc()
// Desc: The main window procedure
//-----------------------------------------------------------------------------
LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch (msg)
    {
        case WM_COMMAND:
            switch( LOWORD(wParam) )
            {
                case IDM_EXIT:
                    // Received key/menu command to exit app
            	    PostMessage( hWnd, WM_CLOSE, 0, 0 );
                    return 0L;
				case ID_FILE_NEWGAME:
					NewGame();
					return 0L;
				case ID_LEVEL_1:
					g_nDelayToMoveDown = DELAY_TO_MOVE_DOWN_LEVEL1;
					::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_1, MF_CHECKED);
					::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_2, MF_UNCHECKED);
					::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_3, MF_UNCHECKED);
					::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_4, MF_UNCHECKED);
					return 0L;
				case ID_LEVEL_2:
					g_nDelayToMoveDown = DELAY_TO_MOVE_DOWN_LEVEL2;
					::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_1, MF_UNCHECKED);
					::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_2, MF_CHECKED);
					::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_3, MF_UNCHECKED);
					::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_4, MF_UNCHECKED);
					return 0L;
				case ID_LEVEL_3:
					g_nDelayToMoveDown = DELAY_TO_MOVE_DOWN_LEVEL3;
					::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_1, MF_UNCHECKED);
					::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_2, MF_UNCHECKED);
					::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_3, MF_CHECKED);
					::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_4, MF_UNCHECKED);
					return 0L;
				case ID_LEVEL_4:
					g_nDelayToMoveDown = DELAY_TO_MOVE_DOWN_LEVEL4;
					::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_1, MF_UNCHECKED);
					::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_2, MF_UNCHECKED);
					::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_3, MF_UNCHECKED);
					::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_4, MF_CHECKED);
					return 0L;
				case ID_LEVEL_NORMAL:
					CShape::SetMaxNoOfShapesAllowed(NORMAL_GAME);
					::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_CRAZY,  MF_UNCHECKED);
					::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_NORMAL, MF_CHECKED);
					return 0L;
				case ID_LEVEL_CRAZY:
					CShape::SetMaxNoOfShapesAllowed(CRAZY_GAME);
					::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_NORMAL, MF_UNCHECKED);
					::CheckMenuItem(::GetMenu(hWnd), ID_LEVEL_CRAZY,  MF_CHECKED);
					return 0L;
					
				case ID_HELP_ABOUT:
					DialogBox(g_hInstance, 
                     MAKEINTRESOURCE(IDD_ABOUT), hWnd, (DLGPROC)AboutDlgProc);
					 break;
            }
            break; // Continue with default processing

		case WM_ACTIVATE:
			if (wParam == WA_ACTIVE || wParam == WA_CLICKACTIVE)
				g_bIsPaused = false;
			if (wParam == WA_INACTIVE)
				g_bIsPaused = true;
			break;

        case WM_PAINT:
            // Update the screen if we need to refresh. This case occurs 
            // when in windowed mode and the window is behind others.
            // The app will not be active, but it will be visible.
            if( g_pDisplay )
            {
                // Display the new position of the sprite
                if( DisplayFrame() == DDERR_SURFACELOST )
                {
                    // If the surfaces were lost, then restore and try again
                    RestoreSurfaces();
                    DisplayFrame();
                }
            }
            break; // Continue with default processing to validate the region

        case WM_QUERYNEWPALETTE:
            if( g_pDisplay )
            {
                // If we are in windowed mode with a desktop resolution in 8 bit 
                // color, then the palette we created during init has changed 
                // since then.  So get the palette back from the primary 
                // DirectDraw surface, and set it again so that DirectDraw 
                // realises the palette, then release it again. 
                LPDIRECTDRAWPALETTE pDDPal = NULL; 
                g_pDisplay->GetFrontBuffer()->GetPalette( &pDDPal );
                g_pDisplay->GetFrontBuffer()->SetPalette( pDDPal );
                SAFE_RELEASE( pDDPal );
            }
            break;

        case WM_GETMINMAXINFO:
            {
                // Don't allow resizing in windowed mode.  
                // Fix the size of the window to 640x480 (client size)
                MINMAXINFO* pMinMax = (MINMAXINFO*) lParam;

                DWORD dwFrameWidth    = GetSystemMetrics( SM_CXSIZEFRAME );
                DWORD dwFrameHeight   = GetSystemMetrics( SM_CYSIZEFRAME );
                DWORD dwMenuHeight    = GetSystemMetrics( SM_CYMENU );
                DWORD dwCaptionHeight = GetSystemMetrics( SM_CYCAPTION );

                pMinMax->ptMinTrackSize.x = WINDOW_WIDTH  + dwFrameWidth * 2;
                pMinMax->ptMinTrackSize.y = WINDOW_HEIGHT + dwFrameHeight * 2 + 
                                            dwMenuHeight + dwCaptionHeight;

                pMinMax->ptMaxTrackSize.x = pMinMax->ptMinTrackSize.x;
                pMinMax->ptMaxTrackSize.y = pMinMax->ptMinTrackSize.y;
            }
            return 0L;

        case WM_MOVE:
	        if( g_pDisplay )
		        g_pDisplay->UpdateBounds();
            return 0L;

        case WM_EXITMENULOOP:
            // Ignore time spent in menu
            g_dwLastTick = timeGetTime();
            break;

        case WM_EXITSIZEMOVE:
            // Ignore time spent resizing
            g_dwLastTick = timeGetTime();
            break;

        case WM_SIZE:
            // Check to see if we are losing our window...
            if( SIZE_MAXHIDE==wParam || SIZE_MINIMIZED==wParam )
                g_bActive = FALSE;
            else
                g_bActive = TRUE;

	        if( g_pDisplay )
		        g_pDisplay->UpdateBounds();
            break;
       case WM_KEYDOWN: 
		   if (g_bIsGameOver == false) {
			   switch (wParam) 
			   { 
			   case VK_LEFT: 
				   // Process the LEFT ARROW key. 
				   g_pCurrShape->MoveLeft();
				  // ::PlaySound(MAKEINTRESOURCE( IDR_SOUNDMOVE), g_hInstance, SND_RESOURCE | SND_ASYNC);
				   break; 
			   case VK_RIGHT: 
				   // Process the RIGHT ARROW key. 
				   g_pCurrShape->MoveRight();
				   //	::PlaySound(MAKEINTRESOURCE( IDR_SOUNDMOVE), g_hInstance, SND_RESOURCE | SND_ASYNC);
				   break; 
			   case VK_DOWN: 
				   // Process the DOWN ARROW key. 
				   MoveDownShape();
				   //::PlaySound(MAKEINTRESOURCE( IDR_SOUNDMOVE), g_hInstance, SND_RESOURCE | SND_ASYNC);
				   break; 
			   case VK_UP: 
				   // Process the DOWN ARROW key. 
				   //g_pCurrShape->MoveUp();
				   g_pCurrShape->Rotate();
				   //::PlaySound(MAKEINTRESOURCE( IDR_SOUNDMOVE), g_hInstance, SND_RESOURCE | SND_ASYNC);
				   break; 
			   case VK_CLEAR: 
				   // Process the DOWN ARROW key. 
				   while(g_pCurrShape->MoveDown());
				   MoveDownShape();
				   //::PlaySound(MAKEINTRESOURCE( IDR_SOUNDMOVE), g_hInstance, SND_RESOURCE | SND_ASYNC);
				   break; 

			   default:
				   break;
			   }
		   }
			break;
		case WM_CHAR:
			switch (wParam)
			{
			case 'R':
			case 'r':
				g_pCurrShape->Rotate();
				break;
			case ' ':
				if (g_bIsGameOver)
					NewGame();
				break;
			case '5':
				while (g_pCurrShape->MoveDown());
				break;

/*
			case 'N':
			case 'n':
				g_pCurrShape->NextShape();
				break;
*/
			default:
				break;
			}
			break;

             
        case WM_DESTROY:
            // Cleanup and close the app
            FreeDirectDraw();
            PostQuitMessage( 0 );
            return 0L;
    }

    return DefWindowProc(hWnd, msg, wParam, lParam);
}




//-----------------------------------------------------------------------------
// Name: ProcessNextFrame()
// Desc: Move the sprites, blt them to the back buffer, then 
//       flip or blt the back buffer to the primary buffer
//-----------------------------------------------------------------------------
HRESULT ProcessNextFrame( HWND hWnd )
{
    HRESULT hr;

    // Figure how much time has passed since the last time
    DWORD dwCurrTick = timeGetTime();
    DWORD dwTickDiff = dwCurrTick - g_dwLastTick;

	Sleep(50);
    // Don't update if no time has passed 
    if( dwTickDiff < 100 )
        return S_OK; 

	g_nPulse++;
    g_dwLastTick = dwCurrTick;

	if (! g_bIsPaused) {
		if ((g_nPulse % g_nDelayToMoveDown) == 0)
			MoveDownShape();
	}


    // Check the cooperative level before rendering
    if( FAILED( hr = g_pDisplay->GetDirectDraw()->TestCooperativeLevel() ) )
    {
        switch( hr )
        {
            case DDERR_EXCLUSIVEMODEALREADYSET:
                // Do nothing because some other app has exclusive mode
                Sleep(10);
                return S_OK;

            case DDERR_WRONGMODE:
                // The display mode changed on us. Update the
                // DirectDraw surfaces accordingly
                FreeDirectDraw();
                return InitDirectDraw( hWnd );
        }
        return hr;
    }

    // Display the sprites on the screen
    if( FAILED( hr = DisplayFrame() ) )
    {
        if( hr != DDERR_SURFACELOST )
            return hr;

        // The surfaces were lost so restore them 
        RestoreSurfaces();
    }

    return S_OK;
}








//-----------------------------------------------------------------------------
// Name: DisplayFrame()
// Desc: Blts a the sprites to the back buffer, then it blts or flips the 
//       back buffer onto the primary buffer.
//-----------------------------------------------------------------------------
HRESULT DisplayFrame()
{
    HRESULT hr;

    // Blt the help text on the backbuffer, ignoring errors until the flip
    g_pDisplay->Blt( 0, 0, g_pSecondarySurface, &g_rcBackground );


    // Blt all the sprites onto the back buffer using color keying,
    // ignoring errors until the last blt. Note that all of these sprites 
    // use the same DirectDraw surface.
	g_FlooredBlocks.Display();
	g_pCurrShape->Display();
	g_pNextShape->Display();

	if (g_bIsGameOver) {
		// Blt the help text on the backbuffer, ignoring errors until the flip
		g_pDisplay->Blt( 80, 150, g_pGameOverSurface, NULL );
	} else

	if (g_bIsPaused) {
		g_pDisplay->Blt(80, 150, g_pPauseSurface, NULL);
	}

	char szScore[50];
	wsprintf(szScore,"%06d",g_nScore);
    if( FAILED( hr = g_pScoreSurface->DrawText( 0/*hFont*/, szScore, 0,0,0, RGB(255,255,0) ) ) )
        return hr;
	
	g_pDisplay->Blt( SCORE_X, SCORE_Y, g_pScoreSurface, NULL );
	
    // We are in windowed mode so perform a blt from the backbuffer 
    // to the primary, returning any errors like DDERR_SURFACELOST
    if( FAILED( hr = g_pDisplay->Present() ) )
        return hr;

    return S_OK;
}




//-----------------------------------------------------------------------------
// Name: RestoreSurfaces()
// Desc: Restore all the surfaces, and redraw the sprite surfaces.
//-----------------------------------------------------------------------------
HRESULT RestoreSurfaces()
{
    LPDIRECTDRAWPALETTE pDDPal = NULL; 
    HRESULT hr;

    if( FAILED( hr = g_pDisplay->GetDirectDraw()->RestoreAllSurfaces() ) )
        return hr;


    // We need to release and re-load, and set the palette again to 
    // redraw the bitmap on the surface.  Otherwise, GDI will not 
    // draw the bitmap on the surface with the right palette
    if( FAILED( hr = g_pDisplay->CreatePaletteFromBitmap( &pDDPal, "IDB_Graphics" ) ) )
        return hr;

    g_pDisplay->SetPalette( pDDPal );

    SAFE_RELEASE( pDDPal );

    // No need to re-create the surface, just re-draw it.
    if( FAILED( hr = g_pSecondarySurface->DrawBitmap( "IDB_Graphics", BITMAP_WIDTH, BITMAP_HEIGHT )))
	    return hr;

	g_FlooredBlocks.Display();
	g_pCurrShape->Display();
	g_pNextShape->Display();
	if (g_bIsGameOver) {
		// No need to re-create the surface, just re-draw it.
		if( FAILED( hr = g_pGameOverSurface->DrawText( NULL, GAMEOVERTEXT, 
			80,150, RGB(0,0,0), RGB(255, 255, 0) ) ) )
			return hr;
	}

    return S_OK;
}

//////////////////////////////////////////////
// Display the Block
//////////////////////////////////////////////
void DisplayBlock(SBlock Block) 
{
	if (Block.nY < 1) return;
	RECT rcBlock = g_rcBlock;
	rcBlock.left = Block.nColor * BLOCK_DIAMETER;
	rcBlock.right = Block.nColor * BLOCK_DIAMETER + BLOCK_DIAMETER;
	
	
	
	g_pDisplay->Blt( (DWORD)Block.nX * BLOCK_DIAMETER - 2 , 
		(DWORD)Block.nY * BLOCK_DIAMETER , 
		g_pSecondarySurface, &rcBlock );
	
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions