Original Post
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?