
float4x4 mvp : ModelViewProjection;
float4x4 mv : ModelView;
float4x4 mvit : ModelViewIT;

float3 Color = float3(0,1,0);

float4 vertex(uniform float4x4 modelViewProj,
              uniform float4x4 modelView,
              uniform float4x4 modelViewIT,
              float4 P : POSITION,
              float4 N : NORMAL,
	      float2 uvIn : TEXCOORD0,
              out float4 CC : COLOR0,
              out float3 Pcam : TEXCOORD1,
              out float3 Ncam : TEXCOORD2,
	      out float2 uv : TEXCOORD0) : POSITION
{
    CC.xyz = .5 * Color.xyz + .5 * normalize(N.xyz);
    Pcam = mul(modelView, P).xyz;
    Ncam = mul(modelViewIT, N).xyz;
    uv = uvIn;
    return mul(modelViewProj, P);
}

float4 fragment(uniform float3 C,
                float3 Pcam : TEXCOORD1, 
                float3 Ncam : TEXCOORD2) : COLOR 
{
    float3 Plight = float3(-10,10,10);
    float3 wi = normalize(Plight - Pcam);
    float3 wo = normalize(-Pcam);
    float3 H = normalize(wi+wo);
    Ncam = normalize(Ncam);
    float3 Ci = float3(.1, .1, .1);
    Ci += max(0., dot(wi, Ncam)) * (.5 * Color + pow(max(0., dot(Ncam, H)), 20.f));
    return float4(Ci, 1);
}

technique FragmentBlinnLighting {
    pass {
        VertexProgram = compile arbvp1 vertex(mvp, mv, mvit);
        FragmentProgram = compile arbfp1 fragment(Color.gbr);
    }
}

technique FixedFunctionLighting {
    pass {
        LightingEnable = true;
        LightEnable[0] = true;
        LightPosition[0] = float4(-10, 10, 10, 1);
        LightAmbient[0] = float4(.1,.1,.1,.1);
        LightDiffuse[0] = float4(1,1,1,1);
        LightSpecular[0] = float4(1,1,1,1);

        MaterialShininess = 10.f;
        MaterialAmbient = float4(1,1,1,1);
        MaterialDiffuse = float4(.5, .5, .5, 1);
        MaterialSpecular = float4(.5, .5, .5, 1);
    }
}

technique FixedFunctionFog {
    pass {
        FogEnable = true;
        FogMode = linear;
        FogDensity = 5.;
        FogStart = 0.;
        FogEnd = 5;
        FogColor = float4(.5, .5, .5, .5);
    }
}

technique VertexProgram {
    pass {
        VertexProgram = compile arbvp1 vertex(mvp, mv, mvit);
        DepthFunc = lequal;
    }
}

float4 texsimple(uniform sampler2D sampler,
                float2 uv : TEXCOORD0) : COLOR {
    return tex2D(sampler, uv);
}

sampler2D checkerSampler < 
    string image = "checkerboard";
    int frequency = 15;
    float3 color0 = float3(1,1,0);
    float3 color1 = float3(0,0,1);
> = sampler_state {
        generateMipMap = true;
        minFilter = LinearMipMapLinear;
        magFilter = Linear;
        WrapS = ClampToEdge;
        WrapT = ClampToEdge;
};

technique TextureSimple {
    pass {
        FragmentProgram = compile arbfp1 texsimple(checkerSampler);
    }
}

sampler2D anisoCheckerSampler < 
    string image = "checkerboard";
    int frequency = 15;
    float3 color0 = float3(1,1,0);
    float3 color1 = float3(0,0,1);
> = sampler_state {
        generateMipMap = true;
        minFilter = LinearMipMapLinear;
        magFilter = Linear;
        WrapS = ClampToEdge;
        WrapT = ClampToEdge;
        MaxAnisotropy = 8;
};

technique TextureAniso {
    pass {
        FragmentProgram = compile arbfp1 texsimple(anisoCheckerSampler);
    }
}

//
// Unsized array of interfaces example
//

interface Light {
    float3 illuminate(float3 p, out float3 L);
};

struct PointLight : Light {
    float3 Plight, Clight;
    float3 illuminate(float3 P, out float3 L) {
        L = normalize(Plight - P);
        return Clight;
    }
};

struct SpotLight : Light {
    float3 Plight, Clight, target;
    float3 illuminate(float3 P, out float3 L) {
        L = normalize(Plight - P);
        float3 shine = normalize(Plight - target);
        float costheta = dot(L, shine);
        return Clight * smoothstep(0.98, 1., costheta);
    }
};


Light lights[];

float4 multilight(uniform float3 ambient,
                  uniform float3 diffuse,
                  uniform float3 specular,
                  uniform float shine,
                  float3 Pcam : TEXCOORD1, 
                  float3 Ncam : TEXCOORD2) : COLOR 
{
    float3 wo = normalize(-Pcam);
    float3 result = ambient;
    float3 Nn = normalize(Ncam);
    float3 afactor = 0;
    float3 dfactor = 0;
    float3 sfactor = 0;
    for (int i = 0; i < lights.length; i++) {
        float3 Ln;
        float3 lcolor = lights[i].illuminate(Pcam, Ln);
        float3 Hn = normalize(wo + Ln);
        float ldn = dot(Ln,Nn);
        float hdn = dot(Hn,Nn);
        float4 litV = lit(ldn, hdn, shine);
        afactor += lcolor;
        dfactor += lcolor*litV.y;
        sfactor += lcolor*litV.y*litV.z;
    }
    result = afactor*ambient + dfactor*diffuse + sfactor*specular;
    return float4(result, 1.);
}

technique UnsizedArray {
    pass {
        VertexProgram = compile arbvp1 vertex(mvp, mv, mvit);
        FragmentProgram = compile arbfp1 multilight(Color*.1,
                                                    Color*.5,
                                                    Color*.9, 40.);
    }
}
