Click here to Skip to main content
15,881,757 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 396.1K   6.2K   125  
An interpretation of a popular falling block game implemented with DirectX that attempts to avoid any copyright infringement.
/* DDSurface.h ****************************************************************
Author:		Paul Watt, Copyright (c) 2002
Date:		9/29/2001
Purpose:	
******************************************************************************/
#if !defined(AFX_DDSURFACE_H__C4C1824D_3173_4021_8C39_FE1706277249__INCLUDED_)
#define AFX_DDSURFACE_H__C4C1824D_3173_4021_8C39_FE1706277249__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <windows.h>
#include <ddraw.h>
#include <MEMORY>
using std::auto_ptr;

/* Class **********************************************************************
Author:		Paul Watt
Date:		9/29/2001
Purpose:	This class will represent a basic Direct Draw surface for use with
			drawing DriectDraw.
******************************************************************************/
class DDSurface  
{
friend DDSurface* CreateSurface(IDirectDraw7 *pDirectDraw, UINT nBufferCount);


protected:
	IDirectDrawSurface7		*m_pSurface;
	DDSURFACEDESC2			m_ddsd;

	HWND					m_hWnd;
	HDC						m_hDC;

	DDSurface();

//	HRESULT GetDC(void);
//	HRESULT ReleaseDC(void);

public:
	HRESULT GetDC(void);
	HRESULT ReleaseDC(void);

	HDC GetH ()
	{
		GetDC();
		return m_hDC;
	}
	/* Constructor / Destructor **************************************************/
	virtual ~DDSurface();

	virtual bool Attach(IDirectDrawSurface7 *pSurface);
	virtual bool Detach(IDirectDrawSurface7 **ppSurface);

	virtual HRESULT Initialize(IDirectDraw7 *pDirectDraw, UINT nBufferCount);
	virtual void Release(void);

	BYTE  * Lock  (RECT * pRect=NULL);
	HRESULT Unlock(RECT * pRect=NULL);
	HRESULT Restore();

	/* Cast operators ************************************************************/
	operator IDirectDrawSurface7* &()
	{
		return m_pSurface;
	}

	operator HDC()
	{
		return m_hDC;
	}

	/* Member access functions ***************************************************/
	int GetWidth(void) const;
	int GetHeight(void) const;
	int GetPitch(void) const;
	void GetOrigin (POINT &ptOrigin) const;

	HWND GetWindow();
	HWND SetWindow(HWND hNewWindow);

	void GetSurfaceDesc(DDSURFACEDESC2 &ddsd);

	/* Surface maintenence functions *********************************************/
	HRESULT CreatePrimarySurface(IDirectDraw7 * pDD, int nBackBuffer);
	
	virtual HRESULT RestoreSurface(void); // restore surface if lost

	HRESULT SetClipper(LPDIRECTDRAWCLIPPER lpDDClipper);

	HRESULT DrawBitmap(const BITMAPINFO * pDIB, int x, int y, int width, int height);

	HRESULT FillColor (RECT *pDest, DWORD dwFillColor);

	HRESULT GetSourceColorKey(DWORD &color);
	HRESULT SetSourceColorKey(DWORD color);
	HRESULT Blt    (LPRECT lpDestRect, DDSurface *pddSurface, LPRECT lpSrcRect, DWORD dwFlags, LPDDBLTFX lpDDBltFx); 
	HRESULT BltFast(DWORD dwX, DWORD dwY, DDSurface *pddSurface, LPRECT lpSrcRect, DWORD dwTrans); 

	HRESULT Flip   (DDSurface *pddSurface, DWORD dwFlags);
	HRESULT GetAttachedSurface(DDSCAPS2 &DDSCaps, DDSurface **ppddAttachedSurface);

};

typedef auto_ptr<DDSurface> auto_DDSurface;

