//////////////////////////////////////////////////////////////////////////////////
// Project Name:   [ CDX BitmapFont, CDXVertTextScroller and CDXHorizTextScroller Class Demo ]
// Author:         [ Ioannis Karagiorgos - karagior@pluto.fernuni-hagen.de ]
// Revision:       [ 1.00 ]
//////////////////////////////////////////////////////////////////////////////////


// This file was made with the CDXCreator 1.1b by Andreas Löffler.
// For updates or questions visit the CDX-Website at: http://www.cdx.sk

// You must link this program with: cdx.lib ddraw.lib dxguid.lib dinput.lib winmm.lib
// Have fun!

#include <windows.h>
#include <windowsx.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>

#define CDXINCLUDEALL
#include <CDX.h>


#include "CDXBitmapFont.h"
#include "CDXHorizTextScroller.h"
#include "CDXVertTextScroller.h"


#define PART1 1
#define PART2 2
#define PART3 3
#define PART4 4
#define PART5 5


CDXScreen   *   Screen;             // screen object
int             ActivePart;         // which part of the demo is running?
bool            EndProgram;         // indicates if the program should end
bool            NextPart;           // indicates if the app should switch to the next part
BOOL            bActive;            // Is the program running?
HWND            WindowHandle;       // used to terminate the application
bool            Left;               // flag for left or right scrolling

// needed for part1
CDXBitmapFont   * P1Font , * P1HintFont , * P1TextFont, * P1BlackFont;
CDXLayer        * P1Layer;
RECT            P1ClipRect = { 0 , 0 , 640 , 480 };

// needed for part2
CDXBitmapFont   * P2Font , * P2HintFont;
CDXLayer        * P2Layer;
CDXHorizTextScroller * P2Scroll1 , * P2Scroll2;
RECT            P2ClipRect1 = { 0 , 150 , 640 , 480 };
RECT            P2ClipRect2 = { 0 , 240 , 640 , 480 };


// needed for part3
CDXBitmapFont   * P3Font , * P3HintFont;
CDXLayer        * P3Layer;
CDXHorizTextScroller * P3Scroll;
int             P3OffsetArray[640];
RECT            P3ClipRect = { 0 , 250 , 640 , 480 };

// needed for part4
CDXBitmapFont   * P4Font , * P4HintFont;
CDXLayer        * P4Layer;
CDXHorizTextScroller * P4Scroll;
int             P4OffsetArray[640];
RECT            P4ClipRect = { 0 , 220 , 640 , 480 };

// needed for part5
CDXBitmapFont   * P5Font , * P5HintFont;
CDXLayer        * P5Layer;
CDXVertTextScroller * P5Scroll;
RECT            P5ClipRect = { 0 , 120 , 640 , 400 };

// --------------------------------------------------------------------------------------
// inits part1 of the demo
// --------------------------------------------------------------------------------------
void InitPart1( void )
{
	// create font Arial, Height=36, Color=Red
    // other attributes are default: ColorKey=0, Backgroundcolor=0,Attributes=FW_NORMAL,
    // SurfaceType = CDXMEM_VIDTHENSYS
    P1Font = new CDXBitmapFont( Screen , "Arial" , 36 , RGB( 190 , 0 , 0 ) );

    P1HintFont = new CDXBitmapFont( Screen , "Arial" , 50 , RGB( 0 , 0 , 190 ) ,
                                    0 , 0 , FW_BOLD );

    P1TextFont = new CDXBitmapFont( Screen , "Courier New" , 28 , RGB( 190 , 0 , 0 ) ,
                                    0 , 0 , FW_BOLD );

	// Because we're in 8-bit, we pass in "15" for the ColorKey parameter
	// (white), if we were in any higher bitdepth, we'd pass in 
	// RGB(255,255,255);
	P1BlackFont = new CDXBitmapFont( Screen, "Courier New" , 28 , RGB(0,0,0),
							15, RGB(255,255,255), FW_BOLD);

    P1Layer = new CDXLayer( );
	P1Layer->Create(Screen,"forest.bmp",CDXMEM_VIDTHENSYS);
}




