/* -*-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.
*/
//osgFX - Copyright (C) 2003 Marco Jez

#ifndef OSGFX_BUMPMAPPING_
#define OSGFX_BUMPMAPPING_

#include <osgFX/Export>
#include <osgFX/Effect>

#include <osg/ref_ptr>
#include <osg/Texture2D>

namespace osgFX
{

    /**
     This effect makes surfaces appear bumpy. Children nodes must use two textures, 
     one for diffuse color and one for the normal map (which can be created 
     from a height map with tools like nVIDIA's normal map generator). Furthermore, 
     tangent-space basis vectors must be created and assigned to each Geometry; this 
     can be done quickly by calling BumpMapping::prepareChildren(). Note that both 
     diffuse and normal map textures must have corresponding UV maps defined in 
     Geometry objects.
     This effect defines a preferred technique which uses ARB vertex & fragment 
     programs, and a fallback technique which doesn't use fragment programs. The 
     latter is more limited though since it can't handle ambient and specular 
     components.
     */
    class OSGFX_EXPORT BumpMapping: public Effect {
    public:
        BumpMapping();
        BumpMapping(const BumpMapping& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);

        META_Effect(osgFX, BumpMapping, 
        
            "Bump Mapping", 
            
            "This effect makes surfaces appear bumpy. Children nodes must use two textures, "
            "one for diffuse color and one for the normal map (which can be created "
            "from a height map with tools like nVIDIA's normal map generator). Furthermore, "
            "tangent-space basis vectors must be created and assigned to each Geometry; this "
            "can be done quickly by calling BumpMapping::prepareChildren(). Note that both "
            "diffuse and normal map textures must have corresponding UV maps defined in "
            "Geometry objects.\n"
            "This effect defines a preferred technique which uses ARB vertex & fragment "
            "programs, and a fallback technique which doesn't use fragment programs. The "
            "latter is more limited though since it can't handle ambient and specular "
            "components.",
            
            "Marco Jez");
            
        
        /** get the OpenGL light number */
        inline int getLightNumber() const;
        
        /** set the OpenGL light number that will be used in lighting computations */
        inline void setLightNumber(int n);
        
        /** get the texture unit that contains diffuse color texture. Default is 1 */
        inline int getDiffuseTextureUnit() const;
        
        /** set the texture unit that contains diffuse color texture. Default is 1 */
        inline void setDiffuseTextureUnit(int n);

        /** get the texture unit that contains normal map texture. Default is 0 */
        inline int getNormalMapTextureUnit() const;
        
        /** set the texture unit that contains normal map texture. Default is 0 */
        inline void setNormalMapTextureUnit(int n);
        
        /** get the diffuse color texture that overrides children's texture */
        inline osg::Texture2D* getOverrideDiffuseTexture();
        
        /** get the const diffuse color texture that overrides children's texture */
        inline const osg::Texture2D* getOverrideDiffuseTexture() const;
        
        /** set the diffuse color texture that overrides children's texture */
        inline void setOverrideDiffuseTexture(osg::Texture2D* texture);
        
        /** get the normal map texture that overrides children's texture */
        inline osg::Texture2D* getOverrideNormalMapTexture();
        
        /** get the const normal map texture that overrides children's texture */
        inline const osg::Texture2D* getOverrideNormalMapTexture() const;

        /** set the normal map texture that overrides children's texture */
        inline void setOverrideNormalMapTexture(osg::Texture2D* texture);
        
        /**
         prepare a Geometry for bump lighting. Tangent-space basis vectors are
         generated and attached to the geometry as vertex attribute arrays.
         */
        void prepareGeometry(osg::Geometry* geo);
        
        /** prepare a Node for bump lighting, calling prepareGeometry() for each Geometry */
        void prepareNode(osg::Node* node);
        
        /** prepare children for bump lighting. Actually calls prepareNode() for each child */
        void prepareChildren();
        
        /** set up a demo environment with predefined diffuse and normal maps, as well as texture coordinates */
        void setUpDemo();

    protected:
        virtual ~BumpMapping() {}
        BumpMapping &operator=(const BumpMapping &) { return *this; }

        bool define_techniques();

    private:
        int _lightnum;
        int _diffuse_unit;
        int _normal_unit;
        osg::ref_ptr<osg::Texture2D> _diffuse_tex;
        osg::ref_ptr<osg::Texture2D> _normal_tex;
    };

    // INLINE METHODS    
   
    inline int BumpMapping::getLightNumber() const
    {
        return _lightnum;
    }
    
    inline void BumpMapping::setLightNumber(int n)
    {
        _lightnum = n;
        dirtyTechniques();
    }
    
    inline int BumpMapping::getDiffuseTextureUnit() const
    {
        return _diffuse_unit;
    }
    
    inline void BumpMapping::setDiffuseTextureUnit(int n)
    {
        _diffuse_unit = n;
        dirtyTechniques();
    }
    
    inline int BumpMapping::getNormalMapTextureUnit() const
    {
        return _normal_unit;
    }
    
    inline void BumpMapping::setNormalMapTextureUnit(int n)
    {
        _normal_unit = n;
        dirtyTechniques();
    }
    
    inline osg::Texture2D* BumpMapping::getOverrideDiffuseTexture()
    {
        return _diffuse_tex.get();
    }

    inline const osg::Texture2D* BumpMapping::getOverrideDiffuseTexture() const
    {
        return _diffuse_tex.get();
    }
    
    inline void BumpMapping::setOverrideDiffuseTexture(osg::Texture2D* texture)
    {
        _diffuse_tex = texture;
        dirtyTechniques();
    }

    inline osg::Texture2D* BumpMapping::getOverrideNormalMapTexture()
    {
        return _normal_tex.get();
    }

    inline const osg::Texture2D* BumpMapping::getOverrideNormalMapTexture() const
    {
        return _normal_tex.get();
    }
    
    inline void BumpMapping::setOverrideNormalMapTexture(osg::Texture2D* texture)
    {
        _normal_tex = texture;
        dirtyTechniques();
    }

}

#endif