#include <iostream>
#include <osg/Geode>
#include <osg/TexGen>
#include <osg/Material>
#include <osg/Texture2D>
#include <osg/MatrixTransform>
#include <osg/ShapeDrawable>
#include <osg/BlendFunc>
#include <osgText/Text>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osgViewer/View>
#include <osgViewer/CompositeViewer>
#include <osgGA/TrackballManipulator>

#include "VirtualProgram.h"

using osgCandidate::VirtualProgram;

////////////////////////////////////////////////////////////////////////////////
// Example shaders assume:
// one texture
// one directional light 
// front face lighting
// color material mode not used (its not supported by GLSL anyway)
// diffuse/ambient/emissive/specular factors defined in material structure
// all coords and normal except gl_Position are in view space
////////////////////////////////////////////////////////////////////////////////

char MainVertexShaderSource[] =
"vec4 texture( in vec3 position, in vec3 normal );                          \n" //1
"void lighting( in vec3 position, in vec3 normal );                         \n" //2
"                                                                           \n" //3
"void main ()                                                               \n" //4
"{                                                                          \n" //5
"    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;                \n" //6
"    vec4 position4 = gl_ModelViewMatrix * gl_Vertex;                       \n" //7
"    vec3 position = position4.xyz / position4.w;                           \n" //8
"    vec3 normal = normalize( gl_NormalMatrix * gl_Normal );                \n" //9
"    gl_TexCoord[0] = texture( position, normal );                          \n" //10
"    lighting( position, normal );                                          \n" //11
"}                                                                          \n";//12

char TexCoordTextureVertexShaderSource[] =
"vec4 texture( in vec3 position, in vec3 normal )                           \n" //1
"{                                                                          \n" //2
"    return gl_TextureMatrix[0] * gl_MultiTexCoord0;                        \n" //3
"}                                                                          \n";//4

char SphereMapTextureVertexShaderSource[] =
"vec4 texture( in vec3 position, in vec3 normal )                           \n" //1
"{                                                                          \n" //2
"    vec3 u = normalize( position );                                        \n" //3
"    vec3 r = reflect(u, normal);                                           \n" //4
"    float m = 2.0 * sqrt(r.x * r.x + r.y * r.y + (r.z+1.0) * (r.z+1.0));   \n" //5
"    return vec4(r.x / m + 0.5, r.y / m + 0.5, 1.0, 1.0 );                  \n" //6
"}                                                                          \n";//7

char PerVertexDirectionalLightingVertexShaderSource[] = 
"void lighting( in vec3 position, in vec3 normal )                          \n" //1
"{                                                                          \n" //2
"    float NdotL = dot( normal, normalize(gl_LightSource[0].position.xyz) );\n" //3
"    NdotL = max( 0.0, NdotL );                                             \n" //4
"    float NdotHV = dot( normal, gl_LightSource[0].halfVector.xyz );        \n" //5
"    NdotHV = max( 0.0, NdotHV );                                           \n" //6
"                                                                           \n" //7
"    gl_FrontColor = gl_FrontLightModelProduct.sceneColor +                 \n" //8
"                    gl_FrontLightProduct[0].ambient +                      \n" //9
"                    gl_FrontLightProduct[0].diffuse * NdotL;               \n" //10
"                                                                           \n" //11
"    gl_FrontSecondaryColor = vec4(0.0);                                    \n" //12
"                                                                           \n" //13
"    if ( NdotL * NdotHV > 0.0 )                                            \n" //14
"        gl_FrontSecondaryColor = gl_FrontLightProduct[0].specular *        \n" //15
"                                 pow( NdotHV, gl_FrontMaterial.shininess );\n" //16
"                                                                           \n" //17
"    gl_BackColor = gl_FrontColor;                                          \n" //18
"    gl_BackSecondaryColor = gl_FrontSecondaryColor;                        \n" //19
"}                                                                          \n";//20

