www.pudn.com > bookcode.rar > main.cpp


//Example2_4 
//main.cpp 
//Ernest Pazera 
//07OCT2001 
//TGO-02-C , D 
//Libs: d3d8.lib 
 
#include 	//include windows stuff 
#include 		//standard input/output 
#include "D3D8.h"	//include direct3d8 stuff 
#include "d3dfmtutils.h"	//include format utility functions 
#include "resource.h"	//include resource IDs 
 
//constants 
	//window class name 
	const char* WINDOWCLASS = "3D42DGP" ; 
	//window title 
	const char* WINDOWTITLE = "Example 2.4 (TGO-02-C, D): Conway's Game of Life" ; 
	//screen dimensions 
	const int SCREENWIDTH = 512 ; 
	const int SCREENHEIGHT = 384 ; 
	//cell size 
	const int CELLWIDTH = 8 ; 
	const int CELLHEIGHT = 8 ; 
	//cell columns and rows 
	const int CELLCOLUMNS = SCREENWIDTH / CELLWIDTH ; 
	const int CELLROWS = SCREENHEIGHT / CELLHEIGHT ; 
 
//globals 
	//instance handle 
	HINSTANCE g_hInstance = NULL ; 
	//window handle 
	HWND g_hWnd = NULL ; 
	//IDirect3D8 pointer 
	IDirect3D8* g_pd3d = NULL ; 
	//device type in use 
	D3DDEVTYPE g_devtype ; 
	//device pointer 
	IDirect3DDevice8* g_pd3ddev = NULL ; 
	//maps 
	bool g_Alive [ CELLCOLUMNS ] [ CELLROWS ] ; 
	bool g_Birth [ CELLCOLUMNS ] [ CELLROWS ] ; 
	bool g_Death [ CELLCOLUMNS ] [ CELLROWS ] ; 
	//cell rectangles 
	D3DRECT g_rccells [ CELLCOLUMNS ] [ CELLROWS ] ; 
	//running flag 
	bool g_Running = false ; 
 
//function prototypes 
	//winmain 
	int WINAPI WinMain ( HINSTANCE hInstance , HINSTANCE hPrevInstance , LPSTR lpCmdLine , int nShowCmd ) ; 
	//window procedure 
	LRESULT CALLBACK TheWindowProc ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam ) ; 
	//initialization 
	void Prog_Init ( ) ; 
	//clean up 
	void Prog_Done ( ) ; 
	//redraw frame 
	void RedrawFrame ( ) ; 
	//clear the map 
	void ClearMap ( ) ; 
	//update the map  
	void UpdateMap ( ) ; 
 
 