/* Class **********************************************************************
Author:		Paul Watt
Date:		11/9/2001
Purpose:	The offscreen surface class is useful for general purpose drawing
			and creation of bitmaps.
******************************************************************************/
class DDOffScreenSurface : public DDSurface
{
friend DDOffScreenSurface* CreateOffScreenSurface(IDirectDraw7 *pDirectDraw, DWORD dwWidth, DWORD dwHeight);
friend DDOffScreenSurface* CreateOffScreenSurface(IDirectDraw7 *pDirectDraw, const BITMAPINFO * pDIB);
friend DDOffScreenSurface* CreateOffScreenSurface(IDirectDraw7 *pDirectDraw, const TCHAR *pszFileName);

protected:
	DDOffScreenSurface();
public:
	virtual ~DDOffScreenSurface();

	virtual HRESULT Initialize(IDirectDraw7 *pDirectDraw, UINT nBufferCount);
	virtual HRESULT Initialize(IDirectDraw7 *pDirectDraw, DWORD dwWidth, DWORD dwHeight);
	virtual HRESULT Initialize(IDirectDraw7 *pDirectDraw, const BITMAPINFO * pDIB);
};

typedef auto_ptr<DDOffScreenSurface> auto_DDOffScreenSurface;

/* DDSurface implementation **************************************************/
/* Public *********************************************************************
Author:		Paul Watt
Date:		5/4/2002
Purpose:	Restores memory allocation for a lost video surface.
Parameters:	NONE
Return:		HRESULT indicates the status of this function.
******************************************************************************/
inline HRESULT DDSurface::Restore()
{
	return m_pSurface->Restore();
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		9/29/2001
Purpose:	Returns the width of this surface.
Parameters:	NONE
Return:		-
******************************************************************************/
inline int DDSurface::GetWidth(void) const
{
	return m_ddsd.dwWidth;
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		9/29/2001
Purpose:	Returns the height of this surface.
Parameters:	NONE
Return:		-
******************************************************************************/
inline int DDSurface::GetHeight(void) const
{
	return m_ddsd.dwHeight;
}


/* Global *********************************************************************
Author:		Paul Watt
Date:		9/29/2001
Purpose:	
Parameters:			
Return:		
******************************************************************************/
inline int DDSurface::GetPitch(void) const
{
	return m_ddsd.lPitch;
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		10/6/2001
Purpose:	Returns the origin of this surface.  If this surface represents a
			window, then the surface will be the origin of the client area, 
			otherwise the origin will be (0,0);
Parameters:	ptOrigin[in/out]: a reference to the point that will accept the
				origin position.
Return:		-
******************************************************************************/
inline void DDSurface::GetOrigin (POINT &ptOrigin) const
{
			//C: Test which type of surface this is.
	if (NULL == m_hWnd)
	{
		ptOrigin.x = 0;
		ptOrigin.y = 0;
	}
	else
	{
		RECT rClient;

		::GetClientRect(m_hWnd, &rClient);
		ptOrigin.x = rClient.left;
		ptOrigin.y = rClient.top;

		::ClientToScreen(m_hWnd, &ptOrigin);
	}
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		4/20/2002
Purpose:	Returns the handle of the window that this surface is associated with.
Parameters:	NONE
Return:		-
******************************************************************************/
inline HWND DDSurface::GetWindow()
{

}


/* Public *********************************************************************
Author:		Paul Watt
Date:		4/20/2002
Purpose:	Sets the handle of the window that this surface is associated with.
			This is inportant because the surface will automatically provide
			surface offset support relating to the window.
Parameters:	hNewWindow[in]: Handle to the new window.  This value may be NULL.
Return:		Returns the previous window handle associated with this surface.
******************************************************************************/
inline HWND DDSurface::SetWindow(HWND hNewWindow)
{
	HWND hWndOld = m_hWnd;
	m_hWnd = hNewWindow;

	return hWndOld;
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		5/19/2002
Purpose:	Returns the surface description for this surface.
Parameters:	ddsd[out]: A reference to a DDSURFACEDESC2 structure that will 
				accept the result.
Return:		-
******************************************************************************/
inline void DDSurface::GetSurfaceDesc(DDSURFACEDESC2 &ddsd)
{
	ddsd = m_ddsd;
}


/* Protected ******************************************************************
Author:		Paul Watt
Date:		9/29/2001
Purpose:	Retreives a DC for use with this surface.
Parameters:	NONE
Return:		HRESULT indicating the status fo this function.
******************************************************************************/
inline HRESULT DDSurface::GetDC(void)
{
	if (m_hDC)
	{
		return S_OK;
	}

    return m_pSurface->GetDC(&m_hDC);
}


/* Protected ******************************************************************
Author:		Paul Watt
Date:		9/29/2001
Purpose:	Releases any DC that was received from the window that this surface
			represents.
Parameters:	NONE
Return:		HRESULT indicating the status of this function.
******************************************************************************/
inline HRESULT DDSurface::ReleaseDC(void)
{
	if (!m_hDC)
	{
		return S_OK;
	}
	
	HRESULT hr = m_pSurface->ReleaseDC(m_hDC);
	m_hDC = NULL;
	return hr;
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		4/6/2002
Purpose:	Draws a bitmap onto this surface.  This method works through the
			GDI, therefore it is slow, and it is only recommended to use this
			function for initializing the surface.
Parameters:	pDIB[in]: The bitmap databits.
			x[in]:
			y[in]:
			width[in]:
			height[in]:
Return:		HRESULT indicating the status of this function.
******************************************************************************/
inline HRESULT DDSurface::DrawBitmap(const BITMAPINFO * pDIB, int x, int y, int width, int height)
{
			//C: Verify input parameters.
	if (!pDIB)
	{
		return E_INVALIDARG;
	}
			//C: Insure that the DC has been allocated for this object.
	if (SUCCEEDED(GetDC()))
	{
#pragma message( REMIND( "PMW: Turn this into a function" ) )
const BITMAPINFOHEADER *bmih = &pDIB->bmiHeader;
DWORD dwCount;
if ( bmih->biBitCount <= 8 )
{
	if ( bmih->biClrUsed )
	{
		dwCount = bmih->biClrUsed;
	}
	else
	{
		dwCount = 1 << bmih->biBitCount;
	}
}
else if ( bmih->biCompression==BI_BITFIELDS )
{
	dwCount = 3 + bmih->biClrUsed;
}
else
{
	dwCount = bmih->biClrUsed;
}

			//C: Blt the bitmap to the surface.
		StretchDIBits	(
						m_hDC, 
						x, y, 
						width, height,
						0, 0, 
						pDIB->bmiHeader.biWidth, pDIB->bmiHeader.biHeight, 
						& pDIB->bmiColors[dwCount], 
						pDIB, 
						DIB_RGB_COLORS, 
						SRCCOPY
						);
			//C: Release the DC.
        return ReleaseDC();
    }
	else
	{
		return E_FAIL;
	}
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		4/6/2002
Purpose:	Sets the source color key for blt operations.
Parameters:	color[in]: The color to set for the key.
Return:		HRESULT indicates the status of this function.
******************************************************************************/
inline HRESULT DDSurface::GetSourceColorKey(DWORD &color)
{
	DDCOLORKEY key;
			//C: Set the color key.
	HRESULT hr = m_pSurface->GetColorKey(DDCKEY_SRCBLT, &key);
			//C: Get the color.  For a color key, the high and the low value
			//   should be equal, we will simply use the low value.
	color = key.dwColorSpaceLowValue;

	return hr;
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		4/6/2002
Purpose:	Sets the source color key for blt operations.
Parameters:	color[in]: The color to set for the key.
Return:		HRESULT indicates the status of this function.
******************************************************************************/
inline HRESULT DDSurface::SetSourceColorKey(DWORD color)
{
	DDCOLORKEY key;
			//C: By setting these two values = it tells the surface that there
			//   is only one color.
	key.dwColorSpaceLowValue = color;
	key.dwColorSpaceHighValue = color;
			//C: Set the color key.
	return m_pSurface->SetColorKey(DDCKEY_SRCBLT, &key);
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		11/9/2001
Purpose:	Blts the data from the pddSurface to this surface.
Parameters:	lpDestRect[in]: 
			pddSurface[in]:
			lpSrcRect[in]:
			dwFlags[in]:
			lpDDBltFx[in]:
Return:		HRESULT indicating the status of this function.
******************************************************************************/
inline HRESULT DDSurface::Blt(LPRECT lpDestRect, DDSurface *pddSurface, LPRECT lpSrcRect, DWORD dwFlags, LPDDBLTFX lpDDBltFx)
{
			//C: Offset the dimensions for the destination.
	ClientToScreen(m_hWnd, (POINT*)lpDestRect);
	ClientToScreen(m_hWnd, ((POINT*)lpDestRect) + 1);
			//C: Offset the dimensions for the source if it exists.
	if (NULL != pddSurface && NULL != lpSrcRect)
	{
		ClientToScreen(pddSurface->m_hWnd, (POINT*)lpSrcRect);
		ClientToScreen(pddSurface->m_hWnd, ((POINT*)lpSrcRect) + 1);
	}

	IDirectDrawSurface7* pSurface = (NULL == pddSurface ? NULL : pddSurface->m_pSurface);
	return m_pSurface->Blt(lpDestRect, pSurface, lpSrcRect, dwFlags, lpDDBltFx);
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		11/7/2001
Purpose:	Access function to blit.
Parameters:	Blts the data from pddSurface this surface.
			dwX[in]:
			dwY[in]:
			pddSurface[in]:
			lpSrcRect[in]:
			dwFlags[in]:
			dwTrans[in]:
Return:		HRESULT indicating the status of this function.
******************************************************************************/
inline HRESULT DDSurface::BltFast(DWORD dwX, DWORD dwY,  DDSurface *pddSurface, LPRECT lpSrcRect, DWORD dwTrans)
{
	IDirectDrawSurface7* pSurface = (NULL == pddSurface ? NULL : pddSurface->m_pSurface);
	return m_pSurface->BltFast(dwX, dwY, pSurface, lpSrcRect, dwTrans);
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		11/16/2001
Purpose:	Flips memory pages on the video card.  This function will only
			work for a surface that has exclusive full-screen mode.
Parameters:	pddSurface[in]:
			dwFlags[in]:
Return:		HRESULT indicating the status of this function.
******************************************************************************/
inline HRESULT DDSurface::Flip(DDSurface *pddSurface, DWORD dwFlags)
{
	IDirectDrawSurface7* pSurface = (NULL == pddSurface ? NULL : pddSurface->m_pSurface);
	return m_pSurface->Flip(pSurface, dwFlags);
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		11/16/2001
Purpose:	Retrieves a surface that is attached to this surface with the 
			attributes specified in lpDDSCaps.
Parameters:	DDSCaps[in]:
			pddAttachedSurface[in/out]: Address of a pointer that will accept
				the newly created surface.
Return:		An HRESULT will be returned to indicate the status of this function.
******************************************************************************/
inline HRESULT DDSurface::GetAttachedSurface(DDSCAPS2 &DDSCaps, DDSurface **ppddAttachedSurface)
{
			//C: Verify input parameters.
	if (NULL == ppddAttachedSurface)
	{
		return E_FAIL;
	}
			//C: Initialize output parameters.
	*ppddAttachedSurface = NULL;
			//C: Get the attached surface from this surface.
	LPDIRECTDRAWSURFACE7 pAttachedSurface;
	HRESULT hr = m_pSurface->GetAttachedSurface(&DDSCaps, &pAttachedSurface);
	if (FAILED(hr))
	{
		return hr;
	}
			//C: Create a blank DDSurface object and attach the newly created
			//   surface to it.
	*ppddAttachedSurface = new DDSurface;
	if (NULL == *ppddAttachedSurface)
	{
		pAttachedSurface->Release();
		return E_FAIL;
	}
	
	(*ppddAttachedSurface)->Attach(pAttachedSurface);

			//C: Return success.
	return S_OK;
}


/* DDOffScreenSurface implementation *****************************************/


/* Global functions **********************************************************/
DDSurface* CreateSurface(IDirectDraw7 *pDirectDraw, UINT nBufferCount);
DDOffScreenSurface* CreateOffScreenSurface(IDirectDraw7 *pDirectDraw, DWORD dwWidth, DWORD dwHeight);
DDOffScreenSurface* CreateOffScreenSurface(IDirectDraw7 *pDirectDraw, const BITMAPINFO * pDIB);
DDOffScreenSurface* CreateOffScreenSurface(IDirectDraw7 *pDirectDraw, const TCHAR *pszFileName);



#endif // !defined(AFX_DDSURFACE_H__C4C1824D_3173_4021_8C39_FE1706277249__INCLUDED_)

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