Click here to Skip to main content
15,895,746 members
Articles / Multimedia / DirectX

Adventures In Abattoirville

Rate me:
Please Sign up or sign in to vote.
5.00/5 (5 votes)
31 Jul 2001MIT5 min read 109.5K   3.3K   32  
A Maze based game.
//-----------------------------------------------------------------------------
// File: Main.cpp
//
//-----------------------------------------------------------------------------
#define STRICT
#include <windows.h>
#include <ddraw.h>
#include <dshow.h>
#include <mmsystem.h>
#include <math.h>
#include <fstream>
#include <list>
#include "resource.h"
#include "DSUtil.h"
#include "ddutil.h"
#include "Maze.h"
#include "Sprite.h"
#include "SpriteManager.h"
#include "GameErrors.h"
#include "InputLayer.h"
#include "Keyboard.h"
#include "ijl.h"  // Intel JPEG header file
//#define DISPLAY_STATUS
#undef DISPLAY_STATUS
//-----------------------------------------------------------------------------
// Defines, constants, and global variables
//-----------------------------------------------------------------------------
#define SAFE_DELETE(p)  { if(p) { delete (p);     (p)=NULL; } }
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }

#define TITLE "Adventure in Abit"
#define SPLASHFILENAME "AdvInAbat.jpg"
#define CHOICEFILENAME "choose.jpg"
#define GAMEOVERBADFILENAME "GameOver.jpg"
#define GAMEOVERGOODFILENAME "Finish.jpg"

#define SCREEN_WIDTH    1024
#define SCREEN_HEIGHT   768
#define SCREEN_BPP      16
#define SPRITE_WIDTH    64
#define SPRITE_HEIGHT   64
#define MAZETEXTURE_WIDTH    32
#define MAZETEXTURE_HEIGHT   32

#define TYPE_PLAYER   1
#define TYPE_ENEMY1 2
#define TYPE_ENEMY2 3
#define TYPE_ENEMY3 4
#define TYPE_ENEMY4 5
#define TYPE_POO    10
#define TYPE_SPECIAL 11
#define TYPE_BULLET  12

#define ST_STAND_STILL 1 
#define ST_WALK_UP     2
#define ST_WALK_DOWN   3
#define ST_WALK_LEFT   4
#define ST_WALK_RIGHT  5
#define ST_DEFAULT     6
#define ST_KEY         7
#define ST_DOOR        8
#define ST_FOOD1       9
#define ST_FOOD2       (ST_FOOD1+1)
#define ST_FOOD3       (ST_FOOD1+2)
#define ST_FOOD4       (ST_FOOD1+3)
#define ST_FOOD5       (ST_FOOD1+4)
#define ST_FOOD6       (ST_FOOD1+5)

#define GAMESTATE_SPLASHSCREEN 0
#define GAMESTATE_CHOICE       1
#define GAMESTATE_RUNNING      2
#define GAMESTATE_GAMEOVERBAD  3
#define GAMESTATE_GAMEOVERGOOD 4

#define POO_DELAY   500
#define INVULNERABLE_DELAY  200
#define NO_OF_LIFE     4
#define NO_OF_SPECIALS 5

#define GAMESTATUS_TEXT "Dead Pigs:%d Dead Enemies:%d"
char g_szGameStatus[200];

#define LIFE_LEFT_TEXT "Lives:%d"
char g_szLifeLeft[100];

#define GAMESCORE_TEXT "Score:%06d"
char g_szScore[100];

CDisplay*            g_pDisplay        = NULL;
#ifdef DISPLAY_STATUS
CSurface*            g_pTextSurface    = NULL;  
#endif
CSurface*            g_pLifeTextSurface = NULL;  
CSurface*            g_pScoreTextSurface = NULL;  
CSurface*            g_pLevelTextSurface = NULL;  
CSurface*            g_pMazeSurface    = NULL;  
CSurface*            g_pSpriteSurface  = NULL;
CSurface*            g_pSplashSurface  = NULL;
RECT                 g_rcWindow;            
RECT                 g_rcViewport;          
RECT                 g_rcScreen;            
BOOL                 g_bWindowed   = false;  
BOOL                 g_bActive     = FALSE;
DWORD                g_dwLastTick;
CMaze                g_Maze(MAKEINTRESOURCE(IDB_TEXTURE));
CSprite              g_PigSprite;
CSprite              g_RabbitSprite;
CSprite              g_SheepSprite;
CSprite*             g_pPlayerSprite = NULL;
CSprite              g_Enemy1Sprite;
CSprite              g_Enemy2Sprite;
CSprite              g_Enemy3Sprite;
CSprite              g_Enemy4Sprite;
CSprite              g_Enemy5Sprite;
CSprite              g_PigPooSprite;
CSprite              g_RabbitPooSprite;
CSprite              g_SheepPooSprite;
CSprite*              g_pPooSprite= NULL;
CSprite              g_SpecialSprite;
CSprite              g_BulletSprite;
CSpriteManager       g_EnemySpriteManager;
CSound*              g_pSplashSound = NULL;
CSound*              g_pPickupSound = NULL;
CSoundManager*       g_pSoundManager = NULL;
int                  g_nGameState = GAMESTATE_SPLASHSCREEN;
int                  g_nPigDead = 0;
int                  g_nEnemyDead = 0;
long                 g_nPooDelay = 0;
long                 g_nNoOfEnemies = 10;
long                 g_nLivesLeft = NO_OF_LIFE;
long                 g_nNoOfSpecials = NO_OF_SPECIALS;
long                 g_nScore = 0;

struct SLEVEL {
	char  szLevelFile[100];
	int   nNoOfEnemys;
}* g_pLevel;

long                 g_nNoOfLevels;
long                 g_nCurrLevel=0;


HINSTANCE g_hInstance;
HWND      g_hMainWnd;

//-----------------------------------------------------------------------------
// Function-prototypes
//-----------------------------------------------------------------------------
LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
HRESULT WinInit( HINSTANCE hInst, int nCmdShow, HWND* phWnd, HACCEL* phAccel );
HRESULT InitDirectDraw( HWND hWnd );
VOID    FreeDirectDraw();
HRESULT InitDirectDrawMode( HWND hWnd, BOOL bWindowed );
HRESULT ProcessNextFrame( HWND hWnd );
HRESULT DisplayFrame();
HRESULT RestoreSurfaces();
bool LoadJPEG(bool bFromFile, LPCTSTR szName,  CSurface** ppSurface);
void DisplaySplashScreen(bool bDisplay);
void InitSprites();
void InitLevel();
void MoveCharacterRelative(long dX, long dY);

struct SHandleInput: public iKeyboardReceiver
{
	SHandleInput() {
		cInputLayer::Create( g_hInstance, g_hMainWnd, 
			true, true, false );
		Input()->GetKeyboard()->SetReceiver( this );
	}
	~SHandleInput() {
		cInputLayer::Destroy();
	}
	void KeyUp( int key ) 
	{
		switch(g_nGameState) 
		{
		case GAMESTATE_SPLASHSCREEN: 
			{
				switch( key )
				{
					
				case DIK_SPACE:
					{
						g_nGameState=GAMESTATE_CHOICE;
						g_pSplashSound->Stop();
						LoadJPEG(true, CHOICEFILENAME,  &g_pSplashSurface);
						
						break;
					}
				}
				
			}
			break;
			
		case GAMESTATE_CHOICE:
			{
				bool bKeyHit = false;
				
				switch( key )
				{
				case DIK_1: g_pPlayerSprite = &g_PigSprite; 
					g_pPooSprite = &g_PigPooSprite;
					bKeyHit = true; break;
				case DIK_2: g_pPlayerSprite = &g_RabbitSprite;
					g_pPooSprite = &g_RabbitPooSprite;
					bKeyHit = true;break;
				case DIK_3: g_pPlayerSprite = &g_SheepSprite; 
					g_pPooSprite = &g_SheepPooSprite;
					bKeyHit = true;	break;
				}
				if (bKeyHit) {
					g_nGameState=GAMESTATE_RUNNING;
					InitLevel();
				}
			}
			break;
			
		case GAMESTATE_RUNNING: 
			{
				switch( key )
				{
					// move up
				case DIK_UP:
				case DIK_NUMPAD8:
					// move down
				case DIK_DOWN:
				case DIK_NUMPAD2:
					// turn right
				case DIK_RIGHT:
				case DIK_NUMPAD6:
					// turn left
				case DIK_LEFT:
				case DIK_NUMPAD4:
					g_pPlayerSprite->SetState(ST_STAND_STILL);
					g_pPlayerSprite->m_Movement.m_dx = g_pPlayerSprite->m_Movement.m_dy =0;
					break;
				}
			}
			break;
		case GAMESTATE_GAMEOVERGOOD: 
		case GAMESTATE_GAMEOVERBAD: 
			{
				switch( key )
				{
					
				case DIK_SPACE:
					{
						g_nGameState=GAMESTATE_SPLASHSCREEN;
						g_nLivesLeft = NO_OF_LIFE;
						g_nScore=0;
						g_nCurrLevel=0;
						
						break;
					}
				}
				
			}
			break;
			
		}
	}
	
	
	void KeyDown( int key )
	{
		switch(g_nGameState) {
			
			
		case GAMESTATE_RUNNING: 
			{
				switch( key )
				{
					
					// move up
				case DIK_UP:
				case DIK_NUMPAD8:
					{
						g_pPlayerSprite->SetState(ST_WALK_UP);
						g_pPlayerSprite->m_Movement.m_dy = -2;
						g_pPlayerSprite->m_Movement.m_dx = 0;
						break;
					}
					
					// move down
				case DIK_DOWN:
				case DIK_NUMPAD2:
					{
						g_pPlayerSprite->SetState(ST_WALK_DOWN);
						g_pPlayerSprite->m_Movement.m_dy = 2;
						g_pPlayerSprite->m_Movement.m_dx = 0;
						break;
					}
					
					// Shoot
				case DIK_SPACE:
					{
						if (g_nPooDelay == 0 && g_pPlayerSprite->GetState()!= ST_KILL) {
							RECT rc = g_pPlayerSprite->GetRect();
							g_pPooSprite->MoveTo(rc.left,rc.top);
							g_nPooDelay = POO_DELAY;
							g_pPooSprite->SetState(ST_DEFAULT);
						}
						break;
					}
					
					// turn right
				case DIK_RIGHT:
				case DIK_NUMPAD6:
					{
						g_pPlayerSprite->SetState(ST_WALK_RIGHT); 
						g_pPlayerSprite->m_Movement.m_dx = 2;
						g_pPlayerSprite->m_Movement.m_dy = 0;
						break;
					}
					
					// turn left
				case DIK_LEFT:
				case DIK_NUMPAD4:
					{
						g_pPlayerSprite->SetState(ST_WALK_LEFT);
						g_pPlayerSprite->m_Movement.m_dx = -2;
						g_pPlayerSprite->m_Movement.m_dy = 0;
						break;
					}
				}
			}
		}
	}
} *  g_pHandleInput = NULL;