char MainFragmentShaderSource[] =
"vec4 texture( void );                                                      \n" //1
"void lighting( inout vec4 color );                                         \n" //2
"                                                                           \n" //3
"void main ()                                                               \n" //4
"{                                                                          \n" //5
"    vec4 color = texture();                                                \n" //6
"    lighting( color );                                                     \n" //7
"    gl_FragColor = color;                                                  \n" //8
"}                                                                          \n";//9

char TextureFragmentShaderSource[] =
"uniform sampler2D baseTexture;                                             \n" //1
"vec4 texture( void )                                                       \n" //2
"{                                                                          \n" //3
"    return texture2D( baseTexture, gl_TexCoord[0].xy );                    \n" //4
"}                                                                          \n";//5

char ProceduralBlueTextureFragmentShaderSource[] =
"vec4 texture( void )                                                       \n" //1
"{                                                                          \n" //2
"    return vec4( 0.3, 0.3, 1.0, 1.0 );                                     \n" //3
"}                                                                          \n";//4

char PerVertexLightingFragmentShaderSource[] =
"void lighting( inout vec4 color )                                          \n" //1
"{                                                                          \n" //2
"    color = color * gl_Color + gl_SecondaryColor;                          \n" //3
"}                                                                          \n";//4

char PerFragmentLightingVertexShaderSource[] =
"varying vec3 Normal;                                                       \n" //1
"varying vec3 Position;                                                     \n" //2
"                                                                           \n" //3
"void lighting( in vec3 position, in vec3 normal )                          \n" //4
"{                                                                          \n" //5
"    Normal = normal;                                                       \n" //6
"    Position = position;                                                   \n" //7
"}                                                                          \n";//8

char PerFragmentDirectionalLightingFragmentShaderSource[] =
"varying vec3 Normal;                                                       \n" //1
"varying vec3 Position; // not used for directional lighting                \n" //2
"                                                                           \n" //3
"void lighting( inout vec4 color )                                          \n" //4
"{                                                                          \n" //5
"    vec3 n = normalize( Normal );                                          \n" //5
"    float NdotL = dot( n, normalize(gl_LightSource[0].position.xyz) );     \n" //6
"    NdotL = max( 0.0, NdotL );                                             \n" //7
"    float NdotHV = dot( n, gl_LightSource[0].halfVector.xyz );             \n" //8
"    NdotHV = max( 0.0, NdotHV );                                           \n" //9
"                                                                           \n" //10
"    color *= gl_FrontLightModelProduct.sceneColor +                        \n" //11
"             gl_FrontLightProduct[0].ambient +                             \n" //12
"             gl_FrontLightProduct[0].diffuse * NdotL;                      \n" //13
"                                                                           \n" //14
"    if ( NdotL * NdotHV > 0.0 )                                            \n" //15
"        color += gl_FrontLightProduct[0].specular *                        \n" //16
"                 pow( NdotHV, gl_FrontMaterial.shininess );                \n" //17
"}                                                                          \n";//18