//window procedure 
LRESULT CALLBACK TheWindowProc ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam ) 
{ 
	//which message did we get? 
	switch ( uMsg ) 
	{ 
	case WM_LBUTTONDOWN : //left button press 
		{ 
			//check for running state 
			if ( g_Running ) 
			{ 
				//is running, so return 0 
				return ( 0 ) ; 
			} 
 
			//grab x and y location 
			int x = LOWORD ( lParam ) ; 
			int y = HIWORD ( lParam ) ; 
 
			//calculate cell 
			x /= CELLWIDTH ; 
			y /= CELLHEIGHT ; 
 
			//toggle alive state 
			g_Alive [ x ] [ y ] = ! g_Alive [ x ] [ y ] ; 
 
			//redraw the frame 
			RedrawFrame ( ) ; 
			 
			//return 0 
			return ( 0 ) ; 
		} break ; 
	case WM_TIMER : 
		{ 
			//only execute if currently running 
			if ( g_Running ) 
			{ 
				//update map 
				UpdateMap ( ) ; 
 
				//redraw frame 
				RedrawFrame ( ) ; 
			} 
			//return 0 
			return ( 0 ) ; 
		} break ;  
	case WM_COMMAND: 
		{ 
			//which command? 
			int nCommand = LOWORD ( wParam ) ; 
			switch ( nCommand ) 
			{ 
			case ID_GAME_GO : //start running 
				{ 
					//update menu items 
					CheckMenuItem ( GetMenu ( hWnd ) , ID_GAME_GO , MF_CHECKED ) ; 
					EnableMenuItem ( GetMenu ( hWnd ) , ID_GAME_GO , MF_GRAYED ) ; 
					CheckMenuItem ( GetMenu ( hWnd ) , ID_GAME_STOP , MF_UNCHECKED ) ; 
					EnableMenuItem ( GetMenu ( hWnd ) , ID_GAME_STOP , MF_ENABLED ) ; 
					EnableMenuItem ( GetMenu ( hWnd ) , ID_GAME_NEXTFRAME , MF_GRAYED ) ; 
					EnableMenuItem ( GetMenu ( hWnd ) , ID_MAP_CLEAR , MF_GRAYED ) ; 
					//set running state 
					g_Running = true ; 
				} break ; 
			case ID_GAME_STOP : //start running 
				{ 
					//update menu items 
					CheckMenuItem ( GetMenu ( hWnd ) , ID_GAME_GO , MF_UNCHECKED ) ; 
					EnableMenuItem ( GetMenu ( hWnd ) , ID_GAME_GO , MF_ENABLED ) ; 
					CheckMenuItem ( GetMenu ( hWnd ) , ID_GAME_STOP , MF_CHECKED ) ; 
					EnableMenuItem ( GetMenu ( hWnd ) , ID_GAME_STOP , MF_GRAYED ) ; 
					EnableMenuItem ( GetMenu ( hWnd ) , ID_GAME_NEXTFRAME , MF_ENABLED ) ; 
					EnableMenuItem ( GetMenu ( hWnd ) , ID_MAP_CLEAR , MF_ENABLED ) ; 
					//set running state 
					g_Running = false ; 
					//show the frame 
					RedrawFrame ( ) ; 
				} break ; 
			case ID_GAME_EXIT : //exit game 
				{ 
					//destroy the window 
					DestroyWindow ( hWnd ) ; 
				} break ; 
			case ID_MAP_CLEAR : //clear map 
				{ 
					//only if not currently running 
					if ( !g_Running )  
					{ 
						//clear the map 
						ClearMap ( ) ; 
						//redraw the frame 
						RedrawFrame ( ) ; 
					} 
				} break ; 
			case ID_GAME_NEXTFRAME : //go one frame forward 
				{ 
					//only execute if not currently running 
					if ( !g_Running )  
					{ 
						//update the map 
						UpdateMap ( ) ; 
						//redraw the frame 
						RedrawFrame ( ) ; 
					} 
				} break ;  
			} 
			//return 0 
			return ( 0 ) ; 
		} break ; 
	case WM_DESTROY : //window being destroyed 
		{ 
			//destroy the timer 
			KillTimer ( hWnd , 0 ) ; 
 
			//quit 
 
			PostQuitMessage ( 0 ) ; 
 
			//message handled, return 0 
 
			return ( 0 ) ; 
 
		} break ; 
	default:  //all other messages, send to default handler 
		return ( DefWindowProc ( hWnd , uMsg , wParam , lParam ) ) ; 
	} 
} 
 
//winmain 
int WINAPI WinMain ( HINSTANCE hInstance , HINSTANCE hPrevInstance , LPSTR lpCmdLine , int nShowCmd ) 
{ 
	//grab instance handle 
	g_hInstance = hInstance ; 
 
	//redirect stderr and stdout output 
	freopen ( "stdout.txt" , "w" , stdout ) ; 
 
	//fill in window class 
	WNDCLASSEX wc ; 
	wc.cbClsExtra = 0 ;	//no extra class information 
	wc.cbSize = sizeof ( WNDCLASSEX ) ; //size of structure 
	wc.cbWndExtra = 0 ;	//no extra window information 
	wc.hbrBackground = ( HBRUSH ) GetStockObject ( BLACK_BRUSH ) ;	//black brush 
	wc.hCursor = NULL ;	//no cursor 
	wc.hIcon = NULL ;	//no icon 
	wc.hIconSm = NULL ;	//no small icon 
	wc.hInstance = g_hInstance ;	//instance handle 
	wc.lpfnWndProc = TheWindowProc ;	//window procedure 
	wc.lpszClassName = WINDOWCLASS ;	//name of class 
	wc.lpszMenuName = NULL ;	//no menu 
	wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC ;	//class styles 
 
	//register window class 
	RegisterClassEx ( &wc ) ; 
 
	//create window 
	g_hWnd = CreateWindowEx ( 0 , WINDOWCLASS , WINDOWTITLE , WS_CAPTION | WS_BORDER | WS_SYSMENU | WS_VISIBLE , 0 , 0 , 640 , 480 , NULL , LoadMenu ( g_hInstance , MAKEINTRESOURCE ( IDR_MAINMENU ) ) , g_hInstance , NULL ) ; 
 
	//show the window 
	ShowWindow ( g_hWnd , nShowCmd ) ; 
 
	//initialization 
	Prog_Init ( ) ; 
 
	MSG msg ; 
	//message pump 
	for ( ; ; )  
	{ 
		//check for a message 
		if ( PeekMessage( &msg , NULL , 0 , 0 , PM_REMOVE ) ) 
		{ 
			//message exists 
 
			//check for quit message 
			if ( msg.message == WM_QUIT ) break ; 
 
			//translate the message 
			TranslateMessage ( &msg ) ; 
 
			//dispatch the message 
			DispatchMessage ( &msg ) ; 
		} 
	} 
 
	//clean up 
	Prog_Done ( ) ; 
 
	//exit 
	return ( msg.wParam ) ; 
} 
 
