/*****************************************************************************
 * $LastChangedDate: 2011-02-04 19:23:35 -0500 (Fri, 04 Feb 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   Stars.
 *//*
 * 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 SKY_STARS_CC 1
#define NEED_PLANET_CLASS 1
#include "base/module.hh"
#include "base/random.hh"
using namespace base;
#include "math/module.hh"
#include "math/graphics.hh"
using namespace math;
#include "gfx/module.hh"
#include "gfx/osg.hh"
using namespace gfx;
#include "world/module.hh"
#include "world/conf.hh"
#include "world/planet.hh"
using namespace world;
#include "sky/module.hh"
#include "sky/stars.hh"
#include "sky/sky_dome.hh"

#include <osg/Point>

namespace sky {

namespace defs {
const osg::Vec4f STAR_COLOR( 0.7f, 0.7f, 0.9f, 1.0f );  // bluish-white
}

////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////  Stars  //////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/*****************************************************************************
 * ctor/dtor.
 * SkyDome must be passed since Sky ctor calls Stars ctor,
 * so calling GET_SKY_DOME() would cause an infinite cycle.
 *****************************************************************************/
Stars::Stars( const WorldVertex& pos, const uint count, SkyDome& skyDome )
:   Object(Graph::MakeMinimalGraph(),pos),
    mGeode(new osg::Geode)
{
    // Construction of mGeode is convoluted.
    GetGraph()->AttachNode( mGeode.get() );
    RefPtr<osg::Geometry>  geom     = new osg::Geometry;
    RefPtr<osg::StateSet>  stateSet = mGeode->getOrCreateStateSet();
    RefPtr<osg::Vec3Array> vertexs  = new osg::Vec3Array;
    RefPtr<osg::Vec4Array> colors   = new osg::Vec4Array;

    // Use radius slightly smaller that SkyDome,
    // so that stars will be inside and not occluded by SkyDome.
    const fp skyDomeRadius = skyDome.GetRadius() * (WORLD_CONF.mFlatWorld ? 0.95f : 1.35f);

    // For the amount of stars.
    const fp latDegRange = WORLD_CONF.mFlatWorld ? 90.0f-5.0f : 180.0f-5.0f;
    for ( uint i = 0; i < count; ++i )
    {
        // Append to vertex array.
        const Degree latDeg = Random::random_f( latDegRange );
        const Degree lonDeg = Random::random_f( 360.0f );
        vertexs->push_back( math::ComputeVertexOnDome( latDeg, lonDeg, skyDomeRadius ) );
    }

    // Build geometry.
    geom->setVertexArray( vertexs.get() );
    geom->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::POINTS, 0, vertexs->size() ) );
    mGeode->addDrawable( geom.get() );

    // Build color array.
    colors->push_back( defs::STAR_COLOR );
    geom->setColorArray( colors.get() );
    geom->setColorBinding( osg::Geometry::BIND_OVERALL );

    // Set point size.
    const fp pointSize = 1.0f;
    RefPtr<osg::Point> point = new osg::Point;
    point->setSize( pointSize );
    stateSet->setAttribute( point.get() );
}

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

/*****************************************************************************
 * For scene-graph to render optimally, nodes should be sorted by state.
 *****************************************************************************/
NodeSort
Stars::GetNodeSort( void )
{
    const NodeSort::Attribs attribs( NodeSort::Attribs::NO_SHADER
                                   | NodeSort::Attribs::NO_FOG );
    return NodeSort( attribs );
}

} // namespace sky