////////////////////////////////////////////////////////////////////////////////
osg::Node * CreateModel( const char * file )
{
    if ( file ) {
        osg::Node * node = NULL;        
        node = osgDB::readNodeFile( file );
        if( node )
            return node;
    }

    // File not found - create textured sphere 
    osg::Geode * geode = new osg::Geode;
    osg::ref_ptr<osg::TessellationHints> hints = new osg::TessellationHints;
    hints->setDetailRatio( 0.3 );

#if 1
    osg::ref_ptr<osg::ShapeDrawable> shape = new osg::ShapeDrawable
        ( new osg::Sphere(osg::Vec3(0.0f, 0.0f, 0.0f), 4.0 ), hints.get() );
#else
    osg::ref_ptr<osg::ShapeDrawable> shape = new osg::ShapeDrawable
        ( new osg::Box( osg::Vec3(-1.0f, -1.0f, -1.0f), 2.0, 2.0, 2.0 ) );
#endif

    shape->setColor(osg::Vec4(0.8f, 0.8f, 0.8f, 1.0f));

    geode->addDrawable( shape.get() );

    osg::StateSet * stateSet = new osg::StateSet;

    osg::Texture2D * texture =  new osg::Texture2D( 
        osgDB::readImageFile("Images/land_shallow_topo_2048.jpg") 
    );

    osg::Material * material = new osg::Material;

    material->setAmbient
        ( osg::Material::FRONT_AND_BACK, osg::Vec4( 0.9, 0.9, 0.9, 1.0 ) );

    material->setDiffuse
        ( osg::Material::FRONT_AND_BACK, osg::Vec4( 0.9, 0.9, 0.9, 1.0 ) );

#if 1
    material->setSpecular
        ( osg::Material::FRONT_AND_BACK, osg::Vec4( 0.7, 0.3, 0.3, 1.0 ) );

    material->setShininess( osg::Material::FRONT_AND_BACK, 25 );

#endif

    stateSet->setAttributeAndModes( material );
    stateSet->setTextureAttributeAndModes( 0,texture, osg::StateAttribute::ON );

    geode->setStateSet( stateSet );
    return geode;
}
////////////////////////////////////////////////////////////////////////////////
// Convenience method to simplify code a little ...
void SetVirtualProgramShader( VirtualProgram * virtualProgram,
                              std::string shader_semantics,
                              osg::Shader::Type shader_type,
                              std::string shader_name,
                              std::string shader_source )
{
    osg::Shader * shader = new osg::Shader( shader_type );
    shader->setName( shader_name );
    shader->setShaderSource( shader_source );
    virtualProgram->setShader( shader_semantics, shader );
}
///////////////////////////////////////////////////////////////////////////////
void AddLabel( osg::Group * group, const std::string & label, float offset )
{
    osg::Vec3 center( 0, 0, offset * 0.5 );
    osg::Geode * geode = new osg::Geode;

    // Make sure no program breaks text outputs 
    geode->getOrCreateStateSet()->setAttribute
      ( new osg::Program, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED );

    // Turn off stage 1 texture set in parent transform (otherwise it darkens text)
    geode->getOrCreateStateSet()->setTextureMode( 1, GL_TEXTURE_2D, osg::StateAttribute::OFF );

    group->addChild( geode );

    osgText::Text* text = new osgText::Text;
    geode->addDrawable( text );
    text->setFont("fonts/times.ttf");
    text->setCharacterSize( offset * 0.1 );
    text->setPosition(center);
    text->setAlignment( osgText::TextBase::CENTER_CENTER );
    text->setAxisAlignment(osgText::Text::SCREEN);

    osg::Vec4 characterSizeModeColor(1.0f,0.0f,0.5f,1.0f);
#if 1
    // reproduce outline bounding box compute problem with backdrop on.
    text->setBackdropType(osgText::Text::OUTLINE);
    text->setDrawMode(osgText::Text::TEXT | osgText::Text::BOUNDINGBOX);
#endif

    text->setText( label );
}
////////////////////////////////////////////////////////////////////////////////
osg::Node * CreateAdvancedHierarchy( const char * file = NULL )
{
    osg::Node * model = CreateModel( file );
    if( !model ) return NULL;
    float offset = model->getBound().radius() * 1.3; // diameter

    // Create transforms for translated instances of the model
    osg::MatrixTransform * transformCenterMiddle  = new osg::MatrixTransform( );
    transformCenterMiddle->setMatrix( osg::Matrix::translate( 0,0, offset * 0.5 ) );
    transformCenterMiddle->addChild( model );

    osg::MatrixTransform * transformCenterTop  = new osg::MatrixTransform( );
    transformCenterMiddle->addChild( transformCenterTop );
    transformCenterTop->setMatrix( osg::Matrix::translate( 0,0,offset ) );
    transformCenterTop->addChild( model );

    osg::MatrixTransform * transformCenterBottom  = new osg::MatrixTransform( );
    transformCenterMiddle->addChild( transformCenterBottom );
    transformCenterBottom->setMatrix( osg::Matrix::translate( 0,0,-offset ) );
    transformCenterBottom->addChild( model );

    osg::MatrixTransform * transformLeftBottom  = new osg::MatrixTransform( );
    transformCenterBottom->addChild( transformLeftBottom );
    transformLeftBottom->setMatrix( osg::Matrix::translate( -offset * 0.8,0, -offset * 0.8 ) );
    transformLeftBottom->addChild( model );

    osg::MatrixTransform * transformRightBottom  = new osg::MatrixTransform( );
    transformCenterBottom->addChild( transformRightBottom );
    transformRightBottom->setMatrix( osg::Matrix::translate( offset * 0.8,0, -offset * 0.8 ) );
    transformRightBottom->addChild( model );

    // Set default VirtualProgram in root StateSet 
    // With main vertex and main fragment shaders calling 
    // lighting and texture functions defined in aditional shaders
    // Lighting is done per vertex using simple directional light
    // Texture uses stage 0 TexCoords and TexMap

    if( 1 ) 
    {
        // NOTE:
        // duplicating the same semantics name in virtual program 
        // is only possible if its used for shaders of differing types
        // here for VERTEX and FRAGMENT

        VirtualProgram * vp = new VirtualProgram( );
        transformCenterMiddle->getOrCreateStateSet()->setAttribute( vp );
        AddLabel( transformCenterMiddle, "Per Vertex Lighting Virtual Program", offset );

        SetVirtualProgramShader( vp, "main", osg::Shader::VERTEX,
            "Vertex Main", MainVertexShaderSource );

        SetVirtualProgramShader( vp, "main", osg::Shader::FRAGMENT,
            "Fragment Main", MainFragmentShaderSource );

        SetVirtualProgramShader( vp, "texture",osg::Shader::VERTEX,
            "Vertex Texture Coord 0", TexCoordTextureVertexShaderSource );

        SetVirtualProgramShader( vp, "texture",osg::Shader::FRAGMENT,
            "Fragment Texture", TextureFragmentShaderSource );

        SetVirtualProgramShader( vp, "lighting",osg::Shader::VERTEX,
            "Vertex Lighting", PerVertexDirectionalLightingVertexShaderSource );

        SetVirtualProgramShader( vp, "lighting",osg::Shader::FRAGMENT,
            "Fragment Lighting", PerVertexLightingFragmentShaderSource );

        transformCenterMiddle->getOrCreateStateSet()->
            addUniform( new osg::Uniform( "baseTexture", 0 ) );

    }

    // Override default vertex ligting with pixel lighting shaders
    // For three bottom models
    if( 1 ) 
    {
        AddLabel( transformCenterBottom, "Per Pixel Lighting VP", offset );
        VirtualProgram * vp = new VirtualProgram( );
        transformCenterBottom->getOrCreateStateSet()->setAttribute( vp );

        SetVirtualProgramShader( vp, "lighting",osg::Shader::VERTEX,
            "Vertex Shader For Per Pixel Lighting", 
            PerFragmentLightingVertexShaderSource );

        SetVirtualProgramShader( vp, "lighting",osg::Shader::FRAGMENT,
            "Fragment Shader For Per Pixel Lighting", 
            PerFragmentDirectionalLightingFragmentShaderSource );
    }

    // Additionaly set bottom left model texture to procedural blue to 
    // better observe smooth speculars done through per pixel lighting
    if( 1 ) 
    {
        AddLabel( transformLeftBottom, "Blue Tex VP", offset );
        VirtualProgram * vp = new VirtualProgram( );
        transformLeftBottom->getOrCreateStateSet()->setAttribute( vp );

        SetVirtualProgramShader( vp, "texture",osg::Shader::FRAGMENT,
            "Fragment Shader Procedural Blue Tex", 
            ProceduralBlueTextureFragmentShaderSource );
    }

    // Additionaly change texture mapping to SphereMAp in bottom right model 
    if( 1 )
    {
        AddLabel( transformRightBottom, "EnvMap Sphere VP", offset );

        osg::StateSet * ss = transformRightBottom->getOrCreateStateSet();
        VirtualProgram * vp = new VirtualProgram( );
        ss->setAttribute( vp );
        SetVirtualProgramShader( vp, "texture",osg::Shader::VERTEX,
            "Vertex Texture Sphere Map", SphereMapTextureVertexShaderSource );

        osg::Texture2D * texture =  new osg::Texture2D(
//            osgDB::readImageFile("Images/reflect.rgb") 
            osgDB::readImageFile("Images/skymap.jpg") 
        );

        // Texture is set on stage 1 to not interfere with label text
        // The same could be achieved with texture override 
        // but such approach also turns off label texture
        ss->setTextureAttributeAndModes( 1, texture, osg::StateAttribute::ON );
        ss->addUniform( new osg::Uniform( "baseTexture", 1 ) );

#if 0 // Could be useful with Fixed Vertex Pipeline
        osg::TexGen * texGen = new osg::TexGen();
        texGen->setMode( osg::TexGen::SPHERE_MAP );

        // Texture states applied
        ss->setTextureAttributeAndModes( 1, texGen, osg::StateAttribute::ON );
#endif

    }


    // Top center model usues osg::Program overriding VirtualProgram in model
    if( 1 ) 
    {
        AddLabel( transformCenterTop, "Fixed Vertex + Simple Fragment osg::Program", offset );
        osg::Program * program = new osg::Program;
        program->setName( "Trivial Fragment + Fixed Vertex Program" );

        transformCenterTop->getOrCreateStateSet( )->setAttributeAndModes
            ( program, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );

        osg::Shader * shader = new osg::Shader( osg::Shader::FRAGMENT );
        shader->setName( "Trivial Fragment Shader" );
        shader->setShaderSource(
            "uniform sampler2D baseTexture;                                          \n"
            "void main(void)                                                         \n"
            "{                                                                       \n"
            "    gl_FragColor = gl_Color * texture2D( baseTexture,gl_TexCoord[0].xy);\n"
            "}                                                                       \n"
            );

        program->addShader( shader );
    }

    return transformCenterMiddle;
}

