//Shader code by Mark Blosser
//WEBSITE:  www.hyrumark.com
//EMAIL:  mjblosser@gmail.com

//Shader edited for Nomad Mod

//Description:  Shader for SEGMENTS in FPSC. Uses normal mapping and specular, combined with lightmap texture auto-generated from FPS Creator.

//Textures: 
//"texture_D.dds"      diffuse texture
//"texture_I.dd"       specular texture
//"texture_N.dds"       normal map texture
/************* UNTWEAKABLES **************/

float4x4 World      : WORLD;

float4x4 WorldViewProj : WorldViewProjection;
float4x4 WorldIT : WorldInverseTranspose;
float4x4 ViewInv : ViewInverse;
float4x4 View : View;
float4 eyePos : CameraPosition;
float4x4 WorldInv : WorldInverse;
float4 clipPlane : ClipPlane;



/******TWEAKABLES***************************/



float LightHeight : Power
<
    string UIWidget = "slider";
    float UIMin = -100.0;
    float UIMax = 200.0;
    float UIStep = 10;
    string UIName =  "specular power";
> = 20.0;

float SpecAmount : Power
<
    string UIWidget = "slider";
    float UIMin = 0.0;
    float UIMax = 2.0;
    float UIStep = 0.1;
    string UIName =  "specular power";
> = 1.4;

float Glossiness : Power
<
    string UIWidget = "slider";
    float UIMin = 1.0;
    float UIMax = 128.0;
    float UIStep = 1;
    string UIName =  "Glossiness";
> = 24.0;

float BumpIntensity : Power
<
    string UIWidget = "slider";
    float UIMin = -2.0;
    float UIMax = 2.0;
    float UIStep = 0.1;
    string UIName =  "bump intensity";
> = 1.5;

float Tiling : Power
<
    string UIWidget = "slider";
    float UIMin = 1.0;
    float UIMax = 5.0;
    float UIStep = 1.0;
    string UIName =  "bump intensity";
> = 1.0;



/*********** SPOTFLASH VALUES FROM FPSC **********/

float4 SpotFlashPos;


float4 SpotFlashColor;


float SpotFlashRange //fixed value that FPSC uses
<
string UIName = "SpotFlash Range";

> = {600.00};



/******VALUES PULLED FROM FPSC - NON TWEAKABLE**********/

float4 AmbiColor : Ambient
<
    string UIName =  "Ambient Light Color";
> = {0.05f, 0.05f, 0.05f, 1.0f};

// Supports dynamic lights (using CalcLighting function)
float4 g_lights_pos0;
float4 g_lights_pos1;
float4 g_lights_pos2;
float4 g_lights_pos3;
float4 g_lights_atten0;
float4 g_lights_atten1;
float4 g_lights_atten2;
float4 g_lights_atten3;
float4 g_lights_diffuse0;
float4 g_lights_diffuse1;
float4 g_lights_diffuse2;
float4 g_lights_diffuse3;

//----------------
// FOG sensitivity
//----------------
float4 FogColor : Diffuse
<
    string UIName =  "Fog Color";
    string UIType = "Color";
> = {0.0f, 0.0f, 0.0f, 0.0000001f};



/****************** TEXTURES AND SAMPLERS*********************/

texture LightMap : DiffuseMap
<
    string Name = "LM.tga";
    string type = "2D";
>;

texture DiffuseMap : DiffuseMap
<
    string Name = "D.tga";
    string type = "2D";
>;

//could be anything here - ill,spec,normal,cube
texture SpecularMap : DiffuseMap
<
    string Name = "I.tga";
    string type = "2D";
>;

texture NormalMap : DiffuseMap
<
    string Name = "N.tga";
    string type = "2D";
>;



//Lightmap texture
sampler2D LightmapSampler = sampler_state
{
    Texture   = <LightMap>;
    MipFilter = ANISOTROPIC;
    MinFilter = ANISOTROPIC;
    MagFilter = ANISOTROPIC;
};


//Diffuse Texture _D
sampler2D DiffuseSampler = sampler_state
{
    Texture   = <DiffuseMap>;
    MipFilter = ANISOTROPIC;
    MinFilter = ANISOTROPIC;
    MagFilter = ANISOTROPIC;
};

