Skip to main content
gamedev.net
🔒 Locked

Sluggish code

Started by Sabonis Jun 1, 2003 at 2:28 PM 2 replies 650+ views
Original Post
Sabonis
Sabonis
Here is the code im developing with the help of "Zen of direct 3d"
#define WIN32_LEAN_AND_MEAN

// The main windows include file

#include <windows.h>
#include <mmsystem.h>

#include <d3d8.h>
#include <d3dx8.h>

#include "Engine.h"

int GameInit();
int GameLoop();
int GameShutdown();
int Render();


CConsole Console;

int ConsoleParser( CCommand* pCommand );

HWND g_hWndMain;

// The window procedure to handle events

long CALLBACK WndProc( HWND hWnd, UINT uMessage, 
                                WPARAM wParam, LPARAM lParam )
{

	// Switch the windows message to figure out what it is

	switch( uMessage )
	{
		case WM_CREATE:	// The CreateWindow() function was just called

		{
			// One Time Initialization

			return 0;
		}

		case WM_PAINT:	// The window needs to be redrawn

		{
			ValidateRect( hWnd, NULL );

			return 0;
		}

		case WM_KEYDOWN:
		{
			Console.OnKeyDown( wParam );

			return 0;
		}

		case WM_CHAR:
		{
			Console.OnChar( wParam );

			return 0;
		}
		
		case WM_DESTROY:	// The window is about to be closed

		{
			// Our main window is closing.  This means we want our app to exit.

			// Tell windows to put a WM_QUIT message in our message queue

			PostQuitMessage( 0 );
			return 0;
		}

		default:			// Some other message

		{
			// Let windows handle this message

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

// The windows entry point. The application will start executing here

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
                                     PSTR pstrCmdLine, int iCmdShow )
{
	HWND hWnd;		// The handle to our main window

	MSG msg;		// The message windows is sending us

	WNDCLASSEX wc;	// The window class used to create our window


	// The name of our class and also the title to our window

	static char strAppName[] = "First Windows App, Zen Style";

	// Fill in the window class with the attributes for our main window


	// The size of this struture in bytes

	wc.cbSize			= sizeof( WNDCLASSEX );
	
	//  The style of the window.

	wc.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	// Useless information.  Just set to zero.

	wc.cbClsExtra		= 0;
	// Useless information.  Just set to zero.

	wc.cbWndExtra		= 0;
	// The name of our event handler

	wc.lpfnWndProc		= WndProc;
	// A handle to the applications instance

	wc.hInstance		= hInstance;
	// The handle to the brush to use for the window background

	wc.hbrBackground	= (HBRUSH)GetStockObject( DKGRAY_BRUSH );
	// A handle to the icon to use for the window

	wc.hIcon			= LoadIcon( NULL, IDI_APPLICATION );
	// A handle to a smaller version of the apps icon

	wc.hIconSm			= LoadIcon( NULL, IDI_APPLICATION );
	// A handle to the cursor to use while the mouse is over our window

	wc.hCursor			= LoadCursor( NULL, IDC_CROSS );
	// A handle to the resource to use as our menu

	wc.lpszMenuName		= NULL;
	// The human readable name for this class

	wc.lpszClassName	= strAppName;

	// Register the class with windows

	RegisterClassEx( &wc );

	// Create the window based on the previous class

	hWnd = CreateWindowEx( WS_EX_TOPMOST,	// Advanced style settings

	            strAppName,			// The name of the class

				strAppName,			// The window caption

				WS_OVERLAPPEDWINDOW,// The window style

			   	CW_USEDEFAULT,		// The initial x position 

                CW_USEDEFAULT,		// The initial y position

			   	512, 512,			// The intiial width / height

				NULL,				// Handle to parent window						

				NULL,				// Handle to the menu

				hInstance,			// Handle to the apps instance

				NULL );				// Advanced context


	g_hWndMain = hWnd;

	// Display the window we just created

	ShowWindow( hWnd, iCmdShow );
	// Draw the window contents for the first time

	UpdateWindow( hWnd );

	if( FAILED( GameInit() ) )
	{
		SetError( "Initialization Failed" );
		GameShutdown();
		return E_FAIL;
	}

	// Start the message loop

	while( TRUE )
	{
		// Check if a message is waiting for processing

		if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
		{
			// Check if the message is to quit the application

			if( msg.message == WM_QUIT )
				// Exit the message loop

				break;
			
			// Change the format of certain messages

			TranslateMessage( &msg );
			// Pass the message to WndProc() for processing

			DispatchMessage( &msg );
		}
		else
		{
			GameLoop();
		}
	}
	
	GameShutdown();

	// Return control to windows with the exit code

	return msg.wParam;
}

LPDIRECT3DSURFACE8 pTransSurf = 0;
LPDIRECT3DSURFACE8 pTransSurf1 = 0;
LPDIRECT3DSURFACE8 pSpaceSurf = 0;

int GameInit()
{
	
	HRESULT r = 0;
	
	// Acquire a pointer to IDirect3D8

	g_pD3D = Direct3DCreate8( D3D_SDK_VERSION );
	if( g_pD3D == NULL )
	{
		SetError( "Could not create IDirect3D8 object" );
		return E_FAIL;
	}

	// Create the device

	r = InitDirect3DDevice( g_hWndMain, 640, 480, FALSE, D3DFMT_X8R8G8B8, g_pD3D, &g_pDevice );
	if( FAILED( r ) )
	{
		SetError( "Initialization of the device failed" );
		return E_FAIL;
	}

	// Clear the back buffer

	g_pDevice->Clear( 0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0, 0, 55 ), 1.0f, 0 );


	// Get a pointer to the back buffer and save it in a global variable

	r = g_pDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &g_pBackSurface );
	if( FAILED( r ) )
	{
		SetError( "Couldnt get backbuffer" );
		return E_FAIL;
	}	

	LoadAlphabet( "Alphabet vSmall.bmp", 8, 16 );

	srand( GetTickCount() );
	
	InitTiming();

	// Initialize the console

	Console.Initialize( g_pDevice, g_pBackSurface );
	Console.OutputString( "The Zen Console" );
	Console.SetParserCallback( ConsoleParser );

	// Load up the bitmaps

	LoadBitmapToSurface( "Fighter1.bmp", &pTransSurf1, g_pDevice );
	LoadBitmapToSurface( "Fighter.bmp", &pTransSurf, g_pDevice );
	LoadBitmapToSurface( "Space.bmp", &pSpaceSurf, g_pDevice );
			
	return S_OK;
}

int GameLoop()
{
	FrameCount();
	
	Render();

	if( GetAsyncKeyState( VK_ESCAPE ) )
		PostQuitMessage(0);
	
	return S_OK;
}

int GameShutdown()
{
	Console.Shutdown();

	// Release the surfaces

	pTransSurf->Release();
	pTransSurf1->Release();
	pSpaceSurf->Release();

	UnloadAlphabet();

	// Release the pointer to the back surface

	if( g_pBackSurface )
		g_pBackSurface->Release();
	
	// Release the pointer to IDirect3DDevice8

	if( g_pDevice )
		g_pDevice->Release();
	
	// Release the pointer to IDirect3D8

	if( g_pD3D )
		g_pD3D->Release();

	return S_OK;
}