////////////////////////////////////////////////////////////////////////////////
// Shders not used in the example but left for fun if anyone wants to play 
char LightingVertexShaderSource[] = 
"// Forward declarations                                                    \n" //1
"                                                                           \n" //2
"void SpotLight( in int i, in vec3 eye, in vec3 position, in vec3 normal,   \n" //3
"            inout vec4 ambient, inout vec4 diffuse, inout vec4 specular ); \n" //4
"                                                                           \n" //5
"void PointLight( in int i, in vec3 eye, in vec3 position, in vec3 normal,  \n" //6
"            inout vec4 ambient, inout vec4 diffuse, inout vec4 specular ); \n" //7
"                                                                           \n" //8
"void DirectionalLight( in int i, in vec3 normal,                           \n" //9
"            inout vec4 ambient, inout vec4 diffuse, inout vec4 specular ); \n" //10
"                                                                           \n" //11
"const int NumEnabledLights = 1;                                            \n" //12
"                                                                           \n" //13
"void lighting( in vec3 position, in vec3 normal )                          \n" //14
"{                                                                          \n" //15
"    vec3  eye = vec3( 0.0, 0.0, 1.0 );                                     \n" //16
"    //vec3  eye = -normalize(position);                                    \n" //17
"                                                                           \n" //18
"    // Clear the light intensity accumulators                              \n" //19
"    vec4 amb  = vec4(0.0);                                                 \n" //20
"    vec4 diff = vec4(0.0);                                                 \n" //21
"    vec4 spec = vec4(0.0);                                                 \n" //22
"                                                                           \n" //23
"    // Loop through enabled lights, compute contribution from each         \n" //24
"    for (int i = 0; i < NumEnabledLights; i++)                             \n" //25
"   {                                                                       \n" //26
"       if (gl_LightSource[i].position.w == 0.0)                            \n" //27
"           DirectionalLight(i, normal, amb, diff, spec);                   \n" //28
"       else if (gl_LightSource[i].spotCutoff == 180.0)                     \n" //29
"           PointLight(i, eye, position, normal, amb, diff, spec);          \n" //30
"       else                                                                \n" //31
"           SpotLight(i, eye, position, normal, amb, diff, spec);           \n" //32
"    }                                                                      \n" //33
"                                                                           \n" //34
"    gl_FrontColor = gl_FrontLightModelProduct.sceneColor +                 \n" //35
"                    amb * gl_FrontMaterial.ambient +                       \n" //36
"                    diff * gl_FrontMaterial.diffuse;                       \n" //37
"                                                                           \n" //38
"    gl_FrontSecondaryColor = vec4(spec*gl_FrontMaterial.specular);         \n" //39
"                                                                           \n" //40
"    gl_BackColor = gl_FrontColor;                                          \n" //41
"    gl_BackSecondaryColor = gl_FrontSecondaryColor;                        \n" //42
"}                                                                          \n";//43