// --------------------------------------------------------------------------------------
// inits part2 of the demo
// --------------------------------------------------------------------------------------
void InitPart2( void )
{
	// create font Arial, Height=36, Color=Red
    // other attributes are default: ColorKey=0, Backgroundcolor=0,Attributes=FW_NORMAL,
    // SurfaceType = CDXMEM_VIDTHENSYS
    P2Font = new CDXBitmapFont( Screen , "Arial" , 36 , RGB( 190 , 0 , 0 ) );

    P2HintFont = new CDXBitmapFont( Screen , "Arial" , 50 , RGB( 0 , 0 , 190 ) ,
                                    0 , 0 , FW_BOLD );

    P2Layer = new CDXLayer( );
	P1Layer->Create(Screen,"forest.bmp",CDXMEM_VIDTHENSYS);

    P2Scroll1 = new CDXHorizTextScroller( Screen , &P2ClipRect1 ,
                                          "This is a demonstration of the CDXHorizTextScroller class, this one wraps around when it reaches its end" ,
                                          true , P2Font );

    P2Scroll2 = new CDXHorizTextScroller( Screen , &P2ClipRect2 ,
                                          "This text is with transparent background, it also wraps around when it reaches its end. Press O or P to change the text scrolling direction" ,
                                          true , P2Font );
    Left = true;
}




// --------------------------------------------------------------------------------------
// inits part3 of the demo
// --------------------------------------------------------------------------------------
void InitPart3( void )
{
    int     i;
    double  d;
	// create font Arial, Height=36, Color=Red
    // other attributes are default: ColorKey=0, Backgroundcolor=0,Attributes=FW_NORMAL,
    // SurfaceType = CDXMEM_VIDTHENSYS
    P3Font = new CDXBitmapFont( Screen , "Arial" , 36 , RGB( 190 , 0 , 0 ) );

    P3HintFont = new CDXBitmapFont( Screen , "Arial" , 50 , RGB( 0 , 0 , 190 ) ,
                                    0 , 0 , FW_BOLD );

    P3Layer = new CDXLayer( );
	P1Layer->Create(Screen,"forest.bmp",CDXMEM_VIDTHENSYS);

    P3Scroll = new CDXHorizTextScroller( Screen , &P3ClipRect ,
                                          "This is a demonstration of the CDXHorizTextScroller class, this one wraps around when it reaches its end" ,
                                          true , P3Font );

    Left = true;

    // init OffsetArray1 with sinus wave and OffsetArray2 with cosinus wave
    for( i=0; i<640; i++ )
    {
        d = sin( 3.141596/180 * i ) * 30;
        P3OffsetArray[i] = (int)d;
    }
}




// --------------------------------------------------------------------------------------
// inits part4 of the demo
// --------------------------------------------------------------------------------------
void InitPart4( void )
{
    int     i;
    double  d;
	// create font Arial, Height=36, Color=Red
    // other attributes are default: ColorKey=0, Backgroundcolor=0,Attributes=FW_NORMAL,
    // SurfaceType = CDXMEM_VIDTHENSYS
    P4Font = new CDXBitmapFont( Screen , "Arial" , 36 , RGB( 190 , 0 , 0 ) );

    P4HintFont = new CDXBitmapFont( Screen , "Arial" , 50 , RGB( 0 , 0 , 190 ) ,
                                    0 , 0 , FW_BOLD );

    P4Layer = new CDXLayer( );
	P1Layer->Create(Screen,"forest.bmp",CDXMEM_VIDTHENSYS);

    P4Scroll = new CDXHorizTextScroller( Screen , &P4ClipRect ,
                                          "This text is with transparent background, it also wraps around when it reaches its end. Press O or P to change the text scrolling direction" ,
                                          true , P4Font );
    Left = true;

    // init OffsetArray1 with sinus wave and OffsetArray2 with cosinus wave
    for( i=0; i<640; i++ )
    {
        d = cos( 3.141596/180 * i ) * 50;
        P4OffsetArray[i] = (int)d;
    }
}



