// --------------------------------------------------------------------------------------------------
// PARAMETERS:
// --------------------------------------------------------------------------------------------------
#define PCF_W 4
#define PCF_H 4

float shSmooth <string uiname="Light Smooth"; float uimin = 0; float uimax = 1;> = 0.2;
float ShadowBias = 0.2;
float ShadowIntensity = 0.8;

float3 lPos1 <string uiname="LightPosition1";> = {0, -5, 2};
float3 lTarg1 <string uiname="LightTarget1";> = {0, 0, 0};

float3 lPos2 <string uiname="LightPosition2";> = {0, -5, 2};
float3 lTarg2 <string uiname="LightTarget2";> = {0, 0, 0};

float3 lPos3 <string uiname="LightPosition3";> = {0, -5, 2};
float3 lTarg3 <string uiname="LightTarget3";> = {0, 0, 0};

float4 lAmb1  : COLOR <String uiname="AmbientColor1";>  = {0.2, 0.2, 0.2, 1};
float4 lDiff1 : COLOR <String uiname="DiffuseColor1";>  = {0.85, 0.85, 0.85, 1};
float4 lSpec1 : COLOR <String uiname="SpecularColor1";> = {0.35, 0.35, 0.35, 1};

float4 lAmb2  : COLOR <String uiname="AmbientColor2";>  = {0.2, 0.2, 0.2, 1};
float4 lDiff2 : COLOR <String uiname="DiffuseColor2";>  = {0.85, 0.85, 0.85, 1};
float4 lSpec2 : COLOR <String uiname="SpecularColor2";> = {0.35, 0.35, 0.35, 1};

float4 lAmb3  : COLOR <String uiname="AmbientColor3";>  = {0.2, 0.2, 0.2, 1};
float4 lDiff3 : COLOR <String uiname="DiffuseColor3";>  = {0.85, 0.85, 0.85, 1};
float4 lSpec3 : COLOR <String uiname="SpecularColor3";> = {0.35, 0.35, 0.35, 1};


float lPower <String uiname="Power"; float uimin=0.0;> = 25.0;     //shininess of specular highlight

bool l1Enabled <string uiname="LightEnabled1";> = true;
bool l2Enabled <string uiname="LightEnabled2";> = false;
bool l3Enabled <string uiname="LightEnabled3";> = false;

bool l1ShadowEnabled <string uiname="LightShadowEnabled1";> = true;
bool l2ShadowEnabled <string uiname="LightShadowEnabled2";> = false;
bool l3ShadowEnabled <string uiname="LightShadowEnabled3";> = false;

bool hasDiffuseTexture <string uiname="HasDiffuseTexture1";> = false;

float4x4 lvXf1 <string uiname="LightView1";>;
float4x4 lpXf1 <string uiname="LightProjection1";>;
float4x4 lvXf2 <string uiname="LightView2";>;
float4x4 lpXf2 <string uiname="LightProjection2";>;
float4x4 lvXf3 <string uiname="LightView3";>;
float4x4 lpXf3 <string uiname="LightProjection3";>;


//transforms
float4x4 World: WORLD;        //the models world matrix
float4x4 View: VIEW;         //view matrix as set via Renderer (EX9)
float4x4 Projection: PROJECTION;   //projection matrix as set via Renderer (EX9)


float Alpha <float uimin=0.0; float uimax=1.0;> = 1;

//texture
texture DiffuseTexture <string uiname="Texture";>;
sampler Samp = sampler_state    //sampler for doing the texture-lookup
{
    Texture   = (DiffuseTexture);          //apply a texture to the sampler
    MipFilter = LINEAR;         //sampler states
    MinFilter = LINEAR;
    MagFilter = LINEAR;
};

texture DepthTex1 <string uiname="DepthTexture1";>;
sampler DepthSamp1 = sampler_state    //sampler for doing the texture-lookup
{
    Texture   = (DepthTex1);
    MipFilter = NONE;
    MinFilter = NONE;
    MagFilter = NONE;
};

texture DepthTex2 <string uiname="DepthTexture2";>;
sampler DepthSamp2 = sampler_state    //sampler for doing the texture-lookup
{
    Texture   = (DepthTex2);
    MipFilter = NONE;
    MinFilter = NONE;
    MagFilter = NONE;
};

