Click here to Skip to main content
15,891,136 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.2K   6.2K   125  
An interpretation of a popular falling block game implemented with DirectX that attempts to avoid any copyright infringement.
/* DDrawWindow.h **************************************************************
Author:		Paul Watt, Copyright (c) 2002
Date:		5/4/2002
Purpose:	This file contains the declaration for a view type window that 
			supports DirectDraw access.
******************************************************************************/
#ifndef __DDRAWWINDOW_H
#define __DDRAWWINDOW_H

/* Include Files *************************************************************/
#include <DDSurface.h>
#include <ATLWin.h>

#ifndef SAFE_RELEASE
#define SAFE_RELEASE(ptr) if(ptr) {(ptr)->Release(); ptr = NULL;}
#endif

/* Class **********************************************************************
Author:		Paul Watt
Date:		5/4/2002
Purpose:	Class that encapsulates the details that are required to build
			a DirectDraw view.  This class  is meant to derive from any class
			that has a m_hWnd member.
******************************************************************************/
template <class Base>
class DDrawWindowT : public Base
{
protected:
	IDirectDraw7	*m_pDD;
	DDSurface		*m_pSurface;
	DDSurface		*m_pBackSurface;

	bool m_isWindowed;	

	DWORD m_dwBackgroundColor;

			//C: Display functions.
	virtual HRESULT Erase ();
	HRESULT Flip();

	virtual HRESULT DestroyObjects();
	virtual HRESULT Init();

	virtual HRESULT AdjustWindowForModeChange ();
public:
	DDrawWindowT ();
	~DDrawWindowT();
			//C: Creation and destruction methods.
	HRESULT InitClipper	();

	DWORD   GetBackgroundColor  ();
	HRESULT SetBackgroundColor  (DWORD dwColor);

	HRESULT SetFullScreenDisplay(DWORD dwWidth, DWORD dwHeight, DWORD dwBPP);
	HRESULT SetWindowedDisplay  ();

			//C: Member access functions.
	IDirectDraw7*	GetDirectDraw();
	DDSurface*		GetFrontBuffer();
	DDSurface*		GetBackBuffer();

	bool			IsWindowed();
};


/* DDrawWindowT inline implementation *******************************************/
/* Public *********************************************************************
Author:		Paul Watt
Date:		5/4/2002
Purpose:	Constructor
******************************************************************************/
template<class Base>
inline DDrawWindowT<Base>::DDrawWindowT ()
{
	m_pDD			= NULL;
	m_pSurface		= NULL;
	m_pBackSurface	= NULL;

	m_isWindowed = false;
			//C: The default background color is black.
	m_dwBackgroundColor = 0x00000000;
}

/* Public *********************************************************************
Author:		Paul Watt
Date:		5/4/2002
Purpose:	Destructor.
Note:		Any class that derives from this class should place all desctruction
			code in the DestroyObjects virtual function.
******************************************************************************/
template<class Base>
inline DDrawWindowT<Base>::~DDrawWindowT ()
{
	DestroyObjects();
}


/* Protected ******************************************************************
Author:		Paul Watt
Date:		5/4/2002
Purpose:	Any operations that need to occur in order to initialize the display
			when the mode has changed should be added to this function.
Parameters:	NONE
Results:	HRESULT indicates the status of this function.
******************************************************************************/
template<class Base>
inline HRESULT DDrawWindowT<Base>::Init()
{
			//C: Initialize the primary surface.
	m_pSurface->FillColor(NULL, GetBackgroundColor());
			//C: Eraseo the back buffer.
	Erase();

	return S_OK;
}


/* Protected ******************************************************************
Author:		Paul Watt
Date:		5/17/2002
Purpose:	This function is called when the screen mode is changed from
			Windowed to FullScreen or vice versa.
Parameters:	NONE
Return:		HRESULT indicates the status of this function.
******************************************************************************/
template<class Base>
inline HRESULT DDrawWindowT<Base>::AdjustWindowForModeChange ()
{
	return S_OK;
}