// --------------------------------------------------------------------------------------
// inits part5 of the demo
// --------------------------------------------------------------------------------------
void InitPart5( void )
{
	// create font Arial, Height=36, Color=Red
    // other attributes are default: ColorKey=0, Backgroundcolor=0,Attributes=FW_NORMAL,
    // SurfaceType = CDXMEM_VIDTHENSYS
    P5Font = new CDXBitmapFont( Screen , "Arial" , 36 , RGB( 190 , 0 , 0 ) );

    P5HintFont = new CDXBitmapFont( Screen , "Arial" , 50 , RGB( 0 , 0 , 190 ) ,
                                    0 , 0 , FW_BOLD );

    P5Layer = new CDXLayer( );
	P1Layer->Create(Screen,"forest.bmp",CDXMEM_VIDTHENSYS);

    P5Scroll = new CDXVertTextScroller( Screen , &P5ClipRect ,
                                          "The CDXVertScrollText class displays\nscroll text scrolling up and down.\nThe text \
is broken in separate lines automatically, and you can choose if you want the text to be displayed left aligned, right aligned or centered.\n\
\nYou can choose between transparent text and for better performace text with colored background.\nThis text is displayed in centered mode.\n\
 I maybe try to implement a block mode in which the text is printed in a way that it fits the whole line." ,
                                          CDX_CENTERJUSTIFY , 4 , P5Font );
    Left = true;

}



// --------------------------------------------------------------------------------------
// frees variables allocated by part1 of the demo
// --------------------------------------------------------------------------------------
void FreePart1( void )
{
    delete P1Font;
    delete P1HintFont;
    delete P1TextFont;
	delete P1BlackFont;
    delete P1Layer;
}




// --------------------------------------------------------------------------------------
// frees variables allocated by part2 of the demo
// --------------------------------------------------------------------------------------
void FreePart2( void )
{
    delete P2Font;
    delete P2HintFont;
    delete P2Layer;
    delete P2Scroll1;
    delete P2Scroll2;
}




// --------------------------------------------------------------------------------------
// frees variables allocated by part3 of the demo
// --------------------------------------------------------------------------------------
void FreePart3( void )
{
    delete P3Font;
    delete P3HintFont;
    delete P3Layer;
    delete P3Scroll;
}




// --------------------------------------------------------------------------------------
// frees variables allocated by part4 of the demo
// --------------------------------------------------------------------------------------
void FreePart4( void )
{
    delete P4Font;
    delete P4HintFont;
    delete P4Layer;
    delete P4Scroll;
}



// --------------------------------------------------------------------------------------
// frees variables allocated by part5 of the demo
// --------------------------------------------------------------------------------------
void FreePart5( void )
{
    delete P5Font;
    delete P5HintFont;
    delete P5Layer;
    delete P5Scroll;
}