//initialization 
void Prog_Init ( )  
{ 
	//set up timer 
	SetTimer ( g_hWnd , 0 , 50 , NULL ) ; 
 
	//resize main window 
	RECT rcClient ; 
	SetRect ( &rcClient , 0 , 0 , SCREENWIDTH , SCREENHEIGHT ) ; 
	AdjustWindowRectEx ( &rcClient , WS_CAPTION | WS_BORDER | WS_SYSMENU | WS_VISIBLE , TRUE , 0 ) ; 
	OffsetRect ( &rcClient , -rcClient.left , -rcClient.top ) ; 
	SetWindowPos ( g_hWnd , NULL , 0 , 0 , rcClient.right , rcClient.bottom , SWP_NOMOVE | SWP_NOZORDER ) ; 
 
	//create the IDirect3D8 object 
	g_pd3d = Direct3DCreate8 ( D3D_SDK_VERSION ) ; 
 
	//error check 
	if ( g_pd3d ) 
	{ 
		//success 
		fprintf ( stdout , "IDirect3D8 object created successfully.\n" ) ; 
	} 
	else 
	{ 
		//failure 
		fprintf ( stdout , "IDirect3D8 object creation failed.\n" ) ; 
 
		//cannot proceed, so return 
		return ; 
	} 
 
	//grab the current display mode of the default adapter 
	D3DDISPLAYMODE mode ; 
	g_pd3d->GetAdapterDisplayMode ( D3DADAPTER_DEFAULT , & mode ) ; 
 
	//set up presentation parameters 
	D3DPRESENT_PARAMETERS parms; 
 
	//back buffer information 
	parms.BackBufferWidth = 0 ; //use client width 
	parms.BackBufferHeight = 0 ; //use client height 
	parms.BackBufferFormat = mode.Format ; //use format of current display mode 
	parms.BackBufferCount = 1 ; //make one back buffer 
 
	//multisampling  
	parms.MultiSampleType = D3DMULTISAMPLE_NONE ; 
 
	//swap effect 
	parms.SwapEffect = D3DSWAPEFFECT_COPY ; //we want to copy from back buffer to screen 
	parms.Windowed = TRUE ; //windowed mode 
 
	//destination window 
	parms.hDeviceWindow = g_hWnd ;  
 
	//depth buffer information 
	parms.EnableAutoDepthStencil = FALSE ; 
	parms.AutoDepthStencilFormat = D3DFMT_UNKNOWN ; 
 
	//flags 
	parms.Flags = 0 ; 
 
	//refresh rate and presentation interval 
	parms.FullScreen_RefreshRateInHz = 0 ; 
	parms.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT ; 
 
	//attempt to create a HAL device 
	HRESULT hr ; //store return values in this variable 
	hr = g_pd3d->CreateDevice ( D3DADAPTER_DEFAULT , D3DDEVTYPE_HAL , g_hWnd , D3DCREATE_SOFTWARE_VERTEXPROCESSING , &parms , &g_pd3ddev ) ; 
 
	//error check 
	if ( FAILED ( hr ) ) 
	{ 
		//could not create HAL device 
		fprintf ( stdout , "Could not create HAL device!\n" ) ; 
 
		//attempt to make REF device 
		hr = g_pd3d->CreateDevice ( D3DADAPTER_DEFAULT , D3DDEVTYPE_REF , g_hWnd , D3DCREATE_SOFTWARE_VERTEXPROCESSING , &parms , &g_pd3ddev ) ; 
 
		if ( FAILED ( hr ) ) 
		{ 
			//could not create REF device 
			fprintf ( stdout , "Could not create REF device!\n" ) ; 
 
			//post a quit message 
			PostQuitMessage ( 0 ) ; 
		} 
		else 
		{ 
			//successfully made REF device, store this value in a global 
			g_devtype = D3DDEVTYPE_REF ; 
 
			//report 
			fprintf ( stdout , "Successfully created REF device.\n" ) ; 
		} 
	} 
	else 
	{ 
		//successfully made a HAL device, store this value in a global 
		g_devtype = D3DDEVTYPE_HAL ; 
 
		//report 
		fprintf ( stdout , "Successfully created HAL device.\n" ) ; 
	} 
 
	//clear the map 
	ClearMap ( ) ; 
 
	srand ( GetTickCount ( ) ) ; 
 
	//set up map rectangles and randomize map 
	for ( int x = 0 ; x < CELLCOLUMNS ; x ++ ) 
	{ 
		for ( int y = 0 ; y < CELLROWS ; y ++ ) 
		{ 
			g_rccells [ x ] [ y ].x1 = x * CELLWIDTH ; 
			g_rccells [ x ] [ y ].y1 = y * CELLHEIGHT ; 
			g_rccells [ x ] [ y ].x2 = x * CELLWIDTH + CELLWIDTH ; 
			g_rccells [ x ] [ y ].y2 = y * CELLHEIGHT + CELLHEIGHT ; 
 
			if ( rand ( ) & 1 ) 
			{ 
				g_Alive [ x ] [ y ] = true ; 
			} 
		} 
	} 
 
	//draw the frame 
	RedrawFrame ( ) ; 
} 
 
