CelShading.cg        
//
// The maximum number of lights per-object. Decrease this value if you need some extra performance.
//
// If you change this, then you must enter 'CelShading.program' and change the '$numLights'
// variable to match this definition.
#define NUM_LIGHTS 6

//
// Vertex program
float4 main_vp(
		float4 iPos		: POSITION,
		float3 iNorm		: NORMAL,
		float2 iUV		: TEXCOORD0,
		out float3 oPos		: TEXCOORD0,
		out float3 oNorm	: TEXCOORD1,
		out float2 oUV		: TEXCOORD2,
		uniform float4x4 worldViewProj ) : POSITION
{
	oPos = iPos.xyz;
	oNorm = iNorm;
	oUV = iUV;
	
	return mul(worldViewProj, iPos);
}

//
// Colored surface fragment program
float4 main_fp(
		float3 iPos 	: TEXCOORD0,
		float3 iNorm	: TEXCOORD1,
		float3 iUV	: TEXCOORD2,
		
		uniform float3 eyePosition,
		
		uniform float4 ambientColor,
		uniform float4 diffuseColor,
		uniform float4 specularColor,
		uniform float4 emissiveColor,
		uniform float shininess,
		
		uniform float3 ambientLight,
		
		// Light params
		uniform float4 lightDiffuse[NUM_LIGHTS],
		uniform float4 lightSpecular[NUM_LIGHTS],
		uniform float4 lightPosition[NUM_LIGHTS],
		uniform float4 lightAttenuation[NUM_LIGHTS],
		
		// Texture params
		uniform sampler1D diffuseRamp	: register(s0),
		uniform sampler1D specRamp		: register(s1) ) : COLOR
{
	float4 surfaceColor = float4(ambientLight,1)*ambientColor;
	float4 specularSurface = 0;
	
	for (int i = 0; i < NUM_LIGHTS; i++)
	{
		float3 norm = normalize(iNorm);

		//
		// Calculate light vector and distance
		float3 lightVec = 0;
		if (lightPosition[i].w == 1)
			lightVec = lightPosition[i].xyz - iPos*lightPosition[i].w;
		else
			lightVec = lightPosition[i].xyz;
		
		float lightDist = length(lightVec);
		lightVec = normalize(lightVec);

		//
		// Calculate the direction in-between the light direction and the camera's direction.
		float3 eyeVec = normalize(eyePosition - iPos);
		float3 halfDir = normalize(lightVec + eyeVec);
		
		//
		// Calculate luminosity based on light attenuation
		float luminosity = 1.f;
		if(lightAttenuation[i].x > lightDist && lightPosition[i].w == 1)
			luminosity = 1.f / 
				( lightAttenuation[i].y + lightAttenuation[i].z*lightDist + 
				  lightAttenuation[i].w*(lightDist*lightDist) );
		
		//
		// Get diffuse component based on the dot product of the normal and the light direction,
		// multiplied by the luminosity component.
		float diffComponent = max(dot(norm, lightVec), 0)*luminosity;
		
		//
		// Get specular component based on the dot product of the normal and the half-camera-light
		// direction, multiplied by the luminosity component.
		float specComponent = pow(max(dot(norm, halfDir), 0), shininess)*luminosity;
		
		float diffuse = tex1D(diffuseRamp, diffComponent).r;
		float specular = tex1D(specRamp, specComponent).r;
				
		surfaceColor += diffuse*diffuseColor*lightDiffuse[i];
		specularSurface += specular*lightSpecular[i]*specularColor;
	}
	
	return emissiveColor + surfaceColor + specularSurface;
}
//
// Decal + Specular Mapping fragment program
float4 mainDecal_fp(
		float3 iPos 	: TEXCOORD0,
		float3 iNorm	: TEXCOORD1,
		float3 iUV	: TEXCOORD2,
		
		uniform float3 eyePosition,
		
		uniform float4 ambientColor,
		uniform float4 diffuseColor,
		uniform float4 specularColor,
		uniform float4 emissiveColor,
		uniform float shininess,
		
		uniform float3 ambientLight,
		
		// Light params
		uniform float4 lightDiffuse[NUM_LIGHTS],
		uniform float4 lightSpecular[NUM_LIGHTS],
		uniform float4 lightPosition[NUM_LIGHTS],
		uniform float4 lightAttenuation[NUM_LIGHTS],
		
		// Texture params
		uniform sampler1D diffuseRamp	: register(s0),
		uniform sampler1D specRamp		: register(s1),
		
		uniform sampler2D decalTex		: register(s2)) : COLOR
{
	float4 surfaceColor = float4(ambientLight,1)*ambientColor;
	float4 specularSurface = 0;
	float4 texColor		= tex2D(decalTex, iUV);
	
	for (int i = 0; i < NUM_LIGHTS; i++)
	{
		float3 norm = normalize(iNorm);

		//
		// Calculate light vector and distance
		float3 lightVec = 0;
		if (lightPosition[i].w == 1)
			lightVec = lightPosition[i].xyz - iPos*lightPosition[i].w;
		else
			lightVec = lightPosition[i].xyz;
		
		float lightDist = length(lightVec);
		lightVec = normalize(lightVec);

		//
		// Calculate the direction in-between the light direction and the camera's direction.
		float3 eyeVec = normalize(eyePosition - iPos);
		float3 halfDir = normalize(lightVec + eyeVec);
		
		//
		// Calculate luminosity based on light attenuation
		float luminosity = 1.f;
		if(lightAttenuation[i].x > lightDist && lightPosition[i].w == 1)
			luminosity = 1.f / 
				( lightAttenuation[i].y + lightAttenuation[i].z*lightDist + 
				  lightAttenuation[i].w*(lightDist*lightDist) );
		
		//
		// Get diffuse component based on the dot product of the normal and the light direction,
		// multiplied by the luminosity component.
		float diffComponent = max(dot(norm, lightVec), 0)*luminosity;
		
		//
		// Get specular component based on the dot product of the normal and the half-camera-light
		// direction, multiplied by the luminosity component.
		float specComponent = pow(max(dot(norm, halfDir), 0), shininess)*luminosity;
		
		float diffuse = tex1D(diffuseRamp, diffComponent).r;
		float specular = tex1D(specRamp, specComponent).r;
				
		surfaceColor += diffuse*diffuseColor*lightDiffuse[i];
		specularSurface += specular*lightSpecular[i]*specularColor;
	}
	
	return texColor*(emissiveColor + surfaceColor) + specularSurface;
}
//
// Decal + Specular Mapping fragment program
float4 mainDecalSpec_fp(
		float3 iPos 	: TEXCOORD0,
		float3 iNorm	: TEXCOORD1,
		float3 iUV	: TEXCOORD2,
		
		uniform float3 eyePosition,
		
		uniform float4 ambientColor,
		uniform float4 diffuseColor,
		uniform float4 specularColor,
		uniform float4 emissiveColor,
		uniform float shininess,
		
		uniform float3 ambientLight,
		
		// Light params
		uniform float4 lightDiffuse[NUM_LIGHTS],
		uniform float4 lightSpecular[NUM_LIGHTS],
		uniform float4 lightPosition[NUM_LIGHTS],
		uniform float4 lightAttenuation[NUM_LIGHTS],
		
		// Texture params
		uniform sampler1D diffuseRamp	: register(s0),
		uniform sampler1D specRamp		: register(s1),
		
		uniform sampler2D decalTex		: register(s2),
		uniform sampler2D specMap		: register(s3)) : COLOR
{
	float4 surfaceColor = float4(ambientLight,1)*ambientColor;
	float4 specularSurface = 0;
	float4 texColor		= tex2D(decalTex, iUV);
	float4 specMapColor	= tex2D(specMap, iUV);
	
	for (int i = 0; i < NUM_LIGHTS; i++)
	{
		float3 norm = normalize(iNorm);

		//
		// Calculate light vector and distance
		float3 lightVec = 0;
		if (lightPosition[i].w == 1)
			lightVec = lightPosition[i].xyz - iPos*lightPosition[i].w;
		else
			lightVec = lightPosition[i].xyz;
		
		float lightDist = length(lightVec);
		lightVec = normalize(lightVec);

		//
		// Calculate the direction in-between the light direction and the camera's direction.
		float3 eyeVec = normalize(eyePosition - iPos);
		float3 halfDir = normalize(lightVec + eyeVec);
		
		//
		// Calculate luminosity based on light attenuation
		float luminosity = 1.f;
		if(lightAttenuation[i].x > lightDist && lightPosition[i].w == 1)
			luminosity = 1.f / 
				( lightAttenuation[i].y + lightAttenuation[i].z*lightDist + 
				  lightAttenuation[i].w*(lightDist*lightDist) );
		
		//
		// Get diffuse component based on the dot product of the normal and the light direction,
		// multiplied by the luminosity component.
		float diffComponent = max(dot(norm, lightVec), 0)*luminosity;
		
		//
		// Get specular component based on the dot product of the normal and the half-camera-light
		// direction, multiplied by the luminosity component.
		float specComponent = pow(max(dot(norm, halfDir), 0), shininess)*luminosity;
		
		float diffuse = tex1D(diffuseRamp, diffComponent).r;
		float specular = tex1D(specRamp, specComponent).r;
				
		surfaceColor += diffuse*diffuseColor*lightDiffuse[i];
		specularSurface += specular*lightSpecular[i]*specularColor;
	}
	
	return texColor*(emissiveColor + surfaceColor) + specMapColor*specularSurface;
}