/*
* This source file is part of the osgOcean library
* 
* Copyright (C) 2009 Kim Bale
* Copyright (C) 2009 The University of Hull, UK
* 
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later
* version.

* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* http://www.gnu.org/copyleft/lesser.txt.
*/

#pragma once
#include <osgOcean/ScreenAlignedQuad>
#include <osg/Geode>
#include <osg/Uniform>
#include <osg/Program>
#include <osg/BlendFunc>
#include <osg/Texture>
#include <osgUtil/CullVisitor>
#include <string>

namespace osgOcean
{
    /** 
    * Screen aligned quad used to display the god ray frame buffer.
    */
    class OSGOCEAN_EXPORT GodRayBlendSurface : public osg::Geode
    {
    private:
        osg::Vec3   _HGg;                          /**< Controls degree of forward light scattering. */
        osg::Vec3f  _sunDir;                       /**< sun direction */
        float       _intensity;                    /**< Intensity tweak */
        osg::ref_ptr<osg::StateSet> _stateset;
        osg::ref_ptr<osg::Vec3Array> _normalArray; /**< Stores the ray vectors for the view direction at the corners of the screen aligned quad */

    public:
        /** 
        * Default Constructor.
        */
        GodRayBlendSurface( void );
        
        /** 
        * Constructor.
        * Calls build().
        */
        GodRayBlendSurface( const osg::Vec3f& corner, const osg::Vec2f& dims, osg::TextureRectangle* texture );
        
        GodRayBlendSurface( const GodRayBlendSurface &copy, 
            const osg::CopyOp &copyop = osg::CopyOp::SHALLOW_COPY );

        virtual const char* libraryName() const { return "osgOcean"; }
        virtual const char* className() const { return "GodRayBlendSurface"; }
        virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const GodRayBlendSurface*>(obj) != 0; }

    protected:
        ~GodRayBlendSurface(void){};

    public:
        /** 
        * Removes all drawables and creates and adds quad geometry, program and stateset. 
        */
        void build( const osg::Vec3f& corner, const osg::Vec2f& dims, osg::TextureRectangle* texture );
    
        /**
        * Updates the _normalArray with new view vectors.
        */ 
        void update( const osg::Matrixd& view, const osg::Matrixd& proj );

        /**
        * Sets the degree of forward light scattering.
        */
        inline void setEccentricity( float g )
        {
            _HGg = osg::Vec3f(1.f-(g*g), 1.f+(g*g), 2.f*g);

            if( _stateset.valid() )
                _stateset->getUniform("osgOcean_HGg")->set(_HGg);
        }

        /**
        * Blend intensity tweak.
        */
        inline void setIntensity( float i )
        {
            _intensity = i;

            if( _stateset.valid() )
                _stateset->getUniform("osgOcean_Intensity")->set(_intensity);
        }

        /**
        * Set sun direction
        */ 
        inline void setSunDirection( const osg::Vec3f& sunDir )
        {
            _sunDir = sunDir;

            if( _stateset.valid() )
                _stateset->getUniform("osgOcean_SunDir")->set(_sunDir);
        }

    private:
        /**
        * Loads the shaders and returns program.
        */ 
        osg::Program* createShader(void);

    // ---------------------------------------------
    //            Callback declarations
    // ---------------------------------------------

    protected:
        /**
        * Animation data structure.
        */
        class GodRayBlendDataType: public osg::Referenced
        {
        private:
            GodRayBlendSurface& _blendSurface;
            osg::Matrixd _view;
            osg::Matrixd _projection;

        public:
            GodRayBlendDataType( GodRayBlendSurface& godRays );

            GodRayBlendDataType( const GodRayBlendDataType& copy, 
                const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY );

            inline void setViewMatrix( const osg::Matrixd& viewMatrix ){
                _view=viewMatrix;
            }
            inline void setProjMatrix( const osg::Matrixd& projMatrix ){
                _projection=projMatrix;
            }

            void update( void );
        };

        /**
        * Update/Cull animation callback.
        * Cull callback stores view and projection matrices needed for animation.
        * Update callback calls parents update function.
        * @see GodRayBlendSurface::update().
        */
        class GodRayBlendCallback: public osg::NodeCallback
        {
        public:
            virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
        };
    };
}