// --------------------------------------------------------------------------------------
// displays part1 on the screen
// --------------------------------------------------------------------------------------
void DisplayPart1( void )
{
    char HintText[64];

    // set up the text for the hint on bottom of display
    strcpy( HintText , "press any key to go to next part" );

    // draw header of part1
    P1Layer->Draw( Screen->GetBack() );
    P1Font->DrawAligned( 0 , 0 , 640 , "Demonstration of CDXBitmapFont class" , 
                         Screen->GetBack() , CDX_CENTERJUSTIFY );

    // draw examples
    P1TextFont->SetColor( RGB( 190 , 0 , 0 ) );
    P1TextFont->Draw( 10 , 70 , "Normal text in Courier New fontheight = 28" , Screen->GetBack() );
// TODO: uncomment when DrawClipped is implemented
//    P1TextFont->DrawClipped( 398 , 100 , "Clipped normal text in Courier New" , 
//                             Screen->GetBack() , &P1ClipRect );
    P1TextFont->DrawTrans( 10 , 150 , "Normal text with transparent background" , Screen->GetBack() );

    P1TextFont->SetColor( RGB( 80 , 80 , 80 ) );
// TODO: uncomment when DrawClipped is implemented
//    P1TextFont->DrawTransClipped( 250 , 200 , "Clipped normal text with transparent background" , 
//                             Screen->GetBack() , &P1ClipRect );

	// Should be transparent
	P1BlackFont->DrawTrans(10, 250, "Black Text on a transparent background", Screen->GetBack());

    P1Font->DrawAlignedTrans( 0 , 300 , 640 , "Centered Text" , 
                              Screen->GetBack() , CDX_CENTERJUSTIFY );

    P1Font->DrawAlignedTrans( 0 , 350 , 640 , "Right Aligned Text" , 
                              Screen->GetBack() , CDX_RIGHTJUSTIFY );

    // draw message to press any key to continue
    P1HintFont->DrawAlignedTrans( 0 , 
                                  480 - P1HintFont->GetCharacterHeight( 'A' ) ,
                                  640 ,
                                  HintText ,
                                  Screen->GetBack() ,
                                  CDX_CENTERJUSTIFY );

    Screen->Flip();
}




// --------------------------------------------------------------------------------------
// displays part2 on the screen
// --------------------------------------------------------------------------------------
void DisplayPart2( void )
{
    char HintText[64];

    // set up the text for the hint on bottom of display
    strcpy( HintText , "press any key to go to next part" );

    // draw header of part1
    P2Layer->Draw( Screen->GetBack() );
    P2Font->DrawAligned( 0 , 0 , 640 , "Demonstration of CDXHorizTextScroller class" , 
                         Screen->GetBack() , CDX_CENTERJUSTIFY );

    // draw information text
    P2Font->DrawTrans( 30 , 60 , "Press O or P to change scroller direction" , Screen->GetBack() );

    // draw Scroller 1
    P2Scroll1->Draw( Screen->GetBack() );
    P2Scroll2->DrawTrans( Screen->GetBack() );

    if( Left == true )
    {
        P2Scroll1->ScrollLeft();
        P2Scroll2->ScrollLeft( 2 );
    }
    else
    {
        P2Scroll1->ScrollRight();
        P2Scroll2->ScrollRight( 2 );
    }

    // draw message to press any key to continue
    P2HintFont->DrawAlignedTrans( 0 , 
                                  480 - P1HintFont->GetCharacterHeight( 'A' ) ,
                                  640 ,
                                  HintText ,
                                  Screen->GetBack() ,
                                  CDX_CENTERJUSTIFY );
    Screen->Flip();
}



// --------------------------------------------------------------------------------------
// displays part3 on the screen
// --------------------------------------------------------------------------------------
void DisplayPart3( void )
{
    char HintText[64];

    // set up the text for the hint on bottom of display
    strcpy( HintText , "press any key to go to next part" );

    // draw header of part1
    P3Layer->Draw( Screen->GetBack() );
    P3Font->DrawAligned( 0 , 0 , 640 , "CDXHorizScroller class with effects" , 
                         Screen->GetBack() , CDX_CENTERJUSTIFY );

    // draw information text
    P3Font->DrawTrans( 30 , 60 , "Press O or P to change scroller direction" , Screen->GetBack() );

    // draw Scroller 1
    P3Scroll->DrawOffset( Screen->GetBack() , P3OffsetArray );

    if( Left == true )
    {
        P3Scroll->ScrollLeft();
    }
    else
    {
        P3Scroll->ScrollRight();
    }

    // draw message to press any key to continue
    P3HintFont->DrawAlignedTrans( 0 , 
                                  480 - P1HintFont->GetCharacterHeight( 'A' ) ,
                                  640 ,
                                  HintText ,
                                  Screen->GetBack() ,
                                  CDX_CENTERJUSTIFY );
    Screen->Flip();
}



