<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE fshShader SYSTEM "fshShadingBlock.dtd">
<codeblocks label="root" type="std" class="STATIC_BLOCK">
<codeblock label="declarations" type="std" class="STATIC_BLOCK">
//
//  fsh.xml
//
//  Copyright 2011-2012 Apple Inc. All rights reserved.
//

#define MAX_LIGHTS      3

#define MAX_TEXTURES    3
#define MAX_TEX_COORDS  3
#define S               0
#define T               1
#define R               2
#define STR             3

#define GLKTextureTarget2d              0
#define GLKTextureTargetCubeMap         1

#define GLKTextureEnvAttribReplace         0
#define GLKTextureEnvAttribModulate        1
#define GLKTextureEnvAttribDecal           2

#define GLKTexGenModeObjectLinear      0
#define GLKTexGenModeEyeLinear         1
#define GLKTexGenModeSphereMap         2
#define GLKTexGenModeReflectionMap     3

#ifndef GL_ES
#define lowp
#define mediump
#define highp

#define IN_VERT  in
#define OUT_VERT out
#define IN_FRAG  in
#define OUT_FRAG out

#define texture2D   texture
#define textureCube texture

out vec4 out_color;
#else
#define IN_VERT  attribute
#define OUT_VERT varying
#define IN_FRAG  varying
#define OUT_FRAG

precision highp float;
#define out_color gl_FragColor
#endif

struct texGen_s
{
    lowp  int       mode;
    highp vec4      plane;
    highp vec4      eyePlaneByInvModelview;
};

struct texture_s
{
    mat4                matrix;
    lowp vec4           envColor;
    texGen_s            texGen[STR];
};

uniform lowp sampler2D         unit2d[3];
uniform lowp samplerCube     unitCube[3];

/////////////////////////////////////////////////////////////////////////////////////
// Globals
/////////////////////////////////////////////////////////////////////////////////////
uniform lowp vec4   lightModelAmbientColor;


/////////////////////////////////////////////////////////////////////////////////////
// LIGHT
/////////////////////////////////////////////////////////////////////////////////////
uniform bool        light_enabled[MAX_LIGHTS];
uniform vec4        light_positionEye[MAX_LIGHTS];
uniform lowp vec4   light_ambientColor[MAX_LIGHTS];
uniform lowp vec4   light_diffuseColor[MAX_LIGHTS];
uniform lowp vec4   light_specularColor[MAX_LIGHTS];
uniform vec3        light_normalizedSpotDirectionEye[MAX_LIGHTS];
uniform float       light_spotExponent[MAX_LIGHTS];
uniform float       light_spotCutoffAngle[MAX_LIGHTS];
uniform float       light_constantAttenuation[MAX_LIGHTS];
uniform float       light_linearAttenuation[MAX_LIGHTS];
uniform float       light_quadraticAttenuation[MAX_LIGHTS];


/////////////////////////////////////////////////////////////////////////////////////
// MATERIAL
/////////////////////////////////////////////////////////////////////////////////////
struct material_s
{
    lowp vec4 ambientColor;
    lowp vec4 diffuseColor;
    lowp vec4 specularColor;
    lowp vec4 emissiveColor;
    float shininess;
};

uniform material_s  material;


/////////////////////////////////////////////////////////////////////////////////////
// FOG
/////////////////////////////////////////////////////////////////////////////////////
#define GLKFogModeExp           0
#define GLKFogModeExp2          1
#define GLKFogModeExpLinear     2

struct fog_s
{
    lowp int  mode;
    lowp vec4 color;
    float     density;
    float     start;
    float     end;
};

uniform texture_s    textures[MAX_TEXTURES];
uniform fog_s        fog;


/////////////////////////////////////////////////////////////////////////////////////
// Reflection Mapping
/////////////////////////////////////////////////////////////////////////////////////
uniform highp mat3   reflectionMapMatrix;


/////////////////////////////////////////////////////////////////////////////////////
// Varyings
/////////////////////////////////////////////////////////////////////////////////////
IN_FRAG lowp    vec4 v_color;

