/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield 
 *
 * This library is open source and may be redistributed and/or modified under  
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or 
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 * 
 * This library 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 
 * OpenSceneGraph Public License for more details.
*/

#ifndef OSGTERRAIN_GEOMETRYTECHNIQUE
#define OSGTERRAIN_GEOMETRYTECHNIQUE 1

#include <osg/MatrixTransform>
#include <osg/Geode>
#include <osg/Geometry>

#include <osgTerrain/TerrainTechnique>
#include <osgTerrain/Locator>

namespace osgTerrain {

class OSGTERRAIN_EXPORT GeometryTechnique : public TerrainTechnique
{
    public:

        GeometryTechnique();

        /** Copy constructor using CopyOp to manage deep vs shallow copy.*/
        GeometryTechnique(const GeometryTechnique&,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
        
        META_Object(osgTerrain, GeometryTechnique);
        
        virtual void init();
        
        virtual Locator* computeMasterLocator();
        
        virtual osg::Vec3d computeCenterModel(Locator* masterLocator);
        
        virtual void generateGeometry(Locator* masterLocator, const osg::Vec3d& centerModel);
        
        virtual void applyColorLayers();
        
        virtual void applyTransparency();
        
        virtual void smoothGeometry();

        virtual void update(osgUtil::UpdateVisitor* nv);

        virtual void cull(osgUtil::CullVisitor* nv);

        /** Traverse the terain subgraph.*/
        virtual void traverse(osg::NodeVisitor& nv);

        virtual void cleanSceneGraph();

        void setFilterBias(float filterBias);
        float getFilterBias() const { return _filterBias; }
        
        void setFilterWidth(float filterWidth);
        float getFilterWidth() const { return _filterWidth; }

        void setFilterMatrix(const osg::Matrix3& matrix);
        osg::Matrix3& getFilterMatrix() { return _filterMatrix; }
        const osg::Matrix3& getFilterMatrix() const { return _filterMatrix; }
        
        enum FilterType
        {
            GAUSSIAN,
            SMOOTH,
            SHARPEN
        };
        
        void setFilterMatrixAs(FilterType filterType);


    private:

        virtual ~GeometryTechnique();

        struct BufferData
        {
            osg::ref_ptr<osg::MatrixTransform>  _transform;
            osg::ref_ptr<osg::Geode>            _geode;
            osg::ref_ptr<osg::Geometry>         _geometry;
        };
        
        unsigned int                        _currentReadOnlyBuffer;
        unsigned int                        _currentWriteBuffer;
        
        BufferData                          _bufferData[2];
        
        void swapBuffers();

        inline BufferData& getReadOnlyBuffer() { return _bufferData[_currentReadOnlyBuffer]; }
        inline BufferData& getWriteBuffer() { return _bufferData[_currentWriteBuffer]; }
        
                
        float                               _filterBias;
        osg::ref_ptr<osg::Uniform>          _filterBiasUniform;
        float                               _filterWidth;
        osg::ref_ptr<osg::Uniform>          _filterWidthUniform;
        osg::Matrix3                        _filterMatrix;
        osg::ref_ptr<osg::Uniform>          _filterMatrixUniform;
};

}

#endif