//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: Entry point to the program. Initializes everything and calls
//       UpdateFrame() when idle from the message pump.
//-----------------------------------------------------------------------------
int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int nCmdShow )
{
    MSG	   msg;
    HWND   hWnd;
    HACCEL hAccel;
	
    srand( GetTickCount() );
	
	wsprintf((char*)g_szGameStatus, (char*)GAMESTATUS_TEXT,0,0);
	wsprintf((char*)g_szLifeLeft, (char*)LIFE_LEFT_TEXT,g_nLivesLeft -1);
	wsprintf((char*)g_szScore, (char*)GAMESCORE_TEXT,g_nScore);
	
	g_hInstance = hInst;
	
	char szName[200];
	std::fstream LevelData("config.txt",std::ios::in );
    LevelData.getline(szName,200);
	
	// Read number of horizontal lines
	LevelData >> g_nNoOfLevels;   // Number of Horizontal rows
	g_pLevel = new SLEVEL[g_nNoOfLevels];
	if (g_pLevel == NULL)
		return -1;
	for (int nI = 0; nI < g_nNoOfLevels; nI++) {
		LevelData >> g_pLevel[nI].szLevelFile;
		LevelData >> g_pLevel[nI].nNoOfEnemys;
	}
	
    if( FAILED( WinInit( hInst, nCmdShow, &hWnd, &hAccel ) ) )
        return FALSE;
	
	
    if( FAILED( InitDirectDraw( hWnd ) ) )
    {
        MessageBox( hWnd, TEXT("DirectDraw init failed. ")
			TEXT("The program will now exit. "), TEXT("Maze Test program"), 
			MB_ICONERROR | MB_OK );
        return FALSE;
    }
	InitSprites();
	
    g_dwLastTick = timeGetTime();
	
    while( TRUE )
    {
        // Look for messages, if none are found then 
        // update the state and display it
        if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
        {
            if( 0 == GetMessage(&msg, NULL, 0, 0 ) )
            {
                // WM_QUIT was posted, so exit
				FreeDirectDraw();
				CoUninitialize();
				delete[] g_pLevel;
                return (int)msg.wParam;
            }
			
            // Translate and dispatch the message
            if( 0 == TranslateAccelerator( hWnd, hAccel, &msg ) )
            {
                TranslateMessage( &msg ); 
                DispatchMessage( &msg );
            }
        }
        else
        {
            if( g_bActive )
            {
                // Move the sprites, blt them to the back buffer, then 
                // flip or blt the back buffer to the primary buffer
                if( FAILED( ProcessNextFrame( hWnd ) ) )
                {
                    SAFE_DELETE( g_pDisplay );
					
                    MessageBox( hWnd, TEXT("Displaying the next frame failed. ")
						TEXT("The program will now exit. "), TEXT("Adv In Abt"), 
						MB_ICONERROR | MB_OK );
                    return FALSE;
                }
            }
            else
            {
                // Go to sleep if we have nothing else to do
                WaitMessage();
				
                // Ignore time spent inactive 
                g_dwLastTick = timeGetTime();
            }
        }
    }
	
}




