/* -*-c++-*- */
/* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
* Copyright 2008-2010 Pelican Mapping
* http://osgearth.org
*
* osgEarth 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 2 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>
*/
#ifndef OSGEARTH_OVERLAY_DECORATOR
#define OSGEARTH_OVERLAY_DECORATOR

#include <osgEarth/Common>
#include <osgEarth/ShaderComposition>
#include <osgEarth/TerrainEngineNode>
#include <osg/Camera>
#include <osg/CoordinateSystemNode>
#include <osg/Texture2D>
#include <osg/TexGenNode>
#include <osg/Uniform>
#include <osgUtil/CullVisitor>

namespace osgEarth
{
    /**
     * Projects an overlay scene graph onto the main model.
     *
     * The OverlayDecorator is automatically installed in the MapNode and is used
     * to display ModelLayer's whose "overlay" property is set to true.
     *
     * This class is similar in scope to osgSim::OverlayNode, but is optimized
     * for use with osgEarth and geocentric terrains.
     */
    class OSGEARTH_EXPORT OverlayDecorator : public TerrainDecorator
    {
    public:
        OverlayDecorator();

        /**
         * The scene graph to be sampled an overlaid on the terrain.
         */
        void setOverlayGraph( osg::Node* node );
        osg::Node* getOverlayGraph() const { return _overlayGraph.get(); }

        /**
         * Explicity sets the texture unit to use. Note! When you add this class
         * to a MapNode, it will automatically allocate a free texture unit; so you
         * usually do NOT need to call this method.
         */
        void setTextureUnit( int unit );
        int getTextureUnit() const { return *_textureUnit; }

        /**
         * The size (resolution in both directions) of the overlay texture. By
         * default, this defaults to 4096 or your hardware's maximum supported
         * texture size, whichever is less.
         */
        void setTextureSize( int texSize );
        int getTextureSize() const { return *_textureSize; }

        /**
         * Whether mipmapping is enabled on the projected overlay texture. Mapmapping
         * will improve the visual appearance, but will use more memory, and may affect
         * performance for overlays that are dynamic.
         */
        void setMipmapping( bool value );
        bool getMipmapping() const { return _mipmapping; }


    public: // TerrainDecorator
        virtual void onInstall( TerrainEngineNode* engine );
        virtual void onUninstall( TerrainEngineNode* engine );

    public: // osg::Node
        void traverse( osg::NodeVisitor& nv );
        
    public: //osg::Group overrides
#if 0
        virtual bool addChild( Node *child );
        virtual bool insertChild( unsigned int index, Node *child );
        virtual bool removeChildren(unsigned int pos,unsigned int numChildrenToRemove);
        virtual bool replaceChild( Node *origChild, Node* newChild );
        virtual bool setChild( unsigned  int i, Node* node );
        virtual osg::BoundingSphere computeBound() const;
#endif

    private:
        void updateRTTCamera( osg::NodeVisitor& nv );
        void cull( osgUtil::CullVisitor* cv );
        void reinit();
        void initSubgraphShaders( osg::StateSet* set );
        void initRTTShaders( osg::StateSet* set );

    private:
        //osg::ref_ptr<osg::Group>      _subgraphContainer;
        osg::ref_ptr<osg::Node>       _overlayGraph;
        osg::ref_ptr<osg::Camera>     _rttCamera;
        osg::ref_ptr<osg::Texture2D>  _projTexture;
        osg::ref_ptr<osg::TexGenNode> _texGenNode;
        osg::ref_ptr<osg::Uniform>    _texGenUniform;
        osg::ref_ptr<osg::Uniform>    _warpUniform;
        osg::ref_ptr<osg::StateSet>   _subgraphStateSet;
        optional<int>                 _explicitTextureUnit;
        optional<int>                 _textureUnit;
        optional<int>                 _textureSize;
        bool                          _reservedTextureUnit;
        bool                          _useShaders;
        bool                          _useWarping;
        float                         _warp;
        bool                          _visualizeWarp;
        bool                          _isGeocentric;
        double                        _maxProjectedMapExtent;
        bool                          _mipmapping;

        osg::Matrixd _rttViewMatrix, _rttProjMatrix;
        osg::Matrixd _projectorViewMatrix, _projectorProjMatrix;
        osg::ref_ptr<const osg::EllipsoidModel> _ellipsoid;
        osg::ref_ptr<osgEarth::VirtualProgram> _vp;
        osg::ref_ptr<TerrainEngineNode> _engine;
    };

} // namespace osgEarth

#endif //OSGEARTH_OVERLAY_DECORATOR
