#include "DevLib.h"
/******************************************************************************
 * View.cpp                                                                   *
 ******************************************************************************
 * Project      : Futura (DevLib Demo)                                        *
 * License      : LGPL (full notice can be found at root directory)           *
 * Created by   : Arnaud Storq (norecess@devlib-central.org)                  *
 ******************************************************************************/
#include "View.h"
#include "Application.h"

// ---------------------------------------------------------------------------- DEFINE
#define VIEW_DISTANCE   40
#define SHIP_YPOS       -0.028f
#define SHIP_ZPOS       -0.11f
#define CAM_YPOS        -0.05f
#define HUDSHIP_WIDTH   8

// ---------------------------------------------------------------------------- CONSTRUCTOR
View::View( )
{
    m_3 = false;
    m_2 = false;
    m_1 = false;
    m_go = false;
}

// ---------------------------------------------------------------------------- DESTRUCTOR
View::~View( )
{
}

// ---------------------------------------------------------------------------- CREATE VIEW
View *View::createView( )
{
    return new View( );
}

// ---------------------------------------------------------------------------- DISPLAY UPDATE
void View::displayUpdate( ViewType type, Player *player )
{
    RenderSystem *rs = RenderSystemManager::getRenderSystem( );

    // switch view
    switch( type )
    {
    case VIEW_FULLSCREEN:
        rs->setViewport( 0, 0, rs->getWidth( ), rs->getHeight( ) );
        break;

    case VIEW_TOP:
        rs->setViewport( 0, 0, rs->getWidth( ), rs->getHeight( ) / 2 );
        break;

    case VIEW_BOTTOM:
        rs->setViewport( 0, rs->getHeight( ) / 2, rs->getWidth( ), rs->getHeight( ) / 2 );
        break;
    }

    // display game
    Application::getInstance( )->getBackground( )->displayUpdate( );
    displayView( player );
    displayHud( player );

    // switch to fullscreen view
    rs->setViewport( 0, 0, rs->getWidth( ), rs->getHeight( ) );
}

// ---------------------------------------------------------------------------- DISPLAY VIEW
void View::displayView( Player *player )
{
    RenderSystem *rs = RenderSystemManager::getRenderSystem( );

    Level *level = Application::getInstance( )->getLevel( );
    float time = Application::getInstance( )->getTime( );

    // Clear Z-buffer 
    rs->clear( CLEAR_MODE_ZBUFFER );

    // Set matrix projection
    rs->setMatrixMode( MATRIX_MODE_PROJECTION );
    Matrix matrixProjection;
    matrixProjection.setPerspective(    0.00001f, // minimum Z-value
        1000.0f, // maximum Z-value
        45.0f, // focal
        ( (float) rs->getWidth( ) ) / ( (float) rs->getHeight( ) ) // ratio
        );
    rs->loadMatrix( matrixProjection );

    // Set view projection
    rs->setMatrixMode( MATRIX_MODE_MODELVIEW );	
    rs->loadIdentityMatrix( );

    rs->pushMatrix( );

    // Set culling
    rs->setRenderState( RS_CULLING, RV_CULLING_CCW );

    // Set Z-buffer state
    rs->setRenderState( RS_ZBUFFER, RV_ZBUFFER_LESS );

    // Retreive current line of tiles
    int currLineOfTiles = (int) ( player->getPosZ( ) / level->getTileSize( ) );

    // Compute current camera X position
    float camX = -( player->getPosX( ) + ( level->getTileSize( ) * 0.5f ) );

    // Compute current camera Z position
    float camZ = player->getPosZ( );
    while( camZ > level->getTileSize( ) )
    {
        camZ -= level->getTileSize( );
    }

    rs->popMatrix( );
    rs->pushMatrix( );

    rs->translateMatrix( camX, CAM_YPOS, camZ );

    // For each lines..
    for ( int y = 0; ( y < VIEW_DISTANCE ) && ( y < ( level->getTrackHeight( ) - currLineOfTiles ) ); ++y )
    {
        // Next line
        rs->translateMatrix( 0.0f, 0.0f, -level->getTileSize( ) );

        rs->pushMatrix( );

        rs->rotateMatrix( -90.0f, 1.0f, 0.0f, 0.0f );

        // Render the tiles of the current line
        for ( int x = 0; x < level->getTrackWidth( ); ++x )
        {
            rs->translateMatrix( level->getTileSize( ), 0.0f, 0.0f );

            TileType type = level->getTrackTile( x, currLineOfTiles + y );
            level->getTile( type )->render( );
        }

        rs->popMatrix( );
    }

    // Compute ship's gravitation
    float gravPosX = sin( time * 2.8f ) * 0.003f;
    float gravPosY = 0.003f + cos( time * 1.7f ) * 0.003f;

    // Get ship's scaling
    float scale = player->getShip( )->getScale( );

    // Compute ship's X position
    float posX = scale * ( player->getPosX( ) - ( ( (float) level->getTrackWidth( ) ) * 0.5f ) * level->getTileSize( ) );

    // Set transformation matrix
    rs->popMatrix( );

    rs->translateMatrix( posX + gravPosX , SHIP_YPOS + gravPosY + player->getPosY( ), SHIP_ZPOS );

    rs->rotateMatrix( sin( time * 1.9f ) * 2.0f, 1.0f, 0.0f, 0.0f );
    rs->rotateMatrix( sin( time * 2.8f ) * 2.0f, 0.0f, 1.0f, 0.0f );
    rs->rotateMatrix( sin( time * 1.7f ) * 2.5f, 0.0f, 0.0f, 1.0f );

    rs->scaleMatrix( scale, scale, scale );

    // Render ship
    player->getShip( )->setEnvmap( level->getShipEnvmap( ) );
    player->getShip( )->render( );
}