int Render()
{
	HRESULT r = 0;

	g_pDevice->Clear( 0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0, 0, 25 ), 1.0f, 0 );
	
	// Make sure the device is valid

	if( !g_pDevice )
	{
		SetError( "Cannot render because there is no device" );
		return E_FAIL;
	}

	// Return if the device is not ready;

	r = ValidateDevice();
	if( FAILED( r ) )
	{
		return E_FAIL;
	}


	// Copy the background surface to the back buffer

	D3DLOCKED_RECT Locked;
	CopySurfaceToSurface( 0, pSpaceSurf, 0, g_pBackSurface, 0, D3DCOLOR_ARGB( 0, 255, 0, 255 ) );
	
	// Lock the back surface

	g_pBackSurface->LockRect( &Locked, 0, 0 );

	// Set random pixels

	for( int i = 0 ; i < 200 ; i++ )
	{
		int r = rand()%255;
		
		SetPixel32( rand()%639, rand()%479, D3DCOLOR_XRGB( r, r, r ), Locked.Pitch, (DWORD*)Locked.pBits );
	}

	PrintFrameRate( 600, 400, (DWORD*)Locked.pBits, Locked.Pitch );

	PrintString( 0, 400, "Press F11 for the console", 
		TRUE, D3DCOLOR_ARGB( 0, 255, 0, 255), (DWORD*)Locked.pBits, Locked.Pitch );
	
	g_pBackSurface->UnlockRect();

	D3DSURFACE_DESC d3dsd;
	
	pTransSurf->GetDesc( &d3dsd );
	
	static UINT x = 0;
	static UINT y = 0;

	static BOOL bForwardX = TRUE; 
	static BOOL bForwardY = TRUE;

	// Bounce the spaceship around the screen

	if( x > 639 - d3dsd.Width )
	{
		bForwardX = FALSE;
	}

	if( y > 479 - d3dsd.Height )
	{
		bForwardY = FALSE;
	}

	if( x < 1 )
	{
		bForwardX = TRUE;

	}

	if( y < 1 )
	{
		bForwardY = TRUE;
	}

	if( bForwardX )
		x++;
	else
		x--;
	
	if( bForwardY )
		y++;
	else
		y--;
	
	POINT point = { x, y };

	// Copy the spaceship surface around

	if( bForwardX )
	CopySurfaceToSurface( 0, pTransSurf1, &point, g_pBackSurface, TRUE, D3DCOLOR_ARGB( 0, 255, 0, 255 ) );
	else
	CopySurfaceToSurface( 0, pTransSurf, &point, g_pBackSurface, TRUE, D3DCOLOR_ARGB( 0, 255, 0, 255 ) );

	Console.Render();

	
	
	r = g_pDevice->Present( NULL, NULL, NULL, NULL );

	return S_OK;
}

int ConsoleParser( CCommand* pCommand )
{
	char* pstrCmd = pCommand->pstrCommand;
	char* pstrParams[MAX_PARAMS];
	memcpy( &pstrParams, &(pCommand->pstrParams), sizeof( pstrParams ) );
	int NumParams = pCommand->NumParams;
	
	if( MATCH( pstrCmd, "exit" ) || MATCH( pstrCmd, "quit" ) )
	{
		PostQuitMessage(0);
		return 0;
	}
	if( MATCH( pstrCmd, "cls" ) )
	{
		Console.Clear();
		return 0;
	}

	return -1;
}





HRESULT RestoreGraphics();

LPDIRECT3DSURFACE8 g_pBackSurface = 0;

int g_DeviceWidth = 0;
int g_DeviceHeight = 0;

const int MAX_CHARSPERLINE = 256;

#define MATCH(a, b) (!strcmp( a, b ))

D3DPRESENT_PARAMETERS g_SavedPresParams;

/**************************************************************
***************************************************************

				Generic Code

***************************************************************
**************************************************************/

// Output an error to the debug window

void SetError( char* String )
{
	OutputDebugString( "ERROR: " );
	OutputDebugString( String );
	OutputDebugString( "\n" );
}

/**************************************************************
***************************************************************

				Direct3D Initialization Code

***************************************************************
**************************************************************/

// Initializes the Direct3D device

int InitDirect3DDevice( HWND hWndTarget, int Width, int Height, BOOL bWindowed, 
							D3DFORMAT FullScreenFormat, LPDIRECT3D8 pD3D, 
							LPDIRECT3DDEVICE8* ppDevice )
{
	// Structure to hold information about the rendering method

	D3DPRESENT_PARAMETERS d3dpp;
	// Structure to hold information about the current display mode

	D3DDISPLAYMODE d3ddm;

	HRESULT r = 0;
	
	if( *ppDevice )
		(*ppDevice)->Release();

	// Initialize the structure to 0

	ZeroMemory( &d3dpp, sizeof( D3DPRESENT_PARAMETERS ) );

	// Get the settings for the current display mode

	r = pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm );
	if( FAILED( r ) )
	{
		SetError( "Could not get display adapter information" );
		return E_FAIL;
	}
	
	// The width of the back buffer in pixels

	d3dpp.BackBufferWidth = Width;
	// The height of the buffer in pixels

	d3dpp.BackBufferHeight = Height;
	// The format of the back buffer

	d3dpp.BackBufferFormat = bWindowed ? d3ddm.Format : FullScreenFormat;

	// The number of back buffers

	d3dpp.BackBufferCount = 1;

	// The type of multisampling

	d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
	// The swap effect

	d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
	
	// The handle to the window that we want to render to 

	d3dpp.hDeviceWindow = hWndTarget;	
	// Windowed or fullscreen

	d3dpp.Windowed = bWindowed;

	// Let Direct3D manage the depth buffer

	d3dpp.EnableAutoDepthStencil = TRUE;
	// Set the depth buffer format to 16 bits

	d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
	
	// Use the default refresh rate available

	d3dpp.FullScreen_RefreshRateInHz = 0;
	
	// Present the information as fast as possible

	d3dpp.FullScreen_PresentationInterval = bWindowed ? 0 : D3DPRESENT_INTERVAL_IMMEDIATE;
	// Allow the back buffer to be accessed for 2D work

	d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;

	// Acquire a pointer to IDirect3DDevice8

	r = pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWndTarget,
							D3DCREATE_SOFTWARE_VERTEXPROCESSING, 
							&d3dpp, ppDevice );
	if( FAILED( r ) )
	{
		SetError( "Could not create the render device" );
		return E_FAIL;
	}

	// Save global copies of the device dimensions

	g_DeviceHeight = Height;
	g_DeviceWidth = Width;

	// Save a copy of the pres params for use in device validation later

	g_SavedPresParams = d3dpp;

	return S_OK;
}

/**************************************************************
***************************************************************

						2D Graphics Code

***************************************************************
**************************************************************/

// Set a pixel to specified color

void SetPixel32( int x, int y, DWORD Color, int Pitch, DWORD* pData )
{
	// Make sure the pixel is within screen boundaries

	if( x > g_DeviceWidth || x < 0 )
		return;

	if( y > g_DeviceHeight || y < 0 )
		return;
		
	// Set the pixel

	pData[ ((Pitch/4) * y) + x ] = Color;
}

// Draw a rectangle

void Rectangle32( D3DRECT* pRect, DWORD Color, int Pitch, DWORD* pData )
{
	// Use local variables to avoid dereferencing inside the loop

	int y1 = pRect->y1;
	int y2 = pRect->y2;
	int x1 = pRect->x1;
	int x2 = pRect->x2;

	// Convert the pitch from bytes to DWORDS

	int Pitch32 = Pitch / 4;
	
	// Get the offset into the target

	DWORD Offset = y1 * Pitch32 + x1;

	// Loop for each row of the rectangle

	for( int y = y1 ; y < y2 ; y++ )
	{
		// Loop for each column in the image

		for( int x = x1 ; x < x2 ; x++ )
		{
			// Set the pixel to the correct color

			pData[ Offset + x ] = Color;			
		}

		// Increment the offset to the next row of the rectangle

		Offset += Pitch32;
	}
}