char SpotLightShaderSource[] = 
"void SpotLight(in int i,                                                   \n" //1
"               in vec3 eye,                                                \n" //2
"               in vec3 position,                                           \n" //3
"               in vec3 normal,                                             \n" //4
"               inout vec4 ambient,                                         \n" //5
"               inout vec4 diffuse,                                         \n" //6
"               inout vec4 specular)                                        \n" //7
"{                                                                          \n" //8
"    float nDotVP;          // normal . light direction                     \n" //9
"    float nDotHV;          // normal . light half vector                   \n" //10
"    float pf;              // power factor                                 \n" //11
"    float spotDot;         // cosine of angle between spotlight            \n" //12
"    float spotAttenuation; // spotlight attenuation factor                 \n" //13
"    float attenuation;     // computed attenuation factor                  \n" //14
"    float d;               // distance from surface to light source        \n" //15
"    vec3 VP;               // direction from surface to light position     \n" //16
"    vec3 halfVector;       // direction of maximum highlights              \n" //17
"                                                                           \n" //18
"    // Compute vector from surface to light position                       \n" //19
"    VP = vec3(gl_LightSource[i].position) - position;                      \n" //20
"                                                                           \n" //21
"    // Compute distance between surface and light position                 \n" //22
"    d = length(VP);                                                        \n" //23
"                                                                           \n" //24
"    // Normalize the vector from surface to light position                 \n" //25
"    VP = normalize(VP);                                                    \n" //26
"                                                                           \n" //27
"    // Compute attenuation                                                 \n" //28
"    attenuation = 1.0 / (gl_LightSource[i].constantAttenuation +           \n" //29
"                         gl_LightSource[i].linearAttenuation * d +         \n" //30
"                         gl_LightSource[i].quadraticAttenuation *d*d);     \n" //31
"                                                                           \n" //32
"    // See if point on surface is inside cone of illumination              \n" //33
"    spotDot = dot(-VP, normalize(gl_LightSource[i].spotDirection));        \n" //34
"                                                                           \n" //35
"    if (spotDot < gl_LightSource[i].spotCosCutoff)                         \n" //36
"        spotAttenuation = 0.0; // light adds no contribution               \n" //37
"    else                                                                   \n" //38
"        spotAttenuation = pow(spotDot, gl_LightSource[i].spotExponent);    \n" //39
"                                                                           \n" //40
"    // Combine the spotlight and distance attenuation.                     \n" //41
"    attenuation *= spotAttenuation;                                        \n" //42
"                                                                           \n" //43
"    halfVector = normalize(VP + eye);                                      \n" //44
"                                                                           \n" //45
"    nDotVP = max(0.0, dot(normal, VP));                                    \n" //46
"    nDotHV = max(0.0, dot(normal, halfVector));                            \n" //47
"                                                                           \n" //48
"    if (nDotVP == 0.0)                                                     \n" //49
"        pf = 0.0;                                                          \n" //50
"    else                                                                   \n" //51
"        pf = pow(nDotHV, gl_FrontMaterial.shininess);                      \n" //52
"                                                                           \n" //53
"    ambient  += gl_LightSource[i].ambient * attenuation;                   \n" //54
"    diffuse  += gl_LightSource[i].diffuse * nDotVP * attenuation;          \n" //55
"    specular += gl_LightSource[i].specular * pf * attenuation;             \n" //56
"}                                                                          \n";//57

