/////////////////////////////////////////////////////////////////////
// CDXMappyDemo.cpp : Defines the entry point for the application.
/////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////
// Generated by the CDX Application Wizard
// By: Michael Rich [istan@alltel.net]
//
// With valuable help from:
//   Ioannis Karagiorgos, for the debugging help
//   Bil Simser, for the good ideas and constructive criticism
/////////////////////////////////////////////////////////////////////

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include <vector>				  // this is the include for the STL list
using namespace std;

#define CDXINCLUDEALL     // this define includes all headers, otherwise include one by one
#include <cdx.h>
#include "cdxmappy.h"
#include "cdxmenu.h"


// ----------------------------------------------------------------------------------
// Global Variables
// ----------------------------------------------------------------------------------
char szAppName[]   = "CDXMappyDemo by Ioannis Karagiorgos";
char szClassName[] = "CDXMappyDemoWndClass";

HINSTANCE	g_hInst;			// instance handle
HWND		g_hWnd;				// window handle

// Flags for the DirectDraw object
BOOL		g_bFullScreen   = FALSE; // running fullscreen?
BOOL		VSync           = TRUE;	// VSync on/off
BOOL		DrawBackground  = TRUE;	// transparent background map on/off
BOOL		IsMenuActive    = TRUE;	// is the menu active or the demo?
BOOL		TripleBuffer    = TRUE;	// triple buffering on/off
BOOL		BackBufferInVRAM= TRUE;// backbuffer in vram/sysram

// screen resolution and color depth
int			ScreenWidth   = 640,
			ScreenHeight  = 480,
			ScreenBPP     = 8;

// These are the flags if a key is pressed
int			keyup=0, keydn=0, keysp=0, keyen=0, keyf1=0, keyesc=0 , keyv=0 , keyb=0, keyf2=0;

// These are the flags if a mouse button is pressed
int			lmb = 0, rmb = 0;

// map coordinates
int			mapx=0, mapy=0;

// mouse pointer and menu variables
int			MouseX              = 16, 
            MouseY              = 16;
int			MouseActiveMenuItem = 0;
int			CurrentItem         = 0;

char		MapForeground[] = "map.fmp";           // Foreground Map
char		MapBackground[] = "parallax.bmp";      // Background bitmap


// video mode structure and list with video modes
typedef struct SVMODE { 
		DWORD Width; 
		DWORD Height;
		DWORD BPP;
} VMODE;

vector<VMODE *> ModesList;


#define MOUSECURSOR_WIDTH   32	  // Mouse-Cursor-Sprite-Width
#define MOUSECURSOR_HEIGHT  32	  // Mouse-Cursor-Sprite-Height


// ----------------------------------------------------------------------------------
// CDX Objects, remember to set them to 0 !
// ----------------------------------------------------------------------------------
CDXScreen	    * Screen     = 0;
CDXInput	    * Input      = 0;
CDXMappy	    * Map        = 0;
CDXMenu		    * Menu       = 0;
CDXMusic        * KillerMid  = 0;
CDXSprite       * Cursor     = 0;

BLKSTR			* blockInfo; // block structure for a CDXMappy tile




// ----------------------------------------------------------------------------------
// Get and set the mouse cursor position
// ----------------------------------------------------------------------------------
void cdx_GetSetMousePosition()
{
	long PosX = 0, 
		 PosY = 0;
  
	Input->GetMousePos( &PosX, &PosY );			// Get Mouse position

	if( Input->GetKeyState(CDXKEY_MOUSELEFT))		// check left button
		lmb = 1; else lmb = 0;

	if( Input->GetKeyState(CDXKEY_MOUSERIGHT))	// check left button
		rmb = 1; else rmb = 0;

	// keep the mouse cursor within the visible area!
	if( PosX < 0 ) PosX = 0;
	if( PosY < 0 ) PosY = 0;

	if( PosX + MOUSECURSOR_WIDTH > ScreenWidth )
		PosX = ScreenWidth - MOUSECURSOR_WIDTH;
  
	if( PosY + MOUSECURSOR_HEIGHT > ScreenHeight )
		PosY = ScreenHeight - MOUSECURSOR_HEIGHT;
  
	// set sprite to current mouse position
	Cursor->SetPos( (int)PosX, (int)PosY );

	// keep the virtual mouse position also within the visible area
	Input->SetMousePos( PosX, PosY );

	MouseX = (int) PosX;
	MouseY = (int) PosY;

	// get the correct menu item according to the mouse position
	if( MouseY > 30 && MouseX >= 100 && MouseX <= 210 )
		MouseActiveMenuItem = (int) (MouseY / 20) - 1;
    else
		MouseActiveMenuItem = Menu->GetCurrentItem();
}