//Effect Texture _I (could be anything here - ill,spec,normal,cube)
sampler2D SpecularSampler = sampler_state
{
    Texture   = <SpecularMap>;
    MipFilter = ANISOTROPIC;
    MinFilter = ANISOTROPIC;
    MagFilter = ANISOTROPIC;
};

//Effect Texture _N (could be anything here - ill,spec,normal,cube)
sampler2D NormalSampler = sampler_state
{
    Texture   = <NormalMap>;
    MipFilter = ANISOTROPIC;
    MinFilter = ANISOTROPIC;
    MagFilter = ANISOTROPIC;
};


;

/************* DATA STRUCTS **************/

struct appdata {
    float4 Position	: POSITION;
    float4 UV0		: TEXCOORD0;
    float4 UV1		: TEXCOORD1;
    float4 Normal	: NORMAL;
    
};



/*data passed to pixel shader*/
struct vertexOutput
{
    float4 Position    : POSITION;
    float2 TexCoord     : TEXCOORD0;
    float2 TexCoordLM   : TEXCOORD1;
    float3 LightVec	    : TEXCOORD2;
    float3 WorldNormal	: TEXCOORD3;
    float4 WPos : TEXCOORD4;
    float3 objEyeVec : TEXCOORD5;
    float Fog : TEXCOORD6;  
    float clip : TEXCOORD7;
};


/*******Vertex Shader***************************/

vertexOutput mainVS(appdata IN)   
{
    
	vertexOutput OUT;
    
    //float4 tempPos = float4(IN.Position, 1);
    float4 worldSpacePos = mul(IN.Position, World);
    
    OUT.WorldNormal = normalize(mul(IN.Normal, WorldIT).xyz);
    
    //object space eye position
    float4 objSpaceEyePos = mul(ViewInv[3] , WorldInv);
    OUT.objEyeVec = (objSpaceEyePos.xyz - IN.Position.xyz);
   
    float3 eyeoffset = float3 (10,LightHeight,0);
    OUT.LightVec = normalize (eyePos+eyeoffset - worldSpacePos );
    OUT.Position = mul(IN.Position, WorldViewProj);
    OUT.TexCoord  = Tiling * IN.UV0 ; 
    OUT.TexCoordLM  = IN.UV1; 
    
    OUT.WPos =   worldSpacePos;  
    
     // calculate FOG colour
    float4 cameraPos = mul( worldSpacePos, View );
    float fogstrength = cameraPos.z * FogColor.w;
    OUT.Fog = min(fogstrength,1.0);

    // all shaders should send the clip value to the pixel shader (for refr/refl)                                                                     
    OUT.clip = dot(worldSpacePos, clipPlane);                                                                      
                                           

    return OUT;
}


/****************Framgent Shader*****************/


float4 CalcSpotFlash( float3 worldNormal, float3 worldPos )
{
float4 output = (float4)0.0;
float3 toLight = SpotFlashPos.xyz - worldPos.xyz;
float3 lightDir = normalize( toLight );
float lightDist = length( toLight );

float MinFalloff = 200; //falloff start distance - 50,0,.01 are very cool too for lanterns
float LinearFalloff = 1;
float ExpFalloff = .005; // 1/200

float fAtten = 1.0/(LinearFalloff*lightDist); //simplified linear falloff to fit in ps2.0

SpotFlashPos.w = clamp(0,1,SpotFlashPos.w -.2);

output += max(0,dot( lightDir, worldNormal ) * SpotFlashColor*fAtten * (SpotFlashPos.w) );

return output;
}



float4 CalcLighting( float3 worldNormal, float3 worldPos )
{
    float4 output = (float4)0.0;
    // light 0
    float3 toLight = g_lights_pos0.xyz - worldPos;
    float lightDist = length( toLight );
    float fAtten = 1.0/dot( g_lights_atten0, float4(1,lightDist,lightDist*lightDist,0) );
    float3 lightDir = normalize( toLight );
    output += max(0,dot( lightDir, worldNormal ) * g_lights_diffuse0 * fAtten);
    // light 1
    toLight = g_lights_pos1.xyz - worldPos;
    lightDist = length( toLight );
    fAtten = 1.0/dot( g_lights_atten1, float4(1,lightDist,lightDist*lightDist,0) );
    lightDir = normalize( toLight );
    output += max(0,dot( lightDir, worldNormal ) * g_lights_diffuse1 * fAtten);

    return output;
}