// This uses hardware accelaration to draw a rectangle.  It only works for

// the back buffer

void Rectangle32Fast( D3DRECT* pRect, DWORD Color, LPDIRECT3DDEVICE8 pDevice )
{
	pDevice->Clear( 1, pRect, D3DCLEAR_TARGET, Color, 0.0f, 0 );
}

// Loads a bitmap to a surface

int LoadBitmapToSurface( char* PathName, LPDIRECT3DSURFACE8* ppSurface, LPDIRECT3DDEVICE8 pDevice )
{
	HRESULT r;
	HBITMAP hBitmap;
	BITMAP Bitmap;
	
	// Load the bitmap first using the GDI to get info about it

	hBitmap = (HBITMAP)LoadImage( NULL, PathName, IMAGE_BITMAP, 0, 0, 
									LR_LOADFROMFILE | LR_CREATEDIBSECTION );
	if( hBitmap == NULL )
	{
		// The file probably does not exist

		SetError( "Unable to load bitmap" );
		return E_FAIL;
	}

	// Get information about the object

	GetObject( hBitmap, sizeof( BITMAP ), &Bitmap );
	// Unload the bitmap from memory

	DeleteObject( hBitmap );

	// Now create a surface using the information gained from

	// the previous load

	r = pDevice->CreateImageSurface( Bitmap.bmWidth, 
								Bitmap.bmHeight, D3DFMT_X8R8G8B8, ppSurface );
	if( FAILED( r ) )
	{
		SetError( "Unable to create surface for bitmap load" );
		return E_FAIL;
	}

	// Load the image again, this time using Direct3D to load

	// it directly to the new surface

	r = D3DXLoadSurfaceFromFile( *ppSurface, NULL, NULL, PathName, 
									NULL, D3DX_FILTER_NONE, 0, NULL );
	if( FAILED( r ) )
	{
		SetError( "Unable to load file to surface" );
		return E_FAIL;
	}

	return S_OK;
}

/*-----------------------------------------------------------------------
CopySurfaceToSurface()
Parameters:
1) Pointer to a RECT that defines the dimensions for the source rectangle. If
	set to NULL then the entire source surface is used.
2) Pointer to the source surface.  Must be valid
3) Pointer to a POINT that defines where the origin on the destination should
	be for the source image.  If NULL then copying will start at (0, 0)
	on the destination.
4) Pointer to the destination surface.  Must be valid
5) Flag indicating if transparency is wanted
6) The colorkey to use if transparency is enabled.

Notes:
Call this function to copy one surface to another with transparency if
required.  Make sure that both surfaces are valid and NOT locked before
you pass them to this function, otherwise it will fail.
-----------------------------------------------------------------------*/

HRESULT CopySurfaceToSurface( RECT* pSourceRect, LPDIRECT3DSURFACE8 pSourceSurf, POINT* pDestPoint, 
								LPDIRECT3DSURFACE8 pDestSurf, BOOL bTransparent, D3DCOLOR ColorKey )
{
	// Holds error return values

	HRESULT r = 0;	
	
	// Holds information about the surfaces when they are locked

	D3DLOCKED_RECT LockedSource;
	D3DLOCKED_RECT LockedDest;

	// Make sure the source surface is valid

	if( !pSourceSurf )
		return E_FAIL;

	// Make sure the destination surface is valid

	if( !pDestSurf )
		return E_FAIL;

	// The source rectangle

	RECT SourceRect;
	// The destination point

	POINT DestPoint;

	// Holds information about the source surface

	D3DSURFACE_DESC d3dsdSource;
	// Get information about the source surface

	pSourceSurf->GetDesc( &d3dsdSource );

	// Holds information about the destination surface

	D3DSURFACE_DESC d3dsdDest;
	// Get information about the destination surface

	pDestSurf->GetDesc( &d3dsdDest );

	// If a source rectangle was specified then copy it

	// into the local RECT structure

	if( pSourceRect )
		SourceRect = *pSourceRect;
	else
		// Otherwise set the rectangle to encompas the entire source surface

		SetRect( &SourceRect, 0, 0, d3dsdSource.Width, d3dsdSource.Height );
	
	// If a destination point was specified then copy it

	// to the local POINT structure

	if( pDestPoint )
		DestPoint = *pDestPoint;
	else
	{
		// Otherwise set the point to (0,0)

		DestPoint.x = DestPoint.y = 0;
	}

	// Lock the source surface.

	r = pSourceSurf->LockRect( &LockedSource, 0, D3DLOCK_READONLY  );
	if( FAILED( r ) )
		// Fatal Error

		return E_FAIL;

	// Lock the destination surface

	r = pDestSurf->LockRect( &LockedDest, 0, 0 );
	if( FAILED( r ) )
	{
		// Fatal error, so unlock the source

		// surface before exiting

		pSourceSurf->UnlockRect();
		return E_FAIL;
	}

	// Modify the pitch to be DWORD compatible

	LockedSource.Pitch /= 4;
	LockedDest.Pitch /= 4;

	// Get 32bit pointers to the surface data

	DWORD* pSourceData = (DWORD*)LockedSource.pBits;
	DWORD* pDestData = (DWORD*)LockedDest.pBits;

	// Get the offset into the source surface

	int SourceOffset = SourceRect.top * LockedSource.Pitch + SourceRect.left;
	// Get the offset into the destination surface

	int DestOffset = DestPoint.y * LockedDest.Pitch + DestPoint.x;

	// Loop for each row of the source image

	for( int y = 0 ; y < SourceRect.bottom ; y++ )
	{
		// Loop for each column of the source image

		for( int x = 0 ; x < SourceRect.right ; x++ )
		{
			// If transparency was requested

			if( bTransparent )
			{
				// Then check to see if the current source pixel

				// matches the color key.  If it does then do

				// not copy it.

				if( pSourceData[ SourceOffset ] != ColorKey )
				{
					// The current pixel does not match the color

					// key so it is ok to copy it to the destination

					pDestData[ DestOffset ] = pSourceData[ SourceOffset ];
				}
			}
			else // Transparency was not requested

			{
				// Copy the source pixel to the destination

				// without any comparison

				pDestData[ DestOffset ] = pSourceData[ SourceOffset ];
			}

			// Increment to the next pixel in the destination

			DestOffset++;
			// Increment to the next pixel in the source

			SourceOffset++;
		}
		
		// Move the source offset to the next row of the image

		// by adding the pitch minus the width of the source image 

		SourceOffset += LockedSource.Pitch - SourceRect.right;
		// Move the destination offset to the next row of the image

		DestOffset += LockedDest.Pitch - SourceRect.right;
	}

	// Copying is complete so unlock the surfaces

	pSourceSurf->UnlockRect();
	pDestSurf->UnlockRect();
	
	// Return success

	return S_OK;
}

/**************************************************************
***************************************************************

						DC to Surface Code

***************************************************************
**************************************************************/

// Creates a GDI DC that can be copied to a surface later

