//////////////////////////////////////////////////////////////////////////////
//
// Asura_FullScreenSFX_System.cpp
//
// Copyright (c) 2003 Rebellion. All rights reserved.
//
// Description:
//
//     Full screen effects like fades, flashes, etc.
//
//////////////////////////////////////////////////////////////////////////////

// I N C L U D E S ///////////////////////////////////////////////////////////

#include "Core/Asura.h"

// This file's header.
#include "SpecialFX/Asura_FullScreenSFX_System.h"

// Engine independent.
#include "Core/Asura_Maths.h"
#include "Core/Asura_Timers.h"
#include "Debugging/Asura_Assert.h"

#ifndef ASURA_USE_FSFX
#include "SpecialFX/Asura_Glow_System.h"
#endif

// G L O B A L S /////////////////////////////////////////////////////////////

static Asura_FullScreenSFX_System::FADE g_eFadeType;
static float                            g_fFadeDuration;      // Only valid if current fade type is not FADE_NONE.
static float                            g_fRemainingFadeTime; //                        "
static float                            g_fOriginalFadeAlpha; //                        "
static u_int                            g_uCurFadeColour;     //                        "

#ifndef ASURA_USE_FSFX
static bool								g_bGlowEnabled = false;
#endif

static bool								g_bMotionBlurEnabled = false;
static u_char							g_uMotionBlurAlpha = 0;

// P R O T O T Y P E S   A N D   I N L I N E   F U N C T I O N S /////////////

static void UpdateFade( void );

// C L A S S   I M P L E M E N T A T I O N S /////////////////////////////////

//
// Asura_FullScreenSFX_System.
//

void Asura_FullScreenSFX_System::BeginFade( FADE eRequestedType, float fDuration, u_int uColour )
{
    Asura_Assert( FADE_NONE != eRequestedType, "Invalid fade type requested." );

    // Specifying a 0 alpha in the colour doesn't make any sense since we'll
    // never see that fade at all (since we blend from 0 to the specified
    // alpha or vice versa.)
    Asura_Assert( uColour >> 24, "Alpha is 0 in specified colour." );

    // For convenience, we'll allow certain fade transitions without an
    // intervening CancelFade(). We'll be quite restrictive about it, however,
    // to help ensure the caller is using this class's functionality properly.
    if( FADE_NONE != g_eFadeType )
    {
        if( FADE_TO_COLOUR == g_eFadeType && FADE_FROM_COLOUR == eRequestedType && uColour == g_uCurFadeColour )
        {
            // This is ok because the caller has faded to a colour and is
            // now asking fade that colour back out again.
        }
        else
        {
            // Anything else is invalid.
            Asura_Assert( false, "Fade already active. Call CancelFade() before requesting a new one." );
        }
    }

    g_eFadeType           = eRequestedType;
    g_fFadeDuration       = fDuration;
    g_fRemainingFadeTime  = fDuration;
    g_fOriginalFadeAlpha  = static_cast<float>( uColour >> 24 );
    g_uCurFadeColour      = uColour;
	// If we're fading to a colour, remove the alpha from the current colour so it doesn't matter whether this was called before or after the SFX update this frame.
	if (FADE_TO_COLOUR == g_eFadeType)
	{
		g_uCurFadeColour &= 0xFFFFFF;
	}
}

void Asura_FullScreenSFX_System::CancelFade( void )
{
    g_eFadeType = FADE_NONE;
}

void Asura_FullScreenSFX_System::Initialise( void )
{
	Reset();

#ifndef ASURA_USE_FSFX
	Asura_Glow_System::Initialise();
#endif
	Asura_FullScreenSFX_System::Platform_InitialiseMotionBlur();
}

bool Asura_FullScreenSFX_System::IsFadeComplete( void )
{
    bool bFinished;

    switch( g_eFadeType )
    {
        case FADE_TO_COLOUR:
            bFinished = !g_fRemainingFadeTime;
            break;

        case FADE_FROM_COLOUR:
            bFinished = false;
            break;

        default:
            Asura_Assert( false, "Invalid fade type." );
            // Just fall through to NONE case.

        case FADE_NONE:
            bFinished = true;
            break;
    }

    return bFinished;
}

