Index: data/Media/materials/programs/AmbientOneTexture.glsl
===================================================================
--- data/Media/materials/programs/AmbientOneTexture.glsl	(revision 5026)
+++ data/Media/materials/programs/AmbientOneTexture.glsl	(revision 5026)
@@ -0,0 +1,13 @@
+uniform vec4 ambient;
+
+/*
+  Basic ambient lighting vertex program
+*/
+void main()
+{
+	gl_Position = ftransform();
+	gl_TexCoord[0] = gl_MultiTexCoord0;
+	gl_FrontColor = ambient;
+}
+
+
Index: data/Media/materials/programs/Example_Basic.cg
===================================================================
--- data/Media/materials/programs/Example_Basic.cg	(revision 5026)
+++ data/Media/materials/programs/Example_Basic.cg	(revision 5026)
@@ -0,0 +1,272 @@
+/*
+  Basic ambient lighting vertex program
+*/
+void ambientOneTexture_vp(float4 position : POSITION,
+						  float2 uv		  : TEXCOORD0,
+						  
+						  out float4 oPosition : POSITION,
+						  out float2 oUv	   : TEXCOORD0,
+						  out float4 colour    : COLOR,
+
+						  uniform float4x4 worldViewProj,
+						  uniform float4 ambient)
+{
+	oPosition = mul(worldViewProj, position);
+	oUv = uv;
+	colour = ambient;
+}
+
+/*
+  Single-weight-per-vertex hardware skinning, 2 lights
+  The trouble with vertex programs is they're not general purpose, but
+  fixed function hardware skinning is very poorly supported
+*/
+void hardwareSkinningOneWeight_vp(
+	float4 position : POSITION,
+	float3 normal   : NORMAL,
+	float2 uv       : TEXCOORD0,
+	float  blendIdx : BLENDINDICES,
+	
+
+	out float4 oPosition : POSITION,
+	out float2 oUv       : TEXCOORD0,
+	out float4 colour           : COLOR,
+	// Support up to 24 bones of float3x4
+	// vs_1_1 only supports 96 params so more than this is not feasible
+	uniform float3x4   worldMatrix3x4Array[24],
+	uniform float4x4 viewProjectionMatrix,
+	uniform float4   lightPos[2],
+	uniform float4   lightDiffuseColour[2],
+	uniform float4   ambient)
+{
+	// transform by indexed matrix
+	float4 blendPos = float4(mul(worldMatrix3x4Array[blendIdx], position).xyz, 1.0);
+	// view / projection
+	oPosition = mul(viewProjectionMatrix, blendPos);
+	// transform normal
+	float3 norm = mul((float3x3)worldMatrix3x4Array[blendIdx], normal);
+	// Lighting - support point and directional
+	float3 lightDir0 = 	normalize(
+		lightPos[0].xyz -  (blendPos.xyz * lightPos[0].w));
+	float3 lightDir1 = 	normalize(
+		lightPos[1].xyz -  (blendPos.xyz * lightPos[1].w));
+
+	oUv = uv;
+	colour = ambient + 
+		(saturate(dot(lightDir0, norm)) * lightDiffuseColour[0]) + 
+		(saturate(dot(lightDir1, norm)) * lightDiffuseColour[1]);
+	
+}	
+
+/*
+  Single-weight-per-vertex hardware skinning, shadow-caster pass
+*/
+void hardwareSkinningOneWeightCaster_vp(
+	float4 position : POSITION,
+	float3 normal   : NORMAL,
+	float  blendIdx : BLENDINDICES,
+	
+
+	out float4 oPosition : POSITION,
+	out float4 colour    : COLOR,
+	// Support up to 24 bones of float3x4
+	// vs_1_1 only supports 96 params so more than this is not feasible
+	uniform float3x4   worldMatrix3x4Array[24],
+	uniform float4x4 viewProjectionMatrix,
+	uniform float4   ambient)
+{
+	// transform by indexed matrix
+	float4 blendPos = float4(mul(worldMatrix3x4Array[blendIdx], position).xyz, 1.0);
+	// view / projection
+	oPosition = mul(viewProjectionMatrix, blendPos);
+	
+	colour = ambient;
+	
+}	
+
+/*
+  Two-weight-per-vertex hardware skinning, 2 lights
+  The trouble with vertex programs is they're not general purpose, but
+  fixed function hardware skinning is very poorly supported
+*/
+void hardwareSkinningTwoWeights_vp(
+	float4 position : POSITION,
+	float3 normal   : NORMAL,
+	float2 uv       : TEXCOORD0,
+	float4 blendIdx : BLENDINDICES,
+	float4 blendWgt : BLENDWEIGHT,
+	
+
+	out float4 oPosition : POSITION,
+	out float2 oUv       : TEXCOORD0,
+	out float4 colour           : COLOR,
+	// Support up to 24 bones of float3x4
+	// vs_1_1 only supports 96 params so more than this is not feasible
+	uniform float3x4   worldMatrix3x4Array[24],
+	uniform float4x4 viewProjectionMatrix,
+	uniform float4   lightPos[2],
+	uniform float4   lightDiffuseColour[2],
+	uniform float4   ambient)
+{
+	// transform by indexed matrix
+	float4 blendPos = float4(0,0,0,0);
+	int i;
+	for (i = 0; i < 2; ++i)
+	{
+		blendPos += float4(mul(worldMatrix3x4Array[blendIdx[i]], position).xyz, 1.0) * blendWgt[i];
+	}
+	// view / projection
+	oPosition = mul(viewProjectionMatrix, blendPos);
+	// transform normal
+	float3 norm = float3(0,0,0);
+	for (i = 0; i < 2; ++i)
+	{
+		norm += mul((float3x3)worldMatrix3x4Array[blendIdx[i]], normal) * 
+		blendWgt[i];
+	}
+	norm = normalize(norm);
+	// Lighting - support point and directional
+	float3 lightDir0 = 	normalize(
+		lightPos[0].xyz -  (blendPos.xyz * lightPos[0].w));
+	float3 lightDir1 = 	normalize(
+		lightPos[1].xyz -  (blendPos.xyz * lightPos[1].w));
+
+	
+	oUv = uv;
+	colour = float4(0.5, 0.5, 0.5, 1) + 
+		(saturate(dot(lightDir0, norm)) * lightDiffuseColour[0]) + 
+		(saturate(dot(lightDir1, norm)) * lightDiffuseColour[1]);
+	
+}
+
+/*
+  Two-weight-per-vertex hardware skinning, shadow caster pass
+*/
+void hardwareSkinningTwoWeightsCaster_vp(
+	float4 position : POSITION,
+	float3 normal   : NORMAL,
+	float2 uv       : TEXCOORD0,
+	float4 blendIdx : BLENDINDICES,
+	float4 blendWgt : BLENDWEIGHT,
+	
+
+	out float4 oPosition : POSITION,
+	out float4 colour           : COLOR,
+	// Support up to 24 bones of float3x4
+	// vs_1_1 only supports 96 params so more than this is not feasible
+	uniform float3x4   worldMatrix3x4Array[24],
+	uniform float4x4 viewProjectionMatrix,
+	uniform float4   ambient)
+{
+	// transform by indexed matrix
+	float4 blendPos = float4(0,0,0,0);
+	int i;
+	for (i = 0; i < 2; ++i)
+	{
+		blendPos += float4(mul(worldMatrix3x4Array[blendIdx[i]], position).xyz, 1.0) * blendWgt[i];
+	}
+	// view / projection
+	oPosition = mul(viewProjectionMatrix, blendPos);
+	
+
+	colour = ambient;
+		
+	
+}
+
+
+/*
+  Four-weight-per-vertex hardware skinning, 2 lights
+  The trouble with vertex programs is they're not general purpose, but
+  fixed function hardware skinning is very poorly supported
+*/
+void hardwareSkinningFourWeights_vp(
+	float4 position : POSITION,
+	float3 normal   : NORMAL,
+	float2 uv       : TEXCOORD0,
+	float4 blendIdx : BLENDINDICES,
+	float4 blendWgt : BLENDWEIGHT,
+	
+
+	out float4 oPosition : POSITION,
+	out float2 oUv       : TEXCOORD0,
+	out float4 colour           : COLOR,
+	// Support up to 24 bones of float3x4
+	// vs_1_1 only supports 96 params so more than this is not feasible
+	uniform float3x4   worldMatrix3x4Array[24],
+	uniform float4x4 viewProjectionMatrix,
+	uniform float4   lightPos[2],
+	uniform float4   lightDiffuseColour[2],
+	uniform float4   ambient)
+{
+	// transform by indexed matrix
+	float4 blendPos = float4(0,0,0,0);
+	int i;
+	for (i = 0; i < 4; ++i)
+	{
+		blendPos += float4(mul(worldMatrix3x4Array[blendIdx[i]], position).xyz, 1.0) * blendWgt[i];
+	}
+	// view / projection
+	oPosition = mul(viewProjectionMatrix, blendPos);
+	// transform normal
+	float3 norm = float3(0,0,0);
+	for (i = 0; i < 4; ++i)
+	{
+		norm += mul((float3x3)worldMatrix3x4Array[blendIdx[i]], normal) * 
+		blendWgt[i];
+	}
+	norm = normalize(norm);
+	// Lighting - support point and directional
+	float3 lightDir0 = 	normalize(
+		lightPos[0].xyz -  (blendPos.xyz * lightPos[0].w));
+	float3 lightDir1 = 	normalize(
+		lightPos[1].xyz -  (blendPos.xyz * lightPos[1].w));
+
+	
+	oUv = uv;
+	colour = ambient + 
+		(saturate(dot(lightDir0, norm)) * lightDiffuseColour[0]) + 
+		(saturate(dot(lightDir1, norm)) * lightDiffuseColour[1]);
+	
+}
+
+void hardwareMorphAnimation(float3 pos1 : POSITION,
+			  float4 normal		: NORMAL,
+			  float2 uv		  : TEXCOORD0,
+			  float3 pos2	  : TEXCOORD1,
+						  
+			  out float4 oPosition : POSITION,
+			  out float2 oUv	   : TEXCOORD0,
+			  out float4 colour    : COLOR,
+
+			  uniform float4x4 worldViewProj, 
+			  uniform float4 anim_t)
+{
+	// interpolate
+	float4 interp = float4(pos1 + anim_t.x*(pos2 - pos1), 1.0f);
+	
+	oPosition = mul(worldViewProj, interp);
+	oUv = uv;
+	colour = float4(1,0,0,1);
+}
+
+void hardwarePoseAnimation(float3 pos : POSITION,
+			  float4 normal		: NORMAL,
+			  float2 uv		  : TEXCOORD0,
+			  float3 pose1	  : TEXCOORD1,
+			  float3 pose2	  : TEXCOORD2,
+						  
+			  out float4 oPosition : POSITION,
+			  out float2 oUv	   : TEXCOORD0,
+			  out float4 colour    : COLOR,
+
+			  uniform float4x4 worldViewProj, 
+			  uniform float4 anim_t)
+{
+	// interpolate
+	float4 interp = float4(pos + anim_t.x*pose1 + anim_t.y*pose2, 1.0f);
+	
+	oPosition = mul(worldViewProj, interp);
+	oUv = uv;
+	colour = float4(1,0,0,1);
+}
Index: data/Media/materials/programs/Example_Basic.hlsl
===================================================================
--- data/Media/materials/programs/Example_Basic.hlsl	(revision 5026)
+++ data/Media/materials/programs/Example_Basic.hlsl	(revision 5026)
@@ -0,0 +1,273 @@
+/*
+  Basic ambient lighting vertex program
+*/
+void ambientOneTexture_vp(float4 position : POSITION,
+						  float2 uv		  : TEXCOORD0,
+						  
+						  out float4 oPosition : POSITION,
+						  out float2 oUv	   : TEXCOORD0,
+						  out float4 colour    : COLOR,
+
+						  uniform float4x4 worldViewProj,
+						  uniform float4 ambient)
+{
+	oPosition = mul(worldViewProj, position);
+	oUv = uv;
+	colour = ambient;
+}
+
+/*
+  Single-weight-per-vertex hardware skinning, 2 lights
+  The trouble with vertex programs is they're not general purpose, but
+  fixed function hardware skinning is very poorly supported
+*/
+void hardwareSkinningOneWeight_vp(
+	float4 position : POSITION,
+	float3 normal   : NORMAL,
+	float2 uv       : TEXCOORD0,
+	float  blendIdx : BLENDINDICES,
+	
+
+	out float4 oPosition : POSITION,
+	out float2 oUv       : TEXCOORD0,
+	out float4 colour           : COLOR,
+	// Support up to 24 bones of float3x4
+	// vs_1_1 only supports 96 params so more than this is not feasible
+	uniform float3x4   worldMatrix3x4Array[24],
+	uniform float4x4 viewProjectionMatrix,
+	uniform float4   lightPos[2],
+	uniform float4   lightDiffuseColour[2],
+	uniform float4   ambient)
+{
+	// transform by indexed matrix
+	float4 blendPos = float4(mul(worldMatrix3x4Array[blendIdx], position).xyz, 1.0);
+	// view / projection
+	oPosition = mul(viewProjectionMatrix, blendPos);
+	// transform normal
+	float3 norm = mul((float3x3)worldMatrix3x4Array[blendIdx], normal);
+	// Lighting - support point and directional
+	float3 lightDir0 = 	normalize(
+		lightPos[0].xyz -  (blendPos.xyz * lightPos[0].w));
+	float3 lightDir1 = 	normalize(
+		lightPos[1].xyz -  (blendPos.xyz * lightPos[1].w));
+
+	oUv = uv;
+	colour = ambient + 
+		(saturate(dot(lightDir0, norm)) * lightDiffuseColour[0]) + 
+		(saturate(dot(lightDir1, norm)) * lightDiffuseColour[1]);
+	
+}	
+
+/*
+  Single-weight-per-vertex hardware skinning, shadow-caster pass
+*/
+void hardwareSkinningOneWeightCaster_vp(
+	float4 position : POSITION,
+	float3 normal   : NORMAL,
+	float  blendIdx : BLENDINDICES,
+	
+
+	out float4 oPosition : POSITION,
+	out float4 colour    : COLOR,
+	// Support up to 24 bones of float3x4
+	// vs_1_1 only supports 96 params so more than this is not feasible
+	uniform float3x4   worldMatrix3x4Array[24],
+	uniform float4x4 viewProjectionMatrix,
+	uniform float4   ambient)
+{
+	// transform by indexed matrix
+	float4 blendPos = float4(mul(worldMatrix3x4Array[blendIdx], position).xyz, 1.0);
+	// view / projection
+	oPosition = mul(viewProjectionMatrix, blendPos);
+	
+	colour = ambient;
+	
+}	
+
+/*
+  Two-weight-per-vertex hardware skinning, 2 lights
+  The trouble with vertex programs is they're not general purpose, but
+  fixed function hardware skinning is very poorly supported
+*/
+void hardwareSkinningTwoWeights_vp(
+	float4 position : POSITION,
+	float3 normal   : NORMAL,
+	float2 uv       : TEXCOORD0,
+	float4 blendIdx : BLENDINDICES,
+	float4 blendWgt : BLENDWEIGHT,
+	
+
+	out float4 oPosition : POSITION,
+	out float2 oUv       : TEXCOORD0,
+	out float4 colour           : COLOR,
+	// Support up to 24 bones of float3x4
+	// vs_1_1 only supports 96 params so more than this is not feasible
+	uniform float3x4   worldMatrix3x4Array[24],
+	uniform float4x4 viewProjectionMatrix,
+	uniform float4   lightPos[2],
+	uniform float4   lightDiffuseColour[2],
+	uniform float4   ambient)
+{
+	// transform by indexed matrix
+	float4 blendPos = float4(0,0,0,0);
+	int i;
+	for (i = 0; i < 2; ++i)
+	{
+		blendPos += float4(mul(worldMatrix3x4Array[blendIdx[i]], position).xyz, 1.0) * blendWgt[i];
+	}
+	// view / projection
+	oPosition = mul(viewProjectionMatrix, blendPos);
+	// transform normal
+	float3 norm = float3(0,0,0);
+	for (i = 0; i < 2; ++i)
+	{
+		norm += mul((float3x3)worldMatrix3x4Array[blendIdx[i]], normal) * 
+		blendWgt[i];
+	}
+	norm = normalize(norm);
+	// Lighting - support point and directional
+	float3 lightDir0 = 	normalize(
+		lightPos[0].xyz -  (blendPos.xyz * lightPos[0].w));
+	float3 lightDir1 = 	normalize(
+		lightPos[1].xyz -  (blendPos.xyz * lightPos[1].w));
+
+	
+	oUv = uv;
+	colour = ambient + 
+		(saturate(dot(lightDir0, norm)) * lightDiffuseColour[0]) + 
+		(saturate(dot(lightDir1, norm)) * lightDiffuseColour[1]);
+	
+}
+
+/*
+  Two-weight-per-vertex hardware skinning, shadow caster pass
+*/
+void hardwareSkinningTwoWeightsCaster_vp(
+	float4 position : POSITION,
+	float3 normal   : NORMAL,
+	float2 uv       : TEXCOORD0,
+	float4 blendIdx : BLENDINDICES,
+	float4 blendWgt : BLENDWEIGHT,
+	
+
+	out float4 oPosition : POSITION,
+	out float4 colour           : COLOR,
+	// Support up to 24 bones of float3x4
+	// vs_1_1 only supports 96 params so more than this is not feasible
+	uniform float3x4   worldMatrix3x4Array[24],
+	uniform float4x4 viewProjectionMatrix,
+	uniform float4   ambient)
+{
+	// transform by indexed matrix
+	float4 blendPos = float4(0,0,0,0);
+	int i;
+	for (i = 0; i < 2; ++i)
+	{
+		blendPos += float4(mul(worldMatrix3x4Array[blendIdx[i]], position).xyz, 1.0) * blendWgt[i];
+	}
+	// view / projection
+	oPosition = mul(viewProjectionMatrix, blendPos);
+	
+
+	colour = ambient;
+		
+	
+}
+
+
+/*
+  Four-weight-per-vertex hardware skinning, 2 lights
+  The trouble with vertex programs is they're not general purpose, but
+  fixed function hardware skinning is very poorly supported
+*/
+void hardwareSkinningFourWeights_vp(
+	float4 position : POSITION,
+	float3 normal   : NORMAL,
+	float2 uv       : TEXCOORD0,
+	float4 blendIdx : BLENDINDICES,
+	float4 blendWgt : BLENDWEIGHT,
+	
+
+	out float4 oPosition : POSITION,
+	out float2 oUv       : TEXCOORD0,
+	out float4 colour           : COLOR,
+	// Support up to 24 bones of float3x4
+	// vs_1_1 only supports 96 params so more than this is not feasible
+	uniform float3x4   worldMatrix3x4Array[24],
+	uniform float4x4 viewProjectionMatrix,
+	uniform float4   lightPos[2],
+	uniform float4   lightDiffuseColour[2],
+	uniform float4   ambient)
+{
+	// transform by indexed matrix
+	float4 blendPos = float4(0,0,0,0);
+	int i;
+	for (i = 0; i < 4; ++i)
+	{
+		blendPos += float4(mul(worldMatrix3x4Array[blendIdx[i]], position).xyz, 1.0) * blendWgt[i];
+	}
+	// view / projection
+	oPosition = mul(viewProjectionMatrix, blendPos);
+	// transform normal
+	float3 norm = float3(0,0,0);
+	for (i = 0; i < 4; ++i)
+	{
+		norm += mul((float3x3)worldMatrix3x4Array[blendIdx[i]], normal) * 
+		blendWgt[i];
+	}
+	norm = normalize(norm);
+	// Lighting - support point and directional
+	float3 lightDir0 = 	normalize(
+		lightPos[0].xyz -  (blendPos.xyz * lightPos[0].w));
+	float3 lightDir1 = 	normalize(
+		lightPos[1].xyz -  (blendPos.xyz * lightPos[1].w));
+
+	
+	oUv = uv;
+	colour = ambient + 
+		(saturate(dot(lightDir0, norm)) * lightDiffuseColour[0]) + 
+		(saturate(dot(lightDir1, norm)) * lightDiffuseColour[1]);
+	
+}
+
+void hardwareMorphAnimation(float3 pos1 : POSITION,
+			  float4 normal		: NORMAL,
+			  float2 uv		  : TEXCOORD0,
+			  float3 pos2	  : TEXCOORD1,
+						  
+			  out float4 oPosition : POSITION,
+			  out float2 oUv	   : TEXCOORD0,
+			  out float4 colour    : COLOR,
+
+			  uniform float4x4 worldViewProj, 
+			  uniform float4 anim_t)
+{
+	// interpolate
+	float4 interp = float4(pos1 + anim_t.x*(pos2 - pos1), 1.0f);
+	
+	oPosition = mul(worldViewProj, interp);
+	oUv = uv;
+	colour = float4(1,0,0,1);
+}
+
+void hardwarePoseAnimation(float3 pos : POSITION,
+			  float4 normal		: NORMAL,
+			  float2 uv		  : TEXCOORD0,
+			  float3 pose1	  : TEXCOORD1,
+			  float3 pose2	  : TEXCOORD2,
+						  
+			  out float4 oPosition : POSITION,
+			  out float2 oUv	   : TEXCOORD0,
+			  out float4 colour    : COLOR,
+
+			  uniform float4x4 worldViewProj, 
+			  uniform float4 anim_t)
+{
+	// interpolate
+	float4 interp = float4(pos + anim_t.x*pose1 + anim_t.y*pose2, 1.0f);
+	
+	oPosition = mul(worldViewProj, interp);
+	oUv = uv;
+	colour = float4(1,0,0,1);
+}
+
Index: data/Media/materials/programs/skinningTwoWeightsShadowCasterVp.glsl
===================================================================
--- data/Media/materials/programs/skinningTwoWeightsShadowCasterVp.glsl	(revision 5026)
+++ data/Media/materials/programs/skinningTwoWeightsShadowCasterVp.glsl	(revision 5026)
@@ -0,0 +1,40 @@
+// Example GLSL program for skinning with two bone weights per vertex
+
+attribute vec4 blendIndices;
+attribute vec4 blendWeights;
+
+// 3x4 matrix, passed as vec4's for compatibility with GL 2.0
+// GL 2.0 supports 3x4 matrices
+// Support 24 bones ie 24*3, but use 72 since our parser can pick that out for sizing
+uniform vec4 worldMatrix3x4Array[72];
+uniform mat4 viewProjectionMatrix;
+uniform vec4 ambient;
+
+void main()
+{
+	vec3 blendPos = vec3(0,0,0);
+
+	for (int bone = 0; bone < 2; ++bone)
+	{
+		// perform matrix multiplication manually since no 3x4 matrices
+        // ATI GLSL compiler can't handle indexing an array within an array so calculate the inner index first
+	    int idx = int(blendIndices[bone]) * 3;
+        // ATI GLSL compiler can't handle unrolling the loop so do it manually
+        // ATI GLSL has better performance when mat4 is used rather than using individual dot product
+        // There is a bug in ATI mat4 constructor (Cat 7.2) when indexed uniform array elements are used as vec4 parameter so manually assign
+		mat4 worldMatrix;
+		worldMatrix[0] = worldMatrix3x4Array[idx];
+		worldMatrix[1] = worldMatrix3x4Array[idx + 1];
+		worldMatrix[2] = worldMatrix3x4Array[idx + 2];
+		worldMatrix[3] = vec4(0);
+		// now weight this into final 
+		blendPos += (gl_Vertex * worldMatrix).xyz * blendWeights[bone];
+	}
+
+	// apply view / projection to position
+	gl_Position = viewProjectionMatrix * vec4(blendPos, 1);
+	
+	gl_FrontSecondaryColor = vec4(0,0,0,0);
+	gl_FrontColor = ambient;
+	gl_TexCoord[0] = gl_MultiTexCoord0;
+}
Index: data/Media/materials/programs/skinningTwoWeightsVp.glsl
===================================================================
--- data/Media/materials/programs/skinningTwoWeightsVp.glsl	(revision 5026)
+++ data/Media/materials/programs/skinningTwoWeightsVp.glsl	(revision 5026)
@@ -0,0 +1,57 @@
+// Example GLSL program for skinning with two bone weights per vertex
+
+attribute vec4 blendIndices;
+attribute vec4 blendWeights;
+
+// 3x4 matrix, passed as vec4's for compatibility with GL 2.0
+// GL 2.0 supports 3x4 matrices
+// Support 24 bones ie 24*3, but use 72 since our parser can pick that out for sizing
+uniform vec4 worldMatrix3x4Array[72];
+uniform mat4 viewProjectionMatrix;
+uniform vec4 lightPos[2];
+uniform vec4 lightDiffuseColour[2];
+
+void main()
+{
+	vec3 blendPos = vec3(0,0,0);
+	vec3 blendNorm = vec3(0,0,0);
+	
+	for (int bone = 0; bone < 2; ++bone)
+	{
+		// perform matrix multiplication manually since no 3x4 matrices
+        // ATI GLSL compiler can't handle indexing an array within an array so calculate the inner index first
+	    int idx = int(blendIndices[bone]) * 3;
+        // ATI GLSL compiler can't handle unrolling the loop so do it manually
+        // ATI GLSL has better performance when mat4 is used rather than using individual dot product
+        // There is a bug in ATI mat4 constructor (Cat 7.2) when indexed uniform array elements are used as vec4 parameter so manually assign
+		mat4 worldMatrix;
+		worldMatrix[0] = worldMatrix3x4Array[idx];
+		worldMatrix[1] = worldMatrix3x4Array[idx + 1];
+		worldMatrix[2] = worldMatrix3x4Array[idx + 2];
+		worldMatrix[3] = vec4(0);
+		// now weight this into final 
+	    float weight = blendWeights[bone];
+		blendPos += (gl_Vertex * worldMatrix).xyz * weight;
+		
+		mat3 worldRotMatrix = mat3(worldMatrix[0].xyz, worldMatrix[1].xyz, worldMatrix[2].xyz);
+		blendNorm += (gl_Normal * worldRotMatrix) * weight;
+
+	}
+
+	// apply view / projection to position
+	gl_Position = viewProjectionMatrix * vec4(blendPos, 1);
+
+	// simple vertex lighting model
+	vec3 lightDir0 = normalize(
+		lightPos[0].xyz -  (blendPos.xyz * lightPos[0].w));
+	vec3 lightDir1 = normalize(
+		lightPos[1].xyz -  (blendPos.xyz * lightPos[1].w));
+		
+	gl_FrontSecondaryColor = vec4(0);
+	gl_FrontColor = vec4(0.5, 0.5, 0.5, 1.0) 
+		+ clamp(dot(lightDir0, blendNorm), 0.0, 1.0) * lightDiffuseColour[0]
+		+ clamp(dot(lightDir1, blendNorm), 0.0, 1.0) * lightDiffuseColour[1];
+
+	gl_TexCoord[0] = gl_MultiTexCoord0;
+	
+}
Index: data/Media/resources.cfg
===================================================================
--- data/Media/resources.cfg	(revision 5025)
+++ data/Media/resources.cfg	(revision 5026)
@@ -8,5 +8,5 @@
 FileSystem=.
 FileSystem=fonts
-#FileSystem=../Media/materials/programs
+FileSystem=materials/programs
 FileSystem=materials/scripts
 FileSystem=materials/textures