HDC CreateD3DCompatibleDC( int Width, int Height, HBITMAP* phDibSection )
{
	// Create a new DC that is compatible with the current display mode

	HDC hDC = CreateCompatibleDC(0);

	// Temp pointer to the DIB data

	void* pDibSection = 0;

	// Structure to hold information about the bitmap

	BITMAPINFO bi;
	ZeroMemory( &bi, sizeof( BITMAPINFO ) );

	// The size of this structure in bytes

	bi.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
	// The width of the new bitmap

	bi.bmiHeader.biWidth = Width;
	// The height of the new bitmap( negative for a top down image )

	bi.bmiHeader.biHeight = -Height;
	// Obselete - just set to one

	bi.bmiHeader.biPlanes = 1;
	// The bit depth of the surface

	bi.bmiHeader.biBitCount = 32;
	// The compression format.  BI_RGB indicates none

	bi.bmiHeader.biCompression = BI_RGB;
	
	// Create a new DIB

	HBITMAP hDibSection = CreateDIBSection( hDC, &bi, DIB_RGB_COLORS, &pDibSection, NULL, NULL );

	// Select the bitmap into the new DC

	SelectObject( hDC, hDibSection );

	// Update the pointer to the handle to the bitmap

	*phDibSection = hDibSection;

	// Return the handle to the device context

	return hDC;
}

// Copies a GDI DC to Direct3D surface

HRESULT CopyDCToSurface( LPDIRECT3DSURFACE8 pDestSurf, POINT* pDestPoint, 
					HDC hDCSource, HBITMAP hDibSection, RECT* pSrcRect, COLORREF ColorKey )
{
	HRESULT r = 0;
	
	// The source rectangle

	RECT SourceRect;
	// The destination origin point

	POINT DestPoint;

	// Holds information about the bitmap

	DIBSECTION DibSection;

	// Holds information about the surface when locked

	D3DLOCKED_RECT LockedRect;

	// Get information about the bitmap in the DC

	GetObject( hDibSection, sizeof( DIBSECTION ), &DibSection );

	int SrcTotalWidth = DibSection.dsBm.bmWidth;
	int SrcTotalHeight = DibSection.dsBm.bmHeight;

	// If no source rectangle was specified then this indicates

	// that the entire bitmap in the DC is to be copied

	if( !pSrcRect )
		SetRect( &SourceRect, 0, 0, SrcTotalWidth, SrcTotalWidth);
	else
		SourceRect = *(pSrcRect);

	// If no destination point was specified then the origin

	// is set to (0,0)

	if( !pDestPoint )
		DestPoint.x = DestPoint.y = 0;
	else
		DestPoint = *(pDestPoint);

	// Return failure if a valid destination surface was not specified

	if( !pDestSurf )
		return E_FAIL;

	// Return failure if a valid source DC was not specified

	if( !hDCSource )
		return E_FAIL;

	// Lock the source surface

	r = pDestSurf->LockRect( &LockedRect, 0, 0  );
	if( FAILED( r ) )
	{
		SetError( "Unable to lock the surface for GDI transfer" );
		return E_FAIL;
	}

	D3DSURFACE_DESC d3dsd;
	pDestSurf->GetDesc( &d3dsd );

	if( (UINT)(SourceRect.bottom + DestPoint.y) > (UINT)d3dsd.Height )
		SourceRect.bottom = d3dsd.Height;

	if( (UINT)(SourceRect.right + DestPoint.x) > (UINT)d3dsd.Width )
		SourceRect.right = d3dsd.Width;

	// Convert the source and destination data pointers

	// to DWORD( 32 bit) values

	DWORD* pSrcData = (DWORD*)(DibSection.dsBm.bmBits);
	DWORD* pDestData = (DWORD*)(LockedRect.pBits);

	// Convert the pitch to a 32 bit value

	int Pitch32 = LockedRect.Pitch/4;

	// Compute the dimensions for the copy

	int SrcHeight = SourceRect.bottom - SourceRect.top;
	int SrcWidth = SourceRect.right - SourceRect.left;

	// Compute the index into memory

	DWORD SrcOffset = SourceRect.top * SrcTotalWidth + SourceRect.left;
	DWORD DestOffset = DestPoint.y * Pitch32 + DestPoint.x;

	// If not using a color key then a faster copy can be done

	if( ColorKey == -1 )
	{
		// Loop for each row in the image

		for( int y = 0 ; y < SrcHeight ; y++ )
		{
			// Copy this line of the image

			memcpy( (void*)&(pDestData[ DestOffset ]), (void*)&(pSrcData[ SrcOffset ]), SrcWidth*4);

			// Increase the destation pointer by the pitch

			DestOffset+=Pitch32;
			// Increase the source pointer by the total width

			SrcOffset +=SrcTotalWidth;
		}
	}
	else	// a color key was specified

	{
		// Loop for each row in the image

		for( int y = 0 ; y < SrcHeight ; y++ )
		{
			// Loop for each column

			for( int x = 0 ; x < SrcWidth ; x++ )
			{
						
				// If the source pixel is not the same as the color key

				if( pSrcData[ SrcOffset ] != ColorKey )
					// Then copy the pixel to the destination

					pDestData[ DestOffset ] = pSrcData[ SrcOffset ];

				// Move to the next pixel in the source

				SrcOffset++;
				// Move to the next pixel in the destination

				DestOffset++;
			}
			
			DestOffset += Pitch32 - SrcWidth;
		}
	}

	// Unlock the surface

	pDestSurf->UnlockRect();

	// Return success

	return S_OK;
}

// Deletes a GDI DC that was created with CreateD3DCompatibleDC()

void DeleteD3DCompatibleDC( HDC hDC, HBITMAP hDibSection )
{
	// Delete the bitmap

	DeleteObject( hDibSection );
	// Delete the DC

	DeleteDC( hDC );
}

/**************************************************************
***************************************************************

						Device Validation Code

***************************************************************
**************************************************************/

LPDIRECT3D8 g_pD3D = 0;
LPDIRECT3DDEVICE8 g_pDevice = 0;

// Call every frame to check if the device is valid.  If it

// is not then the it is reaquired if possible

HRESULT ValidateDevice()
{
	HRESULT r = 0;
	
	// Test the current state of the device

	r = g_pDevice->TestCooperativeLevel();
	if( FAILED( r ) )
	{
		// If the device is lost then return failure

		if( r == D3DERR_DEVICELOST )
			return E_FAIL;

		// If the device is ready to be reset then attempt to do so

		if( r == D3DERR_DEVICENOTRESET )
		{
			// Release the back surface so it can be recreated

			g_pBackSurface->Release();

			// Reset the device

			r = g_pDevice->Reset( &g_SavedPresParams );
			if( FAILED( r ) )
			{
				// If the device was not reset then exit

				SetError( "Could not reset device" );
				PostQuitMessage( E_FAIL );
				return E_FAIL;
			}
			
			// Reaquire a pointer to the new back buffer

			r = g_pDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &g_pBackSurface );
			if( FAILED( r ) )
			{
				SetError( "Unable to reaquire the back buffer" );
				PostQuitMessage( 0 );
				return E_FAIL;
			}
			g_pDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0, 0, 0 ), 0.0f, 0 );

			RestoreGraphics();
		}
	}

	return S_OK;
}

// Use this function to reinit any surfaces that were lost

// when the device was lost.

HRESULT RestoreGraphics()
{
	
	return S_OK;
}

/**************************************************************
***************************************************************

						Font Engine Code

***************************************************************
**************************************************************/


int g_AlphabetWidth = 0;			// The width of the Alphabet bitmap

int g_AlphabetHeight = 0;			// The height of the Alphabet bitmap

int g_AlphabetLetterWidth = 0;		// The width of a letter