// --------------------------------------------------------------------------------------
// displays part4 on the screen
// --------------------------------------------------------------------------------------
void DisplayPart4( void )
{
    char HintText[64];

    // set up the text for the hint on bottom of display
    strcpy( HintText , "press any key to go to next part" );

    // draw header of part1
    P4Layer->Draw( Screen->GetBack() );
    P4Font->DrawAligned( 0 , 0 , 640 , "CDXHorizScroller class with effects" , 
                         Screen->GetBack() , CDX_CENTERJUSTIFY );

    // draw information text
    P4Font->DrawTrans( 30 , 60 , "Press O or P to change scroller direction" , Screen->GetBack() );

    // draw Scroller 1
    P4Scroll->DrawOffsetTrans( Screen->GetBack() , P4OffsetArray );

    if( Left == true )
    {
        P4Scroll->ScrollLeft();
    }
    else
    {
        P4Scroll->ScrollRight();
    }

    // draw message to press any key to continue
    P4HintFont->DrawAlignedTrans( 0 , 
                                  480 - P1HintFont->GetCharacterHeight( 'A' ) ,
                                  640 ,
                                  HintText ,
                                  Screen->GetBack() ,
                                  CDX_CENTERJUSTIFY );
    Screen->Flip();
}



// --------------------------------------------------------------------------------------
// displays part5 on the screen
// --------------------------------------------------------------------------------------
void DisplayPart5( void )
{
    static int delay = 0;
    char HintText[64];

    // set up the text for the hint on bottom of display
    strcpy( HintText , "press any key to end demo" );

    // draw header of part1
    P5Layer->Draw( Screen->GetBack() );
    P5Font->DrawAligned( 0 , 0 , 640 , "Demonstration of CDXVertTextScroller class" , 
                         Screen->GetBack() , CDX_CENTERJUSTIFY );

    // draw information text
    P5Font->DrawTrans( 30 , 60 , "Press O or P to change scroller direction" , Screen->GetBack() );

    // draw Scroller 1
    P5Scroll->DrawTrans( Screen->GetBack() );

    if( delay == 3 )
    {
        if( Left == true )
        {
            P5Scroll->ScrollUp();
        }
        else
        {
            P5Scroll->ScrollDown();
        }
        delay = 0;
    }

    ++ delay;


    // draw message to press any key to end demonstration
    P5HintFont->DrawAlignedTrans( 0 , 
                                  480 - P1HintFont->GetCharacterHeight( 'A' ) ,
                                  640 ,
                                  HintText ,
                                  Screen->GetBack() ,
                                  CDX_CENTERJUSTIFY );

	// display information about position of text
	sprintf( HintText , "TopEnd : %s , BottomEnd : %s" ,
		(P5Scroll->IsTopEnd( )    == TRUE ) ? "TRUE" : "FALSE" , 
		(P5Scroll->IsBottomEnd( ) == TRUE ) ? "TRUE" : "FALSE" );
    P5Font->DrawTrans( 30 , 400 , HintText , Screen->GetBack() );

    Screen->Flip();
}



// --------------------------------------------------------------------------------------
// switches to the next part of the demo
// --------------------------------------------------------------------------------------
void SwitchPart( void )
{
    if( ActivePart == PART1 )
    {
        FreePart1( );
        InitPart2( );
        ActivePart = PART2;
    }
    else
        if( ActivePart == PART2 )
        {
            FreePart2( );
            InitPart3( );
            ActivePart = PART3;
        }
        else
            if( ActivePart == PART3 )
            {
                FreePart3( );
                InitPart4( );
                ActivePart = PART4;
            }
            else
                if( ActivePart == PART4 )
                {
                    FreePart4( );
                    InitPart5( );
                    ActivePart = PART5;
                }
                else
                    if( ActivePart == PART5 )
                        PostMessage( WindowHandle, WM_CLOSE, 0, 0);
}