texture DepthTex3 <string uiname="DepthTexture3";>;
sampler DepthSamp3 = sampler_state    //sampler for doing the texture-lookup
{
    Texture   = (DepthTex3);
    MipFilter = NONE;
    MinFilter = NONE;
    MagFilter = NONE;
};

struct vs2ps
{
    float4 PosWVP: POSITION;
    float4 TexCd: TEXCOORD0;
    float4 Diffuse: COLOR0;
    float4 Specular: COLOR1;
    float4 Ambient: TEXCOORD1;
    float4 LP1: TEXCOORD2;
    float4 LP2: TEXCOORD3;
    float4 LP3: TEXCOORD4;
    float3 LN1: TEXCOORD5;
    float3 LN2: TEXCOORD6;
    float3 LN3: TEXCOORD7;
};

// --------------------------------------------------------------------------------------------------
// VERTEXSHADERS
// --------------------------------------------------------------------------------------------------

vs2ps VS(
    float4 PosO  : POSITION,
    float3 NormO : NORMAL,
    float4 TexCd : TEXCOORD0)
{
    //inititalize all fields of output struct with 0
    vs2ps Out = (vs2ps)0;

    float3 shades1;
    float3 shades2;
    float3 shades3;

    float4x4 tWV = mul(World, View);

    float3 NormV = normalize(mul(NormO, tWV));
    float4 PosV = mul(PosO, tWV);

    float4 diff = float4(0, 0, 0, 1);;
    float3 shades = 0;
    float4 lSpec = float4(0, 0, 0, 1);;
    float4 lAmb = float4(0, 0, 0, 1);

    int lc = 0;
    float4 TAtt;
    float4 LAtt = float4(0, 0, 0 ,0);

    float4 Pw = mul(PosO, World);

    float4x4 svpXf1;
    float4 Pl1;
    float4x4 svpXf2;
    float4 Pl2;
    float4x4 svpXf3;
    float4 Pl3;

    float4 Ln1;
    float4 Ln2;
    float4 Ln3;

    if (l1Enabled) {
        svpXf1 = mul(lvXf1, lpXf1);
        Pl1 = mul(Pw, svpXf1);
        float3 lDir1 =  lTarg1 - lPos1;
        float3 LightDirV1 = normalize(-mul(lDir1, View));
        float3 ViewDirV1 = normalize(-PosV);
        Ln1 = dot(NormV, LightDirV1);
        float3 H1 = normalize(ViewDirV1 + LightDirV1);
        diff = lDiff1;
        lSpec += lSpec1;
        lAmb = lAmb1;
        shades1 = lit(dot(NormV, LightDirV1), dot(NormV, H1), lPower);
        shades += shades1;
        lc++;
    }
    if (l2Enabled) {
        svpXf2 = mul(lvXf2, lpXf2);
        Pl2 = mul(Pw, svpXf2);
        float3 lDir2 = lTarg2 - lPos2;
        float3 LightDirV2 = normalize(-mul(lDir2, View));
        float3 ViewDirV2 = normalize(-PosV);
        float3 H2 = normalize(ViewDirV2 + LightDirV2);
        diff += lDiff2;
        lSpec += lSpec2;
        lAmb += lAmb2;
        shades2 = lit(dot(NormV, LightDirV2), dot(NormV, H2), lPower);
        shades += shades2;
        lc++;
        Ln2 = dot(NormV, LightDirV2);;
    }
    if (l3Enabled) {
        svpXf3 = mul(lvXf3, lpXf3);
        Pl3 = mul(Pw, svpXf3);
        float3 lDir3 = lTarg3 - lPos3;
        float3 LightDirV3 = normalize(-mul(lDir3, View));
        float3 ViewDirV3 = normalize(-PosV);
        float3 H3 = normalize(ViewDirV3 + LightDirV3);
        diff += lDiff3;
        lSpec += lSpec3;
        lAmb += lAmb3;
        shades3 = lit(dot(NormV, LightDirV3), dot(NormV, H3), lPower);
        shades += shades3;
        lc++;
        Ln3 = dot(NormV, LightDirV3);;
    }

	if (!l1Enabled && !l2Enabled && !l3Enabled)
		shades = 1;

    diff /= lc;

    shades /= lc;
    lAmb /= lc;
    lSpec /= lc;

    diff *= shades.y;
    diff.a = 1;
    float4 spec = lSpec * shades1.z;
    spec.a = 1;

    //position (projected)
    Out.PosWVP  = mul(PosV, Projection);
    Out.TexCd = TexCd;
    Out.Diffuse = diff + lAmb;
    Out.Specular = spec;
    Out.LP1 = Pl1;
    Out.LP2 = Pl2;
    Out.LP3 = Pl3;
    Out.LN1 = Ln1;
    Out.LN2 = Ln2;
    Out.LN3 = Ln3;

    return Out;
}

