
/*********************************************************************
WEAPON SHADER FOR SKINNED MESHES - Diffuse + Normal + Specular + GI + Animated Glow

Pixel shader by Mark Blosser 
mark@hyrumark.com
http://www.hyrumark.com

Vertex shader by The Game Creators www.thegamecreators.com

This shader is for skinned meshes. It uses diffuse, normal, and specular textures.
It includes a fixed point light, and mixes a sky and ground color with the global ambient
light, using the per-pixel normal to determine the blend.  This has the effect of 
simulating global illumination, even with 100% ambient lighting.  Any area of the model pointing
toward the ground will be in shadow, and this includes detail from the normal map.

It will also produce an animated glow effect, and this is controlled by the alpha channel
of the specular map. 

It uses 3 textures:
gun_D :diffuse texture, alpha channel controls transparency
gun_N :normal map texture
gun_R :specular level and color, alpha channel controls animated glow

****************************************************************************/

/************* UNTWEAKABLES **************/

float4x4 WorldIT : WorldInverseTranspose;
float4x4 WorldViewProj : WorldViewProjection;
float4x4 World : World;
float4x4 ViewInv : ViewInverse;
float time : Time;

/*********** DBPRO UNTWEAKABLES **********/
float4x4 boneMatrix[32] : BoneMatrixPalette;


/******SKY COLORS*******************/

float4 groundColor
<
	string UIName = "Color";
	string UIWidget = "Color";
> = {0.4f, 0.4f, 0.4f, 1.0f };

float4 skyColor
<
	string UIName = "Color";
	string UIWidget = "Color";
> = {0.9f, 0.9f, 1.0f, 1.0f };



/************* LIGHTS**************/

//this value has no effect
float4 LightPos : Position
<
    string UIObject = "PointLight";
    string Space = "World";
> = { -100.000000, 700.000000, -200.000000, 1.000000 };

//this determines the position of the light
float4 FixedLightSource
<
    string UIType = "Fixed Light Source";
> = {100.0f, 500.0f, 100.0f, 1.0f};

//not used in this shader variant
float4 LightColor
<
	string UIType = "Color";
> = {0.75f, 0.75f, 0.75f, 1.0f};


/************* SURFACE PROPERTIES**************/

//this value is pulled from FPSC - non tweakable
float4 AmbiColor : Ambient
<
    string UIName =  "Ambient Light Color";
> = {0.5f, 0.5f, 0.5f, 1.0f};


//this value is also pulled from FPSC - used with Ambicolor to calculate light decay
float4 SurfColor : Diffuse
<
    string UIName =  "Surface Color";
    string UIType = "Color";
> = {1.0f, 1.0f, 1.0f, 1.0f};


//this value controls specular glossiness - higher values equal tigher highlights, lower values broader highlights 
float SpecExpon : Power
<
    string UIWidget = "slider";
    float UIMin = 1.0;
    float UIMax = 128.0;
    float UIStep = 1.0;
    string UIName =  "specular power";
> = 60.0;


float Alphavalue : AlphaOverride
<
    string UIName =  "Alpha Override";
> = 1.0f;

/************* TEXTURES **************/

//gun_D 
texture colorTexture : DiffuseMap
<
    string Name = "default_color.dds";
    string type = "2D";
>;

//gun_N
texture normalTexture : DiffuseMap
<
    string Name = "default_bump_normal.dds";
    string type = "2D";
>;

//gun_R
texture reflectMap : ReflectMap
<
	string Name = "default_mask.dds";
    string type = "2D";
>;


sampler2D colorSampler = sampler_state
{
	Texture = <colorTexture>;
	MinFilter = Linear;
	MagFilter = Linear;
	MipFilter = Linear;
};

sampler2D normalSampler = sampler_state
{
	Texture = <normalTexture>;
	MinFilter = Linear;
	MagFilter = Linear;
	MipFilter = Linear;
};

sampler2D reflectSampler = sampler_state
{
	Texture = <reflectMap>;
	MinFilter = Linear;
	MagFilter = Linear;
	MipFilter = Linear;
};




/************* DATA STRUCTS **************/

struct appdata {
    float3 Position	: POSITION;
    float4 UV		: TEXCOORD0;
    float4 Normal	: NORMAL;
    float4 Tangent	: TANGENT0;
    float4 Binormal	: BINORMAL0;
    float4 Blendweight	: TEXCOORD1;
    float4 Blendindices	: TEXCOORD2;
};