char PointLightShaderSource[] = 
"void PointLight(in int i,                                                  \n" //1
"                in vec3 eye,                                               \n" //2
"                in vec3 position,                                          \n" //3
"                in vec3 normal,                                            \n" //4
"                inout vec4 ambient,                                        \n" //5
"                inout vec4 diffuse,                                        \n" //6
"                inout vec4 specular)                                       \n" //7
"{                                                                          \n" //8
"    float nDotVP;      // normal . light direction                         \n" //9
"    float nDotHV;      // normal . light half vector                       \n" //10
"    float pf;          // power factor                                     \n" //11
"    float attenuation; // computed attenuation factor                      \n" //12
"    float d;           // distance from surface to light source            \n" //13
"    vec3  VP;          // direction from surface to light position         \n" //14
"    vec3  halfVector;  // direction of maximum highlights                  \n" //15
"                                                                           \n" //16
"    // Compute vector from surface to light position                       \n" //17
"    VP = vec3(gl_LightSource[i].position) - position;                      \n" //18
"                                                                           \n" //19
"    // Compute distance between surface and light position                 \n" //20
"    d = length(VP);                                                        \n" //21
"                                                                           \n" //22
"    // Normalize the vector from surface to light position                 \n" //23
"    VP = normalize(VP);                                                    \n" //24
"                                                                           \n" //25
"    // Compute attenuation                                                 \n" //26
"    attenuation = 1.0 / (gl_LightSource[i].constantAttenuation +           \n" //27
"                         gl_LightSource[i].linearAttenuation * d +         \n" //28
"                         gl_LightSource[i].quadraticAttenuation * d*d);    \n" //29
"                                                                           \n" //30
"    halfVector = normalize(VP + eye);                                      \n" //31
"                                                                           \n" //32
"    nDotVP = max(0.0, dot(normal, VP));                                    \n" //33
"    nDotHV = max(0.0, dot(normal, halfVector));                            \n" //34
"                                                                           \n" //35
"    if (nDotVP == 0.0)                                                     \n" //36
"        pf = 0.0;                                                          \n" //37
"    else                                                                   \n" //38
"        pf = pow(nDotHV, gl_FrontMaterial.shininess);                      \n" //39
"                                                                           \n" //40
"    ambient += gl_LightSource[i].ambient * attenuation;                    \n" //41
"    diffuse += gl_LightSource[i].diffuse * nDotVP * attenuation;           \n" //42
"    specular += gl_LightSource[i].specular * pf * attenuation;             \n" //43
"}                                                                          \n";//44

