/*****************************************************************************
 * $LastChangedDate: 2011-04-09 21:58:06 -0400 (Sat, 09 Apr 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   Medium particle-system.
 *//*
 * 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).
 *****************************************************************************/

#ifndef FX_PARTSYS_MEDIUM_HH
#define FX_PARTSYS_MEDIUM_HH 1

#include "base/timer.hh"
#include "gfx/module.hh"
#include "gfx/rgba.hh"
using namespace gfx;
#include "fx/partsys.hh"

namespace fx {

//--------------------------------------------------------------------------
namespace defs {

const RGBA  DEFAULT_MEDIUM_PARTSYS_COLOR( 0xff, 0xff, 0xff, 0xa0 );
const Meter DEFAULT_MEDIUM_PARTSYS_GEO_RANGE( 1500.0f );
const fp    DEFAULT_MEDIUM_PARTSYS_MIN_WIDTH = 6.0f;     ///< to simulate 3D scaling of particles
const fp    DEFAULT_MEDIUM_PARTSYS_MAX_WIDTH = 64.0f;

} // namespace defs
//--------------------------------------------------------------------------

class MediumParticleDrawable;

////////////////////////////////////////////////////////////////////////////////
/// @brief Opaque struct that defines a medium particle.
///
/// Indeed, OpenGL points can have a 3D position.
///
struct MediumParticle
{
    WorldVertex     mPosition;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief Particle-system based on OpenGL point-sprites.
///
/// This particle system is very fast but it has deficiencies.
/// Left unimplemented was a mechanism to update particles.
/// MediumParticleSystem has a crude way to adjust size of point sprites
/// by distance (but it's imperfect and hardware limits point size).
///
/// Texture is specified by stateset.
/// Example:
/// new MediumParticleSystem( MediumParticleSystem::Args( Texture::NewTextureAsStateSet( "smoke.png" ) ) );
///
class MediumParticleSystem : public ParticleSystem
{
PREVENT_COPYING(MediumParticleSystem)
typedef ParticleSystem Parent;
friend class FX; friend class shptr<MediumParticleSystem>;
friend class MediumParticleDrawable;
public:
    /// @brief Args for MediumParticleSystem ctor.
    struct Args : public ParticleSystem::Args
    {
        Args( const Milliseconds    lifetime,                                 // base
              const bool            timerEnabled = TimerDefs::TIMER_ENABLED,  // base
              const NodeSort&       nodeSort = NodeSort(fx::defs::PARTSYS_NODE_SORT_ATTRIBS),
              const RGBA            color = fx::defs::DEFAULT_MEDIUM_PARTSYS_COLOR,
              const Meter           geoRange = fx::defs::DEFAULT_MEDIUM_PARTSYS_GEO_RANGE,
              const fp              minWidth = fx::defs::DEFAULT_MEDIUM_PARTSYS_MIN_WIDTH,
              const fp              maxWidth = fx::defs::DEFAULT_MEDIUM_PARTSYS_MAX_WIDTH );

        const NodeSort          mNodeSort;      ///< for state-sorting
        const RGBA              mColor;         ///< color of all particles
        const fp                mRange;         ///< particle reaches it mediumest 2D width at this 3D distance
        const fp                mMinWidth, mMaxWidth;
    };

public:
                    MediumParticleSystem( const Args& arg );
                    ~MediumParticleSystem();
    void            AttachParticle( const MediumParticle& mediumParticle );
    uint            GetParticleCount( void );
    void            SetColorAll( const RGBA color );

private:
    // OSG components:
    bool                            mAttachedToSceneGraph;      ///< lazy-attached in case of no particles
    const NodeSort                  mNodeSort;                  ///< for state-sorting
    RefPtr<osg::StateSet>           mStateSet;                  ///< specifies texture (and any other state)
    RefPtr<osg::Geode>              mGeode;
    RefPtr<osg::Geometry>           mGeom;
    RefPtr<MediumParticleDrawable>  mMediumParticleDrawable;    ///< for adjusting size of every point sprite
public:
    DECLARE_TYPESIG(TYPESIG_MEDIUM_PARTICLE_SYSTEM)
};

} // namespace fx

#endif // FX_PARTSYS_MEDIUM_HH