<codeblock label="light model two-sided per-vertex enabled" type="cond" class="EFFECT">
IN_FRAG lowp    vec4 v_backColor;
</codeblock>
<codeblock label="v_position" type="cond" class="TEXTURE">
IN_FRAG highp   vec4 v_position;
</codeblock>
<codeblock label="v_positionEye" type="cond" class="EFFECT">
IN_FRAG highp   vec4 v_positionEye;
</codeblock>
<codeblock label="v_normalEye" type="cond" class="EFFECT">
IN_FRAG highp   vec3 v_normalEye;
</codeblock>
<codeblock label="use tex coord attrib" type="cond" class="EFFECT">
IN_FRAG highp   vec3 v_texCoord[MAX_TEX_COORDS];
</codeblock>


/////////////////////////////////////////////////////////////////////////////////////
// Temps
/////////////////////////////////////////////////////////////////////////////////////
<codeblock label="color material enabled" type="cond" class="EFFECT">
lowp vec4 materialAmbientColor, materialDiffuseColor;
lowp vec4 baseLightingColor;
vec4 ambientTerm[3];
</codeblock>

<codeblock label="color material disabled" type="cond" class="EFFECT">
#define materialAmbientColor (material.ambientColor)
#define materialDiffuseColor (material.diffuseColor)
uniform lowp vec4 baseLightingColor;
uniform vec4 ambientTerm[3];
</codeblock>

<codeblock label="fog enabled" type="cond" class="FOG">
IN_FRAG mediump float   v_fog;
</codeblock>

</codeblock>

