/*****************************************************************************
 * $LastChangedDate: 2011-04-23 21:07:07 -0400 (Sat, 23 Apr 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   Base class for particle-systems.
 *//*
 * LEGAL:   COPYRIGHT (C) 2008 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
 *****************************************************************************/

#define FX_PARTSYS_CC 1
#include "base/module.hh"
#include "base/stream.hh"
using namespace base;
#include "world/module.hh"
using namespace world;
#include "fx/module.hh"
#include "fx/defs.hh"
#include "fx/fx.hh"
#include "fx/partsys.hh"

namespace fx {

////////////////////////////////////////////////////////////////////////////////
//////////////////////////////  ParticleSystem  ////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/*****************************************************************************
 * ctor/dtor.
 *****************************************************************************/
ParticleSystem::ParticleSystem( const Args& args )
:   mTimeOfDeath(GET_TIMER().GetElapsedTime() + args.mLifetime),
    mTickFunctor(new ParticleSystem::TickFunctor(*this)),
    mRegisteredTickFunctor(false),
    mZombie(false)
{
    SET_TYPESIG(this,TYPESIG_PARTICLE_SYSTEM);

    // Enable updating particles.
    if ( args.mTimerEnabled )
    {
        mRegisteredTickFunctor = true;
        GET_TIMER().Register( mTickFunctor, fx::defs::PARTICLE_SYSTEM_TICK_FREQ );
    }
}

ParticleSystem::~ParticleSystem()
{
    // Must unregister!  Else functor would access a destroyed object.
    if ( mRegisteredTickFunctor )
        GET_TIMER().Unregister( mTickFunctor );

    INVALIDATE_TYPESIG(this,TYPESIG_PARTICLE_SYSTEM);
}

/*****************************************************************************
 * Tick.
 *****************************************************************************/
void
ParticleSystem::Tick( const Milliseconds millisecElapsed )
{
CHECK_TYPESIG(this,TYPESIG_PARTICLE_SYSTEM);

    // Time to die?
    if ( UX( millisecElapsed >= mTimeOfDeath ) )
        Expire();  // RIP
}

// Reflect.
void
ParticleSystem::TickFunctor::Tick( const Milliseconds millisecElapsed )
{
CHECK_TYPESIG(&mParticleSystem,TYPESIG_PARTICLE_SYSTEM);

    mParticleSystem.Tick( millisecElapsed );
}

/*****************************************************************************
 * Expire (zombify) particle-system.
 *****************************************************************************/
void
ParticleSystem::Expire( void )
{
CHECK_TYPESIG(this,TYPESIG_PARTICLE_SYSTEM);

    // Turn into a zombie to be destroyed later by the FX singleton.
    if ( not mZombie )  // once
    {
    #if DEBUG_PARTSYS
        CDEBUG << "ParticleSystem turning into zombie" << std::endl;
    #endif

        // Zombify this.
        mZombie = true;
        GET_FX().AddZombie( this );  // schedule deletion

        // Stop timer-ticks.
        if ( mRegisteredTickFunctor )
        {
            mRegisteredTickFunctor = false;
            GET_TIMER().Unregister( mTickFunctor );
        }
    }
}

} // namespace fx