//-----------------------------------------------------------------------------
// Name: WinInit()
// Desc: Init the window
//-----------------------------------------------------------------------------
HRESULT WinInit( HINSTANCE hInst, int nCmdShow, HWND* phWnd, HACCEL* phAccel )
{
    WNDCLASSEX wc;
    HWND       hWnd;
    HACCEL     hAccel;
	
    // Register the window class
    wc.cbSize        = sizeof(wc);
    wc.lpszClassName = TEXT("AdvInAbatWndClass");
    wc.lpfnWndProc   = MainWndProc;
    wc.style         = CS_VREDRAW | CS_HREDRAW;
    wc.hInstance     = hInst;
    wc.hIcon         = LoadIcon( hInst, MAKEINTRESOURCE(IDI_MAIN) );
    wc.hIconSm       = LoadIcon( hInst, MAKEINTRESOURCE(IDI_MAIN) );
    wc.hCursor       = LoadCursor( NULL, IDC_ARROW );
    wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
    wc.lpszMenuName  = 0;//MAKEINTRESOURCE(IDR_MENU);
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
	
    if( RegisterClassEx( &wc ) == 0 ) {
		LPVOID lpMsgBuf;
		FormatMessage( 
			FORMAT_MESSAGE_ALLOCATE_BUFFER | 
			FORMAT_MESSAGE_FROM_SYSTEM | 
			FORMAT_MESSAGE_IGNORE_INSERTS,
			NULL,
			GetLastError(),
			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
			(LPTSTR) &lpMsgBuf,
			0,
			NULL 
			);
		OutputDebugString( (LPCTSTR)lpMsgBuf);
		// Free the buffer.
		LocalFree( lpMsgBuf );
        return E_FAIL;
	}
	
    // Load keyboard accelerators
    hAccel = LoadAccelerators( hInst, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
	
    // Calculate the proper size for the window given a client of 640x480
    DWORD dwFrameWidth    = GetSystemMetrics( SM_CXSIZEFRAME );
    DWORD dwFrameHeight   = GetSystemMetrics( SM_CYSIZEFRAME );
    DWORD dwMenuHeight    = GetSystemMetrics( SM_CYMENU );
    DWORD dwCaptionHeight = GetSystemMetrics( SM_CYCAPTION );
    DWORD dwWindowWidth   = SCREEN_WIDTH  + dwFrameWidth * 2;
    DWORD dwWindowHeight  = SCREEN_HEIGHT + dwFrameHeight * 2 + 
		dwMenuHeight + dwCaptionHeight;
	
    // Create and show the main window
    DWORD dwStyle = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX;
    hWnd = CreateWindowEx( 0, TEXT("AdvInAbatWndClass"), 
		TEXT("Maze Test program"),
		dwStyle, CW_USEDEFAULT, CW_USEDEFAULT,
		dwWindowWidth, dwWindowHeight, NULL, NULL, hInst, NULL );
    if( hWnd == NULL )
		return E_FAIL;
	
    ShowWindow( hWnd, nCmdShow );
    UpdateWindow( hWnd );
	
    // Save the window size/pos for switching modes
    GetWindowRect( hWnd, &g_rcWindow );
	
    *phWnd   = hWnd;
    *phAccel = hAccel;
	
	g_hMainWnd = hWnd;
    return S_OK;
}

HFONT GetGameFont()
{
	HFONT      hFont ;
	LOGFONT    lf ;
	
	lf.lfHeight         = 40;
	lf.lfWidth          = 20;
	lf.lfEscapement     = 0 ;
	lf.lfOrientation    = 0 ;
	lf.lfWeight         = 0 ;
	lf.lfItalic         = false ; 
	lf.lfUnderline      = false; 
	lf.lfStrikeOut      = false; 
	lf.lfCharSet        = DEFAULT_CHARSET ;
	lf.lfOutPrecision   = 0 ;
	lf.lfClipPrecision  = 0 ;
	lf.lfQuality        = 0 ;
	lf.lfPitchAndFamily = 0 ;
	
	lstrcpy (lf.lfFaceName, "Times New Roman") ;
	
	hFont = CreateFontIndirect (&lf) ;
	//	hfont = (HFONT)GetStockObject(ANSI_VAR_FONT); 
	return hFont;
}

//-----------------------------------------------------------------------------
// Name: InitDirectDraw()
// Desc: Create the DirectDraw object, and init the surfaces
//-----------------------------------------------------------------------------
HRESULT InitDirectDraw( HWND hWnd )
{
    HRESULT hr;
	
    // Initialize all the surfaces we need
    if( FAILED( hr = InitDirectDrawMode( hWnd, g_bWindowed ) ) )
        return hr;
	
    // Create a static IDirectSound in the CSound class.  
    // Set coop level to DSSCL_PRIORITY, and set primary buffer 
    // format to stereo, 22kHz and 16-bit output.
    g_pSoundManager = new CSoundManager();
	
    if( FAILED(hr= g_pSoundManager->Initialize( hWnd, DSSCL_PRIORITY, 2, 22050, 16 ) ) )
    {
        MessageBox( 0, "Error initializing DirectSound.  Game will now exit.", 
			"Game", MB_OK | MB_ICONERROR );
        return hr;
    }
	
	g_pSoundManager->Create(&g_pPickupSound,"PickUp");
	g_pHandleInput = new SHandleInput();
	
    return S_OK;
}




//-----------------------------------------------------------------------------
// Name: InitDirectDrawMode()
// Desc: Called when the user wants to toggle between full-screen and windowed 
//       to create all the needed DDraw surfaces and set the coop level
//-----------------------------------------------------------------------------
HRESULT InitDirectDrawMode( HWND hWnd, BOOL bWindowed )
{
    HRESULT		        hr;
    LPDIRECTDRAWPALETTE pDDPal   = NULL; 
	
    // Release all existing surfaces
	SAFE_DELETE( g_pMazeSurface);  
#ifdef DISPLAY_STATUS
    SAFE_DELETE( g_pTextSurface );
#endif
	SAFE_DELETE( g_pLifeTextSurface );
	SAFE_DELETE( g_pScoreTextSurface );
	SAFE_DELETE( g_pLevelTextSurface );
	SAFE_DELETE( g_pSpriteSurface );
	SAFE_DELETE ( g_pSplashSurface);
	SAFE_DELETE( g_pDisplay );
	
    // The back buffer and primary surfaces need to be created differently 
    // depending on if we are in full-screen or windowed mode
    g_pDisplay = new CDisplay();
	
    if( bWindowed )
    {
        if( FAILED( hr = g_pDisplay->CreateWindowedDisplay( hWnd, SCREEN_WIDTH, 
			SCREEN_HEIGHT ) ) )
            return hr;
		
        // Add the system menu to the window's style
        DWORD dwStyle = GetWindowLong( hWnd, GWL_STYLE );
        dwStyle |= WS_SYSMENU;
        SetWindowLong( hWnd, GWL_STYLE, dwStyle );
		
        // Show the menu in windowed mode 
#ifdef _WIN64
        HINSTANCE hInst = (HINSTANCE) GetWindowLongPtr( hWnd, GWLP_HINSTANCE );
#else
        HINSTANCE hInst = (HINSTANCE) GetWindowLong( hWnd, GWL_HINSTANCE );
#endif
        HMENU hMenu = LoadMenu( hInst, MAKEINTRESOURCE( IDR_MENU ) );
        SetMenu( hWnd, hMenu );
    }
    else
    {
        if( FAILED( hr = g_pDisplay->CreateFullScreenDisplay( hWnd, SCREEN_WIDTH, 
			SCREEN_HEIGHT, SCREEN_BPP ) ) )
        {
            MessageBox( hWnd, TEXT("This display card does not support 640x480x8. "),
				TEXT("DirectDraw Sample"), MB_ICONERROR | MB_OK );
            return hr;
        }
		
        // Disable the menu in full-screen 
        SetMenu( hWnd, NULL );
		
        // Remove the system menu from the window's style
        DWORD dwStyle = GetWindowLong( hWnd, GWL_STYLE );
        dwStyle &= ~WS_SYSMENU;
        SetWindowLong( hWnd, GWL_STYLE, dwStyle );       
    }
	
	
	// Create a surface, and draw text to it.  
#ifdef DISPLAY_STATUS
	if( FAILED( hr = g_pDisplay->CreateSurfaceFromText( &g_pTextSurface, NULL, (char*)g_szGameStatus, 
		RGB(0,0,0), RGB(255, 255, 0) ) ) )
		return hr;
#endif
	HFONT hFont = GetGameFont();
	if( FAILED( hr = g_pDisplay->CreateSurfaceFromText( &g_pLifeTextSurface, hFont, (char*)g_szLifeLeft, 
		RGB(0,0,0), RGB(255, 255, 0) ) ) )
		return hr;
	if( FAILED( hr = g_pDisplay->CreateSurfaceFromText( &g_pScoreTextSurface, hFont, (char*)g_szScore, 
		RGB(0,0,0), RGB(255, 255, 0) ) ) )
		return hr;
	
	
    // Create a surface, and draw a bitmap resource on it.  The surface must 
    // be newly created every time the screen mode is switched since it 
    // uses the pixel format of the primary surface
	// Create a surface, and draw text to it.  
	if( FAILED( hr = g_pDisplay->CreateSurface( &g_pMazeSurface, SCREEN_WIDTH, SCREEN_HEIGHT) ))
		return hr;
	
	if( FAILED( hr = g_pDisplay->CreateSurfaceFromBitmap( &g_pSpriteSurface, MAKEINTRESOURCE(IDB_SPRITE),0, 0) ))
		return hr;
	
	g_pSpriteSurface->SetColorKey(RGB(0,0,0));
	g_Maze.Draw(g_pMazeSurface);
	
	if (g_nGameState == GAMESTATE_SPLASHSCREEN) {
		LoadJPEG(true, SPLASHFILENAME,  &g_pSplashSurface);
	}
	if (g_nGameState == GAMESTATE_CHOICE) {
		LoadJPEG(true, CHOICEFILENAME,  &g_pSplashSurface);
	}
	
	if (g_nGameState == GAMESTATE_GAMEOVERGOOD) {
		LoadJPEG(true, GAMEOVERGOODFILENAME,  &g_pSplashSurface);
	}
	if (g_nGameState == GAMESTATE_GAMEOVERBAD) {
		LoadJPEG(true, GAMEOVERBADFILENAME,  &g_pSplashSurface);
	}
	if (g_nGameState == GAMESTATE_RUNNING){
		g_pDisplay->CreateSurfaceFromText( &g_pLevelTextSurface, hFont, g_Maze.GetName(), 
			RGB(0,0,0), RGB(255, 255, 0) ) ;
		
	}
	DeleteObject(hFont);
    return S_OK;
}

inline bool IsHit(RECT& rc)
{
	return g_Maze.IsHit(rc);
}

void BulletFindPath(CSprite* pSprite)
{
	pSprite->SetState(ST_KILL);
}

void FindPath(CSprite* pSprite)
{
	int nH = rand()%2;
	int nV = rand()%2;
	int nNRnd = rand()%3;
	if (nNRnd) {
		
		if (abs(g_pPlayerSprite->m_ptLocation.x - pSprite->m_ptLocation.x) > 
			abs(g_pPlayerSprite->m_ptLocation.y - pSprite->m_ptLocation.y))
			
		{
			pSprite->m_Movement.m_dy = 0;
			if (g_pPlayerSprite->m_ptLocation.x < pSprite->m_ptLocation.x) {
				pSprite->m_Movement.m_dx= -1 * (rand()%2+1);
				pSprite->SetState(ST_WALK_LEFT);
				
			} else {
				pSprite->m_Movement.m_dx= 1 * (rand()%2+1);
				pSprite->SetState(ST_WALK_RIGHT);
			}
		} else {
			pSprite->m_Movement.m_dx = 0;
			if (g_pPlayerSprite->m_ptLocation.y < pSprite->m_ptLocation.y) {
				pSprite->m_Movement.m_dy= -1 * (rand()%2+1);
				pSprite->SetState(ST_WALK_UP);
			} else {
				pSprite->m_Movement.m_dy= 1 * (rand()%2+1);
				pSprite->SetState(ST_WALK_DOWN);
			}
		}
	} else {
		if (nV) {	
			pSprite->m_Movement.m_dx = 0;
			if (nH) {
				pSprite->m_Movement.m_dy = 1 * (rand()%2+1);
				pSprite->SetState(ST_WALK_DOWN);
			} else {
				pSprite->m_Movement.m_dy = -1 * (rand()%2+1);
				pSprite->SetState(ST_WALK_UP);
			}
		} else {
			pSprite->m_Movement.m_dy = 0;
			if (nH) {
				pSprite->m_Movement.m_dx = 1 * (rand()%2+1);
				pSprite->SetState(ST_WALK_RIGHT);
			} else {
				pSprite->m_Movement.m_dx = -1 * (rand()%2+1);
				pSprite->SetState(ST_WALK_LEFT);
			}
			
		}
	}
	
	if (pSprite->GetType() == TYPE_ENEMY4) {
		if (g_BulletSprite.GetState() == ST_DEAD && pSprite->GetState() != ST_KILL 
			&& pSprite->GetState() != ST_DEAD) {
			RECT rc = pSprite->GetRect();
			g_BulletSprite.MoveTo(rc.left,rc.top);
			g_BulletSprite.SetState(ST_DEFAULT);
			switch (pSprite->GetState()) {
			case ST_WALK_UP:
				g_BulletSprite.m_Movement.m_dx =0;
				g_BulletSprite.m_Movement.m_dy = -3;
				break;
			case ST_WALK_DOWN:
				g_BulletSprite.m_Movement.m_dx =0;
				g_BulletSprite.m_Movement.m_dy = 3;
				break;
			case ST_WALK_LEFT:
				g_BulletSprite.m_Movement.m_dx =-3;
				g_BulletSprite.m_Movement.m_dy = 0;
				break;
			case ST_WALK_RIGHT:
				g_BulletSprite.m_Movement.m_dx =3;
				g_BulletSprite.m_Movement.m_dy = 0;
				break;
			}
		}
	}
}

void DeadPig(CSprite* pSprite)
{
	++g_nPigDead;
	--g_nLivesLeft;
#ifdef DISPLAY_STATUS
	wsprintf((char*)g_szGameStatus, (char*)GAMESTATUS_TEXT, g_nPigDead, g_nEnemyDead);
    SAFE_DELETE( g_pTextSurface );
    g_pDisplay->CreateSurfaceFromText( &g_pTextSurface, NULL, (char*)g_szGameStatus, 
		RGB(0,0,0), RGB(255, 255, 0) );
#endif
	
	SAFE_DELETE( g_pLifeTextSurface );
	wsprintf((char*)g_szLifeLeft, (char*)LIFE_LEFT_TEXT, g_nLivesLeft-1);
	HFONT hFont = GetGameFont();
    g_pDisplay->CreateSurfaceFromText( &g_pLifeTextSurface, hFont , (char*)g_szLifeLeft, 
		RGB(0,0,0), RGB(255, 255, 0) );
	DeleteObject(hFont);
	
	g_pPlayerSprite->MoveTo(1 * MAZETEXTURE_WIDTH, 19 * MAZETEXTURE_HEIGHT);
	g_pPlayerSprite->SetState(ST_WALK_UP);
	g_pPlayerSprite->m_Movement.m_nInvulnerable=INVULNERABLE_DELAY;
	if (g_nLivesLeft == 0) {
		g_nLivesLeft = NO_OF_LIFE;
		g_nGameState = GAMESTATE_GAMEOVERBAD;
		LoadJPEG(true, GAMEOVERBADFILENAME,  &g_pSplashSurface);
	}
	
}

void DeadEnemy(CSprite* pSprite)
{
	++g_nEnemyDead;
#ifdef DISPLAY_STATUS
	wsprintf((char*)g_szGameStatus, (char*)GAMESTATUS_TEXT, g_nPigDead, g_nEnemyDead);
    SAFE_DELETE( g_pTextSurface );
    g_pDisplay->CreateSurfaceFromText( &g_pTextSurface, NULL, (char*)g_szGameStatus, 
		RGB(0,0,0), RGB(255, 255, 0) );
#endif	
	g_nScore += pSprite->m_nPoints;
	SAFE_DELETE( g_pScoreTextSurface );
	wsprintf((char*)g_szScore, (char*)GAMESCORE_TEXT, g_nScore);
	HFONT hFont = GetGameFont();

    g_pDisplay->CreateSurfaceFromText( &g_pScoreTextSurface, hFont, (char*)g_szScore, 
		RGB(0,0,0), RGB(255, 255, 0) );
	DeleteObject(hFont);
	
	if (g_nNoOfEnemies) {
		g_nNoOfEnemies--;
		pSprite->SetState(ST_WALK_LEFT);
		POINT pt = g_Maze.GetRandDeployPoint();
		pt.x *= MAZETEXTURE_WIDTH;
		pt.y *= MAZETEXTURE_HEIGHT;
		pSprite->MoveTo(pt);
		(*pSprite->m_Movement.m_pfnFindPath)(pSprite);
		pSprite->m_Movement.m_nInvulnerable=INVULNERABLE_DELAY;
	}
}
bool KillSpecial(CSprite* pSprite)
{
	if (pSprite->GetState() == ST_DOOR) {
			InitLevel();
			return false;
	}
	return true;
}

void DeadSpecial(CSprite* pSprite)
{
	static long nSpecialState = ST_FOOD1;
	g_nScore += pSprite->m_nPoints;
	SAFE_DELETE( g_pScoreTextSurface );
	wsprintf((char*)g_szScore, (char*)GAMESCORE_TEXT, g_nScore);
	HFONT hFont = GetGameFont();
	g_pDisplay->CreateSurfaceFromText( &g_pScoreTextSurface, hFont, (char*)g_szScore, 
		RGB(0,0,0), RGB(255, 255, 0) );
	DeleteObject(hFont);
	if (g_nNoOfSpecials) {
		pSprite->SetState(rand()%6 + ST_FOOD1);
		POINT pt = g_Maze.GetRandDeployPoint();
		pt.x *= MAZETEXTURE_WIDTH;
		pt.y *= MAZETEXTURE_HEIGHT;
		pSprite->MoveTo(pt);
		nSpecialState = ST_FOOD1;
		--g_nNoOfSpecials;
	} else {
		switch (nSpecialState) {
		case ST_FOOD1:
			pSprite->SetState(ST_KEY);
			POINT pt = g_Maze.GetRandDeployPoint();
			pt.x *= MAZETEXTURE_WIDTH;
			pt.y *= MAZETEXTURE_HEIGHT;
			pSprite->MoveTo(pt);
			nSpecialState = ST_KEY;
			break;
		case ST_KEY:
			pSprite->SetState(ST_DOOR);
			pt = g_Maze.GetRandDeployPoint();
			pt.x *= MAZETEXTURE_WIDTH;
			pt.y *= MAZETEXTURE_HEIGHT;
			pSprite->MoveTo(pt);
			nSpecialState = ST_DOOR;
			break;
		case ST_DOOR:
			InitLevel();
		}
	}
}

void InitSprites()
{
	const int nHeight = SPRITE_HEIGHT;
	const int nWidth = SPRITE_WIDTH;
	POINT pt;
	RECT rcBounding;
	// ---------------- Pig Sprite -----------------------------------//
	g_PigSprite.CreateSprite(&g_pSpriteSurface, TYPE_PLAYER, nHeight,nWidth);
	pt.x = 5*64; pt.y =7*64 ;
	g_PigSprite.AddState(ST_STAND_STILL, pt, 2, 60);
	rcBounding.top = 0;
	rcBounding.bottom = nHeight-10;
	rcBounding.left = 10;
	rcBounding.right= nWidth - 20;
	pt.x = 6*64; pt.y =4*64;
	g_PigSprite.AddState(ST_WALK_UP, pt, 3, 10,&rcBounding);
	rcBounding.top = 10;
	rcBounding.bottom = nHeight-10;
	
	pt.x = 64*9;pt.y = 4*64;
	g_PigSprite.AddState(ST_WALK_DOWN, pt, 3, 10,&rcBounding);
	
	rcBounding.top = 10;
	rcBounding.bottom = nHeight - 20;
	rcBounding.left = 0;
	rcBounding.right=nWidth - 10;
	pt.x = 3*64;pt.y = 4*64;
	//	g_pPlayerSprite->AddState(ST_WALK_LEFT, pt, 2, 20,"WavPigWalk",true);
	g_PigSprite.AddState(ST_WALK_LEFT, pt, 3, 10,&rcBounding);
	pt.x = 64*0;pt.y = 4*64;
	rcBounding.left = 10;
	rcBounding.right=nWidth-10;
	
	g_PigSprite.AddState(ST_WALK_RIGHT, pt, 3, 10,&rcBounding);
	pt.x = 64 * 8; pt.y = 7 * 64;
	g_PigSprite.AddState(ST_KILL, pt, 4, 20);
	g_PigSprite.MoveTo(1 * MAZETEXTURE_WIDTH, 19 * MAZETEXTURE_HEIGHT);
	g_PigSprite.m_pfnDead = DeadPig;
	g_PigSprite.m_Movement.m_pfnCollision = IsHit;
	
	g_PigPooSprite.CreateSprite(&g_pSpriteSurface, TYPE_POO, nHeight,nWidth);
	rcBounding.top = rcBounding.left = 20;
	rcBounding.right=rcBounding.bottom = nHeight - 40;
	pt.x = 0*64;pt.y = 7*64;
	g_PigPooSprite.AddState(ST_DEFAULT, pt, 3, 50,&rcBounding);
	pt.x = 11*64;pt.y = 10*64;
	g_PigPooSprite.AddState(ST_DEAD, pt, 3, 50,&rcBounding);
	g_PigPooSprite.SetState(ST_DEFAULT);
	
	// --------------- Rabbit Sprite -----------------------------//
	g_RabbitSprite.CreateSprite(&g_pSpriteSurface, TYPE_PLAYER, nHeight,nWidth);
	pt.x = 5*64; pt.y =8*64 ;
	g_RabbitSprite.AddState(ST_STAND_STILL, pt, 2, 60);
	rcBounding.top = 0;
	rcBounding.bottom = nHeight-10;
	rcBounding.left = 10;
	rcBounding.right= nWidth - 20;
	pt.x = 6*64; pt.y =5*64;
	g_RabbitSprite.AddState(ST_WALK_UP, pt, 3, 10,&rcBounding);
	rcBounding.top = 10;
	rcBounding.bottom = nHeight-10;
	
	pt.x = 64*9;pt.y = 5*64;
	g_RabbitSprite.AddState(ST_WALK_DOWN, pt, 3, 10,&rcBounding);
	
	rcBounding.top = 10;
	rcBounding.bottom = nHeight - 20;
	rcBounding.left = 0;
	rcBounding.right=nWidth - 10;
	pt.x = 3*64;pt.y = 5*64;
	g_RabbitSprite.AddState(ST_WALK_LEFT, pt, 3, 10,&rcBounding);
	pt.x = 64*0;pt.y = 5*64;
	rcBounding.left = 10;
	rcBounding.right=nWidth-10;
	
	g_RabbitSprite.AddState(ST_WALK_RIGHT, pt, 3, 10,&rcBounding);
	pt.x = 64 * 8; pt.y = 8 * 64;
	g_RabbitSprite.AddState(ST_KILL, pt, 4, 20);
	g_RabbitSprite.MoveTo(1 * MAZETEXTURE_WIDTH, 19 * MAZETEXTURE_HEIGHT);
	g_RabbitSprite.m_pfnDead = DeadPig;
	g_RabbitSprite.m_Movement.m_pfnCollision = IsHit;
	
	g_RabbitPooSprite.CreateSprite(&g_pSpriteSurface, TYPE_POO, nHeight,nWidth);
	rcBounding.top = rcBounding.left = 20;
	rcBounding.right=rcBounding.bottom = nHeight - 40;
	pt.x = 0*64;pt.y = 8*64;
	g_RabbitPooSprite.AddState(ST_DEFAULT, pt, 3, 50,&rcBounding);
	pt.x = 11*64;pt.y = 10*64;
	g_RabbitPooSprite.AddState(ST_DEAD, pt, 3, 50,&rcBounding);
	g_RabbitPooSprite.SetState(ST_DEFAULT);
	
	// --------------- Sheep Sprite -----------------------------//
	g_SheepSprite.CreateSprite(&g_pSpriteSurface, TYPE_PLAYER, nHeight,nWidth);
	pt.x = 5*64; pt.y =9*64 ;
	g_SheepSprite.AddState(ST_STAND_STILL, pt, 2, 60);
	rcBounding.top = 0;
	rcBounding.bottom = nHeight-10;
	rcBounding.left = 10;
	rcBounding.right= nWidth - 20;
	pt.x = 6*64; pt.y =6*64;
	g_SheepSprite.AddState(ST_WALK_UP, pt, 3, 10,&rcBounding);
	rcBounding.top = 10;
	rcBounding.bottom = nHeight-10;
	
	pt.x = 64*9;pt.y = 6*64;
	g_SheepSprite.AddState(ST_WALK_DOWN, pt, 3, 10,&rcBounding);
	
	rcBounding.top = 10;
	rcBounding.bottom = nHeight - 20;
	rcBounding.left = 0;
	rcBounding.right=nWidth - 10;
	pt.x = 3*64;pt.y = 6*64;
	g_SheepSprite.AddState(ST_WALK_LEFT, pt, 3, 10,&rcBounding);
	pt.x = 64*0;pt.y = 6*64;
	rcBounding.left = 10;
	rcBounding.right=nWidth-10;
	
	g_SheepSprite.AddState(ST_WALK_RIGHT, pt, 3, 10,&rcBounding);
	pt.x = 64 * 8; pt.y = 9 * 64;
	g_SheepSprite.AddState(ST_KILL, pt, 4, 20);
	g_SheepSprite.MoveTo(1 * MAZETEXTURE_WIDTH, 19 * MAZETEXTURE_HEIGHT);
	g_SheepSprite.m_pfnDead = DeadPig;
	g_SheepSprite.m_Movement.m_pfnCollision = IsHit;
	
	g_SheepPooSprite.CreateSprite(&g_pSpriteSurface, TYPE_POO, nHeight,nWidth);
	rcBounding.top = rcBounding.left = 20;
	rcBounding.right=rcBounding.bottom = nHeight - 40;
	pt.x = 0*64;pt.y = 9*64;
	g_SheepPooSprite.AddState(ST_DEFAULT, pt, 3, 50,&rcBounding);
	pt.x = 11*64;pt.y = 10*64;
	g_SheepPooSprite.AddState(ST_DEAD, pt, 3, 50,&rcBounding);
	g_SheepPooSprite.SetState(ST_DEFAULT);
	
	// --------------- Enemy Sprites -----------------------------//
	
	g_EnemySpriteManager.SetCollAndPathFn(IsHit, FindPath);
	
	rcBounding.left =  10;
	rcBounding.top =0;
	rcBounding.right = SPRITE_WIDTH - 20;
	rcBounding.bottom = SPRITE_HEIGHT ;
	
    g_Enemy1Sprite.CreateSprite(&g_pSpriteSurface, TYPE_ENEMY1, nHeight,nWidth);
	pt.x = 6*64;pt.y = 0*64;
	g_Enemy1Sprite.AddState(ST_WALK_UP, pt, 2, 20,&rcBounding);
	pt.x = 3*64;pt.y = 0*64;
	g_Enemy1Sprite.AddState(ST_WALK_LEFT, pt, 3, 20,&rcBounding);
	pt.x = 0*64;pt.y = 0*64;
	g_Enemy1Sprite.AddState(ST_WALK_RIGHT, pt, 3, 20,&rcBounding);
	pt.x = 8*64;pt.y = 0*64;
	g_Enemy1Sprite.AddState(ST_WALK_DOWN, pt, 2, 20,&rcBounding);
	pt.x = 10*64;pt.y = 0*64;
	g_Enemy1Sprite.AddState(ST_KILL, pt, 3, 100);
	g_Enemy1Sprite.m_pfnDead= DeadEnemy;
	g_Enemy1Sprite.m_nPoints = 100;
	
	
    g_Enemy2Sprite.CreateSprite(&g_pSpriteSurface, TYPE_ENEMY2, nHeight,nWidth);
	pt.x = 6*64;pt.y = 1*64;
	g_Enemy2Sprite.AddState(ST_WALK_UP, pt, 2, 20,&rcBounding);
	pt.x = 3*64;pt.y = 1*64;
	g_Enemy2Sprite.AddState(ST_WALK_LEFT, pt, 3, 20,&rcBounding);
	pt.x = 0*64;pt.y = 1*64;
	g_Enemy2Sprite.AddState(ST_WALK_RIGHT, pt, 3, 20,&rcBounding);
	pt.x = 8*64;pt.y = 1*64;
	g_Enemy2Sprite.AddState(ST_WALK_DOWN, pt, 2, 20,&rcBounding);
	pt.x = 10*64;pt.y = 1*64;
	g_Enemy2Sprite.AddState(ST_KILL, pt, 3, 100);
	g_Enemy2Sprite.m_pfnDead= DeadEnemy;
	g_Enemy2Sprite.m_nPoints = 100;
	
    g_Enemy3Sprite.CreateSprite(&g_pSpriteSurface, TYPE_ENEMY3, nHeight,nWidth);
	pt.x = 6*64;pt.y = 2*64;
	g_Enemy3Sprite.AddState(ST_WALK_UP, pt, 2, 20,&rcBounding);
	pt.x = 3*64;pt.y = 2*64;
	g_Enemy3Sprite.AddState(ST_WALK_LEFT, pt, 3, 20,&rcBounding);
	pt.x = 0*64;pt.y = 2*64;
	g_Enemy3Sprite.AddState(ST_WALK_RIGHT, pt, 3, 20,&rcBounding);
	pt.x = 8*64;pt.y = 2*64;
	g_Enemy3Sprite.AddState(ST_WALK_DOWN, pt, 2, 20,&rcBounding);
	pt.x = 10*64;pt.y = 2*64;
	g_Enemy3Sprite.AddState(ST_KILL, pt, 3, 100);
	g_Enemy3Sprite.m_pfnDead= DeadEnemy;
	g_Enemy3Sprite.m_nPoints = 100;
	g_EnemySpriteManager.AddSprite(&g_Enemy3Sprite);
	
    g_Enemy4Sprite.CreateSprite(&g_pSpriteSurface, TYPE_ENEMY4, nHeight,nWidth);
	pt.x = 6*64;pt.y = 3*64;
	g_Enemy4Sprite.AddState(ST_WALK_UP, pt, 2, 20,&rcBounding);
	pt.x = 3*64;pt.y = 3*64;
	g_Enemy4Sprite.AddState(ST_WALK_LEFT, pt, 3, 20,&rcBounding);
	pt.x = 0*64;pt.y = 3*64;
	g_Enemy4Sprite.AddState(ST_WALK_RIGHT, pt, 3, 20,&rcBounding);
	pt.x = 8*64;pt.y = 3*64;
	g_Enemy4Sprite.AddState(ST_WALK_DOWN, pt, 2, 20,&rcBounding);
	pt.x = 10*64;pt.y =3*64;
	g_Enemy4Sprite.AddState(ST_KILL, pt, 3, 100);
	g_Enemy4Sprite.m_pfnDead= DeadEnemy;
	g_Enemy4Sprite.m_nPoints = 200;
	g_EnemySpriteManager.AddSprite(&g_Enemy4Sprite);
	
    g_Enemy5Sprite.CreateSprite(&g_pSpriteSurface, TYPE_ENEMY4, nHeight,nWidth);
	pt.x = 6*64;pt.y = 3*64;
	g_Enemy5Sprite.AddState(ST_WALK_UP, pt, 2, 20,&rcBounding);
	pt.x = 3*64;pt.y = 3*64;
	g_Enemy5Sprite.AddState(ST_WALK_LEFT, pt, 3, 20,&rcBounding);
	pt.x = 0*64;pt.y = 3*64;
	g_Enemy5Sprite.AddState(ST_WALK_RIGHT, pt, 3, 20,&rcBounding);
	pt.x = 8*64;pt.y = 3*64;
	g_Enemy5Sprite.AddState(ST_WALK_DOWN, pt, 2, 20,&rcBounding);
	pt.x = 10*64;pt.y =3*64;
	g_Enemy5Sprite.AddState(ST_KILL, pt, 3, 100);
	g_Enemy5Sprite.m_pfnDead= DeadEnemy;
	g_Enemy5Sprite.m_nPoints = 200;
	g_EnemySpriteManager.AddSprite(&g_Enemy5Sprite);
	
	
	
	g_SpecialSprite.CreateSprite(&g_pSpriteSurface, TYPE_SPECIAL, nHeight,nWidth);
	pt.x = 5*64;pt.y = 10*64;
	g_SpecialSprite.AddState(ST_FOOD1, pt, 1, 100);
	pt.x = 6*64;pt.y = 10*64;
	g_SpecialSprite.AddState(ST_FOOD2, pt, 1, 100);
	pt.x = 7*64;pt.y = 10*64;
	g_SpecialSprite.AddState(ST_FOOD3, pt, 1, 100);
	pt.x = 8*64;pt.y = 10*64;
	g_SpecialSprite.AddState(ST_FOOD4, pt, 1, 100);
	pt.x = 9*64;pt.y = 10*64;
	g_SpecialSprite.AddState(ST_FOOD5, pt, 1, 100);
	pt.x = 10*64;pt.y = 10*64;
	g_SpecialSprite.AddState(ST_FOOD6, pt, 1, 100);

	pt.x = 3*64;pt.y = 8*64;
	g_SpecialSprite.AddState(ST_KEY, pt, 2, 50);
	pt.x = 2*64;pt.y = 10*64;
	g_SpecialSprite.AddState(ST_DOOR, pt, 3, 30);
	pt.x = 3*64;pt.y = 7*64;
	g_SpecialSprite.AddState(ST_KILL, pt, 2, 100);
	g_SpecialSprite.m_nPoints = 200;
	g_SpecialSprite.m_pfnDead = DeadSpecial;
	g_SpecialSprite.m_pfnKill = KillSpecial;
	
	g_BulletSprite.CreateSprite(&g_pSpriteSurface, TYPE_BULLET, nHeight,nWidth);
	rcBounding.top = rcBounding.left = 20;
	rcBounding.right=rcBounding.bottom = nHeight - 40;
	pt.x = 0*64;pt.y = 10*64;
	g_BulletSprite.AddState(ST_DEFAULT, pt, 2, 30, &rcBounding);
	pt.x = 11*64;pt.y = 10*64;
	g_BulletSprite.AddState(ST_KILL, pt, 1, 10);
	g_BulletSprite.m_Movement.m_pfnCollision = IsHit;
	g_BulletSprite.m_Movement.m_nPathFindDelay = 5000;
	g_BulletSprite.m_Movement.m_pfnFindPath=BulletFindPath;
	
	g_BulletSprite.SetState(ST_KILL);
/*
	g_Enemy1Sprite.EnableBorder(true);
	g_Enemy2Sprite.EnableBorder(true);
	g_Enemy3Sprite.EnableBorder(true);
	g_PigSprite.EnableBorder(true);
	g_RabbitSprite.EnableBorder(true);
	g_SheepSprite.EnableBorder(true);
	g_BulletSprite.EnableBorder(true);
*/
}

void InitLevel()
{
	if (g_nCurrLevel+1 > g_nNoOfLevels) {
		g_nGameState = GAMESTATE_GAMEOVERGOOD;
		LoadJPEG(true, GAMEOVERGOODFILENAME,  &g_pSplashSurface);
		return;
	}
	int nNoOfEnemies = g_pLevel[g_nCurrLevel].nNoOfEnemys;
	g_Maze.LoadMaze(g_pLevel[g_nCurrLevel++].szLevelFile);
	g_nNoOfEnemies = 10;
	
	SAFE_DELETE( g_pScoreTextSurface );
	wsprintf((char*)g_szScore, (char*)GAMESCORE_TEXT, g_nScore);
	HFONT hFont = GetGameFont();
    g_pDisplay->CreateSurfaceFromText( &g_pScoreTextSurface, hFont, (char*)g_szScore, 
		RGB(0,0,0), RGB(255, 255, 0) );
	
		/*	
		OutputDebugString("\n-----------\n");
		char szDebug[100];
		wsprintf (szDebug,"g_nRows %d, g_nCols :%d Sizeof %d\n",g_nRows,g_nCols,sizeof(short[g_nCols][g_nRows]));
		OutputDebugString(szDebug);
		for (int i=0; i < g_nRows; i++) {
		for(int j=0; j <g_nCols; j++) {
		if (g_nPathArray[i][j] !=0) 
		szDebug[j]='1';
		else
		szDebug[j]='0';
		}
		szDebug[j]='\n';
		szDebug[j+1]='\0';
		OutputDebugString(szDebug);
		}
		OutputDebugString("-----------\n");
	*/
    g_nNoOfSpecials = NO_OF_SPECIALS;
	
	SAFE_DELETE(g_pLevelTextSurface);
    g_pDisplay->CreateSurfaceFromText( &g_pLevelTextSurface, hFont, g_Maze.GetName(), 
		RGB(0,0,0), RGB(255, 255, 0) ) ;
	
	POINT pt= { 0*64, 3*64 };
	g_pPlayerSprite->MoveTo(1 * MAZETEXTURE_WIDTH, 19 * MAZETEXTURE_HEIGHT);
    g_pPlayerSprite->SetState(ST_WALK_UP, true);
	g_pPlayerSprite->m_Movement.m_dx=0;
	g_pPlayerSprite->m_Movement.m_dy=0;
	
	g_pPlayerSprite->m_Movement.m_nInvulnerable=INVULNERABLE_DELAY;
	g_pPooSprite->SetState(ST_DEAD, true);
	
	g_EnemySpriteManager.Destroy();
	
	if (nNoOfEnemies) {
		nNoOfEnemies--;
		pt= g_Maze.GetRandDeployPoint();
		pt.x *= MAZETEXTURE_WIDTH;
		pt.y *= MAZETEXTURE_HEIGHT;
		g_Enemy1Sprite.MoveTo(pt);
		g_Enemy1Sprite.m_Movement.m_dx = -1;
		g_Enemy1Sprite.m_Movement.m_nPathFindDelay = 1000;
		g_Enemy1Sprite.SetState(ST_WALK_LEFT, true);
		g_EnemySpriteManager.AddSprite(&g_Enemy1Sprite);
	}
	
	if (nNoOfEnemies) {
		nNoOfEnemies--;
		pt= g_Maze.GetRandDeployPoint();
		pt.x *= MAZETEXTURE_WIDTH;
		pt.y *= MAZETEXTURE_HEIGHT;
		g_Enemy2Sprite.MoveTo(pt);
		g_Enemy2Sprite.m_Movement.m_dx = 1;
		g_Enemy2Sprite.m_Movement.m_nPathFindDelay = 500;
		g_Enemy2Sprite.SetState(ST_WALK_RIGHT, true);
		g_EnemySpriteManager.AddSprite(&g_Enemy2Sprite);
	}
	if (nNoOfEnemies) {
		nNoOfEnemies--;
		pt= g_Maze.GetRandDeployPoint();
		pt.x *= MAZETEXTURE_WIDTH;
		pt.y *= MAZETEXTURE_HEIGHT;
		g_Enemy3Sprite.MoveTo(pt);
		g_Enemy3Sprite.m_Movement.m_dy = 1;
		g_Enemy3Sprite.m_Movement.m_nPathFindDelay = 300;
		g_Enemy3Sprite.SetState(ST_WALK_DOWN, true);
		g_EnemySpriteManager.AddSprite(&g_Enemy3Sprite);
	}
	if (nNoOfEnemies) {
		nNoOfEnemies--;
		pt= g_Maze.GetRandDeployPoint();
		pt.x *= MAZETEXTURE_WIDTH;
		pt.y *= MAZETEXTURE_HEIGHT;
		g_Enemy4Sprite.MoveTo(pt);
		g_Enemy4Sprite.m_Movement.m_dy = -1;
		g_Enemy4Sprite.m_Movement.m_nPathFindDelay = 200;
		g_Enemy4Sprite.SetState(ST_WALK_UP, true);
		g_EnemySpriteManager.AddSprite(&g_Enemy4Sprite);
	}	
	
	if (nNoOfEnemies) {
		nNoOfEnemies--;
		pt= g_Maze.GetRandDeployPoint();
		pt.x *= MAZETEXTURE_WIDTH;
		pt.y *= MAZETEXTURE_HEIGHT;
		g_Enemy5Sprite.MoveTo(pt);
		g_Enemy5Sprite.m_Movement.m_dy = 1;
		g_Enemy5Sprite.m_Movement.m_nPathFindDelay = 200;
		g_Enemy5Sprite.SetState(ST_WALK_DOWN, true);
		g_EnemySpriteManager.AddSprite(&g_Enemy5Sprite);
	}	
	
	
	pt= g_Maze.GetRandDeployPoint();
	pt.x *= MAZETEXTURE_WIDTH;
	pt.y *= MAZETEXTURE_HEIGHT;
	g_SpecialSprite.MoveTo(pt);
	g_SpecialSprite.SetState(ST_FOOD1, true);
	
//	SIZE szDim = { 64,64};
//	g_Maze.DisplayGrid(true);
//	g_Maze.DisplayDeployRects(szDim);
	g_Maze.Draw(g_pMazeSurface);
	
	SAFE_DELETE( g_pLifeTextSurface );
	wsprintf((char*)g_szLifeLeft, (char*)LIFE_LEFT_TEXT, g_nLivesLeft - 1);
    g_pDisplay->CreateSurfaceFromText( &g_pLifeTextSurface, hFont, (char*)g_szLifeLeft, 
		RGB(0,0,0), RGB(255, 255, 0) );
	
	DeleteObject(hFont);
}


//-----------------------------------------------------------------------------
// Name: FreeDirectDraw()
// Desc: Release all the DirectDraw objects
//-----------------------------------------------------------------------------
VOID FreeDirectDraw()
{
#ifdef DISPLAY_STATUS
    SAFE_DELETE( g_pTextSurface );
#endif
	SAFE_DELETE( g_pLifeTextSurface );
	SAFE_DELETE( g_pScoreTextSurface );
	SAFE_DELETE( g_pLevelTextSurface );
    SAFE_DELETE( g_pMazeSurface );
	SAFE_DELETE( g_pSpriteSurface );
	SAFE_DELETE( g_pSplashSurface);
    SAFE_DELETE( g_pDisplay );

	SAFE_DELETE( g_pSplashSound );
	SAFE_DELETE( g_pPickupSound );
    SAFE_DELETE( g_pSoundManager );
	SAFE_DELETE( g_pHandleInput );
}




//-----------------------------------------------------------------------------
// Name: MainWndProc()
// Desc: The main window procedure
//-----------------------------------------------------------------------------
LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch (msg)
    {
	case WM_COMMAND:
		switch( LOWORD(wParam) )
		{
		case IDM_TOGGLEFULLSCREEN:
			// Toggle the fullscreen/window mode
			if( g_bWindowed )
				GetWindowRect( hWnd, &g_rcWindow );
			
			g_bWindowed = !g_bWindowed;
			
			if( FAILED( InitDirectDrawMode( hWnd, g_bWindowed ) ) )
			{
				SAFE_DELETE( g_pDisplay );
				
				MessageBox( hWnd, TEXT("InitDirectDraw() failed. ")
					TEXT("The sample will now exit. "), TEXT("DirectDraw Sample"), 
					MB_ICONERROR | MB_OK );
				PostMessage( hWnd, WM_CLOSE, 0, 0 );
			}
			
			return 0L;
		case IDM_PAUSE:
			g_bActive = true - g_bActive;
			return 0L;
			
		case IDM_EXIT:
			// Received key/menu command to exit app
			PostMessage( hWnd, WM_CLOSE, 0, 0 );
			return 0L;
		}
		break; // Continue with default processing
		
        case WM_GETMINMAXINFO:
            {
                // Don't allow resizing in windowed mode.  
                // Fix the size of the window to 640x480 (client size)
                MINMAXINFO* pMinMax = (MINMAXINFO*) lParam;
				
                DWORD dwFrameWidth    = GetSystemMetrics( SM_CXSIZEFRAME );
                DWORD dwFrameHeight   = GetSystemMetrics( SM_CYSIZEFRAME );
                DWORD dwMenuHeight    = GetSystemMetrics( SM_CYMENU );
                DWORD dwCaptionHeight = GetSystemMetrics( SM_CYCAPTION );
				
                pMinMax->ptMinTrackSize.x = SCREEN_WIDTH  + dwFrameWidth * 2;
                pMinMax->ptMinTrackSize.y = SCREEN_HEIGHT + dwFrameHeight * 2 + 
					dwMenuHeight + dwCaptionHeight;
				
                pMinMax->ptMaxTrackSize.x = pMinMax->ptMinTrackSize.x;
                pMinMax->ptMaxTrackSize.y = pMinMax->ptMinTrackSize.y;
            }
            return 0L;
			
        case WM_MOVE:
            // Retrieve the window position after a move.  
            if( g_pDisplay )
                g_pDisplay->UpdateBounds();
			
            return 0L;
			
        case WM_SIZE:
            // Check to see if we are losing our window...
            if( SIZE_MAXHIDE==wParam || SIZE_MINIMIZED==wParam )
                g_bActive = FALSE;
            else
                g_bActive = TRUE;
			
            if( g_pDisplay )
                g_pDisplay->UpdateBounds();
            break;
			
        case WM_SETCURSOR:
            // Hide the cursor if in fullscreen 
            if( !g_bWindowed )
            {
                SetCursor( NULL );
                return TRUE;
            }
            break; // Continue with default processing
			
        case WM_QUERYNEWPALETTE:
            if( g_pDisplay && g_pDisplay->GetFrontBuffer() )            
            {
                // If we are in windowed mode with a desktop resolution in 8 bit 
                // color, then the palette we created during init has changed 
                // since then.  So get the palette back from the primary 
                // DirectDraw surface, and set it again so that DirectDraw 
                // realises the palette, then release it again. 
                LPDIRECTDRAWPALETTE pDDPal = NULL; 
                g_pDisplay->GetFrontBuffer()->GetPalette( &pDDPal );
                g_pDisplay->GetFrontBuffer()->SetPalette( pDDPal );
                SAFE_RELEASE( pDDPal );
            }
            break;
			
        case WM_EXITMENULOOP:
            // Ignore time spent in menu
            g_dwLastTick = timeGetTime();
            break;
			
        case WM_EXITSIZEMOVE:
            // Ignore time spent resizing
            g_dwLastTick = timeGetTime();
            break;
			
        case WM_SYSCOMMAND:
            // Prevent moving/sizing and power loss in fullscreen mode
            switch( wParam )
            {
			case SC_MOVE:
			case SC_SIZE:
			case SC_MAXIMIZE:
			case SC_MONITORPOWER:
				if( !g_bWindowed )
					return TRUE;
            }
            break;
            
			case WM_DESTROY:
				// Cleanup and close the app
				FreeDirectDraw();
				PostQuitMessage( 0 );
				return 0L;
				break;
    }
	
    return DefWindowProc(hWnd, msg, wParam, lParam);
}