<codeblock label="main prolog" type="std" class="STATIC_BLOCK">
void main()
{
    // int currLight;
    lowp vec4 color;
        
    <codeblock label="color material enabled" type="cond" class="EFFECT">
    <codeblock label="light model two-sided per-vertex enabled" type="cond" class="EFFECT">
    if(gl_FrontFacing == true)
        color = materialAmbientColor = materialDiffuseColor = v_color;
    else
        color = materialAmbientColor = materialDiffuseColor = v_backColor;
    </codeblock>
    <codeblock label="light model two-sided per-vertex disabled" type="cond" class="EFFECT">
        color = materialAmbientColor = materialDiffuseColor = v_color;
    </codeblock>
    </codeblock>

    <codeblock label="color material disabled" type="cond" class="EFFECT">
    <codeblock label="light model two-sided per-vertex enabled" type="cond" class="EFFECT">
    if(gl_FrontFacing == true)
        color = v_color;
    else
        color = v_backColor;
    </codeblock>
    <codeblock label="light model two-sided per-vertex disabled" type="cond" class="EFFECT">
    color = v_color;
    </codeblock>
    </codeblock>

</codeblock>
    
    <codeblock label="per-pixel lighting enabled" type="cond" class="EFFECT">
    // if(perPixelLightingEnabled == true)
    {
    vec4 specularTerm, diffuseTerm;
    vec3 vertexToLightVec;
    highp float attenuationFactor, spotFactor, nDotL;
        
    <codeblock label="color material enabled" type="cond" class="EFFECT">
    // if(colorMaterialEnabled == true)
    {
    // materialAmbientColor = materialDiffuseColor = color;  
    baseLightingColor = material.emissiveColor + (materialAmbientColor * lightModelAmbientColor);
    ambientTerm[0] = materialAmbientColor * light_ambientColor[0];
    ambientTerm[1] = materialAmbientColor * light_ambientColor[1];
    ambientTerm[2] = materialAmbientColor * light_ambientColor[2];
    }
    </codeblock>
    <codeblock label="color material disabled" type="cond" class="EFFECT">
    // else
    {
    // materialAmbientColor = material.ambientColor;
    // materialDiffuseColor = material.diffuseColor;  
    // baseLightingColor = material.emissiveColor + (materialAmbientColor * lightModelAmbientColor);
    }
    </codeblock>

    color = baseLightingColor;

    <codeblock label="lighting" type="loop" unrollCt="3" loopVar="currLight" class="LIGHT">
    <![CDATA[ // for(currLight = 0; currLight < numLights; currLight++) ]]>
    {
        // if(light_enabled[currLight] == false) continue;

        <codeblock label="directional light" type="cond" class="LIGHT">
        // For directional lights light_positionEye[currLight].xyz is normalized on the CPU side
        vertexToLightVec = light_positionEye[currLight].xyz;
        </codeblock>

        <codeblock label="positional light" type="cond" class="LIGHT">
        vertexToLightVec = normalize(light_positionEye[currLight].xyz - v_positionEye.xyz);
        </codeblock>

        <codeblock label="attenuate lighting enabled" type="cond" class="LIGHT">
        {
            float vertexToLightVecMagnitude = distance(light_positionEye[currLight].xyz, v_positionEye.xyz);

            attenuationFactor = (1.0 /
                (light_constantAttenuation[currLight] +
                light_linearAttenuation[currLight] * vertexToLightVecMagnitude +
                light_quadraticAttenuation[currLight] * vertexToLightVecMagnitude * vertexToLightVecMagnitude));
        }
        </codeblock>

        <codeblock label="attenuate lighting disabled" type="cond" class="LIGHT">
        attenuationFactor = 1.0;
        </codeblock>

        // Calculate diffuse and specular terms
        <codeblock label="light model two-sided per-pixel disabled" type="cond" class="EFFECT">
        nDotL = max(dot(v_normalEye, vertexToLightVec), 0.0);
        </codeblock>

        <codeblock label="light model two-sided per-pixel enabled" type="cond" class="EFFECT">
        if(gl_FrontFacing == true)
            nDotL = max(dot(v_normalEye, vertexToLightVec), 0.0);
        else
            nDotL = max(dot(-v_normalEye, vertexToLightVec), 0.0);
        </codeblock>

        diffuseTerm = nDotL * materialDiffuseColor * light_diffuseColor[currLight];

        <codeblock label="specular not default" type="cond" indexedMask="no" class="MATERIAL">
        if(nDotL != 0.0)
        {
            highp float nDotH;

            <codeblock label="light model two-sided per-pixel disabled" type="cond" class="EFFECT">
            nDotH = max(dot(v_normalEye, normalize(vertexToLightVec + vec3(0.0, 0.0, 1.0))), 0.0);
            </codeblock>

            <codeblock label="light model two-sided per-pixel enabled" type="cond" class="EFFECT">
            if(gl_FrontFacing == true)
                nDotH = max(dot(v_normalEye, normalize(vertexToLightVec + vec3(0.0, 0.0, 1.0))), 0.0);
            else
                nDotH = max(dot(-v_normalEye, normalize(vertexToLightVec + vec3(0.0, 0.0, 1.0))), 0.0);
            </codeblock>

            specularTerm = (pow(nDotH, material.shininess) * material.specularColor * light_specularColor[currLight]);
        }
        else
        {
            specularTerm = vec4(0.0);
        }
        </codeblock>
        <codeblock label="specular is default" type="cond" indexedMask="no" class="MATERIAL">
        specularTerm = vec4(0.0);
        </codeblock>
        
        <codeblock label="spot lighting enabled" type="cond" class="LIGHT">
        <![CDATA[
        // if(light_spotCutoffAngle[currLight] != 180.0)
        {
            vec3 vertexDir = -vertexToLightVec;
            float cosCutoff = cos(light_spotCutoffAngle[currLight]);
            float vertexDirDotSpotDir = max(dot(vertexDir, light_normalizedSpotDirectionEye[currLight]), 0.0);

            if(vertexDirDotSpotDir >= cosCutoff)
            {
                spotFactor = pow(vertexDirDotSpotDir, light_spotExponent[currLight]);
            }
            else
                spotFactor = 0.0;
        }
        ]]>
        </codeblock>

        <codeblock label="spot lighting disabled" type="cond" class="LIGHT">
        spotFactor = 1.0;
        </codeblock>

        color += attenuationFactor * spotFactor * (ambientTerm[currLight] + diffuseTerm + specularTerm);
    }
    </codeblock>

    color.a = materialDiffuseColor.a;
    }
    </codeblock>

    color = clamp(color, 0.0, 1.0);
    
    <codeblock label="texturing enabled" type="cond" class="EFFECT">
    // if(texturingEnabled == true)
    {
        lowp int      currTex;
        lowp vec4     texColor;
        highp vec3    texCoords[MAX_TEXTURES];
        highp float   s, t;

        <codeblock label="texturing" type="loop" unrollCt="3" loopVar="currTex" class="TEXTURE">
        <![CDATA[
        // for(currTex = 0; currTex < numTextures; currTex++)
        ]]>
        {
            <codeblock label="reflection mapping enabled" type="cond" class="TEXTURE">
            <![CDATA[
            /* if(textures[currTex].texGen[R].mode == GLKTexGenModeReflectionMap &&
               textures[currTex].texGen[S].enabled == true &&
               textures[currTex].texGen[T].enabled == true &&
               textures[currTex].texGen[R].enabled == true &&
               textures[currTex].target == GLKTextureTargetCubeMap) */
            ]]>
            {
                texCoords[currTex] = reflectionMapMatrix * reflect(v_positionEye.xyz, normalize(v_normalEye));
            }
            </codeblock>
            <codeblock label="reflection mapping disabled" type="cond" class="TEXTURE">
            // else
            {
                <codeblock label="texGenS enabled" type="cond" class="TEXTURE">
                // if(textures[currTex].texGen[S].enabled == true)
                {
                    <codeblock label="texGenS mode object linear" type="cond" class="TEXTURE">
                    // if(textures[currTex].texGen[S].mode == GLKTexGenModeObjectLinear)
                    {
                        texCoords[currTex].s = dot(textures[currTex].texGen[S].plane, v_position);
                    }
                    </codeblock>
                    <codeblock label="texGenS mode eye linear" type="cond" class="TEXTURE">
                    // else if(textures[currTex].texGen[S].mode == GLKTexGenModeEyeLinear)
                    {
                        texCoords[currTex].s = dot(textures[currTex].texGen[S].eyePlaneByInvModelview, v_positionEye);
                    }
                    </codeblock>
                    <codeblock label="texGenS mode sphere map" type="cond" class="TEXTURE">
                    // else if(textures[currTex].texGen[S].mode == GLKTexGenModeSphereMap)
                    {
                        float m;
                        vec3 reflection, normalizedNormal, normalizedPosition;

                        normalizedPosition = normalize(v_positionEye.xyz);
                        normalizedNormal = normalize(v_normalEye);

                        reflection = normalizedPosition - ((2.0 * normalizedNormal) * dot(normalizedNormal, normalizedPosition));
                        m = 2.0 * sqrt((reflection.x * reflection.x) +
                            (reflection.y * reflection.y) +
                            ((reflection.z + 1.0) * (reflection.z + 1.0)));

                        texCoords[currTex].s = reflection[S] / m + 0.5;
                    }
                    </codeblock>
                }
                </codeblock>
                // else
                <codeblock label="texGenS disabled" type="cond" class="TEXTURE">
                    texCoords[currTex].s = v_texCoord[currTex].s;
                </codeblock>
                <codeblock label="texGenT enabled" type="cond" class="TEXTURE">
                // if(textures[currTex].texGen[T].enabled == true)
                {
                    <codeblock label="texGenT mode object linear" type="cond" class="TEXTURE">
                    // if(textures[currTex].texGen[T].mode == GLKTexGenModeObjectLinear)
                    {
                        texCoords[currTex].t = dot(textures[currTex].texGen[T].plane, v_position);
                    }
                    </codeblock>
                    <codeblock label="texGenT mode eye linear" type="cond" class="TEXTURE">
                    // else if(textures[currTex].texGen[T].mode == GLKTexGenModeEyeLinear)
                    {
                        texCoords[currTex].t = dot(textures[currTex].texGen[T].eyePlaneByInvModelview, v_positionEye);
                    }
                    </codeblock>
                    <codeblock label="texGenT mode sphere map" type="cond" class="TEXTURE">
                    // else if(textures[currTex].texGen[T].mode == GLKTexGenModeSphereMap)
                    {
                        float m;
                        vec3 reflection, normalizedNormal, normalizedPosition;

                        normalizedPosition = normalize(v_positionEye.xyz);
                        normalizedNormal = normalize(v_normalEye);

                        reflection = normalizedPosition - ((2.0 * normalizedNormal) * dot(normalizedNormal, normalizedPosition));
                        m = 2.0 * sqrt((reflection.x * reflection.x) +
                            (reflection.y * reflection.y) +
                            ((reflection.z + 1.0) * (reflection.z + 1.0)));

                        texCoords[currTex].t = reflection[T] / m + 0.5;
                    }
                    </codeblock>
                }
                </codeblock>
                <codeblock label="texGenT disabled" type="cond" class="TEXTURE">
                // else
                    texCoords[currTex].t = v_texCoord[currTex].t;
                </codeblock>
                <codeblock label="texGenR enabled" type="cond" class="TEXTURE">
                // if(textures[currTex].texGen[R].enabled == true)
                {
                    <codeblock label="texGenR mode object linear" type="cond" class="TEXTURE">
                    // if(textures[currTex].texGen[R].mode == GLKTexGenModeObjectLinear)
                    {
                        texCoords[currTex].p = dot(textures[currTex].texGen[R].plane, v_position);
                    }
                    </codeblock>
                    <codeblock label="texGenR mode eye linear" type="cond" class="TEXTURE">
                    // else if(textures[currTex].texGen[R].mode == GLKTexGenModeEyeLinear)
                    {
                        texCoords[currTex].p = dot(textures[currTex].texGen[R].eyePlaneByInvModelview, v_positionEye);
                    }
                    </codeblock>
                    <codeblock label="texGenR mode sphere map" type="cond" class="TEXTURE">
                    // else if(textures[currTex].texGen[R].mode == GLKTexGenModeSphereMap)
                    {
                        float m;
                        vec3 reflection, normalizedNormal, normalizedPosition;

                        normalizedPosition = normalize(v_positionEye.xyz);
                        normalizedNormal = normalize(v_normalEye);

                        reflection = normalizedPosition - ((2.0 * normalizedNormal) * dot(normalizedNormal, normalizedPosition));
                        m = 2.0 * sqrt((reflection.x * reflection.x) +
                            (reflection.y * reflection.y) +
                            ((reflection.z + 1.0) * (reflection.z + 1.0)));

                        texCoords[currTex].p = reflection[R] / m + 0.5;
                    }
                    </codeblock>
                }
                </codeblock>
                <codeblock label="texGenR disabled" type="cond" class="TEXTURE">
                // else
                    texCoords[currTex].p = v_texCoord[currTex].p;
                </codeblock>
            }
            </codeblock>

            <codeblock label="texture matrix enabled" type="cond" class="TEXTURE">
            // if(textures[currTex].matrixEnabled)
            {
                highp vec4 texCoordVec4, texMatrixTexCoordVec4;
                <codeblock label="texture target cubeMap" type="cond" class="TEXTURE">
                // if(textures[currTex].target == GLKTextureTargetCubeMap)
                    texCoordVec4 = vec4(texCoords[currTex].s, texCoords[currTex].t, texCoords[currTex].p, 1.0);
                </codeblock>
                <codeblock label="texture target 2d" type="cond" class="TEXTURE">
                // else if(textures[currTex].target == GLKTextureTarget2d)
                    texCoordVec4 = vec4(texCoords[currTex].s, texCoords[currTex].t, 0, 1.0);
                </codeblock>

                texMatrixTexCoordVec4 = textures[currTex].matrix * texCoordVec4;
                texCoords[currTex].s = texMatrixTexCoordVec4.s;
                texCoords[currTex].t = texMatrixTexCoordVec4.t;

                <codeblock label="texture target cubeMap" type="cond" class="TEXTURE">
                // if(textures[currTex].target == GLKTextureTargetCubeMap)
                    texCoords[currTex].p = texMatrixTexCoordVec4.p;
                </codeblock>
            }
            </codeblock>

            <codeblock label="texture target 2d" type="cond" class="TEXTURE">
            // if(textures[currTex].target == GLKTextureTarget2d)
                texColor = texture2D(unit2d[currTex], texCoords[currTex].st);
            </codeblock>
            <codeblock label="texture target cubeMap" type="cond" class="TEXTURE">
            // else if(textures[currTex].target == GLKTextureTargetCubeMap)
                texColor = textureCube(unitCube[currTex], texCoords[currTex]);
            </codeblock>
            <codeblock label="texture env mode replace" type="cond" class="TEXTURE">
            // if(textures[currTex].envMode == GLKTextureEnvAttribReplace)
                color = texColor;
            </codeblock>
            <codeblock label="texture env mode modulate" type="cond" class="TEXTURE">
            // else if(textures[currTex].envMode == GLKTextureEnvAttribModulate)
                color *= texColor;
            </codeblock>
            <codeblock label="texture env mode decal" type="cond" class="TEXTURE">
            // else if(textures[currTex].envMode == GLKTextureEnvAttribDecal)
                color.rgb = mix(color.rgb, texColor.rgb, texColor.a);
            </codeblock>

			//todo:
            //color.a = 1.0; change texture swizzle
        }
        </codeblock>
    }
    </codeblock>

    <codeblock label="fog enabled" type="cond" class="FOG">
    color = v_fog * color + (1.0 - v_fog) * fog.color;
    </codeblock>

<codeblock label="main epilog" type="std" class="STATIC_BLOCK">
<![CDATA[
    out_color = color;
}
]]>
</codeblock>
</codeblocks>
