/*****************************************************************************
 * $LastChangedDate: 2011-02-04 19:23:35 -0500 (Fri, 04 Feb 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   Splash graphical text.
 *//*
 * LEGAL:   COPYRIGHT (C) 2007 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
 *****************************************************************************/

#define PROGRAM_SPLASH_CC 1
#include "base/module.hh"
using namespace base;
#include "math/module.hh"
#include "math/funcs.hh"
using namespace math;
#include "gfx/module.hh"
#include "gfx/rgb_colors.hh"
using namespace gfx;
#include "hud/module.hh"
#include "hud/font.hh"
using namespace hud;
#include "program/module.hh"
#include "program/conf.hh"
#include "program/splash.hh"

namespace program {

INTERN const fp SPLASH_COLOR_ALPHA = 1.0f;
INTERN TinyArray<4,RGBA> sSplashGradientColors;

////////////////////////////////////////////////////////////////////////////////
////////////////////////////  ProgramSplash  ///////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

ProgramSplash* ProgramSplash::msInstance;

/*****************************************************************************
 * ctor/dtor.
 *****************************************************************************/
ProgramSplash::ProgramSplash( void )
:   mHud(GET_HUD()),
    mHudTextSplash(CtorHudTextSplash()),
    mTickFunctor(new TickFunctor),
    mFadeMilliseconds(PROGRAM_CONF.mSplashFadeMilliseconds),
    mEndMilliseconds(PROGRAM_CONF.mSplashEndMilliseconds)
{
ASSERT( mFadeMilliseconds < mEndMilliseconds );

    mHud.Attach( mHudTextSplash->GetNode() );
}

shptr<HudText>
ProgramSplash::CtorHudTextSplash( void )
{
    // Put splash line at center.
    HudText::Args hudTextArgs;
    hudTextArgs.mText = program::defs::PROGRAM_NAME_LONG;
    hudTextArgs.mPos[XX] = 0;
    hudTextArgs.mPos[YY] = 128;  // move upward a little bit
    Font splashFont = GET_FONT_MAP().GetFont( PROGRAM_CONF.mSplashFontName );
    splashFont.SetSize( PROGRAM_CONF.mSplashFontSize );
    hudTextArgs.mFont = splashFont;
    hudTextArgs.mOrientation = HudText::eOrientation_CENTER;
    hudTextArgs.mAnimation = HudText::eAnimation_FLIP;
    shptr<HudText> hudTextSplash = new HudText( hudTextArgs );
    sSplashGradientColors[HudText::eGradientColor_TOP_LEFT]     = \
    sSplashGradientColors[HudText::eGradientColor_TOP_RIGHT]    = RGBA( 0.0f, 0.8f, 1.0f, 1.0f );
    sSplashGradientColors[HudText::eGradientColor_BOTTOM_LEFT]  = \
    sSplashGradientColors[HudText::eGradientColor_BOTTOM_RIGHT] = RGBA( 0.0f, 0.2f, 1.0f, 1.0f );
    hudTextSplash->SetGradientColors4( sSplashGradientColors );
    return hudTextSplash;
}

ProgramSplash::~ProgramSplash()
{
    // NOP
}

/*****************************************************************************
 * Start the updating of splash.
 *****************************************************************************/
void
ProgramSplash::Start( void )
{
BEGIN_ONCE {
    GET_TIMER().Register( mTickFunctor, program::defs::SPLASH_TICK_FREQ );
} END_ONCE
}

/*****************************************************************************
 * Pulse.
 *****************************************************************************/
void
ProgramSplash::TickFunctor::Tick( const Milliseconds millisecElapsed )
{
    // Reflect.
    GET_PROGRAM_SPLASH().Update( millisecElapsed );
}

/*****************************************************************************
 * This update handler is called at a high rate.
 *****************************************************************************/
void
ProgramSplash::Update( const Milliseconds millisecElapsed )
{
ASSERT( mFadeMilliseconds < mEndMilliseconds );

    // Splash line.
    // For a few seconds, keep alpha constant at 1.0.
    // Then a few seconds after, gradually fade alpha down to 0.
    uint8 splashAlpha = 0;
    if ( millisecElapsed < mFadeMilliseconds )
    {
        // First phase:
        splashAlpha = 0xff;
    }
    else if ( millisecElapsed < mEndMilliseconds )
    {
        // Second phase:
        // | mFadeMilliseconds ... mEndMilliseconds |
        // | 0.0               ...            limit |
        // | alpha = 1.0       ...      alpha = 0.0 |
        const fpx limit   = mEndMilliseconds.FPX() - mFadeMilliseconds.FPX();
        const fpx timeRel = millisecElapsed.FPX() - mFadeMilliseconds.FPX();
        const fpx frac    = Range<fpx>( timeRel / limit, 0.0, 1.0 );  // becomes 1 when timeRel hits limit.
            ASSERT( millisecElapsed >= mFadeMilliseconds );           // frac will exceed 1 if timer is late (normal)
            ASSERT( limit > 0.0 );
            ASSERT( timeRel >= 0.0 );
        splashAlpha = uint8( 0xff * (1.0 - frac) );
    }

    sSplashGradientColors[HudText::eGradientColor_TOP_LEFT][AA]     = \
    sSplashGradientColors[HudText::eGradientColor_TOP_RIGHT][AA]    = \
    sSplashGradientColors[HudText::eGradientColor_BOTTOM_LEFT][AA]  = \
    sSplashGradientColors[HudText::eGradientColor_BOTTOM_RIGHT][AA] = splashAlpha;
    mHudTextSplash->SetGradientColors4( sSplashGradientColors );

    // When done, stop timer-tick.
    if ( splashAlpha == 0 )
    {
        GET_TIMER().Unregister( mTickFunctor );
    }
}

} // namespace program