//-----------------------------------------------------------------------------
// Name: ProcessNextFrame()
// Desc: Move the sprites, blt them to the back buffer, then 
//       flip or blt the back buffer to the primary buffer
//-----------------------------------------------------------------------------
HRESULT ProcessNextFrame( HWND hWnd )
{
    HRESULT hr;
	
    // Figure how much time has passed since the last time
    DWORD dwCurrTick = timeGetTime();
    DWORD dwTickDiff = dwCurrTick - g_dwLastTick;
	
    // Don't update if no time has passed 
    if( dwTickDiff == 0 )
		return S_OK; 
	
	g_dwLastTick = dwCurrTick;
	

	dwTickDiff = 17 - dwTickDiff;
	
	  if (dwTickDiff > 0 && dwTickDiff < 17)
	  Sleep(dwTickDiff);

//	Sleep(10);
	
    // Check the cooperative level before rendering
    if( FAILED( hr = g_pDisplay->GetDirectDraw()->TestCooperativeLevel() ) )
    {
        switch( hr )
        {
		case DDERR_EXCLUSIVEMODEALREADYSET:
		case DDERR_NOEXCLUSIVEMODE:
			// Do nothing because some other app has exclusive mode
			Sleep(10);
			return S_OK;
			
		case DDERR_WRONGMODE:
			// The display mode changed on us. Update the
			// DirectDraw surfaces accordingly
			return InitDirectDrawMode( hWnd, g_bWindowed );
        }
        return hr;
    }
	
    // Display the sprites on the screen
    if( FAILED( hr = DisplayFrame() ) )
    {
        if( hr != DDERR_SURFACELOST )
            return hr;
		
        // The surfaces were lost so restore them 
        RestoreSurfaces();
    }
	
    return S_OK;
}