float4 mainPS(vertexOutput IN) : COLOR
{
    
    // all shaders should receive the clip value                                                                
    clip(IN.clip);
    
     float3 V  = (eyePos - IN.WPos);  
     float3 Vn  = normalize(V);
    
    ////////TANGENT BASIS CONSTRUCTION
    
    // get edge vectors of the pixel triangle
    float3 dp1 = ddx( -V );
    float3 dp2 = ddy( -V );
    float2 duv1 = ddx( IN.TexCoord.xy );
    float2 duv2 = ddy( IN.TexCoord.xy );

    // solve the linear system
    // (not much solving is left going here)
    float2x3 M = float2x3( dp1, dp2 );
    float3 T = mul( float2( duv1.x, duv2.x ), M );
    float3 B = mul( float2( duv1.y, duv2.y ), M );
    float3 Nn = normalize(IN.WorldNormal);
    // construct tangent frame basis matrix 
    float3x3 tangentbasis = float3x3(BumpIntensity* normalize(T),BumpIntensity* normalize(B),Nn );
    ///////////////////////////////////////////////////
        
        
    float4 LM = tex2D(LightmapSampler,IN.TexCoordLM); //sample lightmap texture
    float4 diffuse = tex2D(DiffuseSampler,IN.TexCoord.xy);  //sample diffuse texture    
    float4 lightmap = tex2D(LightmapSampler,IN.TexCoordLM); //sample lightmap texture
    float4 effectmap = tex2D(SpecularSampler,IN.TexCoord.xy);  //sample specular map texture 
    //sample normal map and transform it into tangent space
    float3 Nb = normalize( mul( 2 * tex2D(NormalSampler,IN.TexCoord.xy ) - 1, tangentbasis ) );
      
   
    float3 Ln = normalize(IN.LightVec);
    
   
    //half vector
    float3 Hn = normalize(Vn+Ln);
    
    
    //calculate lighting Half Lambert scale and bias 
    float4 lighting = lit(((dot(Ln,Nb))),dot(Hn,Nb),Glossiness);
        
    //spotflashlighting contribution
    float4 spotflashlighting = CalcSpotFlash ( IN.WorldNormal, IN.WPos.xyz );

    //dynamiclighting contribution
    float4 dynamiclighting = CalcLighting ( IN.WorldNormal, IN.WPos.xyz );
    
    //diffuse light contribution
    float4 diffuseContrib = (lightmap + AmbiColor+ dynamiclighting) * diffuse * lighting.y ;
    
    //specular light contribution
    float4 specContrib = lighting.z * effectmap * (lightmap+0.1)  ;
    
    //hemisphere lighting simulation
    float HemisphereLight = 1 ;  
    float4 sky = lerp(0.5, 1, Nb.g);
    
    
    float4 LMfinal = (AmbiColor+ dynamiclighting+spotflashlighting) * diffuse * lighting.y ;

        
    //final lighting 
    float4 result = LMfinal + diffuseContrib*sky + (SpecAmount*specContrib) +(0.5*lightmap*diffuse) ;

        
    return result;
    return float4((result.xyz*(1-IN.Fog))+(FogColor.xyz*IN.Fog),1);
}


/****** technique ********************************/

technique dx9textured
{
    pass P0
    {
        // lighting
        Lighting       = FALSE;
        FogEnable      = FALSE;
        CullMode = None;
        AlphaBlendEnable = FALSE;
        AlphaTestEnable = FALSE;

        // samplers
        //Sampler[0] = (LightmapSampler);
        //Sampler[1] = (DiffuseSampler);
        //Sampler[2] = (IllSpecSampler);
		//Sampler[3] = (NormalSampler);

        // shaders
        VertexShader = compile vs_3_0 mainVS();
        PixelShader  = compile ps_3_0 mainPS();
    }
}