void Asura_FullScreenSFX_System::Render_Early( void )
{
#ifndef ASURA_USE_FSFX
	if( g_bGlowEnabled )
	{
		Asura_Glow_System::Render();
	}
#endif
}

void Asura_FullScreenSFX_System::Render_Late( void )
{
	if( g_bMotionBlurEnabled )
	{
		Platform_RenderMotionBlur( g_uMotionBlurAlpha );
	}
}

void Asura_FullScreenSFX_System::Render2DEffects()
{
	if( Asura_FullScreenSFX_System::FADE_NONE != g_eFadeType )
	{
		Platform_RenderFade( g_uCurFadeColour );
	}
}

void Asura_FullScreenSFX_System::Reset( void )
{
    CancelFade();
#ifndef ASURA_USE_FSFX
	Asura_Glow_System::Reset();
#endif
}

void Asura_FullScreenSFX_System::Shutdown( void )
{
    Reset();
#ifndef ASURA_USE_FSFX
	Asura_Glow_System::Shutdown();
#endif
}

void Asura_FullScreenSFX_System::Update( void )
{
    UpdateFade();
}

// Glow system
void Asura_FullScreenSFX_System::EnableGlow( bool bEnableGlow )
{
#ifdef ASURA_USE_FSFX
	Asura_Assert( false, "Glow not supported when FSFX enabled - use the FSFX glow system" );
#else
	g_bGlowEnabled = bEnableGlow;
#endif
}

bool Asura_FullScreenSFX_System::IsGlowEnabled()
{
#ifdef ASURA_USE_FSFX
	return false;
#else
	return g_bGlowEnabled;
#endif
}

void Asura_FullScreenSFX_System::EnableMotionBlur( bool bEnableMotionBlur )
{
	g_bMotionBlurEnabled = bEnableMotionBlur;
}

void Asura_FullScreenSFX_System::SetMotionBlurAlpha( u_char uMotionBlurAlpha )
{
	g_uMotionBlurAlpha = uMotionBlurAlpha;
}

// F U N C T I O N   I M P L E M E N T A T I O N S ///////////////////////////

static void UpdateFade( void )
{
    if( Asura_FullScreenSFX_System::FADE_NONE == g_eFadeType ) { return; }

	g_fRemainingFadeTime -= Asura_Timers::GetGameTimeSlice();
	if( g_fRemainingFadeTime <= 0.0f )
    {
        switch( g_eFadeType )
        {
            case Asura_FullScreenSFX_System::FADE_TO_COLOUR:
                g_fRemainingFadeTime = 0.0f;
                break;

            case Asura_FullScreenSFX_System::FADE_FROM_COLOUR:
                Asura_FullScreenSFX_System::CancelFade();
                return;

            default:
                Asura_Assert( false, "Invalid fade type." );
                break;
        }
	}

    g_uCurFadeColour &= 0x00FFFFFFu;

    float fAlpha;
	// (AW - 18.08.2003) - Prevent division by zero.
	if (g_fFadeDuration != 0.0f)
	{
		switch( g_eFadeType )
		{
			default:
				Asura_Assert( false, "Invalid fade type." );
				// Fall through to a proper case to prevent warning about fAlpha
				// being used uninitialised.

			case Asura_FullScreenSFX_System::FADE_TO_COLOUR:
				fAlpha = 1.0f - g_fRemainingFadeTime / g_fFadeDuration;
				break;

			case Asura_FullScreenSFX_System::FADE_FROM_COLOUR:
				fAlpha = g_fRemainingFadeTime / g_fFadeDuration;
				break;
		}
	}
	else
	{
		Asura_Assert(g_fRemainingFadeTime == 0.0f, "Would expect g_fRemainingFadeTime to be 0 if g_fFadeDuration is 0");
		fAlpha = (g_eFadeType == Asura_FullScreenSFX_System::FADE_FROM_COLOUR) ? 0.0f : 1.0f;
	}

    g_uCurFadeColour |= static_cast<u_int>(Asura_Maths::FloatToInt(fAlpha * g_fOriginalFadeAlpha)) << 24;
}