//-----------------------------------------------------------------------------
// Name: DisplayFrame()
// Desc: Blts a the sprites to the back buffer, then it blts or flips the 
//       back buffer onto the primary buffer.
//-----------------------------------------------------------------------------
HRESULT DisplayFrame()
{
    HRESULT hr;
	
	
	if( Input() )
		Input()->UpdateDevices();
	
    // Fill the back buffer with black, ignoring errors until the flip
    g_pDisplay->Clear( 0 );
	
	switch (g_nGameState)
	{
	case GAMESTATE_SPLASHSCREEN:
		{
			if (g_pSplashSound == NULL) {
				g_pSoundManager->Create( &g_pSplashSound, "WavSplashScreen", 0, GUID_NULL );
			}
			if (g_pSplashSound->IsSoundPlaying() == false) {
				g_pSplashSound->Play(0,DSBPLAY_LOOPING);
				LoadJPEG(true, SPLASHFILENAME,  &g_pSplashSurface);
			}
			g_pDisplay->Blt(0,0, g_pSplashSurface, NULL);
			break;
		}
	case GAMESTATE_CHOICE:
		{
			g_pDisplay->Blt(0,0, g_pSplashSurface, NULL);
			break;
		}
		
		
	case GAMESTATE_RUNNING:
		{
			LPDIRECTDRAWSURFACE7 lpdds = g_pDisplay->GetBackBuffer();

			if (g_nPooDelay)
				--g_nPooDelay;
			else {
				g_pPooSprite->SetState(ST_DEAD);
			}
			g_pDisplay->Blt( 0, 0, g_pMazeSurface, NULL );
			
			
			// Blt the help text on the backbuffer, ignoring errors until the flip
#ifdef DISPLAY_STATUS
			g_pDisplay->Blt( 10, 10, g_pTextSurface, NULL );
#endif
			g_pDisplay->Blt( 10, 710, g_pLifeTextSurface, NULL );
			g_pDisplay->Blt( SCREEN_WIDTH - g_pScoreTextSurface->GetSurfaceDesc().dwWidth - 10, 710, g_pScoreTextSurface, NULL );
			g_pDisplay->Blt( SCREEN_WIDTH/2 - g_pLevelTextSurface->GetSurfaceDesc().dwWidth/2, 710, g_pLevelTextSurface, NULL );
			
			
			g_pPooSprite->Update();
			g_pPlayerSprite->Update();
			g_SpecialSprite.Update();
			g_EnemySpriteManager.Update();
			g_BulletSprite.Update();
			g_EnemySpriteManager.KillSpritesColliWith(g_pPooSprite);
			
			if (g_pPlayerSprite->m_Movement.m_nInvulnerable == 0) {
				if (g_EnemySpriteManager.IsHit(g_pPlayerSprite->GetRect()) || g_BulletSprite.IsHit(g_pPlayerSprite->GetRect())) {
					g_pPlayerSprite->SetState(ST_KILL);
					g_BulletSprite.SetState(ST_KILL);
					g_pPlayerSprite->m_Movement.m_dx = g_pPlayerSprite->m_Movement.m_dy =0;
				}
				
			}
			if (g_SpecialSprite.IsHit(g_pPlayerSprite->GetRect()) && g_SpecialSprite.GetState()!=ST_KILL) {
				g_pPickupSound->Play(0,0);
				g_SpecialSprite.SetState(ST_KILL);
			}
			
			g_pPooSprite->Draw(lpdds);
			g_SpecialSprite.Draw(lpdds);
			g_pPlayerSprite->Draw(lpdds);
			g_BulletSprite.Draw(lpdds);
			g_EnemySpriteManager.Draw(lpdds);
			break;
		}
	case GAMESTATE_GAMEOVERGOOD:
	case GAMESTATE_GAMEOVERBAD:
		{
			g_pDisplay->Blt(0,0, g_pSplashSurface, NULL);
		}
	}
	// Flip or blt the back buffer onto the primary buffer
	if( FAILED( hr = g_pDisplay->Present() ) )
		return hr;
	
	return S_OK;
}