// --------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------
long PASCAL WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
		switch(message)
		{
    		case WM_SETCURSOR:
	    		SetCursor(NULL);	// Hide the mouse cursor
		    return TRUE;

			case WM_ACTIVATEAPP:
				 bActive = wParam;
				 break;

            case WM_CHAR :
  	            switch(wParam)
    		    {
	    		    case 'o' :	if( ActivePart > 1 )
                                    Left = true;
                                else
                                    SwitchPart( );
		    			    	break;

	    		    case 'p' :	if( ActivePart > 1 )
                                    Left = false;
                                else
                                    SwitchPart( );
		    			    	break;

                   default  :  SwitchPart();
                               break;
           		}
                
                break;

			case WM_KEYDOWN:
				 switch(wParam)
				 {
					 case VK_ESCAPE:
			 	     PostMessage(hWnd, WM_CLOSE, 0, 0);
		  			 break;
				 }
			  	 break;

			case WM_DESTROY:
                // terminate current part
                switch( ActivePart )
                {
                    case PART1 :    FreePart1( );
                                    break;

                    case PART2 :    FreePart2( );
                                    break;

                    case PART3 :    FreePart3( );
                                    break;

                    case PART4 :    FreePart4( );
                                    break;

                    case PART5 :    FreePart5( );
                                    break;

                }
                
                // destroy screen object
                delete Screen;

                // terminate application
				PostQuitMessage(0);
				break;

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




// --------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------
BOOL InitApp(HINSTANCE hInst, int nCmdShow)
{
		HWND hWnd;
		WNDCLASS WndClass;
		WndClass.style = CS_DBLCLKS;
		WndClass.lpfnWndProc = WinProc;
		WndClass.cbClsExtra = 0;
		WndClass.cbWndExtra = 0;
		WndClass.hInstance = hInst;
		WndClass.hIcon = LoadIcon(hInst, IDI_APPLICATION);
		WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
		WndClass.hbrBackground = ( HBRUSH )GetStockObject(BLACK_BRUSH);
		WndClass.lpszMenuName = 0;
		WndClass.lpszClassName = "FontsDemo";
		RegisterClass(&WndClass);

		hWnd = CreateWindowEx(
		WS_EX_TOPMOST,
	    "FontsDemo",
	    "FontsDemo",
		WS_POPUP,
		0,0,
		GetSystemMetrics(SM_CXSCREEN),
		GetSystemMetrics(SM_CYSCREEN),
		NULL,
		NULL,
		hInst,
		NULL);

		if(!hWnd) 
            CDXError( NULL , "Could not create window" );

		ShowWindow(hWnd, nCmdShow);
		UpdateWindow(hWnd);

        // init variables
        EndProgram   = false;
        NextPart     = false;
        ActivePart   = PART1;
        WindowHandle = hWnd;

        // create and initialize screen object
		Screen = new CDXScreen();
        if( Screen == NULL )
            CDXError( NULL , "Could not create CDXScreen object" );

        // set resolution to 640x480x8 and fill the screen with 0
		if( Screen->CreateFullScreen(hWnd, 640, 480, 8)<0 )
            CDXError( Screen , "Could not set videomode 640x480x8" );
		Screen->Fill(0);

        // load and set palette from bitmap file "forest.bmp"
        if( Screen->LoadPalette( "Forest.bmp" )<0 )
            CDXError( Screen , "Could not load palette from file forest.bmp" );

        // initialize part1 of demo
        InitPart1( );

		return TRUE;
}



// --------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
		MSG msg;

		if(!InitApp(hInst, nCmdShow)) return FALSE;

		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(bActive)
			{
                // determine which part is running
                // and call its display routine
                switch( ActivePart )
                {
                    case PART1 :    DisplayPart1( );
                                    break;

                    case PART2 :    DisplayPart2( );
                                    break;

                    case PART3 :    DisplayPart3( );
                                    break;

                    case PART4 :    DisplayPart4( );
                                    break;

                    case PART5 :    DisplayPart5( );
                                    break;
                }
			}

			else WaitMessage();

		}

}