char DirectionalLightShaderSource[] =
"void DirectionalLight(in int i,                                            \n" //1
"                      in vec3 normal,                                      \n" //2
"                      inout vec4 ambient,                                  \n" //3
"                      inout vec4 diffuse,                                  \n" //4
"                      inout vec4 specular)                                 \n" //5
"{                                                                          \n" //6
"     float nDotVP;         // normal . light direction                     \n" //7
"     float nDotHV;         // normal . light half vector                   \n" //8
"     float pf;             // power factor                                 \n" //9
"                                                                           \n" //10
"     nDotVP = max(0.0, dot(normal,                                         \n" //11
"                normalize(vec3(gl_LightSource[i].position))));             \n" //12
"     nDotHV = max(0.0, dot(normal,                                         \n" //13
"                      vec3(gl_LightSource[i].halfVector)));                \n" //14
"                                                                           \n" //15
"     if (nDotVP == 0.0)                                                    \n" //16
"         pf = 0.0;                                                         \n" //17
"     else                                                                  \n" //18
"         pf = pow(nDotHV, gl_FrontMaterial.shininess);                     \n" //19
"                                                                           \n" //20
"     ambient  += gl_LightSource[i].ambient;                                \n" //21
"     diffuse  += gl_LightSource[i].diffuse * nDotVP;                       \n" //22
"     specular += gl_LightSource[i].specular * pf;                          \n" //23
"}                                                                          \n";//24