//-----------------------------------------------------------------------------
// Name: RestoreSurfaces()
// Desc: Restore all the surfaces, and redraw the sprite surfaces.
//-----------------------------------------------------------------------------
HRESULT RestoreSurfaces()
{
    HRESULT hr;
    LPDIRECTDRAWPALETTE  pDDPal = NULL; 
	
    if( FAILED( hr = g_pDisplay->GetDirectDraw()->RestoreAllSurfaces() ) )
        return hr;
	
	
	// No need to re-create the surface, just re-draw it.
#ifdef DISPLAY_STATUS
	if( FAILED( hr = g_pTextSurface->DrawText( NULL, (char*)g_szGameStatus, 
		0, 0, RGB(0,0,0), RGB(255, 255, 0) ) ) )
		return hr;
#endif
	
	if( FAILED( hr = g_pLifeTextSurface->DrawText( NULL, (char*)g_szLifeLeft, 
		0, 0, RGB(0,0,0), RGB(255, 255, 0) ) ) )
		return hr;
	
	if( FAILED( hr = g_pScoreTextSurface->DrawText( NULL, (char*)g_szScore, 
		0, 0, RGB(0,0,0), RGB(255, 255, 0) ) ) )
		return hr;
	if( FAILED( hr = g_pLevelTextSurface->DrawText( NULL, g_Maze.GetName(), 
		0, 0, RGB(0,0,0), RGB(255, 255, 0) ) ) )
		return hr;
	
	
	g_Maze.Draw(g_pMazeSurface);
	if( FAILED( hr = g_pSpriteSurface->DrawBitmap( "Sprite.bmp"/*MAKEINTRESOURCE( IDB_SPRITE )*/,
		0, 0 ) ) )
        return hr;
	
	if (g_nGameState == GAMESTATE_SPLASHSCREEN) {
		LoadJPEG(true, SPLASHFILENAME,  &g_pSplashSurface);
	}
	if (g_nGameState == GAMESTATE_CHOICE) {
		LoadJPEG(true, CHOICEFILENAME,  &g_pSplashSurface);
	}
	if (g_nGameState == GAMESTATE_GAMEOVERGOOD) {
		LoadJPEG(true, GAMEOVERGOODFILENAME,  &g_pSplashSurface);
	}
	if (g_nGameState == GAMESTATE_GAMEOVERBAD) {
		LoadJPEG(true, GAMEOVERBADFILENAME,  &g_pSplashSurface);
	}
	
    return S_OK;
}
//16Bit Color conversion macros
#define RGB555(r, g, b) ((r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 10))
#define RGB565(r, g, b) ((r >> 3) | ((g >> 2) << 5) | ((b >> 3) << 11))

