/* -*-c++-*- */
/* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
* Copyright 2008-2012 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 OSGEARTHUTIL_TEXTURE_SPLATTER_H
#define OSGEARTHUTIL_TEXTURE_SPLATTER_H

#include <osgEarthUtil/Common>
#include <osgEarth/TerrainEffect>
#include <osgEarth/ImageLayer>
#include <osgEarth/URI>
#include <osg/Image>
#include <osg/Uniform>
#include <osg/Texture2DArray>

using namespace osgEarth;

namespace osgEarth {
class Map;

namespace Util
{
    /**
     * Controller that splats texture on the terrain according to a
     * color mask.
     */
    class OSGEARTHUTIL_EXPORT TextureSplatter : public TerrainEffect
    {
    public:
        /** construct a new splatting controller */
        TextureSplatter();

        /**
         * The image layer that generates the splat mask. You must call
         * this prior to installing the effect. The layer must be installed
         * in the Map with shared=true.
         */            
        void setMaskLayer(ImageLayer* layer) { _maskLayer = layer; }
        ImageLayer* getMaskLayer() { return _maskLayer.get(); }

        /** Sets the LOD at which to start detailing */
        void setStartLOD( unsigned lod );
        unsigned getStartLOD() const { return _startLOD.get(); }

        /** Sets the intensity (0=none, 1=full) */
        void setIntensity( float value );
        float getIntensity() const { return _intensity.get(); }

        /** Sets the attenuation distance, i.e. the distance from the camera
            at which the detail texture will fade out completely. */
        void setAttenuationDistance( float value );
        float getAttenuationDistance() const { return _attenuationDistance.get(); }

        /** Sets the scale factor for the texture (1..) */
        void setScale( float value );
        float getScale() const { return _scale.get(); }

        /** Whether to use the inverse of the mask */
        void setInvert( bool value );
        bool getInvert() const { return _invert.get(); }

    public: // TerrainEffect interface

        void onInstall(TerrainEngineNode* engine);
        void onUninstall(TerrainEngineNode* engine);

    public: // serialization

        TextureSplatter(const Config& conf, const Map* map);
        void mergeConfig(const Config& conf);
        virtual Config getConfig() const;

    protected:
        virtual ~TextureSplatter() { }
        void init();

        optional<float>          _intensity;
        optional<unsigned>       _startLOD;
        optional<std::string>    _maskLayerName;
        optional<float>          _scale;
        optional<float>          _attenuationDistance;
        optional<bool>           _invert;

        struct TextureSource {
            std::string _tag;
            std::string _url;
        };
        std::vector<TextureSource> _textures;

        osg::ref_ptr<osg::Uniform>         _intensityUniform;
        osg::ref_ptr<osg::Uniform>         _startLODUniform;
        osg::ref_ptr<osg::Uniform>         _scaleUniform;
        osg::ref_ptr<osg::Uniform>         _attenuationDistanceUniform;
        osg::ref_ptr<osg::Uniform>         _samplerUniform;
        osg::ref_ptr<osg::Uniform>         _maskUniform;
        osg::ref_ptr<osg::Uniform>         _brightnessUniform;
        osg::ref_ptr<osg::Texture2DArray>  _texture;
        int                                _unit;
        osg::observer_ptr<ImageLayer>      _maskLayer;
        osg::ref_ptr<osgDB::Options>       _dbOptions;

        std::string genFragShader();
    };

} } // namespace osgEarth::Util

#endif // OSGEARTHUTIL_TEXTURE_SPLATTER_H