//clean up 
void Prog_Done ( )  
{ 
	//safe release of device 
	if ( g_pd3ddev )  
	{ 
		//release 
		g_pd3ddev->Release ( ) ; 
 
		//set to null 
		g_pd3ddev = NULL ; 
 
		//report 
		fprintf ( stdout , "IDirect3DDevice8 object released.\n" ) ; 
	} 
 
	//safe release of IDirect3D8 object 
	if ( g_pd3d ) 
	{ 
		//release 
		g_pd3d->Release ( ) ; 
 
		//set to null 
		g_pd3d = NULL ; 
 
		//report action 
		fprintf ( stdout , "IDirect3D8 object released.\n" ) ; 
	} 
} 
 
//redraw frame 
void RedrawFrame ( )  
{ 
	D3DCOLOR col ; 
 
	//loop through cells 
	for ( int x = 0 ; x < CELLCOLUMNS ; x++ ) 
	{ 
		for ( int y = 0 ; y < CELLROWS ; y ++ ) 
		{ 
			//determine color of cell 
			if ( g_Alive [ x ] [ y ] ) 
			{ 
				//alive=white 
				col = D3DCOLOR_XRGB ( 255 , 255 , 255 ) ; 
			} 
			else 
			{ 
				//dead=black 
				col = D3DCOLOR_XRGB ( 0 , 0 , 0 ) ; 
			} 
 
			//clear the cell the appropriate color 
			g_pd3ddev->Clear ( 1 , &g_rccells [ x ] [ y ] , D3DCLEAR_TARGET , col , 0.0f , 0 ) ; 
		} 
	} 
 
	//present the frame 
	g_pd3ddev->Present ( NULL , NULL , NULL , NULL ) ; 
} 
 
//clear the map 
void ClearMap ( )  
{ 
	//clear out the alive map 
	for ( int x = 0 ; x < CELLCOLUMNS ; x++ ) 
	{ 
		for ( int y = 0 ; y < CELLROWS ; y ++ ) 
		{ 
			g_Alive [ x ] [ y ] = false ; 
		} 
	} 
} 
 
//update the map  
void UpdateMap ( )  
{ 
	//loop vars 
	int x , y , neighbors , nx , ny ; 
 
	//check for births and deaths 
	for ( x = 0 ; x < CELLCOLUMNS ; x++ ) 
	{ 
		for ( y = 0 ; y < CELLROWS ; y ++ ) 
		{ 
			//clear birth flag 
			g_Birth [ x ] [ y ] = false ; 
 
			//clear death flag 
			g_Death [ x ] [ y ] = false ; 
 
			//start counting neighbors 
			neighbors = 0 ; 
			for ( nx = x - 1 ; nx <= x + 1 ; nx ++ ) 
			{ 
				for ( ny = y - 1 ; ny <= y + 1 ; ny ++ ) 
				{ 
					//center square doesn't count as neighbor 
					if ( nx == x && ny == y ) continue ; 
 
					//bounds checking 
					if ( nx < 0 ) continue ; 
					if ( ny < 0 ) continue ; 
					if ( nx >= CELLCOLUMNS ) continue ; 
					if ( ny >= CELLROWS ) continue ; 
 
					//check for a neighbor 
					if ( g_Alive [ nx ] [ ny ] ) 
						neighbors ++ ; 
				} 
			} 
 
			//check state of cell 
			if ( g_Alive [ x ] [ y ] ) 
			{ 
				//currently alive 
				//check for death 
				if ( neighbors < 2 || neighbors > 3 )  
				{ 
					g_Death [ x ] [ y ] = true ; 
				} 
			} 
			else 
			{ 
				//currently dead 
				//check for birth 
				if ( neighbors == 3 )  
				{ 
					g_Birth [ x ] [ y ] = true ; 
				} 
			} 
		} 
	} 
 
	//apply births and deaths 
	for ( x = 0 ; x < CELLCOLUMNS ; x++ ) 
	{ 
		for ( y = 0 ; y < CELLROWS ; y ++ ) 
		{ 
			//check for birth 
			if ( g_Birth [ x ] [ y ] ) 
			{ 
				g_Alive [ x ] [ y ] = true ; 
			} 
 
			//check for death 
			if ( g_Death [ x ] [ y ] ) 
			{ 
				g_Alive [ x ] [ y ] = false ; 
			} 
		} 
	} 
}