/* data passed from vertex shader to pixel shader */
struct vertexOutput {
    float4 HPosition	: POSITION;
    float4 TexCoord	: TEXCOORD0;
    float3 LightVec	: TEXCOORD1;
    float3 WorldNormal	: TEXCOORD2;
    float3 WorldEyeVec	: TEXCOORD3;
    float3 WorldTangent	: TEXCOORD4;
    float3 WorldBinorm	: TEXCOORD5;
};

/*********** vertex shader *************************/

vertexOutput mainVS(appdata IN)
{
    vertexOutput OUT;
    float3 netPosition = 0, netNormal = 0;
    for (int i = 0; i < 4; i++)
    {
     float index = IN.Blendindices[i];
     float3x4 model = float3x4(boneMatrix[index][0], boneMatrix[index][1], boneMatrix[index][2]);
     float3 vec3 = mul(model, float4(IN.Position, 1));
     vec3 = vec3 + boneMatrix[index][3].xyz;
     float3x3 rotate = float3x3(model[0].xyz, model[1].xyz, model[2].xyz); 
     float3 norm3 = mul(rotate, IN.Normal);
     netPosition += vec3.xyz * IN.Blendweight[i];
     netNormal += norm3.xyz * IN.Blendweight[i];
    }
    float4 tempPos = float4(netPosition,1.0);
    netNormal = normalize(netNormal);

    float3 worldSpacePos = mul(tempPos, World).xyz;
    OUT.WorldNormal = mul(netNormal, WorldIT).xyz;
    OUT.WorldTangent = mul(IN.Tangent, WorldIT).xyz;
    OUT.WorldBinorm = mul(IN.Binormal, WorldIT).xyz;
    OUT.LightVec = FixedLightSource - worldSpacePos;
    OUT.TexCoord = IN.UV;
    OUT.WorldEyeVec = normalize(ViewInv[3].xyz - worldSpacePos);
    OUT.HPosition = mul(tempPos, WorldViewProj);
    return OUT;
}

/********* pixel shader **********************************/

float4 mainPS(vertexOutput IN) : COLOR
{
    float4 diffusemap = tex2D(colorSampler,IN.TexCoord.xy);
    float3 normalmap = tex2D(normalSampler,IN.TexCoord.xy) * 2 - 1;
    float4 specmap = tex2D(reflectSampler,IN.TexCoord.xy);
    float3 Ln = normalize(IN.LightVec);
    float3 Nn = normalize(IN.WorldNormal);
    float3 Tn = normalize(IN.WorldTangent);
    float3 Bn = normalize(IN.WorldBinorm);
    float3 Nb = (normalmap.z * Nn) + (1.5 *(normalmap.x * Tn + normalmap.y * Bn));
    Nb = normalize(Nb);
    float3 Vn = normalize(IN.WorldEyeVec);
    float3 Hn = normalize(Vn + Ln);
    float4 lighting = lit(dot(Ln,Nb),dot(Hn,Nb),SpecExpon);
    float hdn = lighting.z;
    float ldn = lighting.y;
    
    //calculate whether the per-pixel normal is facing up or down, and use to blend between sky and ground colors
    //this will be added to the ambient color
    float4 sky = lerp(groundColor, skyColor, Nb.g); 
    
    //calculate the sin(time) and scale result, don't allow lower limit to reach 0
    float fadetime = 0.5 * (sin(3 * time) +2);
    
           
    
    //calculate ambient, diffuse, and specular
    float4 diffContrib = SurfColor * diffusemap * ldn ;
    float4 ambContrib = (AmbiColor+0.3) * sky * diffusemap ;
    float4 specContrib =  SurfColor * specmap *   hdn;
    //float4 selfIll = specmap.w * diffusemap;
    
    //calculate an animated self-illumination (glow)
    float4 selfIll = (specmap.w * fadetime) * diffusemap ;
    
        
    //add diffuse ,specular, and glow components, spec is reduced by 40% here
    float4 result = diffContrib + ambContrib + (0.6 *specContrib) + selfIll;
    result.a=diffusemap.a * Alphavalue;

    return result;
}


/****** technique *******/

technique dx9textured
{
	pass p0 
	{		
	        // lighting
        	Lighting       = FALSE;
        	SpecularEnable = FALSE;
	        FogEnable      = FALSE;
	        
	        // samplers
        Sampler[0] = (colorSampler);
        Sampler[1] = (normalSampler);
        Sampler[2] = (reflectSampler);


		// same vertex shader for both DX9 techniques
		VertexShader = compile vs_2_0 mainVS();
		ZEnable = true;
		ZWriteEnable = true;
		CullMode = CCW;
		PixelShader = compile ps_3_0 mainPS();
	}
}

/***************************** eof ***/