int g_AlphabetLetterHeight = 0;		// The height of a letter

int g_AlphabetLettersPerRow = 0;	// The number of letters per row


// The surface holding the alphabet bitmap

LPDIRECT3DSURFACE8 g_pAlphabetSurface = 0;

// Has the alphabet bitmap been loaded yet?

BOOL g_bAlphabetLoaded = FALSE;

// Used to load an alphabet bitmap into memory

HRESULT LoadAlphabet( char* strPathName, int LetterWidth, int LetterHeight )
{
	// Make sure a valid path was specified

	if( !strPathName )
		return E_FAIL;

	// Make sure the size of the letters is greater than 0

	if( !LetterWidth || !LetterHeight )
		return E_FAIL;

	HRESULT r = 0;
	
	// Load the bitmap into memory

	r = LoadBitmapToSurface( strPathName, &g_pAlphabetSurface, g_pDevice );
	if( FAILED( r ) )
	{
		SetError( "Unable to load alphabet bitmap" );
		return E_FAIL;
	}

	// Holds information about the alpahbet surface

	D3DSURFACE_DESC d3dsd;

	// Get information about the alphabet surface

	g_pAlphabetSurface->GetDesc( &d3dsd );

	// Update globals with the letter dimensions

	g_AlphabetWidth = d3dsd.Width;			
	g_AlphabetHeight = d3dsd.Height;
	g_AlphabetLetterWidth = LetterWidth;
	g_AlphabetLetterHeight = LetterHeight;

	// Compute the number of letters in a row

	g_AlphabetLettersPerRow = g_AlphabetWidth / g_AlphabetLetterWidth;

	// Set the loaded flag to TRUE

	g_bAlphabetLoaded = TRUE;

	return S_OK;
}

// Unloads the alphabet from memory

HRESULT UnloadAlphabet()
{
	// Check if the alphabet exists

	if( g_pAlphabetSurface )
	{
		// Release the surface

		g_pAlphabetSurface->Release();
		// NULL the pointer

		g_pAlphabetSurface = 0;
		// Set the loaded flag to FALSE

		g_bAlphabetLoaded = FALSE;
	}

	return S_OK;
}

// Print a character to a surface using the loaded alphabet

void PrintChar( int x, int y, char Character, BOOL bTransparent, 
						D3DCOLOR ColorKey, DWORD* pDestData, int DestPitch )
{
	HRESULT r = 0;
	
	div_t Result;	// Holds the result of divisions


	// The offset into the alphabet image

	int OffsetX = 0, OffsetY = 0;

	POINT LetterDestPoint = { 0, 0 };	// The destination point for the letter

	RECT LetterRect = { 0, 0, 0, 0 };	// The source rectangle for the letter


	// If the alphabet has not been loaded yet then exit

	if( !g_bAlphabetLoaded )
		return;

	// The characters are specified in ASCII code, which begins at 32 so

	// we want to decrement this value by 32 to make it zero based

	Character -= 32;

	// Avoid divide by 0 errors

	if( Character == 0 )
		return;

	// Divide the character code by the number of letters per row.

	// The quotient will help get the vertical offset and the

	// remainder will help get the horizontal offset

	Result = div( Character, g_AlphabetLettersPerRow );

	// Get the horizontal offset by multiplying the remainder

	// by the width of the Letter

	OffsetX = Result.rem * g_AlphabetLetterWidth;
	// Get the vertical offset by multiplying the quotient

	// by the height of the letter

	OffsetY = Result.quot * g_AlphabetLetterHeight;

	// Fill in the source rectangle with the computed offsets

	SetRect( &LetterRect, OffsetX, OffsetY, 
	OffsetX + g_AlphabetLetterWidth, OffsetY + g_AlphabetLetterHeight );
	
	// Fill in the destination point

	LetterDestPoint.x = x;
	LetterDestPoint.y = y;
	
	D3DLOCKED_RECT LockedAlphabet;	// Holds info about the alphabet surface


	// Lock the source surface

	r = g_pAlphabetSurface->LockRect( &LockedAlphabet, 0, D3DLOCK_READONLY  );
	if( FAILED( r ) )
	{
		SetError( "Couldnt lock alphabet surface for PrintChar()" );
		return;
	}
	
	// Get a DWORD pointer to each surface

	DWORD* pAlphaData = (DWORD*)LockedAlphabet.pBits;

	// Convert the BYTE pitch pointer to a DWORD ptr

	LockedAlphabet.Pitch /=4;
	DestPitch /= 4;

	// Compute the offset into the alphabet

	int AlphaOffset = OffsetY * LockedAlphabet.Pitch + OffsetX;
	// Compute the offset into the destination surface

	int DestOffset = y * DestPitch + x;

	// Loop for each row in the letter

	for( int cy = 0 ; cy < g_AlphabetLetterHeight ; cy++ )
	{
		// Loop for each column in the letter

		for( int cx = 0 ; cx < g_AlphabetLetterWidth ; cx++ )
		{
			if( bTransparent )
			{
				// If this alphabet pixel is not transparent

				if( pAlphaData[ AlphaOffset ] != ColorKey )
				{
					// Then copy the pixel to the destination

					pDestData[ DestOffset ] = pAlphaData[ AlphaOffset ];
				}

				// Increment the offsets to the next pixel

				AlphaOffset++;
				DestOffset++;
			}
			else
				pDestData[ DestOffset ] = pAlphaData[ AlphaOffset ];
		}

		// Move the offsets to the start of the next row

		DestOffset += DestPitch - g_AlphabetLetterWidth;
		AlphaOffset += LockedAlphabet.Pitch - g_AlphabetLetterWidth;
	}
	
	// Unlock the surface

	g_pAlphabetSurface->UnlockRect();
	
}



void PrintString( int x, int y, char* String, BOOL bTransparent, 
					D3DCOLOR ColorKey, DWORD* pDestData, int DestPitch )
{
	// Loop for each character in the string

	for( UINT i = 0 ; i < strlen( String ) ; i++ )
	{
		// Print the current character

		PrintChar( x + (g_AlphabetLetterWidth * i), y, String[i], 
							bTransparent, ColorKey, pDestData, DestPitch );
	}	
}

/**************************************************************
***************************************************************

						Timing Code

***************************************************************
**************************************************************/

// The number of high performance ticks per second

INT64 g_Frequency = 0;
// The number of elapsed frames this counting period

int g_FrameCount = 0;
// The number of elapsed frames this second

int g_FrameRate = 0;

HRESULT InitTiming()
{
	// Get the number of counts per second

	QueryPerformanceFrequency( (LARGE_INTEGER*)&g_Frequency );

	// If the frequency is 0 then this system does not have

	// high performance timers

	if( g_Frequency == 0 )
	{
		SetError( "The system does not support high resolution timing" );
		return E_FAIL;
	}

	return S_OK;
}

void FrameCount()
{
	INT64 NewCount = 0;			// The current count

	static INT64 LastCount = 0;	// The last count

	INT64 Difference = 0;		// The differnce since the last count


	// Get the current count

	QueryPerformanceCounter( (LARGE_INTEGER*)&NewCount );
	
	// If the count is 0 then this system does not have

	// high performance timers

	if( NewCount == 0 )
		SetError( "The system does not support high resolution timing" );

	// Increase the frame count

	g_FrameCount++;
	
	// Compute the difference since the last count

	Difference = NewCount - LastCount;
	
	// If more than a second has passed

	if( Difference >= g_Frequency )
	{
		// Record the number of elapsed frames

		g_FrameRate = g_FrameCount;
		// Reset the counter 

		g_FrameCount = 0;

		// Update the last count

		LastCount = NewCount;
	}

}