// --------------------------------------------------------------------------------------------------
// PIXELSHADERS:
// --------------------------------------------------------------------------------------------------

float GetShadowAmount(float4 LightPosition, float3 Norm, sampler DSamp)
{
    float sa = 0;
    float shSm = 0.005 * shSmooth;
    if (Norm.z > 0.0001) {
           int cx = -PCF_W / 2;
           int cy = -PCF_H / 2;
           float totc = 0;
           for (int x = 0; x < PCF_W; x++) {
               for (int y = 0; y < PCF_H; y++) {
                   float tx = (cx + x) * shSm;
                   float ty = (cy + y) * shSm;
                   float2 tlp = LightPosition.xy;
                   float2 nuv = float2(.5,-.5)*(tlp)/LightPosition.w + float2(.5,.5);
                   //float2 tuv = float2(nuv.x, nuv.y);
                   nuv.x += tx;
                   nuv.y += ty;
                   float4 ct = tex2D(DSamp, nuv);
                   float shadMapDepth = ct.x;
                   if (shadMapDepth < LightPosition.z * ShadowBias && shadMapDepth) {
                        totc += ShadowIntensity;
                   }
               }
           }
           totc /= (PCF_W * PCF_H);
           totc = 1.2 - totc;
           sa = totc;
    }
    return sa;
}


float4 PS(vs2ps In): COLOR
{
    float4 col;
    if (hasDiffuseTexture) {
		col = tex2D(Samp, In.TexCd);
	} else {
		col = float4(1, 1, 1, 1);
	}

    if (l1Enabled || l2Enabled || l3Enabled)
		col.rgb *= In.Diffuse + In.Specular;


    if (l1Enabled) {
        float shadAmount1 = GetShadowAmount(In.LP1, In.LN1, DepthSamp1);
         if (In.LN1.z > 0.001 && shadAmount1 > 0) {
			col.rgb *= shadAmount1;
         }
    }
    
    if (l2Enabled) {
       float shadAmount2 = GetShadowAmount(In.LP2, In.LN2, DepthSamp2);
        if (In.LN2.z > 0.001 && shadAmount2 > 0) {
        col.rgb *= shadAmount2;
       }
    }

    if (l3Enabled) {
       float shadAmount3 = GetShadowAmount(In.LP3, In.LN3, DepthSamp3);
        if (In.LN3.z > 0.001 && shadAmount3 > 0) {
                 col.rgb *= shadAmount3;
           }
    }
	
	
    return col;
}

// --------------------------------------------------------------------------------------------------
// TECHNIQUES:
// --------------------------------------------------------------------------------------------------

technique TGouroudLight
{
    pass P0
    {
        VertexShader = compile vs_1_1 VS();
        PixelShader = compile ps_3_0 PS();
    }
}

technique TGouroudLightFF
{
    pass P0
    {
        //transformations
        NormalizeNormals = true;
        WorldTransform[0]   = (World);
        ViewTransform       = (View);
        ProjectionTransform = (Projection);

        //material
        MaterialAmbient  = {1, 1, 1, 1};
        MaterialDiffuse  = {1, 1, 1, 1};
        MaterialSpecular = {1, 1, 1, 1};
        MaterialPower    = (25);

        //texturing
        Sampler[0] = (Samp);
        //TextureTransform[0] = (tTex);
        TexCoordIndex[0] = 0;
        TextureTransformFlags[0] = COUNT2;
        //Wrap0 = U;  // useful when mesh is round like a sphere

        //lighting
        LightEnable[0] = TRUE;
        Lighting       = TRUE;
        SpecularEnable = TRUE;

        LightType[0]     = POINT;
        LightAmbient[0]  = (lAmb1);
        LightDiffuse[0]  = (lDiff1);
        LightSpecular[0] = (lSpec1);
        LightPosition[0] = (lPos1);

        //shading
        ShadeMode = GOURAUD;
        VertexShader = NULL;
        PixelShader  = NULL;
    }
}