/* Public *********************************************************************
Author:		Paul Watt
Date:		5/4/2002
Purpose:	Initializes a clipper for any GDI operations that are performed on 
			the surfaces.
Parameters:	NONE
Results:	
******************************************************************************/
template<class Base>
inline HRESULT DDrawWindowT<Base>::InitClipper ()
{

}

/* Public *********************************************************************
Author:		Paul Watt
Date:		5/4/2002
Purpose:	Returns the current background color for this display.
Parameters:	NONE
Results:	-
******************************************************************************/
template<class Base>
inline DWORD DDrawWindowT<Base>::GetBackgroundColor ()
{
	return m_dwBackgroundColor;
}

/* Public *********************************************************************
Author:		Paul Watt
Date:		5/4/2002
Purpose:	Sets the background color of this display.
Parameters:	dwColor[in]: A DWORD that describes the color in the same pixel format
				as described by the FrontBuffer surface.
Results:	HRESULT indicates the status of this function.
******************************************************************************/
template<class Base>
inline HRESULT DDrawWindowT<Base>::SetBackgroundColor (DWORD dwColor)
{
	m_dwBackgroundColor = dwColor;
	return S_OK;
}

/* Public *********************************************************************
Author:		Paul Watt
Date:		5/4/2002
Purpose:	Initializes the DirectDraw surfaces to Display in full screen mode.
Parameters:	
Results:	
******************************************************************************/
template<class Base>
inline HRESULT DDrawWindowT<Base>::SetFullScreenDisplay (DWORD dwWidth, DWORD dwHeight, DWORD dwBPP)
{
	HRESULT				hr;
			//C: Insure that all of the currently existing DD objects are destroyed.
	DestroyObjects();
			//C: Create a new DirectDraw Context.
			//C: Initialize the directdraw code for this view.
	hr = DirectDrawCreateEx(NULL, (void **) &m_pDD, IID_IDirectDraw7, NULL);
	if ( FAILED( hr ) )
	{
		return hr;
	}

	try
	{
			//C: Flag the display as Full screen mode.
		m_isWindowed = false;
			//C: Adjust the window for this change.
		AdjustWindowForModeChange();
			//C: Get the top level window that is a parent of this window.
		HWND hWndTopLevel = m_hWnd;
		HWND hTemp	= m_hWnd;
		while (hTemp)
		{
			hTemp = ::GetParent(hWndTopLevel);
			if (hTemp)
			{
				hWndTopLevel = hTemp;
			}
		}
			//C: Set the cooperative level for the display.
		hr = m_pDD->SetCooperativeLevel(hWndTopLevel, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
		if ( FAILED(hr) )
		{
			throw hr;
		}
			//C: Change the display mode.
		hr = m_pDD->SetDisplayMode     (dwWidth, dwHeight, dwBPP, 0, 0);
		if ( FAILED(hr) )
		{
			throw hr;
		}
			//C: Create the primary surface with a back buffer attached to it.
		UINT nBackBufferCount = 1;
		m_pSurface = CreateSurface(m_pDD, nBackBufferCount);
		if (NULL == m_pSurface)
		{
			throw hr;
		}
			//C: Get the attached surface to the primary surface for the backbuffer.
		DDSCAPS2 ddSCaps;
		ZeroMemory(&ddSCaps, sizeof(ddSCaps));
		ddSCaps.dwCaps  = DDSCAPS_BACKBUFFER;

		hr = m_pSurface->GetAttachedSurface(ddSCaps, &m_pBackSurface);
		if (FAILED(hr))
		{
			throw hr;
		}
			//C: Initialize the display.
		hr = Init();
		if (FAILED(hr))
		{
			throw hr;
		}
	}
	catch(...)
	{
			//C: Flag the display as windowed mode.
		m_isWindowed = true;
			//C: Adjust the window for this change.
		AdjustWindowForModeChange();
			//C: Destroy all of the surfaces and objects that were created for
			//   this display.
		DestroyObjects();
	}

	return hr;
}

/* Public *********************************************************************
Author:		Paul Watt
Date:		5/4/2002
Purpose:	Initializes the DirectDraw surface to display in windowed mode.
Parameters:	
Results:	
******************************************************************************/
template<class Base>
inline HRESULT DDrawWindowT<Base>::SetWindowedDisplay ()
{
	LPDIRECTDRAWCLIPPER pClipper = NULL;
	HRESULT				hr;
			//C: Insure that all of the currently existing DD objects are destroyed.
	DestroyObjects();
			//C: Create a new DirectDraw Context.
			//C: Initialize the directdraw code for this view.
	hr = DirectDrawCreateEx(NULL, (void **) &m_pDD, IID_IDirectDraw7, NULL);
	if ( FAILED( hr ) )
	{
		return hr;
	}

	try
	{
			//C: Flag the display as windowed mode.
		m_isWindowed = true;
			//C: Get the top level window that is a parent of this window.
		HWND hWndTopLevel = m_hWnd;
		HWND hTemp	= m_hWnd;
		while (hTemp)
		{
			hTemp = ::GetParent(hWndTopLevel);
			if (hTemp)
			{
				hWndTopLevel = hTemp;
			}
		}
			//C: Set the cooperative level for the display.
		hr = m_pDD->SetCooperativeLevel(hWndTopLevel, DDSCL_NORMAL);
		if ( FAILED(hr) )
		{
			throw hr;
		}
			//C: Create the primary surface.
		m_pSurface = CreateSurface(m_pDD, 0);
		if (NULL == m_pSurface)
		{
			throw hr;
		}
			//C: Associate this window with the surface to allow for automatic
			//   offsets.
		m_pSurface->SetWindow(m_hWnd);
			//C: Create a backbuffer surface to match teh size of the window.
		RECT rClient;
		GetClientRect(&rClient);
		m_pBackSurface = ::CreateOffScreenSurface(m_pDD, rClient.right, rClient.bottom);
			//C: Create a clipper to use with the primary surface for GDI calls.		
		hr = m_pDD->CreateClipper(0, & pClipper, NULL);
		if ( FAILED(hr) )
		{
			throw hr;
		}

		hr = pClipper->SetHWnd(0, m_hWnd);
		if ( FAILED(hr) )
		{
			throw hr;
		}

		hr = m_pSurface->SetClipper(pClipper);
		if ( FAILED(hr) )
		{
			throw hr;
		}
			//C: Initialize the display.
		hr = Init();
		if (FAILED(hr))
		{
			throw hr;
		}
			//C: Adjust the window for this change.
		AdjustWindowForModeChange();
	}
	catch(...)
	{
			//C: Flag the display as windowed mode.
		m_isWindowed = false;
			//C: Adjust the window for this change.
		AdjustWindowForModeChange();
			//C: Destroy all of the surfaces and objects that were created for
			//   this display.
		DestroyObjects();
	}
			//C: Free any resources that are not persistent.
	SAFE_RELEASE(pClipper);
			//C: Done;
	return hr;
}

/* Protected ******************************************************************
Author:		Paul Watt
Date:		5/4/2002
Purpose:	Destroys all of the objects that are associated with this window.
Parameters:	NONE
Results:	HRESULT indicates the status of this function call.
******************************************************************************/
template<class Base>
inline HRESULT DDrawWindowT<Base>::DestroyObjects ()
{
			//C: Release all of the surfaces associated with this display.
	delete m_pBackSurface;	
	m_pBackSurface = NULL;

	delete m_pSurface;
	m_pSurface = NULL;
			//C: Restore the cooperative level back to normal mode for the 
			//   DirectDraw context.
	if (m_pDD)
	{
		m_pDD->SetCooperativeLevel(NULL, DDSCL_NORMAL | DDSCL_NOWINDOWCHANGES);
	}

	SAFE_RELEASE(m_pDD);

	return S_OK;
}

/* Public *********************************************************************
Author:		Paul Watt
Date:		5/4/2002
Purpose:	Returns a pointer to the interface to the current directdraw context.
			The caller of this function will need to release their instance of 
			the interface pointer that they recieve.
Parameters:	NONE
Results:	-
******************************************************************************/
template<class Base>
inline IDirectDraw7* DDrawWindowT<Base>::GetDirectDraw ()
{
	m_pDD->AddRef();
	return m_pDD;
}

/* Public *********************************************************************
Author:		Paul Watt
Date:		5/4/2002
Purpose:	Returns a pointer to the DDSurface object that represents the
			Primary, or FrontBuffer for this display.
Parameters:	NONE
Results:	-
******************************************************************************/
template<class Base>
inline DDSurface*DDrawWindowT<Base>::GetFrontBuffer ()
{
	return m_pSurface;
}

/* Public *********************************************************************
Author:		Paul Watt
Date:		5/4/2002
Purpose:	Retruns a pointer to the DDSurface that represents the back surface.
Parameters:	NONE
Results:	-
******************************************************************************/
template<class Base>
inline DDSurface* DDrawWindowT<Base>::GetBackBuffer ()
{
	return m_pBackSurface;
}

/* Public *********************************************************************
Author:		Paul Watt
Date:		5/4/2002
Purpose:	Returns if this display is currently displaying in windowed mode,
				or not.
Parameters:	NONE
Results:	If the display is in windowed mode, then true will be returned, if
			the display is in full screen mode then false will be returned.
******************************************************************************/
template<class Base>
inline bool DDrawWindowT<Base>::IsWindowed ()
{
	return m_isWindowed;
}

/* Public *********************************************************************
Author:		Paul Watt
Date:		5/4/2002
Purpose:	Erases the BackBuffer.  The default method will be to erase the
			surface with the background color.  However this function can be 
			overridden to provide some other method of erasing the backsurface.
Parameters:	NONE
Results:	HRESULT indicates the status of this function.
******************************************************************************/
template<class Base>
inline HRESULT DDrawWindowT<Base>::Erase ()
{
			//C: Verify that the Backsurface is valid.
	if (!m_pBackSurface)
	{
		return E_POINTER;
	}
			//C: Erase the backsruface with the background color.
	return m_pBackSurface->FillColor(NULL, m_dwBackgroundColor);
}

/* Public *********************************************************************
Author:		Paul Watt
Date:		5/4/2002
Purpose:	Flips the backbuffer to the front buffer for this display.
Parameters:	NONE
Results:	HRESULT indicates the status of this function call.
******************************************************************************/
template<class Base>
inline HRESULT DDrawWindowT<Base>::Flip ()
{
	HRESULT hResult;
			//C: Verify that the surface pointers are valid.
	if (NULL == m_pSurface || NULL == m_pBackSurface)
	{
		return E_POINTER;
	}
			//C: Attempt to paint the surface.
	RECT rClient;
	GetClientRect(&rClient);
	while (1)
	{
			//C: The current screen mode will determine how we update the primary surface.
		if (IsWindowed())
		{
			//C: Blt the Back surface to the primary surface.
			DDBLTFX fx;
			fx.dwSize = sizeof(fx);
			fx.dwROP  = SRCCOPY;

			hResult = m_pSurface->Blt(&rClient, m_pBackSurface, NULL, DDBLT_ROP | DDBLT_WAIT, &fx);
		}
		else
		{
			//C: Flip the pages so that on the next vertical sync the back buffer will
			//   become the primary buffer that updates the screen.
			hResult = m_pSurface->Flip(NULL, 0);
		}

		if (DDERR_SURFACELOST == hResult)
		{
			//C: Restore the surfaces.
			m_pSurface->Restore();
			m_pBackSurface->Restore();
		}
			//C: If the buffer is not waiting to complete, then exit with the HRESULT.
		if (DDERR_WASSTILLDRAWING != hResult)
		{
			return hResult;
		}
	}

	return hResult;
}

typedef DDrawWindowT<CWindow> DDrawWindow;

#endif //__DDRAWWINDOW_H

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