Click here to Skip to main content
15,896,063 members
Articles / Multimedia / DirectX

A DirectX Game: Quadrino

Rate me:
Please Sign up or sign in to vote.
4.89/5 (41 votes)
16 Oct 2008CPOL26 min read 397.8K   6.2K   125  
An interpretation of a popular falling block game implemented with DirectX that attempts to avoid any copyright infringement.
/* DDSurface.cpp **************************************************************
Author:		Paul Watt
Date:		9/30/2001
Purpose:	
******************************************************************************/
#include "stdafx.h"
#include "DDSurface.h"

/* Public *********************************************************************
Author:		Paul Watt
Date:		9/30/2001
Purpose:	Constructor
******************************************************************************/
DDSurface::DDSurface()
{
	m_pSurface	= NULL;
	m_hDC		= NULL;
	m_hWnd		= NULL;

	ZeroMemory(&m_ddsd, sizeof(DDSURFACEDESC2));
	m_ddsd.dwSize = sizeof(DDSURFACEDESC2);
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		9/30/2001
Purpose:	Destructor
******************************************************************************/
DDSurface::~DDSurface()
{
	this->Release();
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		11/16/2001
Purpose:	Allows a raw DirectDrawSurface Interface pointer to be attached and
			encapsulated in this object.  If this object currently has an object
			then the function will fail.  In order to release the interface pointer
			without destroying the object call Release.  If you would like to 
			extract the interface pointer and not release it then call Detach.
Parameters:	pSurface[in]: The new interface pointer that will be attached to this
				object.		
Return:		If the function successfully attaches the surface to this obect then
			AddRef will be called on the surface and true will be returned, otherwise
			false.
******************************************************************************/
bool DDSurface::Attach(IDirectDrawSurface7 *pSurface)
{
			//C: Check if this object already has a surface set into it.
	if (NULL != m_pSurface)
	{
		return false;
	}
			//C: Verify input parameters.
	if (NULL == pSurface)
	{
		return false;
	}
			//C: Set this objects surface to the input surface.
	m_pSurface = pSurface;
	m_pSurface->AddRef();
			//C: Initialize all of the necessary parameters.
	m_pSurface->GetSurfaceDesc(&m_ddsd);
			//C: Return success.
	return true;
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		11/16/2001
Purpose:	
Parameters:			
Return:		
******************************************************************************/
bool DDSurface::Detach(IDirectDrawSurface7 **ppSurface)
{
			//C: Verify input parameters.
	if (NULL == ppSurface)
	{
		return false;
	}
			//C: Set ppSurface = to the interface pointer stored in this object.
	*ppSurface = m_pSurface;
	(*ppSurface)->AddRef();
			//C: Release all of the memory associated with this object.
	this->Release();
			//C: Return success
	return true;
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		10/6/2001
Purpose:	
Parameters:			
Return:		
******************************************************************************/
HRESULT DDSurface::Initialize(IDirectDraw7 *pDirectDraw, UINT nBufferCount)
{
			//C: Verify input parameters
	if (NULL == pDirectDraw)
	{
		return -1;
	}

	if ( nBufferCount==0 )
	{
		m_ddsd.dwFlags			 = DDSD_CAPS;
		m_ddsd.ddsCaps.dwCaps	 = DDSCAPS_PRIMARYSURFACE |
								   DDSCAPS_VIDEOMEMORY;
	}
	else
	{
		m_ddsd.dwFlags           = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
		m_ddsd.ddsCaps.dwCaps    = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
		m_ddsd.dwBackBufferCount = nBufferCount;
	}
	
	HRESULT hr = pDirectDraw->CreateSurface(&m_ddsd, &m_pSurface, NULL);

			//C: Finish initializing the ddsd field.
	if (NULL != m_pSurface)
	{
		m_pSurface->GetSurfaceDesc(&m_ddsd);
	}
			//C: Verify that the current display mode is 32-bit or 24-bit color 
			//   because this surface does not support any other modes at this 
			//   point in time.
ATLASSERT (32 == m_ddsd.ddpfPixelFormat.dwRGBBitCount || 
		   24 == m_ddsd.ddpfPixelFormat.dwRGBBitCount ||
		   16 == m_ddsd.ddpfPixelFormat.dwRGBBitCount);

	return hr;
}

/* Public *********************************************************************
Author:		Paul Watt
Date:		9/30/2001
Purpose:	Frees all of the handles for this surface object before the
			destructor is called.  This will be useful in order for object
			caching.
Parameters:	NONE
Return:		-
******************************************************************************/
void DDSurface::Release()
{
			//C: Release the DC handle if one was ever obtained.
	this->ReleaseDC();
			//C: Release the surface handle.
	if (NULL != m_pSurface)
	{

		m_pSurface->Release();
		m_pSurface = NULL;
	}
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		10/6/2001
Purpose:	
Parameters:			
Return:		
******************************************************************************/
BYTE * DDSurface::Lock(RECT * pRect)
{
    if ( FAILED(m_pSurface->Lock(pRect, & m_ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL)) )
	{
		return NULL;
	}
	else
	{
		return (BYTE *) m_ddsd.lpSurface;
	}
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		10/6/2001
Purpose:	
Parameters:			
Return:		
******************************************************************************/
HRESULT DDSurface::Unlock(RECT * pRect)
{
	m_ddsd.lpSurface = NULL;  // make it unavailable

	return m_pSurface->Unlock(pRect);
}


/* Global *********************************************************************
Author:		Paul Watt
Date:		9/30/2001
Purpose:	Restores this surfaces memory if the memory has been lost.  Classes
			that derive from this class will have to restore any data that was 
			previously stored on this surface.
Parameters:	NONE
Return:		HRESULT indicating success or failure.
******************************************************************************/
HRESULT DDSurface::RestoreSurface(void)
{
			//C: Verify that the object has been initialized.
	if ( m_pSurface )
	{
			//C: Check if the memory has been lost.
        if ( m_pSurface->IsLost() )
		{
			//C: The memory has been lost, therefore restore.  This will
			//   reallocate the memory for this surface.
			return m_pSurface->Restore();
		}
		else
		{
			return DD_OK;
		}
	}
	else
	{
		return E_FAIL;
	}
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		11/9/2001
Purpose:	
Parameters:			
Return:		
******************************************************************************/
HRESULT DDSurface::SetClipper(LPDIRECTDRAWCLIPPER lpDDClipper)
{
	return m_pSurface->SetClipper(lpDDClipper);
}

/* Public *********************************************************************
Author:		Paul Watt
Date:		11/7/2001
Purpose:	Fills the destination rectangle of this surface with dwFillColor.
Parameters:	rDest[in]: A destination rectangle to be filled.  If this value
				is NULL, thent eh entire rectangle will be filled.
Return:		
******************************************************************************/
HRESULT DDSurface::FillColor (RECT *pDest, DWORD dwFillColor)
{
	DDBLTFX fx;
	fx.dwSize = sizeof(fx);
	fx.dwFillColor = dwFillColor;

	RECT  rSurface;
	if (NULL == pDest)
	{
		rSurface.left	= 0;
		rSurface.top	= 0;
		rSurface.right	= m_ddsd.dwWidth;
		rSurface.bottom	= m_ddsd.dwHeight;

		pDest = &rSurface;
	}
			//C: Offset the rDest rectangle.
	POINT ptOrigin;
	GetOrigin(ptOrigin);

	::OffsetRect(pDest, ptOrigin.x, ptOrigin.y);

	return this->Blt(pDest,NULL, NULL, DDBLT_COLORFILL, &fx);
}


/* DDOffScreenSurface Implementation *****************************************/
/* Public *********************************************************************
Author:		Paul Watt
Date:		11/9/2001
Purpose:	Constructor
******************************************************************************/
DDOffScreenSurface::DDOffScreenSurface() : DDSurface()
{
			//C: No current operations
}

/* Public *********************************************************************
Author:		Paul Watt
Date:		11/9/2001
Purpose:	Destructor
******************************************************************************/
DDOffScreenSurface::~DDOffScreenSurface()
{
			//C: No current operations
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		11/9/2001
Purpose:	Initializes this off screen surface to match the same parameters
			as the hwnd that is passed in.
Parameters:	pDirectDraw[in]: Handle to the instance of DirectDraw that is being
				used.
			hWnd[in]: A window whose dimensions should be used to calculate the
				size of this surface.  This parameter cannot be NULL;
Return:		
******************************************************************************/
HRESULT DDOffScreenSurface::Initialize(IDirectDraw7 *pDirectDraw, UINT nBufferCount)
{
			//C: The information that is required for this surface does not 
			//   exist.  Mainly the width and height of the surface.
	return E_NOTIMPL;
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		11/9/2001
Purpose:	
Parameters:			
Return:		
******************************************************************************/
HRESULT DDOffScreenSurface::Initialize(IDirectDraw7 *pDirectDraw, DWORD dwWidth, DWORD dwHeight)
{
			//C: Verify input parameters
	if (NULL == pDirectDraw)
	{
		return -1;
	}

	m_ddsd.dwFlags			= DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
	m_ddsd.ddsCaps.dwCaps	= DDSCAPS_OFFSCREENPLAIN;
	m_ddsd.dwWidth			= dwWidth;
	m_ddsd.dwHeight			= dwHeight;
		
	HRESULT hr = pDirectDraw->CreateSurface(&m_ddsd, &m_pSurface, NULL);
			//C: Finish initializing the ddsd field.
	if (NULL != m_pSurface)
	{
		m_pSurface->GetSurfaceDesc(&m_ddsd);
	}

	return hr;
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		4/6/2002
Purpose:	Initializes the new offscreen surface with the data found in the 
			pDIB bitmap.
Parameters:	pDirectDraw7[in]: The directDraw instance to create this surface with.	
			pDIB[in]: The DIB in which to initialize the surface with.  The
				size of the buffer will be the same size as the bitmap.
Return:		HRESULT indicating the status of this function.
******************************************************************************/
HRESULT DDOffScreenSurface::Initialize(IDirectDraw7 *pDirectDraw, const BITMAPINFO * pDIB)
{
			//C: Verify input parameters
	if (!pDirectDraw || !pDIB)
	{
		return E_INVALIDARG;
	}

	m_ddsd.dwFlags			= DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
	m_ddsd.ddsCaps.dwCaps	= DDSCAPS_OFFSCREENPLAIN;
			//C: Extract the size of the bitmap.
	m_ddsd.dwWidth			= pDIB->bmiHeader.biWidth;
	m_ddsd.dwHeight			= abs(pDIB->bmiHeader.biHeight);
		
	HRESULT hr = pDirectDraw->CreateSurface(&m_ddsd, &m_pSurface, NULL);
			//C: Finish initializing the ddsd field.
	if (NULL != m_pSurface)
	{
		m_pSurface->GetSurfaceDesc(&m_ddsd);
	}
			//C: Place the image data from the bitmap into the surface.
	return DrawBitmap(pDIB, 0, 0, m_ddsd.dwWidth, m_ddsd.dwHeight);
}

/* Global Functions **********************************************************/
/* Global *********************************************************************
Author:		Paul Watt
Date:		10/6/2001
Purpose:	Creates a new DDSurface object.  This function will initialize
			the new surface as well.
Parameters:	pDirectDraw[in]: A Pointer to teh DD instance.
			nBufferCount[in]: The number of buffers to attach to this surface.
			hWnd[in]: A window that this surface will represent if any.
Return:		A pointer to a new DDSurface will be returned if the function 
			succeeds, otherwise NULL.
******************************************************************************/
DDSurface* CreateSurface(IDirectDraw7 *pDirectDraw, UINT nBufferCount)
{
	HRESULT hr;
	DDSurface *pSurface = new DDSurface;
	
	hr = pSurface->Initialize(pDirectDraw, nBufferCount);
	if (FAILED(hr))
	{
		delete pSurface;
		pSurface = NULL;
	}

	return pSurface;
}
   

/* Global *********************************************************************
Author:		Paul Watt
Date:		4/6/2002
Purpose:	Creates a new DDOffScreenSurface object that is initialized with
			a bitmap.
Parameters:	pDirectDraw[in]: A Pointer to the DD instance.
			dwWidth[in]: The width of the new surface.
			dwHeight[in]: The height of the new surface.
Return:		A pointer to a new DDOffsecreenSurface will be returned if the function 
			succeeds, otherwise NULL.
******************************************************************************/
DDOffScreenSurface* CreateOffScreenSurface(IDirectDraw7 *pDirectDraw, DWORD dwWidth, DWORD dwHeight)
{
	HRESULT hr;
	DDOffScreenSurface *pSurface = new DDOffScreenSurface;
	
	hr = pSurface->Initialize(pDirectDraw, dwWidth, dwHeight);
	if (FAILED(hr))
	{
		delete pSurface;
		pSurface = NULL;
	}

	return pSurface;
}
   

/* Global *********************************************************************
Author:		Paul Watt
Date:		4/6/2002
Purpose:	Creates a new DDOffScreenSurface object that is initialized with
			a bitmap.
Parameters:	pDirectDraw[in]: A Pointer to teh DD instance.
			pDIB[in]:
Return:		A pointer to a new DDOffScreenSurface will be returned if the function 
			succeeds, otherwise NULL.
******************************************************************************/
DDOffScreenSurface* CreateOffScreenSurface(IDirectDraw7 *pDirectDraw, const BITMAPINFO * pDIB)
{
	HRESULT hr;
	DDOffScreenSurface *pSurface = new DDOffScreenSurface;
	
	hr = pSurface->Initialize(pDirectDraw, pDIB);
	if (FAILED(hr))
	{
		delete pSurface;
		pSurface = NULL;
	}

	return pSurface;
}
   

/* Global *********************************************************************
Author:		Paul Watt
Date:		4/6/2002
Purpose:	Creates a new surface, and initializes that surface with an image
			loaded from a file.
Parameters:	pDirectDraw[in]: 
			pszFileName[in]: The path to the image to intialize the surface with.
Return:		If the function succeeds, then a pointer to a new DDOffscreenSurface
			object that is initialized with the target image will be returned.
			If the function fails then NULL will be returned.
******************************************************************************/
DDOffScreenSurface* CreateOffScreenSurface(IDirectDraw7 *pDirectDraw, const TCHAR* pszFileName)
{
	HANDLE hFile	= NULL;
	HANDLE hMapping = NULL;
	BYTE  *pByte	= NULL;

	DDOffScreenSurface *pSurface = NULL;

	try
	{
			//C: Open the image from pszFileName.
		hFile = ::CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, 
									OPEN_EXISTING, NULL, NULL);
		if (INVALID_HANDLE_VALUE == hFile)
		{
			throw NULL;
		}
			//C: MemoryMap the file.
		hMapping = ::CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
		if (INVALID_HANDLE_VALUE == hMapping)
		{
			throw NULL;
		}
			
		pByte = (BYTE*)::MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
		BITMAPINFO *pDIB = (BITMAPINFO*)(pByte + sizeof(BITMAPFILEHEADER));
		if (!pDIB)
		{
			throw NULL;
		}
		
			//C: Create and initialize the new surface.
		pSurface = CreateOffScreenSurface(pDirectDraw, pDIB);
	}
	catch (...)
	{
			//C: No current operations.
	}
			//C: Free resources.
	if (pByte)
	{
		::UnmapViewOfFile(pByte);
	}

	if (hFile)
	{
		::CloseHandle(hFile);
	}

	if (hMapping)
	{
		::CloseHandle(hMapping);
	}
			//C: Exit.
	return pSurface;
}

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
Engineer
United States United States
I am a software architect and I have been developing software for nearly two decades. Over the years I have learned to value maintainable solutions first. This has allowed me to adapt my projects to meet the challenges that inevitably appear during development. I use the most beneficial short-term achievements to drive the software I develop towards a long-term vision.

C++ is my strongest language. However, I have also used x86 ASM, ARM ASM, C, C#, JAVA, Python, and JavaScript to solve programming problems. I have worked in a variety of industries throughout my career, which include:
• Manufacturing
• Consumer Products
• Virtualization
• Computer Infrastructure Management
• DoD Contracting

My experience spans these hardware types and operating systems:
• Desktop
o Windows (Full-stack: GUI, Application, Service, Kernel Driver)
o Linux (Application, Daemon)
• Mobile Devices
o Windows CE / Windows Phone
o Linux
• Embedded Devices
o VxWorks (RTOS)
o Greenhills Linux
o Embedded Windows XP

I am a Mentor and frequent contributor to CodeProject.com with tutorial articles that teach others about the inner workings of the Windows APIs.

I am the creator of an open source project on GitHub called Alchemy[^], which is an open-source compile-time data serialization library.

I maintain my own repository and blog at CodeOfTheDamned.com/[^], because code maintenance does not have to be a living hell.

Comments and Discussions