// ---------------------------------------------------------------------------- DISPLAY HUD
void View::displayHud( Player *player )
{
    Level *level = Application::getInstance( )->getLevel( );

    Font *littleFont = Application::getInstance( )->getLittleFont( );
    Font *bigFont = Application::getInstance( )->getBigFont( );
    
    RenderSystem *rs = RenderSystemManager::getRenderSystem( );

    rs->setRenderState( RS_BLENDING, RV_BLENDING_TEXTURE_SUBSTRACTIVE );

    // Display background
    for ( int x = 0; x < rs->getWidth( ); x += Application::getInstance( )->getHud( )->getWidth( ) )
    {
        Application::getInstance( )->getHud( )->render( x, 0 );
    }

    // Display ship
    int posX = (int) ( ( ( (float) ( player->getPosZ( ) / level->getTileSize( ) ) ) / ( (float) level->getTrackHeight( ) ) ) * ( (float) ( rs->getWidth( ) - HUDSHIP_WIDTH ) ) );

    rs->setRenderState( RS_BLENDING, RV_BLENDING_TEXTURE_ALPHA );

    Application::getInstance( )->getFade( )->render( posX, 0, posX + HUDSHIP_WIDTH, Application::getInstance( )->getHud( )->getHeight( ) );

    // Display player status
    int charHeight = littleFont->getCharacterHeight( );

    Application::getInstance( )->getFade( )->render( 0, rs->getHeight( ) - charHeight * 2, rs->getWidth( ), rs->getHeight( ) );

    rs->setRenderState( RS_BLENDING, RV_BLENDING_NONE );

    string text( "" );

    if ( player->getFreezeTime( ) < 2.0f )
    {
        if ( player->getFreezeTime( ) < -3.0f )
        {
        }
        else
        if ( player->getFreezeTime( ) < -2.0f )
        {
            text = "3";

            if ( !m_3 )
            {
                Application::getInstance( )->getClickValidate( )->play( );
                m_3 = true;
            }
        }
        else
        if ( player->getFreezeTime( ) < -1.0f )
        {
            text = "2";

            if ( !m_2 )
            {
                Application::getInstance( )->getClickValidate( )->play( );
                m_2 = true;
            }

            m_3 = false;
        }
        else
        if ( player->getFreezeTime( ) < 0.0f )
        {
            text = "1";

            if ( !m_1 )
            {
                Application::getInstance( )->getClickValidate( )->play( );
                m_1 = true;
            }

            m_2 = false;
        }
        else
        if ( player->getFreezeTime( ) < 1.0f )
        {
            text = "GO!";

            if ( !m_go )
            {
                Application::getInstance( )->getGo( )->play( );
                level->getMusic( )->play( );
                m_go = true;
            }

            m_1 = false;
        }
        else
        {
            m_go = false;
        }
    }

    if ( text != "" )
    {
        bigFont->render( ( rs->getWidth( ) - bigFont->getStringWidth( text ) ) / 2, ( rs->getHeight( ) - bigFont->getCharacterHeight( ) ) / 2, text );
    }

    {
        char text[ 256 ];
        int baseY = rs->getHeight( ) - charHeight * 2;
            
        sprintf( text, "SCORE : %d", player->getScore( ) );
        littleFont->render( 0, baseY, text );

        sprintf( text, "SAUTS : %d", player->getJumpCount( ) );
        littleFont->render( rs->getWidth( ) / 2, baseY, text );

        sprintf( text, "VIES : %d", 1 + player->getLifeCount( ) );
        littleFont->render( 0, baseY + charHeight, text );

        int time = 0;
        if ( player->getFreezeTime( ) > 0.0f )
            time = (int) ( player->getFreezeTime( ) );

        sprintf( text, "TEMPS : %d", time );
        littleFont->render( rs->getWidth( ) / 2, baseY + charHeight, text );

        if ( player->getFallY( ) < 0.0f )
        {
            if ( player->getLifeCount( ) == 0 )
            {
                strcpy( text, "MISSION KO!" );
            }
            else
            {
                strcpy( text, "PERDU!" );
            }

            bigFont->render( ( rs->getWidth( ) - bigFont->getStringWidth( text ) ) / 2, ( rs->getHeight( ) - bigFont->getCharacterHeight( ) ) / 2, text );
        }
    }
}