//16Bit Color Formats
#define PF_555  1
#define PF_565  2

//Color modes
#define C16BIT  16
#define C24BIT  24
#define C32BIT  32


//*************
//* Load JPEG *
//*************
bool LoadJPEG(bool bFromFile, LPCTSTR szName,  CSurface** ppSurface)
{
	//Error handle
	IJLERR jerr;
	int  nPixelFormat = PF_555;
	//Create the JPEG object
	JPEG_CORE_PROPERTIES jcprops;
	
	DDPIXELFORMAT DDPixelFormat;
	ZeroMemory(&DDPixelFormat, sizeof(DDPixelFormat));
	DDPixelFormat.dwSize = sizeof(DDPixelFormat);
	
	HRESULT Result = g_pDisplay->GetBackBuffer()->GetPixelFormat(&DDPixelFormat);
	if(Result != DD_OK)
	{
		MessageBox(g_hMainWnd, "Failed to retrieve pixel format", TITLE, MB_OK);
		return false;
	}
	
	
	//Get green bitmask and set pixel format    
	if((DDPixelFormat.dwGBitMask / 32) == 31)
		nPixelFormat = PF_555;
	else if((DDPixelFormat.dwGBitMask / 32) == 63)
		nPixelFormat = PF_565;
	
	
	//Initialize the JPEG object
	jerr = ijlInit(&jcprops);
	if (jerr != IJL_OK)
	{
		MessageBox(g_hMainWnd, "IJLInit problem", TITLE, MB_OK);
		return false;
	}
	
	//Load from File or Resource?
	if (bFromFile)
	{
		//Set the IJL data source as a filename
		jcprops.JPGFile = szName;
		
		//Read JPEG parameters from the file
		jerr = ijlRead(&jcprops, IJL_JFILE_READPARAMS);
	}
	else //(Location == FROM_RESOURCE) or integer ID of resource
	{
		//Resource variables
		BYTE* pmem;
		HGLOBAL hmem;
		DWORD size;
		HRSRC hres;
		
		
		hres = FindResource(NULL, szName, "JPEG");
		if (hres)
		{
			size = SizeofResource(NULL, hres);
			if (!size)
			{
				MessageBox(g_hMainWnd, "Error retrieving resource size",
					TITLE, MB_OK);
				return false;
			}
			hmem = LoadResource(NULL, hres);
			if (hmem == NULL)
			{
				MessageBox(g_hMainWnd, "Error loading resource", TITLE, MB_OK);
				return false;
			}
			pmem = (BYTE *)LockResource(hmem);
			if (pmem == NULL)
			{
				MessageBox(g_hMainWnd, "Error locking resource", TITLE, MB_OK);
				return false;
			}
		}
		else
		{
			MessageBox(g_hMainWnd, "JPEG resource not found", TITLE, MB_OK);
			return false;
		}
		
		//Set the IJL data source as the resource buffer
		jcprops.JPGFile      = NULL;
		jcprops.JPGBytes     = pmem;
		jcprops.JPGSizeBytes = size;
		
		//Read JPEG parameters from the buffer
		jerr = ijlRead(&jcprops, IJL_JBUFF_READPARAMS);
	}
	
	//Make sure Parameter read was successful
	if (jerr != IJL_OK)
	{
		MessageBox(g_hMainWnd, "Error reading JPEG parameters", TITLE, MB_OK);
		return false;
	}
	
	//Prepare a 24Bit buffer to receive image data
	BYTE *buffer24;
	
	//Determine the required size
	long szbuff24 = (jcprops.JPGWidth * C24BIT + 7) / 8
		* jcprops.JPGHeight;
	
	//Resize the buffer
	buffer24 = new BYTE [szbuff24];
	if (buffer24 == NULL)
	{
		MessageBox(g_hMainWnd, "Memory Allocation Error", TITLE, MB_OK);
		return false;
	}
	
	//Set up the DIB specification for the JPEG decoder
	jcprops.DIBWidth    = jcprops.JPGWidth;
	jcprops.DIBHeight   = jcprops.JPGHeight; //Implies a bottom-up DIB.
	jcprops.DIBChannels = 3;
	jcprops.DIBColor    = IJL_BGR;
	jcprops.DIBPadBytes = IJL_DIB_PAD_BYTES(jcprops.JPGWidth,3);
	jcprops.DIBBytes    = reinterpret_cast<BYTE*>(buffer24);
	
	//Set the JPG color space ... this will always be somewhat of an
	//educated guess at best because JPEG is "color blind" (i.e.,
	//nothing in the bit stream tells you what color space the data was
	//encoded from. However, in this example we assume that we are
	//reading JFIF files which means that 3 channel images are in the
	//YCbCr color space and 1 channel images are in the Y color space.
	switch(jcprops.JPGChannels)
	{
	case 1: jcprops.JPGColor = IJL_G;
		break;
		
	case 3: jcprops.JPGColor = IJL_YCBCR;
		break;
		
	default:
		//This catches everything else, but no color twist will be
		//performed by the IJL.
		jcprops.DIBColor = (IJL_COLOR)IJL_OTHER;
		jcprops.JPGColor = (IJL_COLOR)IJL_OTHER;
		break;
	}
	
	//Read JPEG image data into our 24bit buffer
	if (bFromFile)
		jerr = ijlRead(&jcprops, IJL_JFILE_READWHOLEIMAGE);
	else
		jerr = ijlRead(&jcprops, IJL_JBUFF_READWHOLEIMAGE);
	
	//Make sure the read was successful
	if (jerr != IJL_OK)
	{
		MessageBox(g_hMainWnd, "Error reading JPEG image", TITLE, MB_OK);
		return false;
	}
	
	HBITMAP hbm;
	
	//Convert to current CLRMODE
	if (DDPixelFormat.dwRGBBitCount == C16BIT)
	{
		//Create a 16bit buffer
		WORD *buffer16;
		long szbuff16;
		
		//determine the size of our buffer
		szbuff16 = ((jcprops.JPGWidth * C16BIT + 7) / 8)
			* jcprops.JPGHeight;
		
		//resize the buffer and make sure resize works
		buffer16 = new WORD [szbuff16];
		if (buffer16 == NULL)
		{
			MessageBox(g_hMainWnd, "Error creating 16Bit buffer", TITLE, MB_OK);
			return false;
		}
		
		//Start at the beginning of the buffer
		long j = 0;
		
		//Step through the 24bit buffer
		//Retrieve 3 channels at a time and convert their values to 16bit
		for (long i = 0; i < szbuff24; i += 3)   
		{
			//Check the pixel format and write the color data
			//to the 16bit buffer. After the write, advance the
			//16bit buffer by one.
			if (nPixelFormat == PF_555)
				buffer16[j++] = RGB555(buffer24[i], buffer24[i + 1],
				buffer24[i + 2]);
			else
				buffer16[j++] = RGB565(buffer24[i], buffer24[i + 1],
				buffer24[i + 2]);
		}
		
		//Create the bitmap using the new 16bit buffer   
		hbm = CreateBitmap (jcprops.JPGWidth, jcprops.JPGHeight, 1,
			C16BIT, buffer16);
		if(hbm == NULL)
		{
			MessageBox(g_hMainWnd, "Failed to create 16Bit Bitmap", TITLE, MB_OK);
			return false;
		}
		
		//remove the new buffer
		delete buffer16;
	}
	else if (DDPixelFormat.dwRGBBitCount == C24BIT)
	{
		//The data we have from the JPEG is already 24bit
		//Just create the new bitmap from our buffer
		hbm = CreateBitmap (jcprops.JPGWidth, jcprops.JPGHeight, 1,
			C24BIT, buffer24);
		if(hbm == NULL)
		{
			MessageBox(g_hMainWnd, "Failed to create 24Bit Bitmap", TITLE, MB_OK);
			return false;
		}
	}
	else if (DDPixelFormat.dwRGBBitCount == C32BIT)
	{
		//Create a 32bit buffer
		BYTE *buffer32;
		long szbuff32;
		
		//determine the size of our buffer
		szbuff32 = ((jcprops.JPGWidth * C32BIT + 7) / 8)
			* jcprops.JPGHeight;
		
		//resize the buffer and make sure resize works
		buffer32 = new BYTE [szbuff32];
		if (buffer32 == NULL)
		{
			MessageBox(g_hMainWnd, "Error creating 32Bit buffer", TITLE, MB_OK);
			return false;
		}
		
		//Start at the beginning of the 24bit buffer
		long j = 0;
		
		//Step through the 32bit buffer, copying the 3 Channels from
		//the 24bit buffer. However, at the end of each channel, we
		//have to write an extra byte for the 32bit image's alpha
		//channel
		for (long i = 0; i < szbuff32; i += 4)   
		{
			buffer32[i + 0] = buffer24[j++]; //Blue channel
			buffer32[i + 1] = buffer24[j++]; //Green channel
			buffer32[i + 2] = buffer24[j++]; //Red channel
			buffer32[i + 3] = (BYTE)0x00;    //Alpha channel
		}
		
		//Create the bitmap using the new 32bit buffer   
		hbm = CreateBitmap (jcprops.JPGWidth, jcprops.JPGHeight, 1,
			C32BIT, buffer32);
		if(hbm == NULL)
		{
			MessageBox(g_hMainWnd, "Failed to create 32Bit Bitmap",
				TITLE, MB_OK);
			return false;
		}
		
		//remove the 32bit buffer
		delete buffer32;
	}
	else
	{
		MessageBox(g_hMainWnd,
			"Palettized modes not supported. Use a 16, 24, or 32 Bit display.",
			TITLE, MB_OK);
		return false;
	}
	
	//remove the old buffer
	delete buffer24;

	//If DirectDraw Surface is NULL, create it
	if (*ppSurface == NULL)
	{
		//Create the surface from our surface description
		Result = g_pDisplay->CreateSurface(ppSurface,jcprops.JPGWidth,jcprops.JPGHeight );
		if(Result != DD_OK)
		{
			MessageBox(g_hMainWnd, "Could not create surface", TITLE, MB_OK);
			return false;
		}
	}
	
	//Copy bitmap data to DirectDraw Surface
	(*ppSurface)->DrawBitmap(hbm, 0, 0, 0, 0);
	
	// clean up and destroy the JPEG Decompressor
	ijlFree(&jcprops);
	DeleteObject(hbm);
	return true;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Software Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions