<languageVersion : 1.0;>

kernel NormalMapper
<
    namespace : "";
    vendor : "Superflat";
    version : 1;
    description : "This is the good shit.";
>
{
    input image4 src;
    input image4 normalMap;
    output pixel4 result;

    parameter float3 ambient
    <
        minValue: float3(0.0, 0.0, 0.0);
        maxValue: float3(1.0, 1.0, 1.0);
        defaultValue: float3(0.05, 0.07, 0.08);
    >;
    
    parameter float3 light1Position
    <
        minValue: float3(-500.0, -500.0, 0.0);
        maxValue: float3(+500.0, +500.0, 200.0);
        defaultValue: float3(30.0, 110.0, 60.0);
    >;

    parameter float3 light1Colour
    <
        minValue: float3(0.0, 0.0, 0.0);
        maxValue: float3(1.0, 1.0, 1.0);
        defaultValue: float3(1.0, 0.0, 0.0);
    >;
    parameter float light1Att
    <
        minValue: 0.0;
        maxValue: 100.0;
        defaultValue: 1.0;
    >;
    parameter int light1Mask
    <
        minValue: 0;
        maxValue: 15;
        defaultValue: 3;
    >;
    parameter float3 light2Position
    <
        minValue: float3(-500.0, -500.0, 0.0);
        maxValue: float3(+500.0, +500.0, 200.0);
        defaultValue: float3(90.0, 120.0, 30.0);
    >;

    parameter float3 light2Colour
    <
        minValue: float3(0.0, 0.0, 0.0);
        maxValue: float3(1.0, 1.0, 1.0);
        defaultValue: float3(1.0, 0.9, 0.7);
    >;
    parameter float light2Att
    <
        minValue: 0.0;
        maxValue: 100.0;
        defaultValue: 0.5;
    >;
    parameter int light2Mask
    <
        minValue: 0;
        maxValue: 15;
        defaultValue: 4;
    >;
    
    parameter float3 light3Position
    <
        minValue: float3(-500.0, -500.0, 0.0);
        maxValue: float3(+500.0, +500.0, 200.0);
        defaultValue: float3(60.0, 60.0, 60.0);
    >;

    parameter float3 light3Colour
    <
        minValue: float3(0.0, 0.0, 0.0);
        maxValue: float3(1.0, 1.0, 1.0);
        defaultValue: float3(0.0, 1.0, 0.0);
    >;
    parameter float light3Att
    <
        minValue: 0.0;
        maxValue: 100.0;
        defaultValue: 1.0;
    >;
    parameter int light3Mask
    <
        minValue: 0;
        maxValue: 15;
        defaultValue: 0;
    >;

    void
    evaluatePixel()
    {
        float2 positionHere = outCoord();
        float3 diffusePixel = sampleNearest(src,(positionHere)).rgb;
        float2 lightMaskPosition;
        float mask1,mask2,mask3,diffuse1Amount,diffuse2Amount,diffuse3Amount;
        float distance;
        
        //First Light...
        
        float3 toLight = light1Position;
        toLight.xy -= positionHere.xy;
        
        if (light1Att<=0.0 || abs(toLight.x)>64.0 || (toLight.y)>64.0)
        {
            mask1=0.0;
            diffuse1Amount=0.0;
        }
        else
        {
            lightMaskPosition = toLight.xy;
           // lightMaskPosition.y*=-1.0;
            float xOffset=mod(float(light1Mask+1)*128.0,2048.0);
          //  float yOffset=0.0;//float(light1Mask/8)*128.0;
            lightMaskPosition.x+=xOffset+64.0;
            lightMaskPosition.x=clamp(lightMaskPosition.x,xOffset,xOffset+128.0);   
            lightMaskPosition.y+=64.0;//yOffset+64.0;
        //    lightMaskPosition.y=clamp(lightMaskPosition.y,yOffset,yOffset+128.0);   
            mask1 = sampleNearest(normalMap, lightMaskPosition).r;
          
            //float diffuse1Amount = (20.0*light1Att/(length(toLight)+64.0));
            distance=length(toLight);

           // if (distance>=58.0) mask1*=0.8;
           // if (distance>=60.0) mask1*=0.8;
          //  if (distance>=62.0) mask1*=0.8;
         //   if (distance>=64.0) mask1=0.0;
        //    if (light1Mask<8)
         //   {
                if (distance>64.0) 
                {
                    diffuse1Amount=0.0;
                    
                }
                else
                {
                    diffuse1Amount = (64.0*light1Att)/(min(distance,64.0));
                    if (distance>=32.0) diffuse1Amount *= 1.0-((distance-32.0)/32.0);
                }
           // }
            //else
           // {
            //    diffuse1Amount=light1Att;
           // }
            
        }
        
        //Second Light...
        
        toLight = light2Position;
        toLight.xy -= positionHere.xy;
        
        if (light2Att<=0.0 || abs(toLight.x)>64.0 || (toLight.y)>64.0)
        {
            mask2=0.0;
            diffuse2Amount=0.0;
        }
        else
        {
            lightMaskPosition = toLight.xy;
            float xOffset=(float(light2Mask)*128.0);
            lightMaskPosition.x+=xOffset+64.0;
            lightMaskPosition.x=clamp(lightMaskPosition.x,xOffset,xOffset+127.0);   
            lightMaskPosition.y+=64.0;
            mask2 = sampleNearest(normalMap, lightMaskPosition).r;
        
            distance=length(toLight);

            //if (distance>=58.0) mask2*=0.8;
            //if (distance>=60.0) mask2*=0.8;
           // if (distance>=62.0) mask2*=0.8;
         //   if (distance>=64.0) mask2=0.0;
            if (distance>64.0) 
            {
                diffuse2Amount=0.0;
            }
            else
            {
                diffuse2Amount = (64.0*light2Att)/(min(distance,64.0));
                if (distance>=32.0) diffuse2Amount *= 1.0-((distance-32.0)/32.0);
            }
        }
       
        //Third Light..
        toLight = light3Position;
        toLight.xy -= positionHere.xy;
        
        if (light3Att<=0.0 || abs(toLight.x)>64.0 || (toLight.y)>64.0)
        {
            mask3=0.0;
            diffuse3Amount=0.0;
        }
        else
        {      
            lightMaskPosition = toLight.xy;
     //       lightMaskPosition.y*=-1.0;
            float xOffset=mod(float(light3Mask+1)*128.0,2048.0);
            float yOffset=0.0;//float(light3Mask/8)*128.0;
            lightMaskPosition.x+=xOffset+64.0;
            lightMaskPosition.x=clamp(lightMaskPosition.x,xOffset,xOffset+128.0);   
            lightMaskPosition.y+=64.0;//yOffset+64.0;
            //lightMaskPosition.y=clamp(lightMaskPosition.y,yOffset,yOffset+128.0); 
            mask3 = sampleNearest(normalMap, lightMaskPosition).r;
        
            distance=length(toLight);
            
           // if (distance>=58.0) mask3*=0.8;
            //if (distance>=60.0) mask3*=0.8;
           // if (distance>=62.0) mask3*=0.8;
       //     if (distance>=64.0) mask3=0.0;
          //  if (light3Mask<8)
           // {
                if (distance>64.0) 
                {
                    diffuse3Amount=0.0;
                }
                else
                {
                    diffuse3Amount = (64.0*light3Att)/(min(distance,64.0));
                    if (distance>=32.0) diffuse3Amount *= 1.0-((distance-32.0)/32.0);
                }  
            //}
           // else
            //{
             //   diffuse3Amount=light3Att;
            //}
        }
        
        // Combine results:
        
        result.rgb = diffusePixel * ((light1Colour*diffuse1Amount)+(light2Colour*diffuse2Amount)+(light3Colour*diffuse3Amount)) ;
        
        float finalMask=mask1+mask2+mask3;
        finalMask=min(finalMask,1.0);
        result.rgb *= finalMask;
        //result=clamp(result,0.2,1.5);
        result.r=max(result.r,(ambient.r*diffusePixel.r));
        result.g=max(result.g,(ambient.g*diffusePixel.g));
        result.b=max(result.b,(ambient.b*diffusePixel.b));
        
       // result.rgb += (0.07 * sampleNearest(normalMap, float2(positionHere.x+grainOffsetX,positionHere.y+512.0+grainOffsetY))).rgb;
        result.a=1.0;
    }
}