// ----------------------------------------------------------------------------------
// AdjustWinStyle - adjusts the window style according to the mode
// ----------------------------------------------------------------------------------
static void AdjustWinStyle()
{
	if (g_bFullScreen)
	{
		DWORD       dwStyle;

		// change window attributes
		dwStyle     = WS_POPUP | WS_VISIBLE;
		SetWindowLong( g_hWnd, 
					   GWL_STYLE, 
					   dwStyle);
		SetWindowPos(  g_hWnd, 
					   HWND_TOPMOST, 
					   0, 
					   0, 
					   GetSystemMetrics(SM_CXFULLSCREEN),
					   GetSystemMetrics(SM_CYFULLSCREEN), 
					   SWP_NOACTIVATE | SWP_NOZORDER);
	}
	else
	{
		RECT        rect = {0, 0, ScreenWidth , ScreenHeight};
		DWORD       dwStyle;

		// change window attributes
		dwStyle = GetWindowStyle(g_hWnd);
		dwStyle &= ~WS_POPUP;
		dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
		SetWindowLong(g_hWnd, GWL_STYLE, dwStyle);

		// resize the window so that the client area is 640x480
		AdjustWindowRectEx(&rect, GetWindowStyle(g_hWnd), GetMenu(g_hWnd) != NULL,
			GetWindowExStyle(g_hWnd));

		// just in case the window was moved off the visible area of the
		// screen.
		SetWindowPos(g_hWnd, NULL, 0, 0, rect.right-rect.left,
			rect.bottom-rect.top, SWP_NOMOVE | SWP_NOZORDER |
			SWP_NOACTIVATE);
		SetWindowPos(g_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
			SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
	}
}



// ----------------------------------------------------------------------------------
// Resets the flags for all keys and the mouse to 0 (means key/button not pressed)
// ----------------------------------------------------------------------------------
void ResetKeys( void )
{
	keyup  = 0;	// reset state for cursor up
	keydn  = 0;	// reset state for cursor down
	keysp  = 0;	// reset state for space key
	keyen  = 0;	// reset state for enter key
	keyf1  = 0;	// reset state for F1 key
	keyesc = 0;	// reset state for ESC key
	keyv   = 0;	// reset state for key V
	keyb   = 0;	// reset state for key B
	keyf2  = 0;	// reset state for F2 key

	lmb    = 0;	// reset state for left mouse button
	rmb    = 0;	// reset state for right mouse button
}



// ----------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------
void CreateObjects( void )
{
	DWORD	i , j;
	char	Text[256];
	VMODE	* Mode ,  * A , * B;

	Menu = new CDXMenu( );
	Menu->Create( Screen->GetBack( ) , 20 );
	Menu->GetSurface()->ChangeFont("Verdana", 0, 14, FW_BOLD);
	Menu->SetTitle( "use CURSOR keys and RETURN or MOUSE and LEFT BUTTON" , RGB( 0 , 255 , 0 ) );

	// get video mode list
	ModesList.clear( );
	for( i=0; i<Screen->GetNumberOfVideoModes( ); i++ )
	{
		Mode = new VMODE;
		Screen->GetVideoModeInformation( i , &Mode->Width , &Mode->Height , &Mode->BPP );
		if( Mode->Height > 240  && Mode->Height < 384 ) 
			delete Mode;
		else
			if( Mode->Width > 1024 )
				delete Mode; 
			else 
				ModesList.push_back( Mode );
	}

	// sort the video mode list by color depth, little bubble sort :-)
	for( i=0; i<ModesList.size( ); i++ )
		for( j=0; j<ModesList.size( )-1; j++ )
		{
			A = ModesList[ j ];
			B = ModesList[ j+1 ];
			if( A->BPP > B->BPP )
			{
				ModesList[ j ] = B;
				ModesList[ j+1 ] = A;
			}
		}

	// sort by height
	for( i=0; i<ModesList.size( ); i++ )
		for( j=0; j<ModesList.size( )-1; j++ )
		{
			A = ModesList[ j ];
			B = ModesList[ j+1 ];
			if( A->BPP != B->BPP ) continue;
			if( A->Height > B->Height )
			{
				ModesList[ j ] = B;
				ModesList[ j+1 ] = A;
			}
		}

	// set up the menu
	for( i = 0; i<ModesList.size( ); i++ )
	{
		if( i > 19 ) break;
		A = ModesList[ i ];
		sprintf( Text , "%i x %i x %i" , A->Width , A->Height , A->BPP );
		Menu->AddItem( Text , RGB( 255 , 0 , 0 ) , RGB( 255 , 255 , 255 ) );
	}

	Menu->SetCurrentItem(CurrentItem);

	// create the maps
	Map = new CDXMappy( );
	Map->SetColorKey( 0 );
	if( Map->LoadMap( Screen , MapForeground , 0 , 0 , 
                      Screen->GetWidth() , Screen->GetHeight() ) ==  -1 )
        CDXError( Screen , "Could not load map!" );


    if( Map->CreateParallax( MapBackground )  == FALSE )
        CDXError( Screen , "Could not load parallax bitmap" );

	Map->MapInitAnims( );

    sprintf( Text , "MapWidth = %i\n" , Map->GetMapWidth( ) );
    sprintf( Text , "MapHeight = %i\n" , Map->GetMapHeight( ) );

    sprintf( Text , "MapBlockWidth = %i\n" , Map->GetMapBlockWidth( ) );
    sprintf( Text , "MapBlockHeight = %i\n" , Map->GetMapBlockHeight( ) );

    sprintf( Text , "MapWidthInBlocks = %i\n" , Map->GetMapWidthInBlocks( ) );
    sprintf( Text , "MapHeightInBlocks = %i\n" , Map->GetMapHeightInBlocks( ) );

	mapx = (Map->GetMapWidth() - Screen->GetWidth() ) / 2;
	mapy = (Map->GetMapHeight()  - Screen->GetHeight() ) / 2;

	// Load cursor sprite
	Cursor = new CDXSprite();
	Cursor->Create(Screen, "MOUSE.BMP", MOUSECURSOR_WIDTH, MOUSECURSOR_HEIGHT, 1, CDXMEM_SYSTEMONLY);
	if(Cursor==NULL)
        CDXError( Screen , "Could not load cursor bitmap!" );
    Cursor->SetFrame(0);
    Cursor->SetColorKey();
}


// ----------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------
void StartVideoMode( void )
{
	if(g_bFullScreen)
	{
		// start app fullscreen
		if( Screen->CheckIfVideoModeExists( ScreenWidth , ScreenHeight , ScreenBPP ) == TRUE )
		{
			if(FAILED(Screen->CreateFullScreen(g_hWnd, ScreenWidth, ScreenHeight, ScreenBPP)))
				CDXError( NULL , "Could start full screen video mode" );
		}
		else CDXError (NULL, "Video Mode does not exists");
	}		
	else 
	{
		// start app in a window
		if (FAILED(Screen->CreateWindowed(g_hWnd, 640, 480))) 
		CDXError( Screen , "Could not start windowed mode " );
	}
}


// ----------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------
void ChangeVideoMode( void )
{
    // before the video mode is changed, we have to destroy all surfaces
	SAFEDELETE( Cursor );
	SAFEDELETE( Map );
	SAFEDELETE( Menu );

    // set the new video mode
	if( g_bFullScreen )
	{
		Screen->GetDD()->RestoreDisplayMode();
		AdjustWinStyle();
		Screen->CreateBackBufferInVRAM( BackBufferInVRAM );
		Screen->SetTripleBuffering( TripleBuffer );
		if (FAILED(Screen->ChangeVideoMode(ScreenWidth , ScreenHeight , ScreenBPP )))
			CDXError (Screen, "Could not change to Full Screen");
		CDXLOG (">>> Full screen done <<<");
	}
	else
	{
		Screen->GetDD()->RestoreDisplayMode();
		AdjustWinStyle();
		Screen->CreateBackBufferInVRAM( BackBufferInVRAM );
		if (FAILED(Screen->ChangeVideoMode(ScreenWidth , ScreenHeight, 0 )))
			CDXError (Screen, "Could not set window mode");
		
	}
	
    // recreate the surfaces we destroyed before
	CreateObjects( );
}



// ----------------------------------------------------------------------------------
// cdx_Init - handles initialization of the CDX objects
// ----------------------------------------------------------------------------------
BOOL cdx_Init()
{
	// Create the CDXSreen object
	Screen = new CDXScreen();
	if (Screen==NULL) 
        CDXError( NULL , "Could not initialize screen object!" );

    // Load a Midi File
    KillerMid = new CDXMusic( g_hWnd );
    //KillerMid->Play( "Killer.mid" );      // Seal's "Killer" Song

	StartVideoMode( );
	CreateObjects ();

	// create our input object
	Input = new CDXInput();
	if (Input==NULL) 
        CDXError( Screen , "Could not initialize direct input object" );

	// Create input devices
	if(FAILED(Input->Create(g_hInst, g_hWnd)) )
        CDXError( Screen , "Could not create direct input devices!" );

	return TRUE;
}



// ----------------------------------------------------------------------------------
// cdx_DeInit - handles cleanup of CDX objects
// ----------------------------------------------------------------------------------
void cdx_DeInit()
{
	KillerMid->Stop();          // stop the music file playing

	SAFEDELETE( KillerMid );    // destroy CDXMusic object
	SAFEDELETE( Cursor );       // destroy mouse cursor surface
	SAFEDELETE( Map );          // destroy map
	SAFEDELETE( Menu );         // destroy menu object

	SAFEDELETE(Input);	        // destroy CDXInput object
	SAFEDELETE(Screen);         // at the end, destroy the CDXScreen object !
}



// ----------------------------------------------------------------------------------
// cdx_DoMenu - performs drawing of the menu
// ----------------------------------------------------------------------------------
void cdx_DoDemo()
{
    char		Text[256];
    int			curXTile  = 0;
    int			curYTile  = 0;
    static int	time      = 0;
    static int	delay;
    static int	FrameSkip =60;
  
    Input->Update();				// read input from devices
    cdx_GetSetMousePosition();	// Get and set the mouse cursor position

    // if Escape is pressed, back to menu
    if (keyesc == 1 )
    {
        ResetKeys();
  	    ScreenWidth  = 640;
	    ScreenHeight = 480;
	    ScreenBPP    = 8;
	    ChangeVideoMode( );
	    IsMenuActive = TRUE;
	    return;
    }

	// if space is pressed, switch to the next video mode
	if( keysp == 1 )
	{
		VMODE	* Mode;

		CurrentItem ++;
		if( CurrentItem >= Menu->GetItemCount() )
			CurrentItem = 0;
		Mode          = ModesList[ CurrentItem ];
		ScreenWidth   = Mode->Width;
		ScreenHeight  = Mode->Height;
		ScreenBPP     = Mode->BPP;
		g_bFullScreen = TRUE;
		ChangeVideoMode( );
		ResetKeys();
		return;
	}

	// Alt+Enter switches modes
	if ((Input->GetKeyState(CDXKEY_LEFTALT) || Input->GetKeyState(CDXKEY_RIGHTALT))
			&& Input->GetKeyState(CDXKEY_ENTER))
	{
		g_bFullScreen = !g_bFullScreen;
		ChangeVideoMode( );
		Input->FlushKeyboardData();		// clear any data from the keyboard
	}

	// key V toggles VSync
	if( keyv == 1 )
		VSync = !VSync;

	// key B toggles the background map drawing
	if( keyb == 1 )
		DrawBackground = !DrawBackground;

	// F1 key toggles triple buffering
	if( keyf1 == 1 )
	{
		TripleBuffer = !TripleBuffer;
		ChangeVideoMode( );
		ResetKeys();
		return;
	}

	// F2 key toggles backbuffer in VRAM/SYSRAM
	if( keyf2 == 1 )
	{ 
		BackBufferInVRAM = !BackBufferInVRAM;
		ChangeVideoMode( );
		ResetKeys();
		return;
	}

	// cursor left or mouse movement move the map
	if( GetAsyncKeyState( VK_LEFT ) || MouseX == 0 )
	{
		if( mapx > 0 )
			--mapx;
	}

	// cursor up or mouse movement move the map
	if( GetAsyncKeyState( VK_UP ) || MouseY == 0 )
	{
		if( mapy > 0 )
			--mapy;
	}

	// cursor right or mouse movement move the map
	if( GetAsyncKeyState( VK_RIGHT ) || MouseX ==  ScreenWidth - MOUSECURSOR_WIDTH )
	{
		if( mapx + Screen->GetWidth() < Map->GetMapWidth() )
			++mapx;
	}

	// cursor down or mouse movement move the map
	if( GetAsyncKeyState( VK_DOWN ) || MouseY == ScreenHeight - MOUSECURSOR_HEIGHT )
	{
		if( mapy+ Screen->GetHeight() < Map->GetMapHeight() )
			++mapy;
	}

	Map->MapMoveTo( mapx , mapy );	// move map

	// draw  map and if selected the parallax background
	if( DrawBackground )
	{
		if( Map->DrawParallax(Screen->GetBack()) ) 
            Map->RestoreParallax();
		if( Map->MapDrawBGT(Screen->GetBack()) ) 
            Map->MapRestore();
	}
	else
		if( Map->MapDrawBG(Screen->GetBack()) ) Map->MapRestore();

    // draw map foreground layer
	if( Map->MapDrawFG (Screen->GetBack()) ) Map->MapRestore();

    // update animated tiles
	Map->MapUpdateAnims( );

	// top left black rectangle 
	Screen->GetBack()->FillRect( 0 , 0 , 170 , 170 , RGB( 0 , 0 , 0 ) );

	// top right black rectangle 
	Screen->GetBack()->FillRect( Screen->GetWidth()-160 , 0 , Screen->GetWidth() , 20 , RGB( 0 , 0 , 0 ) );

	// bottom black rectangle 
	Screen->GetBack()->FillRect( 0 , Screen->GetHeight() - 20, Screen->GetWidth() , Screen->GetHeight() , RGB( 0 , 0 , 0 ) );

    Screen->GetBack()->GetDC( );
	Screen->GetBack()->SetFont( );
	
    // output screen resolution
	if( !g_bFullScreen )
		sprintf( Text , "Mode %ix%i" , ScreenWidth , ScreenHeight );
	else
		sprintf( Text , "Mode %ix%ix%i" , ScreenWidth , ScreenHeight , ScreenBPP );

	Screen->GetBack()->TextXY( 0 , 0 , RGB( 255 , 255 , 255 ) , Text );
	Screen->GetBack()->TextXY( 0 , 18 , RGB( 255 , 255 , 255 ) , "SPACE for next mode" );
	Screen->GetBack()->TextXY( 0 , 36 , RGB( 255 , 255 , 255 ) , "ESC = back to menu" );

    // output triple buffering information
	if( TripleBuffer )
		Screen->GetBack()->TextXY( 0 , 54 , RGB( 255 , 255 , 255 ) , "Triplebuf on/F1=toggle" );
	else
		Screen->GetBack()->TextXY( 0 , 54 , RGB( 255 , 255 , 255 ) , "Triplebuf off/F1=toggle" );

    // output fullscreen/windowed information
	if( g_bFullScreen )
		Screen->GetBack()->TextXY( 0 , 72 , RGB( 255 , 255 , 255 ) , "ALT/RETURN for windowed" );
	else
		Screen->GetBack()->TextXY( 0 , 72 , RGB( 255 , 255 , 255 ) , "ALT/RETURN for fullscreen" );
  
    // output VSync information
	if( VSync )
		Screen->GetBack()->TextXY( 0 , 90 , RGB( 255 , 255 , 255 ) , "VSync on / V=toggle" );
	else
		Screen->GetBack()->TextXY( 0 , 90 , RGB( 255 , 255 , 255 ) , "VSync off / V=toggle" );
  
    // output background map information
	if( DrawBackground )
		Screen->GetBack()->TextXY( 0 , 108 , RGB( 255 , 255 , 255 ) , "Backgr on / B=toggle" );
	else
		Screen->GetBack()->TextXY( 0 , 108 , RGB( 255 , 255 , 255 ) , "Backgr off / B=toggle" );
  
    // output backbuffer information
	if( BackBufferInVRAM )
		Screen->GetBack()->TextXY( 0 , 126 , RGB( 255 , 255 , 255 ) , "Buffer in VRAM/F2=toggle" );
	else
		Screen->GetBack()->TextXY( 0 , 126 , RGB( 255 , 255 , 255 ) , "Buffer in SYSRAM/F2=toggle" );

    // output frames per second 
	sprintf( Text , "%i fps" , (int)((60000.0/delay)+0.5) );
	Screen->GetBack()->TextXY( 0 , 144 , RGB( 255 , 255 , 255 ) , Text );

	// print mouse information top right
	sprintf( Text, "Mouse X/Y:%4d/%4d", MouseX, MouseY );
    Screen->GetBack()->TextXY( Screen->GetWidth()-160, 0, RGB( 255, 255, 255 ), Text );
    curXTile = (MouseX+mapx) / (int)Map->GetMapBlockWidth();
    curYTile = (MouseY+mapy) / (int)Map->GetMapBlockHeight();

    // output information about current map block
    blockInfo = Map->MapGetBlock( curXTile, curYTile );
    sprintf( Text, "Tile at X=%d, Y=%d block flag is TopL=%d, TopR=%d, Bot.L=%d, Bot.R=%d, Value=%i",
      curXTile, curYTile, blockInfo->tl, blockInfo->tr, blockInfo->bl, blockInfo->br , Map->MapGetTile(curXTile,curYTile));
    Screen->GetBack()->TextXY( 0, Screen->GetHeight() - 20, RGB( 255, 255, 255 ), Text );

    Screen->GetBack()->ReleaseDC( );
	Cursor->Draw(Screen->GetBack() , 0 , 0 , CDXBLT_TRANS );

	Screen->Flip( VSync );

    // update frames per second counter, it counts the time for 60 frames
	-- FrameSkip;
	if( FrameSkip == 0 )
	{
		FrameSkip = 60;
		delay = timeGetTime( ) - time;
		time = timeGetTime( );
	}

	ResetKeys();
}




// ----------------------------------------------------------------------------------
// cdx_DoMenu - performs drawing of the menu
// ----------------------------------------------------------------------------------
void cdx_DoMenu()
{
	char Text[256];
  
    // read input from devices
    Input->Update();

    // Get and set the mouse cursor position
    cdx_GetSetMousePosition();

    // if Escape is pressed, close the application
    if (keyesc == 1 )
    {
  	    ResetKeys();
	    SendMessage(g_hWnd, WM_CLOSE, 0, 0);
	    // return out as the code below is invalid now
	    return;
    }

    // Alt+Enter switches modes
    if ((Input->GetKeyState(CDXKEY_LEFTALT) || Input->GetKeyState(CDXKEY_RIGHTALT))
  	    	&& Input->GetKeyState(CDXKEY_ENTER))
    {
	    g_bFullScreen = !g_bFullScreen;
  	    ChangeVideoMode( );
	    // clear any data from the keyboard
	    Input->FlushKeyboardData();
    }

    // cursor up or mouse over menu item
    if( keyup == 1 || (MouseActiveMenuItem < Menu->GetCurrentItem() && Menu->GetCurrentItem() > 0 ))
  	    Menu->Up( );

    // cursor down or mouse over menu item
    if( keydn == 1 || (MouseActiveMenuItem > Menu->GetCurrentItem() && Menu->GetCurrentItem() < Menu->GetItemCount()) )
        Menu->Down( );
	
		// Enter or left mouse button
		if( keyen  == 1 || lmb == 1 )   
		{
			CurrentItem = Menu->GetCurrentItem();
			VMODE * Mode;
			Mode = ModesList[ Menu->Enter( ) ];
			ScreenWidth   = Mode->Width;
			ScreenHeight  = Mode->Height;
			ScreenBPP     = Mode->BPP;
			ChangeVideoMode( );
			IsMenuActive = FALSE;
			ResetKeys();
			return;
		}

		ResetKeys();

		Screen->GetBack()->Fill(0);     // clear the current frame
		Menu->Draw( 100 , 10 );
		Screen->GetBack()->GetDC( );
		Screen->GetBack()->SetFont( );
		Screen->GetBack()->TextXY( 270 , 70 ,  RGB( 255 , 255 , 255 ) , "(c) 1999 by Ioannis Karagiorgos" );
		Screen->GetBack()->TextXY( 270 , 100 ,  RGB( 255 , 255 , 255 ) , "ALT/RETURN switch windowed/fullscreen" );
		Screen->GetBack()->TextXY( 270 , 140 ,  RGB( 255 , 255 , 255 ) , "ESC to quit" );
		Screen->GetBack()->TextXY( 270 , 200 ,  RGB( 255 , 255 , 255 ) , "... mouse support by Martin Seibert" );
		sprintf( Text, "Mouse X/Y: %4d/%4d  CurItem/MaxItem: %d/%d", MouseX, MouseY, Menu->GetCurrentItem(), Menu->GetItemCount() );
		Screen->GetBack()->ReleaseDC( );
	    Cursor->Draw(Screen->GetBack() , 0 , 0 , CDXBLT_TRANS );

		Screen->Flip();	 // Flip the back buffer to the front
}



// ----------------------------------------------------------------------------------
// WinProc - handles application messages
// ----------------------------------------------------------------------------------
static long PASCAL WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch(message)
	{
		case WM_SETCURSOR:
			SetCursor( NULL );
			return 0;
			break;

		case WM_CHAR:
			if( (char)wParam == ' ' )
				keysp = 1;
			if( (char)wParam == 'v' )
				keyv = 1;
			if( (char)wParam == 'b' )
				keyb = 1;
			return 0;

		case WM_KEYUP:
			switch( (int)wParam )
			{
				case VK_UP :
				{
					keyup = 1;
					keydn = 0;
				}
				break;

				case VK_DOWN :
				{
					keyup = 0;
					keydn = 1;
				}
				break;

				case VK_F1:
					keyf1 = 1;
					break;

				case VK_F2:
					keyf2 = 1;
					break;

				case VK_ESCAPE:
					keyesc = 1;
					break;

				case VK_RETURN:
					keyen = 1;
					break;

			}
			return 0;

		case WM_CLOSE:
			cdx_DeInit();
		case WM_DESTROY:
			PostQuitMessage(0);
		return 0;

		default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
}



// ----------------------------------------------------------------------------------
// InitApp - Create the window and the CDX objects
// ----------------------------------------------------------------------------------
static BOOL InitApp(int nCmdShow)
{
	WNDCLASS WndClass;

	WndClass.style = CS_HREDRAW | CS_VREDRAW;
	WndClass.lpfnWndProc = WinProc;
	WndClass.cbClsExtra = 0;
	WndClass.cbWndExtra = 0;
	WndClass.hInstance = g_hInst;
	WndClass.hIcon = LoadIcon(g_hInst, "APPICON");
	WndClass.hCursor = LoadCursor(0, IDC_ARROW);
	WndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	WndClass.lpszMenuName = 0;
	WndClass.lpszClassName = szClassName;
	RegisterClass(&WndClass);

	g_hWnd = CreateWindowEx(
		WS_EX_TOPMOST,
		szClassName,
		szAppName,
 		WS_POPUP,
		0,
		0,
		GetSystemMetrics(SM_CXFULLSCREEN),
		GetSystemMetrics(SM_CYFULLSCREEN),
		NULL,
		NULL,
		g_hInst,
		NULL);

	if(!g_hWnd) return FALSE;

	if (!g_bFullScreen)
		AdjustWinStyle();


	ShowWindow(g_hWnd, nCmdShow);
	UpdateWindow(g_hWnd);

	return TRUE;
}



// ----------------------------------------------------------------------------------
// WinMain - inital function called by windows
// ----------------------------------------------------------------------------------
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
	MSG msg;

	// save the app instance
	g_hInst = hInstance;


	if(!InitApp(nCmdShow)) 
        CDXError( Screen , "Error in InitApp!" );

	if(!cdx_Init())
        CDXError( Screen , "Could not init cdx!" );

	while(1)
	{
		if(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
		{
			if(!GetMessage(&msg, NULL, 0, 0 )) return msg.wParam;
			TranslateMessage(&msg); 
			DispatchMessage(&msg);
		}
		else
		{
			if( IsMenuActive )
				cdx_DoMenu();
			else
				cdx_DoDemo();
		}
	}
}