// Prints the frame rate to the screen

void PrintFrameRate( int x, int y, DWORD* pDestData, int DestPitch )
{
	char string[4];	// String to hold the frame rate

	
	// Zero out the string

	ZeroMemory( &string, sizeof( string ) );

	// Convert the frame rate to a string

	itoa( g_FrameRate, string, 10 );

	// Output the string to the back surface

	PrintString( x, y, string, TRUE, D3DCOLOR_ARGB( 0, 255, 0, 255 ), pDestData, DestPitch );
}

/**************************************************************
***************************************************************

						Console Code

***************************************************************
**************************************************************/

// ------------------------- CEntry Class

// Used to represent a row of text


class CEntry
{
public:
	CEntry();	// The constructor

	~CEntry();  // The destructor

	
// Variables:

protected:
	char* m_pstrText;	// The text buffer for this entry

	CEntry* m_pNext;	// Pointer to next entry( row )


	int m_VerticalPos;	// The y position to render


// Functions:

public:
	// Returns the next entry(row)

	CEntry* GetNext(){ return m_pNext; }
	// Sets the next entry(row)

	void SetNext( CEntry* pNext ){ m_pNext = pNext; }
	// Draws the text using the GDI to the console surface

	int RenderText( int NumHorzChars, DWORD* pData, int DestPitch );
	// Adds a character to the text buffer

	int OnChar( char Key );
	// Returns the text in the buffer

	int GetText( char* pstrText, int Length );
	// Clears and then sets the text in the buffer

	int SetText( char* pstrText );
	// Returns the number of characters in the buffer

	int GetTextLength(){ return strlen( m_pstrText ); }
	// Sets the vertical position of this entry

	void SetVerticalPos( int Pos ){ m_VerticalPos = Pos; }
	// Returns the vertical position for this entry

	int  GetVerticalPos(){ return m_VerticalPos; }
};

// Constructor

CEntry::CEntry()
{
	// Allocate memory for the buffer

	m_pstrText = new char[MAX_CHARSPERLINE];
	if( m_pstrText )
		ZeroMemory( m_pstrText, sizeof( char[MAX_CHARSPERLINE] ) );
	else
		m_pstrText = 0;
	
	// Zero out member variables

	m_pNext = 0;
	m_VerticalPos = 0;
}
// Destructor

CEntry::~CEntry()
{
	// Delete the text buffer if it exists

	if( m_pstrText )
	{
		delete m_pstrText;
		m_pstrText = 0;
	}
}
// This function copies the text in the buffer

// to the supplied string variable

int CEntry::GetText( char* pstrText, int Length )
{
	// Make sure the length doesnt overrun our buffer

	if( Length > MAX_CHARSPERLINE )
		Length = MAX_CHARSPERLINE;
	
	// Copy the string

	CopyMemory( pstrText, m_pstrText, Length );
	
	return 0;
}
// This function sets the text in the buffer

int CEntry::SetText( char* pstrText )
{
	// Clear out any text that is already there

	ZeroMemory( m_pstrText, sizeof( char[MAX_CHARSPERLINE] ) );
	
	// Make sure the supplied text doesnt overrun our buffer

	int Length = strlen( pstrText );
	if( Length > MAX_CHARSPERLINE )
		Length = MAX_CHARSPERLINE;

	// Copy the supplied text into our buffer

	CopyMemory( m_pstrText, pstrText, strlen( pstrText ) );

	return 0;
}

// This function draws the text to the console surface

// using the GDI

int CEntry::RenderText( int NumHorzChars, DWORD* pData, int DestPitch )
{
	// Only draw the number of characters that fit on the screen

	int Length = strlen( m_pstrText );
	if( Length > NumHorzChars )
		Length = NumHorzChars;
	
	PrintString( 10, m_VerticalPos, m_pstrText, TRUE, 
				D3DCOLOR_ARGB( 0, 255, 0, 255 ), pData, DestPitch );

	return 0;
}
// This function is called whenever a character

// key is pressed that needs to be added to the buffer

int CEntry::OnChar( char Key )
{	
	// Check if the backspace key was pressed

	if( Key == ''\b'' )
	{
		// Make a temporary string holder

		char pstrTemp[MAX_CHARSPERLINE];
		// Get the length of the buffer

		int Length = strlen( m_pstrText );
		
		// If the buffer is empty then return

		if( Length == 0 )
			return 0;

		// Reduce the length of the string by one

		Length--;

		// Copy the string(-1) to the temp string

		CopyMemory( pstrTemp, m_pstrText, Length );	
		// Zero out the buffer

		ZeroMemory( m_pstrText, sizeof( char[MAX_CHARSPERLINE] ) );
		// Copy the text back into the buffer

		CopyMemory( m_pstrText, pstrTemp, Length );
	}
	else // A normal key was pressed

	{
		// Append the text buffer with the character

		strncat( m_pstrText, &Key, 1 );
	}
	
	return 0;
}

const int MAX_PARAMS = 25;

// ------------------------- Command Class

// Holds pre parsed commands


class CCommand
{
public:
	
	// Holds the main command.  eg ''SetScreenRes''

	char* pstrCommand;	
	// Holds the number of parameters. eg 2

	int NumParams;		
	// Holds the parameters.  eg 640 and 480

	char* pstrParams[MAX_PARAMS]; 
	
	// Constructor

	CCommand()
	{
		// Initialize all the variables to 0

		pstrCommand = 0;
		NumParams = 0;
		
		ZeroMemory( &pstrParams, sizeof( pstrParams ) );
	}
	// Destructor

	~CCommand()
	{
		// Destroy the command string

		// if it exists

		if( pstrCommand )
			delete pstrCommand;
		
		// Destroy any parameter strings 

		// if they exist

		for( int i = 0 ; i < MAX_PARAMS ; i++ )
		{
			if( pstrParams[i] )
				delete pstrParams[i];
		}
	}

};

typedef int (*CONSOLE_PARSER_CALLBACK)( CCommand* pCommand );


// ------------------------- Console Class

// Deals with keyboard input, visibility managment, and command parsing

class CConsole
{
public:
	CConsole();
	~CConsole();
	
	// Functions:

public:
	void Shutdown();
	HRESULT Initialize( LPDIRECT3DDEVICE8 pDevice, LPDIRECT3DSURFACE8 pTargetSurface );
	void Render();

	BOOL GetVisibility(){ return m_bVisible; }
	void SetVisibility( BOOL bVisible )
	{ 
		// The render code will figure out when the console

		// is not visible.

		m_bVisible = TRUE;

		// If bVisible is true then the console must be invisible

		// and about to animate down.  Otherwise it will be

		// animating up.

		m_Animation = bVisible ? Down : Up;
	}

	void OutputString( char* pString );
	void Clear();
	int OnChar( char Key );
	int OnKeyDown( WPARAM wParam );

	void SetParserCallback( CONSOLE_PARSER_CALLBACK pfnCallback );
	void PreParse( char* pstrText, CCommand* pCommand );

protected:
	void RotateEntries();
	

	// Variables:

public:


protected:
	BOOL m_bInitialized;	// Has the console been initialized?

	
	int m_Width;	// The width of the console surface

	int m_Height;	// The height of the console surface


	LPDIRECT3DSURFACE8 m_pConsoleSurface; // Pointer to the console surface

	LPDIRECT3DSURFACE8 m_pConsoleBackgroundSurf; // Pointer to the background bitmap surface

	LPDIRECT3DSURFACE8 m_pTargetSurface;	// Pointer to the target render surface( eg back buffer )

	LPDIRECT3DDEVICE8 m_pDevice;	// Pointer to the device


	BOOL m_bVisible;	// Is the console visible?


	// The current state of the console

	enum ANIM{ Up, Down, None }m_Animation;

	CEntry* m_pActiveEntry;	// The active entry(accepts key input)

	CEntry* m_pEntryList;	// The list of old entries


	// Pointer to an external console parser

	CONSOLE_PARSER_CALLBACK m_pfnCallback;
	// Is there an external parser?

	BOOL m_bParserCallback;

};

// Constructor

CConsole::CConsole()
{
	m_pConsoleSurface = 0;
	m_pConsoleBackgroundSurf = 0;
	m_pTargetSurface = 0;

	m_Width = 0;
	m_Height = 0;

	m_bInitialized = FALSE;
	m_bVisible = FALSE;

	m_Animation = None;

	m_pActiveEntry = 0;
	m_pEntryList = 0;

	m_pfnCallback = 0;
	m_bParserCallback = FALSE;
}

// Destructor

CConsole::~CConsole()
{
	// Release the console surface

	if( m_pConsoleSurface )
	{
		m_pConsoleSurface->Release();
		m_pConsoleSurface = 0;
	}

	// Release the background bitmap surface

	if( m_pConsoleBackgroundSurf )
	{
		m_pConsoleBackgroundSurf->Release();
		m_pConsoleBackgroundSurf = 0;
	}

	// Release the target surface

	if( m_pTargetSurface )
	{
		m_pTargetSurface->Release();
		m_pTargetSurface = 0;
	}

	// Destroy all of the entries

	CEntry* pEntry = m_pEntryList;
	CEntry* pTemp = 0;

	if( !pEntry )
		return;

	// Loop for each entry

	while( pEntry->GetNext() )
	{
		// Copy the next entry into a temp pointer

		pTemp = pEntry->GetNext();
		// Delete the current pointer

		delete pEntry;
		// Set the current pointer to the next pointer

		pEntry = pTemp;
	}
}

// Shutsdown the console

void CConsole::Shutdown()
{
	if( m_pConsoleSurface )
	{
		m_pConsoleSurface->Release();
		m_pConsoleSurface = 0;
	}

	if( m_pConsoleBackgroundSurf )
	{
		m_pConsoleBackgroundSurf->Release();
		m_pConsoleBackgroundSurf = 0;
	}

	if( m_pTargetSurface )
	{
		m_pTargetSurface->Release();
		m_pTargetSurface = 0;
	}

	// Destroy all of the entries

	CEntry* pEntry = m_pEntryList;
	CEntry* pTemp = 0;

	if( !pEntry )
		return;

	// Loop for each entry

	while( pEntry->GetNext() )
	{
		// Copy the next entry into a temp pointer

		pTemp = pEntry->GetNext();
		// Delete the current pointer

		delete pEntry;
		// Set the current pointer to the next pointer

		pEntry = pTemp;
	}

	m_pEntryList = 0;

	m_bInitialized = FALSE;
}

// Sets the external command parser

void CConsole::SetParserCallback( CONSOLE_PARSER_CALLBACK pfnCallback )
{
	// Set the function pointer

	m_pfnCallback = pfnCallback;
	// Set the flag to show that a parser has been specified

	m_bParserCallback = TRUE;
}

// Clears the contents of all the entries

void CConsole::Clear()
{
	// Create a pointer to the first entry

	CEntry* pEntry = m_pEntryList;

	// Loop for every entry

	while( pEntry->GetNext() )
	{
		// Set the entries text to nothing

		pEntry->SetText( "" );
		// Get the next entry

		pEntry = pEntry->GetNext();
	}
}

// Handles character input

int CConsole::OnChar( char Key )
{
	// This holds the last key pressed

	static char LastKey = 0;
	
	// If the console is not visible

	// then ignore the keypress

	if( !m_bVisible )
		return 0;

	// Ignore the enter key

	if( Key == ''\r'' )
		return 0;

	// Change the tab key to a space key

	if( Key == ''\t'' )
		Key = '' '';

	// Only allow one space

	if( (Key == '' '') && (LastKey == '' '') )
		return 0;

	// Make sure the first character in a line

	// is not a space

	if( (Key == '' '') && (LastKey == 0 ) )
		return 0;

	// Only send the message to the active

	// entry if the Last Key is not being

	// reset

	if( Key != 0 )
		m_pActiveEntry->OnChar( Key );

	// Update the last key pressed variable

	LastKey = Key;
	
	return 0;
}

// Handles non character keyboard input

int CConsole::OnKeyDown( WPARAM wParam )
{
	int Result = 0; // Holds result of parse operation

	
	// Figure out which key was pressed

	switch( wParam )
	{
		// The F11 key was pressed

		case VK_F11:
		{
			SetVisibility( !GetVisibility() );

			break;
		}
		// The enter key.

		case VK_RETURN:
		{
			// Ignore if the console is not visible

			if( !m_bVisible )
				return 0;

			// Reset the last keypressed

			OnChar( 0 );
			
			// Check if a parser has been set

			if( m_bParserCallback )
			{
				// Create a temporary string

				char* String = new char[MAX_CHARSPERLINE];
				// Get the string from the active entry

				m_pActiveEntry->GetText( String, MAX_CHARSPERLINE );

				// If nothing was typed just ignore it

				if( !MATCH( String, "" ) && !MATCH( String, " " ) )
				{
					// Create a new command class

					CCommand Command;
					// Convert the string into a command

					PreParse( String, &Command );		
					// Send the command to the parser

					Result = m_pfnCallback( &Command );
					if( FAILED( Result ) )
						OutputString( "-- Unknown Command --" );
				}
				
				// Destroy the temporary string

				delete String;
			}
			
			// Move all the entries up

			RotateEntries();
			break;
		}

		// The left arrow key was pressed

		case VK_LEFT:
		{
			// Treat this like a backspace press

			OnChar( ''\b'' );
			break;
		}

	}

	return 0;
}

// Converts the command string into a

// command and a list of parameters

void CConsole::PreParse( char* pstrText, CCommand* pCommand )
{
	// The parameter separators are

	// the comma and space characters

	char Separators[] = " ,";
	// String to hold the current parameter

	char* Token;
	// The number of parameters

	int TokenCount = 0;

	// Convert the string to lowercase

	strlwr( pstrText );

	// Get the command string

	Token = strtok( pstrText, Separators );

	// If the line was not blank...

	if( Token )
	{
		// ...Set the command string to the token.

		// Create a string in the command to hold the command string

		pCommand->pstrCommand = new char[ strlen( Token ) + 1 ];
		// Copy the string into the command string

		strcpy( pCommand->pstrCommand, Token );
	}
	else // The line was blank

	{
		// Create a single character to hold a blank character.

		// This will notify the keypress event that the line

		// was empty

		pCommand->pstrCommand = new char;
		// Copy a bank character into a new

		strcpy( pCommand->pstrCommand, " " );
		// Set the number of parameters to zero

		pCommand->NumParams = 0;
		// Return; there is nothing left to do

		return;
	}

	// Get the next token in the string

	Token = strtok( NULL, Separators );
	
	// Loop for the rest of the tokens

	while( Token != NULL )
	{
		// Allocate memory in the command for this parameter

		pCommand->pstrParams[TokenCount] = new char[ strlen( Token ) + 1 ];
		// Copy the parameter into the allocated memory

		strcpy( pCommand->pstrParams[TokenCount], Token );
		// Get the next token in the string

		Token = strtok( NULL, Separators );
		// Increase the parameter count

		TokenCount++;
		// Make sure there are not too many parameters

		if( TokenCount > MAX_PARAMS )
			break;
	}
	
	// Set the number of parameters in command

	pCommand->NumParams = TokenCount;
}


// Output a string to the console

void CConsole::OutputString( char* pString )
{
	// Move the entries up

	RotateEntries();

	// Set the new active entry to the specified string

	m_pActiveEntry->SetText( pString );
}

// Moves the entries up one row.  The top

// entry is deleted and a new one is

// created for the bottom

void CConsole::RotateEntries()
{
	// Get a pointer to the first entry

	CEntry* pEntry = m_pEntryList;
	// A temporary entry pointer

	CEntry* pTempEntry = 0;
	// A pointer to the new entry

	CEntry* pNewEntry = 0;

	// Loop for each entry

	while( pEntry->GetNext() )
	{
		// Set the temp entry to the current entry

		pTempEntry = pEntry;
		// Increase the vertical position of the current entry

		pEntry->SetVerticalPos( pEntry->GetVerticalPos() - g_AlphabetLetterHeight );
		// Set the current entry to the next entry

		pEntry = pEntry->GetNext();
	}
	
	// The pEntry variable now points to the last

	// entry in the list and pTempEntry to the 2nd last.

	
	// Delete the last entry in the list

	delete pEntry;
	// Get a pointer to the new last entry

	pEntry = pTempEntry;
	// Set the new last entries pNext pointer to zero

	pEntry->SetNext( NULL );

	// Create a new entry for the top of the list

	pNewEntry = new CEntry;

	// Set new entries pNext variable to last first entry

	pNewEntry->SetNext( m_pEntryList );
	// Set the start of the Entry list to the new entry

	m_pEntryList = pNewEntry;

	// Set the active entry to the new entry

	m_pActiveEntry = pNewEntry;
	// Set the vertical position of the new entry to the bottom

	// of the console

	m_pActiveEntry->SetVerticalPos( (m_Height-5) - g_AlphabetLetterHeight );

}

// Initializes the console

HRESULT CConsole::Initialize( LPDIRECT3DDEVICE8 pDevice, LPDIRECT3DSURFACE8 pTargetSurface )
{
	// Make sure a valid device was specified

	if( !pDevice )
		return E_FAIL;

	// Make sure a valid target surface was specified

	if( !pTargetSurface )
		return E_FAIL;

	HRESULT r = 0;

	// Keep a local pointer of the device

	m_pDevice = pDevice;
	// Tell the device there is now another pointer to it

	pDevice->AddRef();

	// Keep a local copy of the target suface

	m_pTargetSurface = pTargetSurface;
	// Tell the surface there is now another reference to it

	pTargetSurface->AddRef();

	// Holds information about the target surface

	D3DSURFACE_DESC d3dsd;
	// Get information about the target surface

	m_pTargetSurface->GetDesc( &d3dsd );

	// Set the dimensions of the console the width and 1/2 the height of the target

	m_Width = d3dsd.Width;
	m_Height = d3dsd.Height / 2;

	// Create a surface for the console

	r = m_pDevice->CreateImageSurface( m_Width, m_Height, D3DFMT_X8R8G8B8, &m_pConsoleSurface );
	if( FAILED( r ) )
	{
		SetError( "Unable to create image surface for console" );
		Shutdown();
		return E_FAIL;
	}

	// Load the background bitmap for the console

	r = LoadBitmapToSurface( "Console Background.bmp", &m_pConsoleBackgroundSurf, m_pDevice );
	if( FAILED( r ) )
	{
		SetError( "Unable to load console background image" );
		Shutdown();
		return E_FAIL;
	}

	// Set the initialized flag to TRUE

	m_bInitialized = TRUE;

	m_pEntryList = new CEntry;		// Start the list with a new entry

	CEntry* pEntry = m_pEntryList;	// Get a temp pointer to the new entry

	m_pActiveEntry = m_pEntryList;	// Set the active entry to the start of the list


	// Compute the number of visible rows of text

	int VisibleRows = m_Height / g_AlphabetLetterHeight;
	
	// Loop for each possible visible row of text

	for( int i = 1 ; i < VisibleRows ; i++ )
	{
		// Create a new entry

		pEntry->SetNext( new CEntry );
		// Set its vertical position to above the previous row

		pEntry->SetVerticalPos( (m_Height-5) - (i * g_AlphabetLetterHeight) );
		// Get a pointer to the new entry

		pEntry = pEntry->GetNext();
	}

	return S_OK;
}

// Renders the console to the target surface

void CConsole::Render()
{
	// Make sure the console has been initialized

	if( !m_bInitialized )
		return;

	// Holds the current vertical position of the 

	// console during scrolling operations

	static int CurrentY = m_Height;
	
	// If the console is animating down then

	// subtract from the current Y coord

	if( m_Animation == Down )
		CurrentY-=10;
	// Else if the console is going up

	// then add to the current Y coord

	else if( m_Animation == Up )
		CurrentY+=10;

	// Stop the animation if the console has completely expanded

	if( m_Animation == Down && CurrentY == 0 )
		m_Animation = None;
	
	// Stop the animation if the console has completely retracted

	if( m_Animation == Up && CurrentY == m_Height )
	{
		m_bVisible = FALSE;
		m_Animation = None;
	}

	// Set the source rectangle

	RECT SourceRect = { 0, CurrentY, m_Width, m_Height };
	// Set the destination point

	POINT DestPoint = { 0, 0 };	

	// If the console is not visible then return

	if( !m_bVisible )
		return;

	// Copy the background surface to the console surface

	D3DXLoadSurfaceFromSurface( m_pConsoleSurface, NULL, NULL, m_pConsoleBackgroundSurf, NULL,
									NULL, D3DX_FILTER_LINEAR, 0 );

	// Get a pointer to the start of the entry list

	CEntry* pEntry = m_pEntryList;

	D3DLOCKED_RECT LockedRect;

	m_pConsoleSurface->LockRect( &LockedRect, 0, 0 );

	// Loop for each entry in the list

	while( pEntry->GetNext() )
	{
		// Render this entry

		pEntry->RenderText( MAX_CHARSPERLINE, (DWORD*)LockedRect.pBits, LockedRect.Pitch );
		// Move to the next entry

		pEntry = pEntry->GetNext();
	}

	m_pConsoleSurface->UnlockRect();

	// Copy the console to the target surface

	m_pDevice->CopyRects( m_pConsoleSurface, &SourceRect, 1, m_pTargetSurface, &DestPoint );

}


i know this is really asking a lot, but can someone have a look and possibly give suggestions as to why i only get 35-60 fps when i run it?
"Only two things are infinite, the universe and human stupidity, and I'm not sure about the former." - Albert Einstein (1879-1955) That is so very true...
bzroom
bzroom
I didn''t look at it but maybe vsync is turned on, try setting your monitors refresh rate at somethign higher like 70 or 80 or 120 and see if u can''t get higher fps.
Scint
Scint
I used to use "Zen" too. I do not think it is your problem, but the book''s problem. I ran his sample programs and got very low frame rates. Perhaps the biggest problem in his code is that he creates the vertex buffer every frame. I highly suggest you look into other places to learn DirectX, and search this forum for optimization techniques.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.