/* -*-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 OSG_TRANSFERFUNCTION
#define OSG_TRANSFERFUNCTION 1

#include <osg/Texture>
#include <osg/Shader>

#include <map>

namespace osg {


/** TransferFunction is a class that provide a 1D,2D or 3D colour look up table
  * that can be used on the GPU as a 1D, 2D or 3D texture.  
  * Typically uses include mapping heights to colours when contouring terrain, 
  * or mapping intensities to colours when volume rendering.
*/
class OSG_EXPORT TransferFunction : public osg::Referenced
{
    public :
    
        TransferFunction();

        osg::Image* getImage() { return _image.get(); }
        const osg::Image* getImage() const { return _image.get(); }
        
    protected:
    
        virtual ~TransferFunction();

        typedef std::vector<osg::Vec4> Colors;

        Colors                      _colors;
        osg::ref_ptr<osg::Image>    _image;
};

/** 1D variant of TransferFunction. */
class OSG_EXPORT TransferFunction1D : public osg::TransferFunction
{
    public:
    
        TransferFunction1D();
    
        void setInputRange(float minimum, float maximum);
        
        void setMinimum(float value) { _minimum = value; }
        float getMinimum() const { return _minimum; }
        
        void setMaximum(float value) { _maximum = value; }
        float getMaximum() const { return _maximum; }

        void allocate(unsigned int numX);

        void clear(const osg::Vec4& color = osg::Vec4(1.0f,1.0f,1.0f,1.0f));
        
        unsigned int getNumberCellsX() const { return _colors.size(); }

        void setValue(unsigned int i, const osg::Vec4& color) { _colors[i] = color; if (_image.valid()) _image->dirty(); }
        const osg::Vec4& getValue(unsigned int i) const { return _colors[i]; }

        osg::Vec4 getInterpolatedValue(float v) const
        {
            float iPos = (v-_minimum)*float(_colors.size()-1)/(_maximum-_minimum);
            if (iPos<0.0) return _colors[0];
            if (iPos>float(_colors.size()-1)) return _colors[_colors.size()-1];
            
            unsigned int iLower = (unsigned int)(iPos);
            unsigned int iUpper = iLower+1;
            if (iUpper>=_colors.size()) return _colors[iLower];
            
            float r = iPos-floorf(iLower);
            const osg::Vec4& cLower = _colors[iLower];
            const osg::Vec4& cUpper = _colors[iUpper];
            return cLower + (cUpper-cLower)*r;
        }
        
        typedef std::map<float, osg::Vec4> ValueMap;
        void assign(const ValueMap& vcm, bool updateMinMaxRange);

    protected:
    
        float _minimum;
        float _maximum;
    
};

}

#endif
