diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 2e7147a3b43a04f2f456ea2876bccdde4599a2fa..71d24bcf13338bbcb3cc59f73a1a18567280d4dc 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -56,7 +56,7 @@ BOOL shouldChange(const LLVector4& v1, const LLVector4& v2)
 LLShaderFeatures::LLShaderFeatures()
 : calculatesLighting(false), isShiny(false), isFullbright(false), hasWaterFog(false),
 hasTransport(false), hasSkinning(false), hasObjectSkinning(false), hasAtmospherics(false), isSpecular(false),
-hasGamma(false), hasLighting(false), calculatesAtmospherics(false)
+hasGamma(false), hasLighting(false), calculatesAtmospherics(false), disableTextureIndex(false)
 {
 }
 
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index d46ddbbe183992ab791626a227e8792b67c82912..392688bba3ddbf9ccf6fc885e99d4f6979488068 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -45,6 +45,7 @@ class LLShaderFeatures
 	bool hasObjectSkinning;
 	bool hasAtmospherics;
 	bool hasGamma;
+	bool disableTextureIndex;
 
 	// char numLights;
 	
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 049dd4346b2feb7dd297c1a72163a41ab88fe77f..053251099650a45dd9dad364afda5d3954e15810 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -203,7 +203,9 @@ void LLTexUnit::disable(void)
 		if (mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE &&
 			mIndex < gGLManager.mNumTextureUnits)
 		{
+			stop_glerror();
 			glDisable(sGLTextureType[mCurrTexType]);
+			stop_glerror();
 		}
 		
 		mCurrTexType = TT_NONE;
@@ -403,6 +405,7 @@ void LLTexUnit::unbind(eTextureType type)
 		activate();
 		mCurrTexture = 0;
 		glBindTexture(sGLTextureType[type], 0);
+		stop_glerror();
 	}
 }
 
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index b8f9c60ca90116a2a2ec167e8bd8d52736c7cae0..6fb1e6e437e36a0a1551e549c546d4b56bccf5d7 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -209,7 +209,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
 	
 		if (features->hasWaterFog)
 		{
-			if (!shader->attachObject("lighting/lightWaterF.glsl"))
+			if (features->disableTextureIndex)
+			{
+				if (!shader->attachObject("lighting/lightWaterNonIndexedF.glsl"))
+				{
+					return FALSE;
+				}
+			}
+			else if (!shader->attachObject("lighting/lightWaterF.glsl"))
 			{
 				return FALSE;
 			}
@@ -217,7 +224,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
 		
 		else
 		{
-			if (!shader->attachObject("lighting/lightF.glsl"))
+			if (features->disableTextureIndex)
+			{
+				if (!shader->attachObject("lighting/lightNonIndexedF.glsl"))
+				{
+					return FALSE;
+				}
+			}
+			else if (!shader->attachObject("lighting/lightF.glsl"))
 			{
 				return FALSE;
 			}
@@ -230,14 +244,28 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
 	
 		if (features->isShiny && features->hasWaterFog)
 		{
-			if (!shader->attachObject("lighting/lightFullbrightShinyWaterF.glsl"))
+			if (features->disableTextureIndex)
+			{
+				if (!shader->attachObject("lighting/lightFullbrightShinyWaterNonIndexedF.glsl"))
+				{
+					return FALSE;
+				}
+			}
+			else if (!shader->attachObject("lighting/lightFullbrightShinyWaterF.glsl"))
 			{
 				return FALSE;
 			}
 		}
 		else if (features->hasWaterFog)
 		{
-			if (!shader->attachObject("lighting/lightFullbrightWaterF.glsl"))
+			if (features->disableTextureIndex)
+			{
+				if (!shader->attachObject("lighting/lightFullbrightWaterNonIndexedF.glsl"))
+				{
+					return FALSE;
+				}
+			}
+			else if (!shader->attachObject("lighting/lightFullbrightWaterF.glsl"))
 			{
 				return FALSE;
 			}
@@ -245,7 +273,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
 		
 		else if (features->isShiny)
 		{
-			if (!shader->attachObject("lighting/lightFullbrightShinyF.glsl"))
+			if (features->disableTextureIndex)
+			{
+				if (!shader->attachObject("lighting/lightFullbrightShinyNonIndexedF.glsl"))
+				{
+					return FALSE;
+				}
+			}
+			else if (!shader->attachObject("lighting/lightFullbrightShinyF.glsl"))
 			{
 				return FALSE;
 			}
@@ -253,7 +288,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
 		
 		else
 		{
-			if (!shader->attachObject("lighting/lightFullbrightF.glsl"))
+			if (features->disableTextureIndex)
+			{
+				if (!shader->attachObject("lighting/lightFullbrightNonIndexedF.glsl"))
+				{
+					return FALSE;
+				}
+			}
+			else if (!shader->attachObject("lighting/lightFullbrightF.glsl"))
 			{
 				return FALSE;
 			}
@@ -266,7 +308,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
 	
 		if (features->hasWaterFog)
 		{
-			if (!shader->attachObject("lighting/lightShinyWaterF.glsl"))
+			if (features->disableTextureIndex)
+			{
+				if (!shader->attachObject("lighting/lightShinyWaterNonIndexedF.glsl"))
+				{
+					return FALSE;
+				}
+			}
+			else if (!shader->attachObject("lighting/lightShinyWaterF.glsl"))
 			{
 				return FALSE;
 			}
@@ -274,7 +323,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
 		
 		else 
 		{
-			if (!shader->attachObject("lighting/lightShinyF.glsl"))
+			if (features->disableTextureIndex)
+			{
+				if (!shader->attachObject("lighting/lightShinyNonIndexedF.glsl"))
+				{
+					return FALSE;
+				}
+			}
+			else if (!shader->attachObject("lighting/lightShinyF.glsl"))
 			{
 				return FALSE;
 			}
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 8c9171ccf45cedbb24fe1cb3890948f17093f190..f715a8e9ba76e78bc8863bdfc62eddedf289f33e 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -1497,7 +1497,14 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
 	}
 	if (data_mask & MAP_VERTEX)
 	{
-		glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
+		if (data_mask & MAP_TEXTURE_INDEX)
+		{
+			glVertexPointer(4,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
+		}
+		else
+		{
+			glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
+		}
 	}
 
 	llglassertok();
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index a9f22193f87a4601aa25b94da85ad4fdb7ded85b..0c4b2415373fa35af62ea05d201a29872eeec643 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -130,6 +130,9 @@ class LLVertexBuffer : public LLRefCount
 		TYPE_CLOTHWEIGHT,
 		TYPE_MAX,
 		TYPE_INDEX,
+		
+		//no actual additional data, but indicates position.w is texture index
+		TYPE_TEXTURE_INDEX,
 	};
 	enum {
 		MAP_VERTEX = (1<<TYPE_VERTEX),
@@ -144,6 +147,7 @@ class LLVertexBuffer : public LLRefCount
 		MAP_WEIGHT = (1<<TYPE_WEIGHT),
 		MAP_WEIGHT4 = (1<<TYPE_WEIGHT4),
 		MAP_CLOTHWEIGHT = (1<<TYPE_CLOTHWEIGHT),
+		MAP_TEXTURE_INDEX = (1<<TYPE_TEXTURE_INDEX),
 	};
 	
 protected:
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
index 3b12a07a27df958a59de4e0dcc10e488b9bdb9ce..f6b7f42c22ae76d259c80cd78bc66c1b15f6d23a 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
@@ -9,9 +9,10 @@
 
 #extension GL_ARB_texture_rectangle : enable
 
-uniform sampler2D diffuseMap;
 uniform sampler2DRect depthMap;
 
+vec4 diffuseLookup(vec2 texcoord);
+
 uniform mat4 shadow_matrix[6];
 uniform vec4 shadow_clip;
 uniform vec2 screen_res;
@@ -47,7 +48,7 @@ void main()
 	
 	vec4 pos = vec4(vary_position, 1.0);
 	
-	vec4 diff= texture2D(diffuseMap, gl_TexCoord[0].xy);
+	vec4 diff= diffuseLookup(gl_TexCoord[0].xy);
 
 	vec4 col = vec4(vary_ambient + vary_directional.rgb, gl_Color.a);
 	vec4 color = diff * col;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
index 2691fc8dedb64b85a8cc3ecac5660e3c842fc23b..5890c30d8fb484f8181d5ee17257165c2bb82040 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
@@ -23,6 +23,7 @@ varying vec3 vary_fragcoord;
 varying vec3 vary_position;
 varying vec3 vary_light;
 varying vec3 vary_pointlight_col;
+varying float vary_texture_index;
 
 uniform float near_clip;
 uniform float shadow_offset;
@@ -61,11 +62,13 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa
 void main()
 {
 	//transform vertex
-	gl_Position = ftransform(); 
+	vec4 vert = vec4(gl_Vertex.xyz, 1.0);
+	vary_texture_index = gl_Vertex.w;
+	gl_Position = gl_ModelViewProjectionMatrix * vert; 
 	
 	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
 	
-	vec4 pos = (gl_ModelViewMatrix * gl_Vertex);
+	vec4 pos = (gl_ModelViewMatrix * vert);
 	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
 	
 	float dp_directional_light = max(0.0, dot(norm, gl_LightSource[0].position.xyz));
@@ -102,7 +105,7 @@ void main()
 
 	gl_FogFragCoord = pos.z;
 	
-	pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	pos = gl_ModelViewProjectionMatrix * vert;
 	vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip);
 	
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarEyesV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarEyesV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..536bacd23c25613db1735bdadd883f85220eb2c6
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarEyesV.glsl
@@ -0,0 +1,21 @@
+/** 
+ * @file avatarEyesV.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+ 
+#version 120
+
+varying vec3 vary_normal;
+
+void main()
+{
+	//transform vertex
+	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
+	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+	
+	vary_normal = normalize(gl_NormalMatrix * gl_Normal);
+
+	gl_FrontColor = gl_Color;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl
index 35cfb80c93882795211bd29c2834427513ac0a2b..f71d9f0b49e3dfc2918acbfb4154184bb19a4098 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl
@@ -20,3 +20,4 @@ void main()
 	vec3 nvn = normalize(vary_normal);
 	gl_FragData[2] = vec4(nvn.xy * 0.5 + 0.5, nvn.z, 0.0);
 }
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..1bbaeb44ff0a43876a7a765454d9a4df62457d89
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl
@@ -0,0 +1,50 @@
+/** 
+ * @file diffuseIndexedF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+ 
+#version 120
+
+varying float vary_texture_index;
+varying vec3 vary_normal;
+
+uniform sampler2D tex0;
+uniform sampler2D tex1;
+uniform sampler2D tex2;
+uniform sampler2D tex3;
+uniform sampler2D tex4;
+uniform sampler2D tex5;
+uniform sampler2D tex6;
+uniform sampler2D tex7;
+
+vec4 diffuseLookup(vec2 texcoord)
+{
+	switch (int(vary_texture_index+0.25))
+	{
+		case 0: return texture2D(tex0, texcoord);
+		case 1: return texture2D(tex1, texcoord);
+		case 2: return texture2D(tex2, texcoord);
+		case 3: return texture2D(tex3, texcoord);
+		case 4: return texture2D(tex4, texcoord);
+		case 5: return texture2D(tex5, texcoord);
+		case 6: return texture2D(tex6, texcoord);
+		case 7: return texture2D(tex7, texcoord);
+	}
+
+	return vec4(0,0,0,0);
+}
+
+void main() 
+{
+	vec3 col = gl_Color.rgb * diffuseLookup(gl_TexCoord[0].xy).rgb;
+
+	//col = vec3(vary_texture_index*0.25, 0, 0);
+	
+	gl_FragData[0] = vec4(col, 0.0);
+	gl_FragData[1] = gl_Color.aaaa; // spec
+	//gl_FragData[1] = vec4(vec3(gl_Color.a), gl_Color.a+(1.0-gl_Color.a)*gl_Color.a); // spec - from former class3 - maybe better, but not so well tested
+	vec3 nvn = normalize(vary_normal);
+	gl_FragData[2] = vec4(nvn.xy * 0.5 + 0.5, nvn.z, 0.0);
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
index 03d3322cb68855adfc5a7c9fe0de09b73ae96a19..b8de629fc86f66b78cdba0402c7c340378a60cc0 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
@@ -8,13 +8,15 @@
 #version 120
 
 varying vec3 vary_normal;
+varying float vary_texture_index;
 
 void main()
 {
 	//transform vertex
-	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
+	gl_Position = gl_ModelViewProjectionMatrix * vec4(gl_Vertex.xyz, 1.0); 
 	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
 	
+	vary_texture_index = gl_Vertex.w;
 	vary_normal = normalize(gl_NormalMatrix * gl_Normal);
 
 	gl_FrontColor = gl_Color;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
index 34298773974b2d35ea7396dceaebf3b7e1d363b9..30231039b0422784db1da230f2a30b8219184992 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
@@ -9,56 +9,48 @@
 
 #extension GL_ARB_texture_rectangle : enable
 
-uniform sampler2D diffuseMap;
-uniform sampler2DRect depthMap;
-uniform sampler2D noiseMap;
-
-uniform vec4 shadow_clip;
-uniform vec2 screen_res;
+varying float vary_texture_index;
+
+uniform sampler2D tex0;
+uniform sampler2D tex1;
+uniform sampler2D tex2;
+uniform sampler2D tex3;
+uniform sampler2D tex4;
+uniform sampler2D tex5;
+uniform sampler2D tex6;
+uniform sampler2D tex7;
+
+vec4 textureLookup(vec2 texcoord)
+{
+	switch (int(vary_texture_index+0.25))
+	{
+		case 0: return texture2D(tex0, texcoord);
+		case 1: return texture2D(tex1, texcoord);
+		case 2: return texture2D(tex2, texcoord);
+		case 3: return texture2D(tex3, texcoord);
+		case 4: return texture2D(tex4, texcoord);
+		case 5: return texture2D(tex5, texcoord);
+		case 6: return texture2D(tex6, texcoord);
+		case 7: return texture2D(tex7, texcoord);
+	}
+
+	return vec4(0,0,0,0);
+}
 
 vec3 fullbrightAtmosTransport(vec3 light);
 vec3 fullbrightScaleSoftClip(vec3 light);
 
-varying vec3 vary_ambient;
-varying vec3 vary_directional;
-varying vec4 vary_position;
-varying vec3 vary_normal;
-varying vec3 vary_fragcoord;
-
-uniform mat4 inv_proj;
-
-vec4 getPosition(vec2 pos_screen)
-{
-	float depth = texture2DRect(depthMap, pos_screen.xy).a;
-	vec2 sc = pos_screen.xy*2.0;
-	sc /= screen_res;
-	sc -= vec2(1.0,1.0);
-	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
-	vec4 pos = inv_proj * ndc;
-	pos /= pos.w;
-	pos.w = 1.0;
-	return pos;
-}
 
 void main() 
 {
-	vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5;
-	frag *= screen_res;
-	
-	vec3 samp_pos = getPosition(frag).xyz; 
-	
 	float shadow = 1.0;
-	vec4 pos = vary_position;
 
-	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy)*gl_Color;
+	vec4 color = textureLookup(gl_TexCoord[0].xy)*gl_Color;
 	
 	color.rgb = fullbrightAtmosTransport(color.rgb);
 
 	color.rgb = fullbrightScaleSoftClip(color.rgb);
 
-	//gl_FragColor = gl_Color;
 	gl_FragColor = color;
-	//gl_FragColor = vec4(1,0,1,1);
-	
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
index 6c38d220e26962bf7ad251ca51fcc3f7e456c0d0..6890360c566abc8be3dc80aeeab67641a714a700 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
@@ -14,30 +14,23 @@ vec3 atmosAffectDirectionalLight(float lightIntensity);
 vec3 scaleDownLight(vec3 light);
 vec3 scaleUpLight(vec3 light);
 
-varying vec3 vary_ambient;
-varying vec3 vary_directional;
-varying vec3 vary_normal;
-varying vec3 vary_fragcoord;
-uniform float near_clip;
-varying vec4 vary_position;
+varying float vary_texture_index;
 
 void main()
 {
 	//transform vertex
-	gl_Position = ftransform(); 
+	vec4 vert = vec4(gl_Vertex.xyz, 1.0);
+	vary_texture_index = gl_Vertex.w;
+
+	gl_Position = gl_ModelViewProjectionMatrix*vert; 
 	
 	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
 	
-	vec4 pos = (gl_ModelViewMatrix * gl_Vertex);
-	vary_position = pos;
-		
+	vec4 pos = (gl_ModelViewMatrix * vert);
+				
 	calcAtmospherics(pos.xyz);
 	
 	gl_FrontColor = gl_Color;
 
 	gl_FogFragCoord = pos.z;
-	
-	pos = gl_ModelViewProjectionMatrix * gl_Vertex;
-	vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip);
-	
 }
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
index 6dfc1b952c1fc52bb82e8d690228c57d65d13457..bd4875f3fff77a8b0b01a0854bda9ff89cb39eb6 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
@@ -9,13 +9,14 @@
 
 #extension GL_ARB_texture_rectangle : enable
 
-uniform sampler2D diffuseMap;
 uniform sampler2DRectShadow shadowMap0;
 uniform sampler2DRectShadow shadowMap1;
 uniform sampler2DRectShadow shadowMap2;
 uniform sampler2DRectShadow shadowMap3;
 uniform sampler2DRect depthMap;
 
+vec4 diffuseLookup(vec2 texcoord);
+
 uniform mat4 shadow_matrix[6];
 uniform vec4 shadow_clip;
 uniform vec2 screen_res;
@@ -105,7 +106,7 @@ void main()
 		}
 	}
 	
-	vec4 diff= texture2D(diffuseMap, gl_TexCoord[0].xy);
+	vec4 diff = diffuseLookup(gl_TexCoord[0].xy);
 
 	vec4 col = vec4(vary_ambient + vary_directional.rgb*shadow, gl_Color.a);
 	vec4 color = diff * col;
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl
index f6160815ebb51b5afa5b3720d8cc2702bd041150..c6c0b0f32af1dd41bde7922edc1f1a5ddfb93df5 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl
@@ -22,6 +22,7 @@ varying vec3 vary_directional;
 varying vec3 vary_fragcoord;
 varying vec3 vary_position;
 varying vec3 vary_pointlight_col;
+varying float vary_texture_index;
 
 uniform float near_clip;
 uniform float shadow_offset;
@@ -60,11 +61,13 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa
 void main()
 {
 	//transform vertex
-	gl_Position = ftransform(); 
+	vec4 vert = vec4(gl_Vertex.xyz, 1.0);
+	vary_texture_index = gl_Vertex.w;
+	gl_Position = gl_ModelViewProjectionMatrix * vert; 
 	
 	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
 	
-	vec4 pos = (gl_ModelViewMatrix * gl_Vertex);
+	vec4 pos = (gl_ModelViewMatrix * vert);
 	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
 	
 	float dp_directional_light = max(0.0, dot(norm, gl_LightSource[0].position.xyz));
@@ -99,7 +102,7 @@ void main()
 
 	gl_FogFragCoord = pos.z;
 	
-	pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	pos = gl_ModelViewProjectionMatrix * vert;
 	vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip);
 	
 }
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightF.glsl
index 342bc2ab6673aaea1d76832502645140401d874e..d5775f45065a9c7def488a3f68e0717834ed18c9 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/lightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightF.glsl
@@ -7,14 +7,40 @@
  
 #version 120
 
-uniform sampler2D diffuseMap;
+uniform sampler2D tex0;
+uniform sampler2D tex1;
+uniform sampler2D tex2;
+uniform sampler2D tex3;
+uniform sampler2D tex4;
+uniform sampler2D tex5;
+uniform sampler2D tex6;
+uniform sampler2D tex7;
+
+varying float vary_texture_index;
+
+vec4 diffuseLookup(vec2 texcoord)
+{
+	switch (int(vary_texture_index+0.25))
+	{
+		case 0: return texture2D(tex0, texcoord);
+		case 1: return texture2D(tex1, texcoord);
+		case 2: return texture2D(tex2, texcoord);
+		case 3: return texture2D(tex3, texcoord);
+		case 4: return texture2D(tex4, texcoord);
+		case 5: return texture2D(tex5, texcoord);
+		case 6: return texture2D(tex6, texcoord);
+		case 7: return texture2D(tex7, texcoord);
+	}
+
+	return vec4(0,0,0,0);
+}
 
 vec3 atmosLighting(vec3 light);
 vec3 scaleSoftClip(vec3 light);
 
 void default_lighting() 
 {
-	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * gl_Color;
+	vec4 color = diffuseLookup(gl_TexCoord[0].xy) * gl_Color;
 	
 	color.rgb = atmosLighting(color.rgb);
 
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightF.glsl
index dad18b588383139379889a453e207972cc1be2e2..e64b089dcaf08501c9986d226213e644f3a39ee9 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightF.glsl
@@ -7,14 +7,40 @@
  
 #version 120
 
-uniform sampler2D diffuseMap;
-
 vec3 fullbrightAtmosTransport(vec3 light);
 vec3 fullbrightScaleSoftClip(vec3 light);
 
+uniform sampler2D tex0;
+uniform sampler2D tex1;
+uniform sampler2D tex2;
+uniform sampler2D tex3;
+uniform sampler2D tex4;
+uniform sampler2D tex5;
+uniform sampler2D tex6;
+uniform sampler2D tex7;
+
+varying float vary_texture_index;
+
+vec4 diffuseLookup(vec2 texcoord)
+{
+	switch (int(vary_texture_index+0.25))
+	{
+		case 0: return texture2D(tex0, texcoord);
+		case 1: return texture2D(tex1, texcoord);
+		case 2: return texture2D(tex2, texcoord);
+		case 3: return texture2D(tex3, texcoord);
+		case 4: return texture2D(tex4, texcoord);
+		case 5: return texture2D(tex5, texcoord);
+		case 6: return texture2D(tex6, texcoord);
+		case 7: return texture2D(tex7, texcoord);
+	}
+
+	return vec4(0,0,0,0);
+}
+
 void fullbright_lighting()
 {
-	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * gl_Color;
+	vec4 color = diffuseLookup(gl_TexCoord[0].xy) * gl_Color;
 	
 	color.rgb = fullbrightAtmosTransport(color.rgb);
 	
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightNonIndexedF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightNonIndexedF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..811a919d52878b08fe1fad125932235b2969faf5
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightNonIndexedF.glsl
@@ -0,0 +1,25 @@
+/** 
+ * @file lightFullbrightF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+ 
+#version 120
+
+vec3 fullbrightAtmosTransport(vec3 light);
+vec3 fullbrightScaleSoftClip(vec3 light);
+
+uniform sampler2D diffuseMap;
+
+void fullbright_lighting()
+{
+	vec4 color = texture2D(diffuseMap,gl_TexCoord[0].xy) * gl_Color;
+	
+	color.rgb = fullbrightAtmosTransport(color.rgb);
+	
+	color.rgb = fullbrightScaleSoftClip(color.rgb);
+
+	gl_FragColor = color;
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyF.glsl
index 73ff81e03a6ffdb2865356b48efde11a54136ae4..f4ac789a741874eb3fc7655b3adc63512a41cc71 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyF.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyF.glsl
@@ -7,15 +7,41 @@
  
 #version 120
 
-uniform sampler2D diffuseMap;
 uniform samplerCube environmentMap;
+uniform sampler2D tex0;
+uniform sampler2D tex1;
+uniform sampler2D tex2;
+uniform sampler2D tex3;
+uniform sampler2D tex4;
+uniform sampler2D tex5;
+uniform sampler2D tex6;
+
+varying float vary_texture_index;
+
+vec4 diffuseLookup(vec2 texcoord)
+{
+	switch (int(vary_texture_index+0.25))
+	{
+		case 0: return texture2D(tex0, texcoord);
+		case 1: return texture2D(tex1, texcoord);
+		case 2: return texture2D(tex2, texcoord);
+		case 3: return texture2D(tex3, texcoord);
+		case 4: return texture2D(tex4, texcoord);
+		case 5: return texture2D(tex5, texcoord);
+		case 6: return texture2D(tex6, texcoord);
+	}
+
+	return vec4(0,0,0,0);
+}
+
+
 
 vec3 fullbrightShinyAtmosTransport(vec3 light);
 vec3 fullbrightScaleSoftClip(vec3 light);
 
 void fullbright_shiny_lighting()
 {
-	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy);
+	vec4 color = diffuseLookup(gl_TexCoord[0].xy);
 	color.rgb *= gl_Color.rgb;
 	
 	vec3 envColor = textureCube(environmentMap, gl_TexCoord[1].xyz).rgb;	
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyNonIndexedF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyNonIndexedF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..51a7ddb89a70defd8b26777342638d93dadd119e
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyNonIndexedF.glsl
@@ -0,0 +1,32 @@
+/** 
+ * @file lightFullbrightShinyF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+ 
+#version 120
+
+uniform samplerCube environmentMap;
+uniform sampler2D diffuseMap;
+
+vec3 fullbrightShinyAtmosTransport(vec3 light);
+vec3 fullbrightScaleSoftClip(vec3 light);
+
+void fullbright_shiny_lighting()
+{
+	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy);
+	color.rgb *= gl_Color.rgb;
+	
+	vec3 envColor = textureCube(environmentMap, gl_TexCoord[1].xyz).rgb;	
+	color.rgb = mix(color.rgb, envColor.rgb, gl_Color.a);
+
+	color.rgb = fullbrightShinyAtmosTransport(color.rgb);
+
+	color.rgb = fullbrightScaleSoftClip(color.rgb);
+
+	color.a = max(color.a, gl_Color.a);
+
+	gl_FragColor = color;
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyWaterF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyWaterF.glsl
index 9b4b58436990b10e00a82b031fbcdbc0c061e7f1..277170e8af58632ffa6cfea9be123e4db869104e 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyWaterF.glsl
@@ -7,8 +7,33 @@
  
 #version 120
 
-uniform sampler2D diffuseMap;
+
 uniform samplerCube environmentMap;
+uniform sampler2D tex0;
+uniform sampler2D tex1;
+uniform sampler2D tex2;
+uniform sampler2D tex3;
+uniform sampler2D tex4;
+uniform sampler2D tex5;
+uniform sampler2D tex6;
+
+varying float vary_texture_index;
+
+vec4 diffuseLookup(vec2 texcoord)
+{
+	switch (int(vary_texture_index+0.25))
+	{
+		case 0: return texture2D(tex0, texcoord);
+		case 1: return texture2D(tex1, texcoord);
+		case 2: return texture2D(tex2, texcoord);
+		case 3: return texture2D(tex3, texcoord);
+		case 4: return texture2D(tex4, texcoord);
+		case 5: return texture2D(tex5, texcoord);
+		case 6: return texture2D(tex6, texcoord);
+	}
+
+	return vec4(0,0,0,0);
+}
 
 vec3 fullbrightShinyAtmosTransport(vec3 light);
 vec3 fullbrightScaleSoftClip(vec3 light);
@@ -16,7 +41,7 @@ vec4 applyWaterFog(vec4 color);
 
 void fullbright_shiny_lighting_water()
 {
-	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy);
+	vec4 color = diffuseLookup(gl_TexCoord[0].xy);
 	color.rgb *= gl_Color.rgb;
 	
 	vec3 envColor = textureCube(environmentMap, gl_TexCoord[1].xyz).rgb;	
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyWaterNonIndexedF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyWaterNonIndexedF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..a9a95940e6f2f2d84ab85eca146072a31f11f36a
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightShinyWaterNonIndexedF.glsl
@@ -0,0 +1,32 @@
+/** 
+ * @file lightFullbrightShinyWaterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+ 
+#version 120
+
+
+uniform samplerCube environmentMap;
+uniform sampler2D diffuseMap;
+
+vec3 fullbrightShinyAtmosTransport(vec3 light);
+vec3 fullbrightScaleSoftClip(vec3 light);
+vec4 applyWaterFog(vec4 color);
+
+void fullbright_shiny_lighting_water()
+{
+	vec4 color = texture2D(diffuseMap,gl_TexCoord[0].xy);
+	color.rgb *= gl_Color.rgb;
+	
+	vec3 envColor = textureCube(environmentMap, gl_TexCoord[1].xyz).rgb;	
+	color.rgb = mix(color.rgb, envColor.rgb, gl_Color.a);
+
+	color.rgb = fullbrightShinyAtmosTransport(color.rgb);
+	color.rgb = fullbrightScaleSoftClip(color.rgb);
+	color.a = max(color.a, gl_Color.a);
+
+	gl_FragColor = applyWaterFog(color);
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightWaterF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightWaterF.glsl
index 3d46c8d8744271a0a07e9ebfa2bc01a8a1f0bb5e..37e33059a6f4c4d7b21ff87efa96bd96d33c421c 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightWaterF.glsl
@@ -7,14 +7,40 @@
  
 #version 120
 
-uniform sampler2D diffuseMap;
+uniform sampler2D tex0;
+uniform sampler2D tex1;
+uniform sampler2D tex2;
+uniform sampler2D tex3;
+uniform sampler2D tex4;
+uniform sampler2D tex5;
+uniform sampler2D tex6;
+uniform sampler2D tex7;
+
+varying float vary_texture_index;
+
+vec4 diffuseLookup(vec2 texcoord)
+{
+	switch (int(vary_texture_index+0.25))
+	{
+		case 0: return texture2D(tex0, texcoord);
+		case 1: return texture2D(tex1, texcoord);
+		case 2: return texture2D(tex2, texcoord);
+		case 3: return texture2D(tex3, texcoord);
+		case 4: return texture2D(tex4, texcoord);
+		case 5: return texture2D(tex5, texcoord);
+		case 6: return texture2D(tex6, texcoord);
+		case 7: return texture2D(tex7, texcoord);
+	}
+
+	return vec4(0,0,0,0);
+}
 
 vec3 fullbrightAtmosTransport(vec3 light);
 vec4 applyWaterFog(vec4 color);
 
 void fullbright_lighting_water()
 {
-	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * gl_Color;
+	vec4 color = diffuseLookup(gl_TexCoord[0].xy) * gl_Color;
 
 	color.rgb = fullbrightAtmosTransport(color.rgb);
 	
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightWaterNonIndexedF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightWaterNonIndexedF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..3d46c8d8744271a0a07e9ebfa2bc01a8a1f0bb5e
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightFullbrightWaterNonIndexedF.glsl
@@ -0,0 +1,23 @@
+/** 
+ * @file lightFullbrightWaterF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+ 
+#version 120
+
+uniform sampler2D diffuseMap;
+
+vec3 fullbrightAtmosTransport(vec3 light);
+vec4 applyWaterFog(vec4 color);
+
+void fullbright_lighting_water()
+{
+	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * gl_Color;
+
+	color.rgb = fullbrightAtmosTransport(color.rgb);
+	
+	gl_FragColor = applyWaterFog(color);
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightNonIndexedF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightNonIndexedF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..787eeb7af67c17dee2e6dbc071b002821fd8158a
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightNonIndexedF.glsl
@@ -0,0 +1,25 @@
+/** 
+ * @file lightF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+ 
+#version 120
+
+uniform sampler2D diffuseMap;
+
+vec3 atmosLighting(vec3 light);
+vec3 scaleSoftClip(vec3 light);
+
+void default_lighting() 
+{
+	vec4 color = texture2D(diffuseMap,gl_TexCoord[0].xy) * gl_Color;
+	
+	color.rgb = atmosLighting(color.rgb);
+
+	color.rgb = scaleSoftClip(color.rgb);
+
+	gl_FragColor = color;
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightShinyF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightShinyF.glsl
index ebe21320b43f8a8118623dae5bd7ba8f2fb5e9e9..9f438f513f04c11f97ff3cc0551794f3a80bd58f 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/lightShinyF.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightShinyF.glsl
@@ -7,8 +7,33 @@
  
 #version 120
 
-uniform sampler2D diffuseMap;
+
 uniform samplerCube environmentMap;
+uniform sampler2D tex0;
+uniform sampler2D tex1;
+uniform sampler2D tex2;
+uniform sampler2D tex3;
+uniform sampler2D tex4;
+uniform sampler2D tex5;
+uniform sampler2D tex6;
+
+varying float vary_texture_index;
+
+vec4 diffuseLookup(vec2 texcoord)
+{
+	switch (int(vary_texture_index+0.25))
+	{
+		case 0: return texture2D(tex0, texcoord);
+		case 1: return texture2D(tex1, texcoord);
+		case 2: return texture2D(tex2, texcoord);
+		case 3: return texture2D(tex3, texcoord);
+		case 4: return texture2D(tex4, texcoord);
+		case 5: return texture2D(tex5, texcoord);
+		case 6: return texture2D(tex6, texcoord);
+	}
+
+	return vec4(0,0,0,0);
+}
 
 vec3 scaleSoftClip(vec3 light);
 vec3 atmosLighting(vec3 light);
@@ -16,7 +41,7 @@ vec4 applyWaterFog(vec4 color);
 
 void shiny_lighting()
 {
-	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy);
+	vec4 color = diffuseLookup(gl_TexCoord[0].xy);
 	color.rgb *= gl_Color.rgb;
 	
 	vec3 envColor = textureCube(environmentMap, gl_TexCoord[1].xyz).rgb;	
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightShinyNonIndexedF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightShinyNonIndexedF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..212eacd6eaabf755116a91c738760a5fe166002e
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightShinyNonIndexedF.glsl
@@ -0,0 +1,32 @@
+/** 
+ * @file lightShinyF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+ 
+#version 120
+
+
+uniform samplerCube environmentMap;
+uniform sampler2D diffuseMap;
+
+vec3 scaleSoftClip(vec3 light);
+vec3 atmosLighting(vec3 light);
+vec4 applyWaterFog(vec4 color);
+
+void shiny_lighting()
+{
+	vec4 color = texture2D(diffuseMap,gl_TexCoord[0].xy);
+	color.rgb *= gl_Color.rgb;
+	
+	vec3 envColor = textureCube(environmentMap, gl_TexCoord[1].xyz).rgb;	
+	color.rgb = mix(color.rgb, envColor.rgb, gl_Color.a);
+
+	color.rgb = atmosLighting(color.rgb);
+
+	color.rgb = scaleSoftClip(color.rgb);
+	color.a = max(color.a, gl_Color.a);
+	gl_FragColor = color;
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightShinyWaterF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightShinyWaterF.glsl
index 7f48e2cf1d5ec1c5ed586b4101fb5b385545e451..5e11f6585c3357b5fefb234ef421606bb51929d1 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/lightShinyWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightShinyWaterF.glsl
@@ -8,15 +8,39 @@
 #version 120
 
 
-uniform sampler2D diffuseMap;
 uniform samplerCube environmentMap;
+uniform sampler2D tex0;
+uniform sampler2D tex1;
+uniform sampler2D tex2;
+uniform sampler2D tex3;
+uniform sampler2D tex4;
+uniform sampler2D tex5;
+uniform sampler2D tex6;
+
+varying float vary_texture_index;
+
+vec4 diffuseLookup(vec2 texcoord)
+{
+	switch (int(vary_texture_index+0.25))
+	{
+		case 0: return texture2D(tex0, texcoord);
+		case 1: return texture2D(tex1, texcoord);
+		case 2: return texture2D(tex2, texcoord);
+		case 3: return texture2D(tex3, texcoord);
+		case 4: return texture2D(tex4, texcoord);
+		case 5: return texture2D(tex5, texcoord);
+		case 6: return texture2D(tex6, texcoord);
+	}
+
+	return vec4(0,0,0,0);
+}
 
 vec3 atmosLighting(vec3 light);
 vec4 applyWaterFog(vec4 color);
 
 void shiny_lighting_water()
 {
-	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy);
+	vec4 color = diffuseLookup(gl_TexCoord[0].xy);
 	color.rgb *= gl_Color.rgb;
 	
 	vec3 envColor = textureCube(environmentMap, gl_TexCoord[1].xyz).rgb;	
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightShinyWaterNonIndexedF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightShinyWaterNonIndexedF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..cb8a24da60c1e062d5278640e8707dd44ff8da69
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightShinyWaterNonIndexedF.glsl
@@ -0,0 +1,29 @@
+/** 
+ * @file lightShinyWaterF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+ 
+#version 120
+
+
+uniform sampler2D diffuseMap;
+uniform samplerCube environmentMap;
+
+vec3 atmosLighting(vec3 light);
+vec4 applyWaterFog(vec4 color);
+
+void shiny_lighting_water()
+{
+	vec4 color = texture2D(diffuseMap,gl_TexCoord[0].xy);
+	color.rgb *= gl_Color.rgb;
+	
+	vec3 envColor = textureCube(environmentMap, gl_TexCoord[1].xyz).rgb;	
+	color.rgb = mix(color.rgb, envColor.rgb, gl_Color.a);
+
+	color.rgb = atmosLighting(color.rgb);
+	color.a = max(color.a, gl_Color.a);
+	gl_FragColor = applyWaterFog(color);
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightWaterF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightWaterF.glsl
index 97eba92d7b51f463f0e6cd877eb3ed6950855fad..022544a9179db05aaae34936eeb7865328c291e6 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/lightWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightWaterF.glsl
@@ -7,14 +7,40 @@
  
 #version 120
 
-uniform sampler2D diffuseMap;
+uniform sampler2D tex0;
+uniform sampler2D tex1;
+uniform sampler2D tex2;
+uniform sampler2D tex3;
+uniform sampler2D tex4;
+uniform sampler2D tex5;
+uniform sampler2D tex6;
+uniform sampler2D tex7;
+
+varying float vary_texture_index;
+
+vec4 diffuseLookup(vec2 texcoord)
+{
+	switch (int(vary_texture_index+0.25))
+	{
+		case 0: return texture2D(tex0, texcoord);
+		case 1: return texture2D(tex1, texcoord);
+		case 2: return texture2D(tex2, texcoord);
+		case 3: return texture2D(tex3, texcoord);
+		case 4: return texture2D(tex4, texcoord);
+		case 5: return texture2D(tex5, texcoord);
+		case 6: return texture2D(tex6, texcoord);
+		case 7: return texture2D(tex7, texcoord);
+	}
+
+	return vec4(0,0,0,0);
+}
 
 vec3 atmosLighting(vec3 light);
 vec4 applyWaterFog(vec4 color);
 
 void default_lighting_water()
 {
-	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * gl_Color;
+	vec4 color = diffuseLookup(gl_TexCoord[0].xy) * gl_Color;
 
 	color.rgb = atmosLighting(color.rgb);
 
diff --git a/indra/newview/app_settings/shaders/class2/lighting/lightWaterNonIndexedF.glsl b/indra/newview/app_settings/shaders/class2/lighting/lightWaterNonIndexedF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..dc16f2d5cd63715feb924378e2df1774ef813642
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/lighting/lightWaterNonIndexedF.glsl
@@ -0,0 +1,23 @@
+/** 
+ * @file lightWaterF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+ 
+#version 120
+
+uniform sampler2D diffuseMap;
+
+vec3 atmosLighting(vec3 light);
+vec4 applyWaterFog(vec4 color);
+
+void default_lighting_water()
+{
+	vec4 color = texture2D(diffuseMap,gl_TexCoord[0].xy) * gl_Color;
+
+	color.rgb = atmosLighting(color.rgb);
+
+	gl_FragColor = applyWaterFog(color);
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/objects/fullbrightShinyV.glsl b/indra/newview/app_settings/shaders/class2/objects/fullbrightShinyV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..e2145e19560e2e5a331fdb6e5e200b5608de0ee8
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/objects/fullbrightShinyV.glsl
@@ -0,0 +1,35 @@
+/**
+ * @file fullbrightShinyV.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+ 
+#version 120
+
+void calcAtmospherics(vec3 inPositionEye);
+
+uniform vec4 origin;
+
+varying float vary_texture_index;
+
+void main()
+{
+	//transform vertex
+	vec4 vert = vec4(gl_Vertex.xyz,1.0);
+	vary_texture_index = gl_Vertex.w;
+	gl_Position = gl_ModelViewProjectionMatrix*vert;
+	
+	vec4 pos = (gl_ModelViewMatrix * vert);
+	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
+	vec3 ref = reflect(pos.xyz, -norm);
+
+	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+	gl_TexCoord[1] = gl_TextureMatrix[1]*vec4(ref,1.0);
+
+	calcAtmospherics(pos.xyz);
+
+	gl_FrontColor = gl_Color;
+
+	gl_FogFragCoord = pos.z;
+}
diff --git a/indra/newview/app_settings/shaders/class2/objects/fullbrightV.glsl b/indra/newview/app_settings/shaders/class2/objects/fullbrightV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..c4a3611a291a9ecded2fee20e7ccbb28d8dc3481
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/objects/fullbrightV.glsl
@@ -0,0 +1,29 @@
+/**
+ * @file fullbrightV.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+ 
+#version 120
+
+void calcAtmospherics(vec3 inPositionEye);
+
+varying float vary_texture_index;
+
+void main()
+{
+	//transform vertex
+	vec4 vert = vec4(gl_Vertex.xyz,1.0);
+	vary_texture_index = gl_Vertex.w;
+	gl_Position = gl_ModelViewProjectionMatrix*vert;
+	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+	
+	vec4 pos = (gl_ModelViewMatrix * vert);
+
+	calcAtmospherics(pos.xyz);
+
+	gl_FrontColor = gl_Color;
+
+	gl_FogFragCoord = pos.z;
+}
diff --git a/indra/newview/app_settings/shaders/class2/objects/shinyV.glsl b/indra/newview/app_settings/shaders/class2/objects/shinyV.glsl
index 4cebb06df080e8b289cccaee534789d54d7177aa..436c193c5d91ae2ac3c08c7c73af7f6bc342de8c 100644
--- a/indra/newview/app_settings/shaders/class2/objects/shinyV.glsl
+++ b/indra/newview/app_settings/shaders/class2/objects/shinyV.glsl
@@ -11,14 +11,18 @@ vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
 
 void calcAtmospherics(vec3 inPositionEye);
 
+varying float vary_texture_index;
+
 uniform vec4 origin;
 
 void main()
 {
 	//transform vertex
-	gl_Position = ftransform();
+	vec4 vert = vec4(gl_Vertex.xyz,1.0);
+	vary_texture_index = gl_Vertex.w;
+	gl_Position = gl_ModelViewProjectionMatrix*vert;
 	
-	vec4 pos = (gl_ModelViewMatrix * gl_Vertex);
+	vec4 pos = (gl_ModelViewMatrix * vert);
 	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
 	vec3 ref = reflect(pos.xyz, -norm);
 
diff --git a/indra/newview/app_settings/shaders/class2/objects/simpleV.glsl b/indra/newview/app_settings/shaders/class2/objects/simpleV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..50d2beee57b570bcf7a8558723832e74e3d36189
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/objects/simpleV.glsl
@@ -0,0 +1,33 @@
+/** 
+ * @file simpleV.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+ 
+#version 120
+
+vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
+void calcAtmospherics(vec3 inPositionEye);
+
+varying float vary_texture_index;
+
+void main()
+{
+	//transform vertex
+	vec4 vert = vec4(gl_Vertex.xyz,1.0);
+	vary_texture_index = gl_Vertex.w;
+	gl_Position = gl_ModelViewProjectionMatrix*vert;
+	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+	
+	vec4 pos = (gl_ModelViewMatrix * vert);
+	
+	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
+
+	calcAtmospherics(pos.xyz);
+
+	vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.));
+	gl_FrontColor = color;
+
+	gl_FogFragCoord = pos.z;
+}
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index 25e4bc847c253dcfd41423ef3575751c21c073c5..b8b12018d238d91c549424285c74c34397dea8e5 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -191,6 +191,14 @@ void LLDrawPool::renderPostDeferred(S32 pass)
 //virtual
 void LLDrawPool::endRenderPass( S32 pass )
 {
+	for (U32 i = 1; i < 8; i++)
+	{ //dummy cleanup of any currently bound textures
+		if (gGL.getTexUnit(i)->getCurrType() != LLTexUnit::TT_NONE)
+		{
+			gGL.getTexUnit(i)->unbind(gGL.getTexUnit(i)->getCurrType());
+			gGL.getTexUnit(i)->disable();
+		}
+	}
 }
 
 //virtual 
@@ -430,14 +438,14 @@ void LLRenderPass::renderTexture(U32 type, U32 mask)
 	pushBatches(type, mask, TRUE);
 }
 
-void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture)
+void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
 {
 	for (LLCullResult::drawinfo_list_t::iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)	
 	{
 		LLDrawInfo* pparams = *i;
 		if (pparams) 
 		{
-			pushBatch(*pparams, mask, texture);
+			pushBatch(*pparams, mask, texture, batch_textures);
 		}
 	}
 }
@@ -456,26 +464,42 @@ void LLRenderPass::applyModelMatrix(LLDrawInfo& params)
 	}
 }
 
-void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
+void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures)
 {
 	applyModelMatrix(params);
 
+	bool tex_setup = false;
+
 	if (texture)
 	{
-		if (params.mTexture.notNull())
+		if (batch_textures && params.mTextureList.size() > 1)
 		{
-			params.mTexture->addTextureStats(params.mVSize);
-			gGL.getTexUnit(0)->bind(params.mTexture, TRUE) ;
-			if (params.mTextureMatrix)
+			for (U32 i = 0; i < params.mTextureList.size(); ++i)
 			{
-				glMatrixMode(GL_TEXTURE);
-				glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
-				gPipeline.mTextureMatrixOps++;
+				if (params.mTextureList[i].notNull())
+				{
+					gGL.getTexUnit(i)->bind(params.mTextureList[i], TRUE);
+				}
 			}
 		}
 		else
-		{
-			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+		{ //not batching textures or batch has only 1 texture -- might need a texture matrix
+			if (params.mTexture.notNull())
+			{
+				params.mTexture->addTextureStats(params.mVSize);
+				gGL.getTexUnit(0)->bind(params.mTexture, TRUE) ;
+				if (params.mTextureMatrix)
+				{
+					tex_setup = true;
+					glMatrixMode(GL_TEXTURE);
+					glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
+					gPipeline.mTextureMatrixOps++;
+				}
+			}
+			else
+			{
+				gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+			}
 		}
 	}
 	
@@ -490,7 +514,7 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
 		gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode);
 	}
 
-	if (params.mTextureMatrix && texture && params.mTexture.notNull())
+	if (tex_setup)
 	{
 		glLoadIdentity();
 		glMatrixMode(GL_MODELVIEW);
diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h
index d3fd9ead0d4ef42a88f3a0d0230ffc03d8586b2b..c7acbb42c62da2c8aa5a471e7c8f5a5aaddfd536 100644
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -146,8 +146,8 @@ class LLRenderPass : public LLDrawPool
 	void resetDrawOrders() { }
 
 	static void applyModelMatrix(LLDrawInfo& params);
-	virtual void pushBatches(U32 type, U32 mask, BOOL texture = TRUE);
-	virtual void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture);
+	virtual void pushBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE);
+	virtual void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE);
 	virtual void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
 	virtual void renderGroups(U32 type, U32 mask, BOOL texture = TRUE);
 	virtual void renderTexture(U32 type, U32 mask);
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 8b5a2ce78182d6e4147c73cb09430aaae7453f88..71eee0188c8d6d0d93cc05f32183bd656ea4fe5f 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -124,7 +124,7 @@ void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass)
 	if (pass == 0)
 	{
 		simple_shader = &gDeferredAlphaProgram;
-		fullbright_shader = &gDeferredFullbrightProgram;
+		fullbright_shader = &gObjectFullbrightProgram;
 	}
 	else
 	{
@@ -228,13 +228,13 @@ void LLDrawPoolAlpha::render(S32 pass)
 			if (!LLPipeline::sRenderDeferred)
 			{
 				simple_shader->bind();
-				pushBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask());
+				pushBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 			}
 			if (fullbright_shader)
 			{
 				fullbright_shader->bind();
 			}
-			pushBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask());
+			pushBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 			LLGLSLShader::bindNoShader();
 		}
 		else
@@ -273,7 +273,14 @@ void LLDrawPoolAlpha::render(S32 pass)
 		}
 	}
 
-	renderAlpha(getVertexDataMask());
+	if (mVertexShaderLevel > 0)
+	{
+		renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX);
+	}
+	else
+	{
+		renderAlpha(getVertexDataMask());
+	}
 
 	gGL.setColorMask(true, false);
 
@@ -341,10 +348,8 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 	BOOL light_enabled = TRUE;
 	S32 diffuse_channel = 0;
 
-	BOOL use_shaders = (LLPipeline::sUnderWaterRender && gPipeline.canUseVertexShaders())
-		|| gPipeline.canUseWindLightShadersOnObjects();
-	
-	
+	BOOL use_shaders = gPipeline.canUseVertexShaders();
+		
 	for (LLCullResult::sg_list_t::iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
 	{
 		LLSpatialGroup* group = *i;
@@ -368,92 +373,107 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 
 				LLRenderPass::applyModelMatrix(params);
 
+				
+				if (params.mFullbright)
 				{
-					if (params.mFullbright)
-					{
-						// Turn off lighting if it hasn't already been so.
-						if (light_enabled || !initialized_lighting)
-						{
-							initialized_lighting = TRUE;
-							if (use_shaders) 
-							{
-								target_shader = fullbright_shader;
-							}
-							else
-							{
-								gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
-							}
-							light_enabled = FALSE;
-						}
-					}
-					// Turn on lighting if it isn't already.
-					else if (!light_enabled || !initialized_lighting)
+					// Turn off lighting if it hasn't already been so.
+					if (light_enabled || !initialized_lighting)
 					{
 						initialized_lighting = TRUE;
 						if (use_shaders) 
 						{
-							target_shader = simple_shader;
+							target_shader = fullbright_shader;
 						}
 						else
 						{
-							gPipeline.enableLightsDynamic();
+							gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
 						}
-						light_enabled = TRUE;
+						light_enabled = FALSE;
 					}
-
-					// If we need shaders, and we're not ALREADY using the proper shader, then bind it
-					// (this way we won't rebind shaders unnecessarily).
-					if(use_shaders && (current_shader != target_shader))
+				}
+				// Turn on lighting if it isn't already.
+				else if (!light_enabled || !initialized_lighting)
+				{
+					initialized_lighting = TRUE;
+					if (use_shaders) 
 					{
-						llassert(target_shader != NULL);
-						if (deferred_render && current_shader != NULL)
-						{
-							gPipeline.unbindDeferredShader(*current_shader);
-							diffuse_channel = 0;
-						}
-						current_shader = target_shader;
-						if (deferred_render)
-						{
-							gPipeline.bindDeferredShader(*current_shader);
-							diffuse_channel = current_shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-						}
-						else
-						{
-							current_shader->bind();
-						}
+						target_shader = simple_shader;
 					}
-					else if (!use_shaders && current_shader != NULL)
+					else
 					{
-						if (deferred_render)
-						{
-							gPipeline.unbindDeferredShader(*current_shader);
-							diffuse_channel = 0;
-						}
-						LLGLSLShader::bindNoShader();
-						current_shader = NULL;
+						gPipeline.enableLightsDynamic();
 					}
+					light_enabled = TRUE;
+				}
 
-					if (params.mGroup)
+				// If we need shaders, and we're not ALREADY using the proper shader, then bind it
+				// (this way we won't rebind shaders unnecessarily).
+				if(use_shaders && (current_shader != target_shader))
+				{
+					llassert(target_shader != NULL);
+					if (deferred_render && current_shader != NULL)
+					{
+						gPipeline.unbindDeferredShader(*current_shader);
+						diffuse_channel = 0;
+					}
+					current_shader = target_shader;
+					if (deferred_render)
+					{
+						gPipeline.bindDeferredShader(*current_shader);
+						diffuse_channel = current_shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+					}
+					else
 					{
-						params.mGroup->rebuildMesh();
+						current_shader->bind();
 					}
+				}
+				else if (!use_shaders && current_shader != NULL)
+				{
+					if (deferred_render)
+					{
+						gPipeline.unbindDeferredShader(*current_shader);
+						diffuse_channel = 0;
+					}
+					LLGLSLShader::bindNoShader();
+					current_shader = NULL;
+				}
 
-					
-					if (params.mTexture.notNull())
+				if (params.mGroup)
+				{
+					params.mGroup->rebuildMesh();
+				}
+
+				bool tex_setup = false;
+
+				if (use_shaders && params.mTextureList.size() > 1)
+				{
+					for (U32 i = 0; i < params.mTextureList.size(); ++i)
 					{
-						gGL.getTexUnit(diffuse_channel)->bind(params.mTexture.get());
-						if(params.mTexture.notNull())
+						if (params.mTextureList[i].notNull())
 						{
-							params.mTexture->addTextureStats(params.mVSize);
+							gGL.getTexUnit(i)->bind(params.mTextureList[i], TRUE);
 						}
+					}
+				}
+				else
+				{ //not batching textures or batch has only 1 texture -- might need a texture matrix
+					if (params.mTexture.notNull())
+					{
+						params.mTexture->addTextureStats(params.mVSize);
+						gGL.getTexUnit(0)->bind(params.mTexture, TRUE) ;
 						if (params.mTextureMatrix)
 						{
+							tex_setup = true;
 							gGL.getTexUnit(0)->activate();
 							glMatrixMode(GL_TEXTURE);
 							glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
 							gPipeline.mTextureMatrixOps++;
 						}
 					}
+					else
+					{
+						gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+					}
 				}
 
 				params.mVertexBuffer->setBuffer(mask);
@@ -480,7 +500,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 					gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
 				}
 			
-				if (params.mTextureMatrix && params.mTexture.notNull())
+				if (tex_setup)
 				{
 					gGL.getTexUnit(0)->activate();
 					glLoadIdentity();
@@ -494,9 +514,6 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 	{
 		gPipeline.unbindDeferredShader(*current_shader);
 		LLVertexBuffer::unbind();	
-		LLGLState::checkStates();
-		LLGLState::checkTextureChannels();
-		LLGLState::checkClientArrays();
 	}
 	
 	if (!light_enabled)
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 645c7ebcaeb933d586074da457beb80c55518d3d..7c017f5694dfac5417004703f73ecaf7648c749e 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -613,11 +613,11 @@ void LLDrawPoolAvatar::beginRigid()
 	{
 		if (LLPipeline::sUnderWaterRender)
 		{
-			sVertexProgram = &gObjectSimpleWaterProgram;
+			sVertexProgram = &gObjectSimpleNonIndexedWaterProgram;
 		}
 		else
 		{
-			sVertexProgram = &gObjectSimpleProgram;
+			sVertexProgram = &gObjectSimpleNonIndexedProgram;
 		}
 		
 		if (sVertexProgram != NULL)
@@ -669,7 +669,7 @@ void LLDrawPoolAvatar::endDeferredImpostor()
 
 void LLDrawPoolAvatar::beginDeferredRigid()
 {
-	sVertexProgram = &gDeferredDiffuseProgram;
+	sVertexProgram = &gDeferredNonIndexedDiffuseProgram;
 				
 	sVertexProgram->bind();
 }
@@ -700,11 +700,11 @@ void LLDrawPoolAvatar::beginSkinned()
 	{
 		if (LLPipeline::sUnderWaterRender)
 		{
-			sVertexProgram = &gObjectSimpleWaterProgram;
+			sVertexProgram = &gObjectSimpleNonIndexedWaterProgram;
 		}
 		else
 		{
-			sVertexProgram = &gObjectSimpleProgram;
+			sVertexProgram = &gObjectSimpleNonIndexedProgram;
 		}
 	}
 	
@@ -789,11 +789,11 @@ void LLDrawPoolAvatar::beginRiggedSimple()
 	{
 		if (LLPipeline::sUnderWaterRender)
 		{
-			sVertexProgram = &gObjectSimpleWaterProgram;
+			sVertexProgram = &gObjectSimpleNonIndexedWaterProgram;
 		}
 		else
 		{
-			sVertexProgram = &gObjectSimpleProgram;
+			sVertexProgram = &gObjectSimpleNonIndexedProgram;
 		}
 	}
 
@@ -864,11 +864,11 @@ void LLDrawPoolAvatar::beginRiggedFullbright()
 	{
 		if (LLPipeline::sUnderWaterRender)
 		{
-			sVertexProgram = &gObjectFullbrightWaterProgram;
+			sVertexProgram = &gObjectFullbrightNonIndexedWaterProgram;
 		}
 		else
 		{
-			sVertexProgram = &gObjectFullbrightProgram;
+			sVertexProgram = &gObjectFullbrightNonIndexedProgram;
 		}
 	}
 
@@ -908,11 +908,11 @@ void LLDrawPoolAvatar::beginRiggedShinySimple()
 	{
 		if (LLPipeline::sUnderWaterRender)
 		{
-			sVertexProgram = &gObjectShinyWaterProgram;
+			sVertexProgram = &gObjectShinyNonIndexedWaterProgram;
 		}
 		else
 		{
-			sVertexProgram = &gObjectShinyProgram;
+			sVertexProgram = &gObjectShinyNonIndexedProgram;
 		}
 	}
 
@@ -953,11 +953,11 @@ void LLDrawPoolAvatar::beginRiggedFullbrightShiny()
 	{
 		if (LLPipeline::sUnderWaterRender)
 		{
-			sVertexProgram = &gObjectFullbrightShinyWaterProgram;
+			sVertexProgram = &gObjectFullbrightShinyNonIndexedWaterProgram;
 		}
 		else
 		{
-			sVertexProgram = &gObjectFullbrightShinyProgram;
+			sVertexProgram = &gObjectFullbrightShinyNonIndexedProgram;
 		}
 	}
 
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 5f89d113917641a515d72e85327aaaffffa2b44e..4ac4b89ab4f7a7fa5ad1a2fa726dae93ef3810a9 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -309,6 +309,9 @@ void LLDrawPoolBump::endRenderPass(S32 pass)
 			llassert(0);
 			break;
 	}
+
+	//to cleanup texture channels
+	LLRenderPass::endRenderPass(pass);
 }
 
 //static
@@ -347,6 +350,11 @@ void LLDrawPoolBump::beginShiny(bool invisible)
 	}
 
 	bindCubeMap(shader, mVertexShaderLevel, diffuse_channel, cube_channel, invisible);
+
+	if (mVertexShaderLevel > 1)
+	{ //indexed texture rendering, channel 0 is always diffuse
+		diffuse_channel = 0;
+	}
 }
 
 //static
@@ -414,16 +422,16 @@ void LLDrawPoolBump::renderShiny(bool invisible)
 		LLGLEnable blend_enable(GL_BLEND);
 		if (!invisible && mVertexShaderLevel > 1)
 		{
-			LLRenderPass::renderTexture(LLRenderPass::PASS_SHINY, sVertexMask);
+			LLRenderPass::pushBatches(LLRenderPass::PASS_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 		}
 		else if (!invisible)
 		{
 			renderGroups(LLRenderPass::PASS_SHINY, sVertexMask);
 		}
-		else // invisible
-		{
-			renderGroups(LLRenderPass::PASS_INVISI_SHINY, sVertexMask);
-		}
+		//else // invisible (deprecated)
+		//{
+			//renderGroups(LLRenderPass::PASS_INVISI_SHINY, sVertexMask);
+		//}
 	}
 }
 
@@ -536,7 +544,15 @@ void LLDrawPoolBump::renderFullbrightShiny()
 	if( gSky.mVOSkyp->getCubeMap() )
 	{
 		LLGLEnable blend_enable(GL_BLEND);
-		LLRenderPass::renderTexture(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask);
+
+		if (mVertexShaderLevel > 1)
+		{
+			LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+		}
+		else
+		{
+			LLRenderPass::renderTexture(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask);
+		}
 	}
 }
 
@@ -836,6 +852,9 @@ void LLDrawPoolBump::endPostDeferredPass(S32 pass)
 		endBump(LLRenderPass::PASS_POST_BUMP);
 		break;
 	}
+
+	//to disable texture channels
+	LLRenderPass::endRenderPass(pass);
 }
 
 void LLDrawPoolBump::renderPostDeferred(S32 pass)
@@ -1292,43 +1311,60 @@ void LLDrawPoolBump::renderBump(U32 type, U32 mask)
 	}
 }
 
-void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
+void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures)
 {
 	applyModelMatrix(params);
 
-	if (params.mTextureMatrix)
+	bool tex_setup = false;
+
+	if (batch_textures && params.mTextureList.size() > 1)
 	{
-		if (mShiny)
+		for (U32 i = 0; i < params.mTextureList.size(); ++i)
 		{
-			gGL.getTexUnit(0)->activate();
-			glMatrixMode(GL_TEXTURE);
+			if (params.mTextureList[i].notNull())
+			{
+				gGL.getTexUnit(i)->bind(params.mTextureList[i], TRUE);
+			}
 		}
-		else
+	}
+	else
+	{ //not batching textures or batch has only 1 texture -- might need a texture matrix
+		if (params.mTextureMatrix)
 		{
-			gGL.getTexUnit(1)->activate();
-			glMatrixMode(GL_TEXTURE);
+			if (mShiny)
+			{
+				gGL.getTexUnit(0)->activate();
+				glMatrixMode(GL_TEXTURE);
+			}
+			else
+			{
+				gGL.getTexUnit(1)->activate();
+				glMatrixMode(GL_TEXTURE);
+				glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
+				gPipeline.mTextureMatrixOps++;
+				gGL.getTexUnit(0)->activate();
+			}
+
 			glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
 			gPipeline.mTextureMatrixOps++;
-			gGL.getTexUnit(0)->activate();
-		}
 
-		glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
-		gPipeline.mTextureMatrixOps++;
-	}
-
-	if (mShiny && mVertexShaderLevel > 1 && texture)
-	{
-		if (params.mTexture.notNull())
-		{
-			gGL.getTexUnit(diffuse_channel)->bind(params.mTexture) ;
-			params.mTexture->addTextureStats(params.mVSize);		
+			tex_setup = true;
 		}
-		else
+
+		if (mShiny && mVertexShaderLevel > 1 && texture)
 		{
-			gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE);
+			if (params.mTexture.notNull())
+			{
+				gGL.getTexUnit(diffuse_channel)->bind(params.mTexture) ;
+				params.mTexture->addTextureStats(params.mVSize);		
+			}
+			else
+			{
+				gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE);
+			}
 		}
 	}
-	
+
 	if (params.mGroup)
 	{
 		params.mGroup->rebuildMesh();
@@ -1336,7 +1372,7 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
 	params.mVertexBuffer->setBuffer(mask);
 	params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
 	gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode);
-	if (params.mTextureMatrix)
+	if (tex_setup)
 	{
 		if (mShiny)
 		{
diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index f4702bf61d4ed3ed8d8a2c6545cc36f0fcdaf64a..476b1d41b7d40d85ac08d6fb353cabe18d4773b3 100644
--- a/indra/newview/lldrawpoolbump.h
+++ b/indra/newview/lldrawpoolbump.h
@@ -55,7 +55,7 @@ protected :
 	virtual void endRenderPass( S32 pass );
 	virtual S32	 getNumPasses();
 	/*virtual*/ void prerender();
-	/*virtual*/ void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture);
+	/*virtual*/ void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE);
 
 	void renderBump(U32 type, U32 mask);
 	void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture);
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index 2e83167851d7abd61941c00da7889d5a386dc7c7..9b73b2f9b6180d9538c7606d37e71a678c5a2c43 100644
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -44,6 +44,43 @@ static LLGLSLShader* fullbright_shader = NULL;
 static LLFastTimer::DeclareTimer FTM_RENDER_SIMPLE_DEFERRED("Deferred Simple");
 static LLFastTimer::DeclareTimer FTM_RENDER_GRASS_DEFERRED("Deferred Grass");
 
+void LLDrawPoolGlow::beginPostDeferredPass(S32 pass)
+{
+	gDeferredFullbrightProgram.bind();
+}
+
+void LLDrawPoolGlow::renderPostDeferred(S32 pass)
+{
+	LLFastTimer t(FTM_RENDER_GLOW);
+	LLGLEnable blend(GL_BLEND);
+	LLGLDisable test(GL_ALPHA_TEST);
+	gGL.flush();
+	/// Get rid of z-fighting with non-glow pass.
+	LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL);
+	glPolygonOffset(-1.0f, -1.0f);
+	gGL.setSceneBlendType(LLRender::BT_ADD);
+	
+	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+	gGL.setColorMask(false, true);
+	pushBatches(LLRenderPass::PASS_GLOW, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+	
+	gGL.setColorMask(true, false);
+	gGL.setSceneBlendType(LLRender::BT_ALPHA);	
+}
+
+void LLDrawPoolGlow::endPostDeferredPass(S32 pass)
+{
+	gDeferredFullbrightProgram.unbind();
+	for (U32 i = 0; i < 8; i++)
+	{
+		if (gGL.getTexUnit(i)->getCurrType() != LLTexUnit::TT_NONE)
+		{
+			gGL.getTexUnit(i)->unbind(gGL.getTexUnit(i)->getCurrType());
+			gGL.getTexUnit(i)->disable();
+		}
+	}
+}
+
 void LLDrawPoolGlow::render(S32 pass)
 {
 	LLFastTimer t(FTM_RENDER_GLOW);
@@ -68,7 +105,15 @@ void LLDrawPoolGlow::render(S32 pass)
 
 	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 	gGL.setColorMask(false, true);
-	renderTexture(LLRenderPass::PASS_GLOW, getVertexDataMask());
+
+	if (shader_level > 1)
+	{
+		pushBatches(LLRenderPass::PASS_GLOW, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+	}
+	else
+	{
+		renderTexture(LLRenderPass::PASS_GLOW, getVertexDataMask());
+	}
 	
 	gGL.setColorMask(true, false);
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
@@ -79,10 +124,10 @@ void LLDrawPoolGlow::render(S32 pass)
 	}
 }
 
-void LLDrawPoolGlow::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
+void LLDrawPoolGlow::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures)
 {
 	glColor4ubv(params.mGlowColor.mV);
-	LLRenderPass::pushBatch(params, mask, texture);
+	LLRenderPass::pushBatch(params, mask, texture, batch_textures);
 }
 
 
@@ -128,8 +173,8 @@ void LLDrawPoolSimple::endRenderPass(S32 pass)
 	LLFastTimer t(FTM_RENDER_SIMPLE);
 	LLRenderPass::endRenderPass(pass);
 
-	if (mVertexShaderLevel > 0){
-
+	if (mVertexShaderLevel > 0)
+	{
 		simple_shader->unbind();
 	}
 }
@@ -142,13 +187,24 @@ void LLDrawPoolSimple::render(S32 pass)
 	{ //render simple
 		LLFastTimer t(FTM_RENDER_SIMPLE);
 		gPipeline.enableLightsDynamic();
-		renderTexture(LLRenderPass::PASS_SIMPLE, getVertexDataMask());
 
-		if (LLPipeline::sRenderDeferred)
-		{ //if deferred rendering is enabled, bump faces aren't registered as simple
-			//render bump faces here as simple so bump faces will appear under water
-			renderTexture(LLRenderPass::PASS_BUMP, getVertexDataMask());
+		if (mVertexShaderLevel > 0)
+		{
+			U32 mask = getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX;
+
+			pushBatches(LLRenderPass::PASS_SIMPLE, mask, TRUE, TRUE);
+
+			if (LLPipeline::sRenderDeferred)
+			{ //if deferred rendering is enabled, bump faces aren't registered as simple
+				//render bump faces here as simple so bump faces will appear under water
+				pushBatches(LLRenderPass::PASS_BUMP, mask, TRUE, TRUE);
+			}
+		}
+		else
+		{
+			renderTexture(LLRenderPass::PASS_SIMPLE, getVertexDataMask());
 		}
+		
 	}
 }
 
@@ -168,6 +224,15 @@ void LLDrawPoolSimple::endDeferredPass(S32 pass)
 	LLRenderPass::endRenderPass(pass);
 
 	gDeferredDiffuseProgram.unbind();
+
+	for (U32 i = 0; i < 8; i++)
+	{
+		if (gGL.getTexUnit(i)->getCurrType() != LLTexUnit::TT_NONE)
+		{
+			gGL.getTexUnit(i)->unbind(gGL.getTexUnit(i)->getCurrType());
+			gGL.getTexUnit(i)->disable();
+		}
+	}
 }
 
 void LLDrawPoolSimple::renderDeferred(S32 pass)
@@ -177,7 +242,7 @@ void LLDrawPoolSimple::renderDeferred(S32 pass)
 
 	{ //render simple
 		LLFastTimer t(FTM_RENDER_SIMPLE_DEFERRED);
-		renderTexture(LLRenderPass::PASS_SIMPLE, getVertexDataMask());
+		pushBatches(LLRenderPass::PASS_SIMPLE, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
 	}
 }
 
@@ -200,11 +265,11 @@ void LLDrawPoolGrass::beginRenderPass(S32 pass)
 
 	if (LLPipeline::sUnderWaterRender)
 	{
-		simple_shader = &gObjectSimpleWaterProgram;
+		simple_shader = &gObjectSimpleNonIndexedWaterProgram;
 	}
 	else
 	{
-		simple_shader = &gObjectSimpleProgram;
+		simple_shader = &gObjectSimpleNonIndexedProgram;
 	}
 
 	if (mVertexShaderLevel > 0)
@@ -285,6 +350,33 @@ void LLDrawPoolFullbright::prerender()
 	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
 }
 
+void LLDrawPoolFullbright::beginPostDeferredPass(S32 pass)
+{
+	gDeferredFullbrightProgram.bind();
+}
+
+void LLDrawPoolFullbright::renderPostDeferred(S32 pass)
+{
+	LLFastTimer t(FTM_RENDER_FULLBRIGHT);
+	
+	gGL.setSceneBlendType(LLRender::BT_ALPHA);
+	U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX;
+	pushBatches(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask, TRUE, TRUE);
+}
+
+void LLDrawPoolFullbright::endPostDeferredPass(S32 pass)
+{
+	gDeferredFullbrightProgram.unbind();
+	for (U32 i = 0; i < 8; i++)
+	{
+		if (gGL.getTexUnit(i)->getCurrType() != LLTexUnit::TT_NONE)
+		{
+			gGL.getTexUnit(i)->unbind(gGL.getTexUnit(i)->getCurrType());
+			gGL.getTexUnit(i)->disable();
+		}
+	}
+}
+
 void LLDrawPoolFullbright::beginRenderPass(S32 pass)
 {
 	LLFastTimer t(FTM_RENDER_FULLBRIGHT);
@@ -313,25 +405,21 @@ void LLDrawPoolFullbright::endRenderPass(S32 pass)
 void LLDrawPoolFullbright::render(S32 pass)
 { //render fullbright
 	LLFastTimer t(FTM_RENDER_FULLBRIGHT);
+	gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
 	if (mVertexShaderLevel > 0)
 	{
 		fullbright_shader->bind();
 		fullbright_shader->uniform1f(LLViewerShaderMgr::FULLBRIGHT, 1.f);
+		U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX;
+		pushBatches(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask, TRUE, TRUE);
 	}
 	else
 	{
 		gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
+		U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR;
+		renderTexture(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask);
 	}
-	
-	//gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.25f);
-	
-	//LLGLEnable test(GL_ALPHA_TEST);
-	//LLGLEnable blend(GL_BLEND);
-	gGL.setSceneBlendType(LLRender::BT_ALPHA);
-	U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR;
-	renderTexture(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask);
-
-	//gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 }
 
 S32 LLDrawPoolFullbright::getNumPasses()
diff --git a/indra/newview/lldrawpoolsimple.h b/indra/newview/lldrawpoolsimple.h
index 5f3bbebbdad5e6df941150e3f387c61ddfc72880..3811b3d398f872193cb6861e63c053f6f926e263 100644
--- a/indra/newview/lldrawpoolsimple.h
+++ b/indra/newview/lldrawpoolsimple.h
@@ -98,9 +98,9 @@ class LLDrawPoolFullbright : public LLRenderPass
 	LLDrawPoolFullbright();
 	
 	/*virtual*/ S32 getNumPostDeferredPasses() { return 1; }
-	/*virtual*/ void beginPostDeferredPass(S32 pass) { beginRenderPass(pass); }
-	/*virtual*/ void endPostDeferredPass(S32 pass) { endRenderPass(pass); }
-	/*virtual*/ void renderPostDeferred(S32 pass) { render(pass); }
+	/*virtual*/ void beginPostDeferredPass(S32 pass);
+	/*virtual*/ void endPostDeferredPass(S32 pass);
+	/*virtual*/ void renderPostDeferred(S32 pass);
 
 	/*virtual*/ void beginRenderPass(S32 pass);
 	/*virtual*/ void endRenderPass(S32 pass);
@@ -126,12 +126,12 @@ class LLDrawPoolGlow : public LLRenderPass
 	virtual void prerender() { }
 
 	/*virtual*/ S32 getNumPostDeferredPasses() { return 1; }
-	/*virtual*/ void beginPostDeferredPass(S32 pass) { beginRenderPass(pass); }
-	/*virtual*/ void endPostDeferredPass(S32 pass) { endRenderPass(pass); }
-	/*virtual*/ void renderPostDeferred(S32 pass) { render(pass); }
+	/*virtual*/ void beginPostDeferredPass(S32 pass); 
+	/*virtual*/ void endPostDeferredPass(S32 pass);
+	/*virtual*/ void renderPostDeferred(S32 pass);
 
 	void render(S32 pass = 0);
-	void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture = TRUE);
+	void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE);
 
 };
 
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index 195ee60a2ef164019287c4ccc860d209e0f3a9a7..81c796b14630f19aea34b1fcdaac174baf95688b 100644
--- a/indra/newview/lldrawpooltree.cpp
+++ b/indra/newview/lldrawpooltree.cpp
@@ -66,11 +66,11 @@ void LLDrawPoolTree::beginRenderPass(S32 pass)
 	
 	if (LLPipeline::sUnderWaterRender)
 	{
-		shader = &gObjectSimpleWaterProgram;
+		shader = &gObjectSimpleNonIndexedWaterProgram;
 	}
 	else
 	{
-		shader = &gObjectSimpleProgram;
+		shader = &gObjectSimpleNonIndexedProgram;
 	}
 
 	if (gPipeline.canUseWindLightShadersOnObjects())
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 9f9e50ad0a5c48db4d72a3c266699adbd38ed2b0..e30522d380f601ac060c7883ee858453088e3c95 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -165,6 +165,7 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
 	mIndexInTex = 0;
 	mTexture		= NULL;
 	mTEOffset		= -1;
+	mTextureIndex = 255;
 
 	setDrawable(drawablep);
 	mVObjp = objp;
@@ -386,6 +387,26 @@ void LLFace::setGeomIndex(U16 idx)
 	}
 }
 
+void LLFace::setTextureIndex(U8 index)
+{
+	if (index != mTextureIndex)
+	{
+		mTextureIndex = index;
+
+		if (mTextureIndex != 255)
+		{
+			mDrawablep->setState(LLDrawable::REBUILD_POSITION);
+		}
+		else
+		{
+			if (mDrawInfo && !mDrawInfo->mTextureList.empty())
+			{
+				llerrs << "Face with no texture index references indexed texture draw info." << llendl;
+			}
+		}
+	}
+}
+
 void LLFace::setIndicesIndex(S32 idx) 
 { 
 	if (mIndicesIndex != idx)
@@ -1573,6 +1594,20 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			mat_vert.affineTransform(*src++, *dst++);
 		}
 		while(dst < end);
+
+		F32 index = (F32) (mTextureIndex < 255 ? mTextureIndex : 0);
+		F32 *index_dst = (F32*) vertices;
+		F32 *index_end = (F32*) end;
+
+		index_dst += 3;
+		index_end += 3;
+		do
+		{
+			*index_dst = index;
+			index_dst += 4;
+		}
+		while (index_dst < index_end);
+		
 	}
 		
 	if (rebuild_normal)
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index b2170c4cf3fd271c7cfd63ab7006d752892c0c3b..b5eaeecd60ea18c533f441e7c9b04c51386ef85f 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -94,6 +94,8 @@ class LLFace
 	U16				getGeomCount()		const	{ return mGeomCount; }		// vertex count for this face
 	U16				getGeomIndex()		const	{ return mGeomIndex; }		// index into draw pool
 	U16				getGeomStart()		const	{ return mGeomIndex; }		// index into draw pool
+	void			setTextureIndex(U8 index);
+	U8				getTextureIndex() const		{ return mTextureIndex; }
 	void			setTexture(LLViewerTexture* tex) ;
 	void            switchTexture(LLViewerTexture* new_texture);
 	void            dirtyTexture();
@@ -262,6 +264,7 @@ class LLFace
 	
 	U16			mGeomCount;			// vertex count for this face
 	U16			mGeomIndex;			// index into draw pool
+	U8			mTextureIndex;		// index of texture channel to use for pseudo-atlasing
 	U32			mIndicesCount;
 	U32			mIndicesIndex;		// index into draw pool for indices (yeah, I know!)
 	S32         mIndexInTex ;
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 8143d6a41f4aa7e89848c2f4970475c34d3ac25a..7f91f9a95271f3d027ebeca3f3700870d2b8c95b 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -3439,6 +3439,8 @@ void renderTextureAnim(LLDrawInfo* params)
 
 void renderBatchSize(LLDrawInfo* params)
 {
+	LLGLEnable offset(GL_POLYGON_OFFSET_FILL);
+	glPolygonOffset(-1.f, 1.f);
 	glColor3ubv((GLubyte*) &(params->mDebugColor));
 	pushVerts(params, LLVertexBuffer::MAP_VERTEX);
 }
@@ -3876,6 +3878,28 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 				renderAgentTarget(avatar);
 			}
 			
+			if (gDebugGL)
+			{
+				for (U32 i = 0; i < drawable->getNumFaces(); ++i)
+				{
+					LLFace* facep = drawable->getFace(i);
+					U8 index = facep->getTextureIndex();
+					if (facep->mDrawInfo)
+					{
+						if (index < 255)
+						{
+							if (facep->mDrawInfo->mTextureList.size() <= index)
+							{
+								llerrs << "Face texture index out of bounds." << llendl;
+							}
+							else if (facep->mDrawInfo->mTextureList[index] != facep->getTexture())
+							{
+								llerrs << "Face texture index incorrect." << llendl;
+							}
+						}
+					}
+				}
+			}
 		}
 		
 		for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 0d9cad914a55755344cc062719da89ec364a05d7..ae5d4fa463f72dbc461fb72155f0e2f29f13fa75 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -91,6 +91,8 @@ class LLDrawInfo : public LLRefCount
 	
 	LLPointer<LLVertexBuffer> mVertexBuffer;
 	LLPointer<LLViewerTexture>     mTexture;
+	std::vector<LLPointer<LLViewerTexture> > mTextureList;
+
 	LLColor4U mGlowColor;
 	S32 mDebugColor;
 	const LLMatrix4* mTextureMatrix;
@@ -684,7 +686,7 @@ class LLVolumeGeometryManager: public LLGeometryManager
 	virtual void rebuildGeom(LLSpatialGroup* group);
 	virtual void rebuildMesh(LLSpatialGroup* group);
 	virtual void getGeometry(LLSpatialGroup* group);
-	void genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort = FALSE);
+	void genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort = FALSE, BOOL batch_textures = FALSE);
 	void registerFace(LLSpatialGroup* group, LLFace* facep, U32 type);
 };
 
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index b818da205eaade022ead9658955b21d79434b092..e60b3f45432fa6cc525284a0b1535698c412b229 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -66,12 +66,20 @@ LLGLSLShader		gObjectSimpleProgram;
 LLGLSLShader		gObjectSimpleWaterProgram;
 LLGLSLShader		gObjectFullbrightProgram;
 LLGLSLShader		gObjectFullbrightWaterProgram;
-
 LLGLSLShader		gObjectFullbrightShinyProgram;
 LLGLSLShader		gObjectFullbrightShinyWaterProgram;
 LLGLSLShader		gObjectShinyProgram;
 LLGLSLShader		gObjectShinyWaterProgram;
 
+LLGLSLShader		gObjectSimpleNonIndexedProgram;
+LLGLSLShader		gObjectSimpleNonIndexedWaterProgram;
+LLGLSLShader		gObjectFullbrightNonIndexedProgram;
+LLGLSLShader		gObjectFullbrightNonIndexedWaterProgram;
+LLGLSLShader		gObjectFullbrightShinyNonIndexedProgram;
+LLGLSLShader		gObjectFullbrightShinyNonIndexedWaterProgram;
+LLGLSLShader		gObjectShinyNonIndexedProgram;
+LLGLSLShader		gObjectShinyNonIndexedWaterProgram;
+
 //object hardware skinning shaders
 LLGLSLShader		gSkinnedObjectSimpleProgram;
 LLGLSLShader		gSkinnedObjectFullbrightProgram;
@@ -113,6 +121,7 @@ LLGLSLShader			gDeferredImpostorProgram;
 LLGLSLShader			gDeferredEdgeProgram;
 LLGLSLShader			gDeferredWaterProgram;
 LLGLSLShader			gDeferredDiffuseProgram;
+LLGLSLShader			gDeferredNonIndexedDiffuseProgram;
 LLGLSLShader			gDeferredSkinnedDiffuseProgram;
 LLGLSLShader			gDeferredSkinnedBumpProgram;
 LLGLSLShader			gDeferredSkinnedAlphaProgram;
@@ -132,6 +141,7 @@ LLGLSLShader			gDeferredShadowProgram;
 LLGLSLShader			gDeferredAvatarShadowProgram;
 LLGLSLShader			gDeferredAttachmentShadowProgram;
 LLGLSLShader			gDeferredAlphaProgram;
+LLGLSLShader			gDeferredAvatarEyesProgram;
 LLGLSLShader			gDeferredFullbrightProgram;
 LLGLSLShader			gDeferredGIProgram;
 LLGLSLShader			gDeferredGIFinalProgram;
@@ -162,6 +172,10 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gObjectFullbrightProgram);
 	mShaderList.push_back(&gObjectFullbrightShinyProgram);
 	mShaderList.push_back(&gObjectFullbrightShinyWaterProgram);
+	mShaderList.push_back(&gObjectSimpleNonIndexedProgram);
+	mShaderList.push_back(&gObjectFullbrightNonIndexedProgram);
+	mShaderList.push_back(&gObjectFullbrightShinyNonIndexedProgram);
+	mShaderList.push_back(&gObjectFullbrightShinyNonIndexedWaterProgram);
 	mShaderList.push_back(&gSkinnedObjectSimpleProgram);
 	mShaderList.push_back(&gSkinnedObjectFullbrightProgram);
 	mShaderList.push_back(&gSkinnedObjectFullbrightShinyProgram);
@@ -185,6 +199,7 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gDeferredAlphaProgram);
 	mShaderList.push_back(&gDeferredSkinnedAlphaProgram);
 	mShaderList.push_back(&gDeferredFullbrightProgram);
+	mShaderList.push_back(&gDeferredAvatarEyesProgram);
 	mShaderList.push_back(&gDeferredPostGIProgram);
 	mShaderList.push_back(&gDeferredEdgeProgram);
 	mShaderList.push_back(&gDeferredPostProgram);
@@ -354,6 +369,7 @@ void LLViewerShaderMgr::setShaders()
 
 	//setup preprocessor definitions
 	LLShaderMgr::instance()->mDefinitions["samples"] = llformat("%d", gGLManager.getNumFBOFSAASamples(gSavedSettings.getU32("RenderFSAASamples")));
+	LLShaderMgr::instance()->mDefinitions["NUM_TEX_UNITS"] = llformat("%d", gGLManager.mNumTextureImageUnits);
 
 	reentrance = true;
 
@@ -585,6 +601,16 @@ void LLViewerShaderMgr::unloadShaders()
 	gObjectFullbrightShinyWaterProgram.unload();
 	gObjectShinyWaterProgram.unload();
 
+	gObjectSimpleNonIndexedProgram.unload();
+	gObjectSimpleNonIndexedWaterProgram.unload();
+	gObjectFullbrightNonIndexedProgram.unload();
+	gObjectFullbrightNonIndexedWaterProgram.unload();
+
+	gObjectShinyNonIndexedProgram.unload();
+	gObjectFullbrightShinyNonIndexedProgram.unload();
+	gObjectFullbrightShinyNonIndexedWaterProgram.unload();
+	gObjectShinyNonIndexedWaterProgram.unload();
+
 	gSkinnedObjectSimpleProgram.unload();
 	gSkinnedObjectFullbrightProgram.unload();
 	gSkinnedObjectFullbrightShinyProgram.unload();
@@ -615,6 +641,7 @@ void LLViewerShaderMgr::unloadShaders()
 	gPostNightVisionProgram.unload();
 
 	gDeferredDiffuseProgram.unload();
+	gDeferredNonIndexedDiffuseProgram.unload();
 	gDeferredSkinnedDiffuseProgram.unload();
 	gDeferredSkinnedBumpProgram.unload();
 	gDeferredSkinnedAlphaProgram.unload();
@@ -706,6 +733,14 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
 	shaders.push_back( make_pair( "lighting/lightFullbrightShinyF.glsl",	mVertexShaderLevel[SHADER_LIGHTING] ) );
 	shaders.push_back( make_pair( "lighting/lightShinyWaterF.glsl",			mVertexShaderLevel[SHADER_LIGHTING] ) );
 	shaders.push_back( make_pair( "lighting/lightFullbrightShinyWaterF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) );
+	shaders.push_back( make_pair( "lighting/lightNonIndexedF.glsl",					mVertexShaderLevel[SHADER_LIGHTING] ) );
+	shaders.push_back( make_pair( "lighting/lightFullbrightNonIndexedF.glsl",			mVertexShaderLevel[SHADER_LIGHTING] ) );
+	shaders.push_back( make_pair( "lighting/lightWaterNonIndexedF.glsl",				mVertexShaderLevel[SHADER_LIGHTING] ) );
+	shaders.push_back( make_pair( "lighting/lightFullbrightWaterNonIndexedF.glsl",	mVertexShaderLevel[SHADER_LIGHTING] ) );
+	shaders.push_back( make_pair( "lighting/lightShinyNonIndexedF.glsl",				mVertexShaderLevel[SHADER_LIGHTING] ) );
+	shaders.push_back( make_pair( "lighting/lightFullbrightShinyNonIndexedF.glsl",	mVertexShaderLevel[SHADER_LIGHTING] ) );
+	shaders.push_back( make_pair( "lighting/lightShinyWaterNonIndexedF.glsl",			mVertexShaderLevel[SHADER_LIGHTING] ) );
+	shaders.push_back( make_pair( "lighting/lightFullbrightShinyWaterNonIndexedF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) );
 	
 	for (U32 i = 0; i < shaders.size(); i++)
 	{
@@ -941,12 +976,53 @@ BOOL LLViewerShaderMgr::loadShadersEffects()
 
 }
 
+void setup_indexed_texture(LLGLSLShader& shader)
+{
+	shader.bind();
+	shader.uniform1i("tex0", 0);
+	shader.uniform1i("tex1", 1);
+	shader.uniform1i("tex2", 2);
+	shader.uniform1i("tex3", 3);
+	shader.uniform1i("tex4", 4);
+	shader.uniform1i("tex5", 5);
+	shader.uniform1i("tex6", 6);
+	shader.uniform1i("tex7", 7);
+
+	S32 cur_tex = 8; //adjust any texture channels that might have been overwritten
+	for (U32 i = 0; i < shader.mTexture.size(); i++)
+	{
+		if (shader.mTexture[i] > -1 && shader.mTexture[i] < 7)
+		{
+			shader.uniform1i(i, cur_tex);
+			shader.mTexture[i] = cur_tex++;
+		}
+	}
+	shader.unbind();
+}
+
+void setup_indexed_texture_with_cubemap(LLGLSLShader& shader)
+{
+	shader.bind();
+	shader.uniform1i("tex0", 0);
+	shader.uniform1i("tex1", 1);
+	shader.uniform1i("tex2", 2);
+	shader.uniform1i("tex3", 3);
+	shader.uniform1i("tex4", 4);
+	shader.uniform1i("tex5", 5);
+	shader.uniform1i("tex6", 6);
+	shader.uniform1i("environmentMap", 7);
+	shader.mTexture[LLViewerShaderMgr::ENVIRONMENT_MAP] = 7;
+	shader.mTexture[LLViewerShaderMgr::DIFFUSE_MAP] = 0;
+	shader.unbind();
+}
+
 BOOL LLViewerShaderMgr::loadShadersDeferred()
 {
 	if (mVertexShaderLevel[SHADER_DEFERRED] == 0)
 	{
 		gDeferredTreeProgram.unload();
 		gDeferredDiffuseProgram.unload();
+		gDeferredNonIndexedDiffuseProgram.unload();
 		gDeferredSkinnedDiffuseProgram.unload();
 		gDeferredSkinnedBumpProgram.unload();
 		gDeferredSkinnedAlphaProgram.unload();
@@ -967,6 +1043,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAvatarAlphaProgram.unload();
 		gDeferredAlphaProgram.unload();
 		gDeferredFullbrightProgram.unload();
+		gDeferredAvatarEyesProgram.unload();
 		gDeferredPostGIProgram.unload();		
 		gDeferredEdgeProgram.unload();		
 		gDeferredPostProgram.unload();		
@@ -992,11 +1069,27 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredDiffuseProgram.mName = "Deferred Diffuse Shader";
 		gDeferredDiffuseProgram.mShaderFiles.clear();
 		gDeferredDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseIndexedF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredDiffuseProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredDiffuseProgram.createShader(NULL, NULL);
+
+		if (success)
+		{ //force tex0-7 to appropriate texture channels
+			setup_indexed_texture(gDeferredDiffuseProgram);
+		}
 	}
 
+	if (success)
+	{
+		gDeferredNonIndexedDiffuseProgram.mName = "Non Indexed Deferred Diffuse Shader";
+		gDeferredNonIndexedDiffuseProgram.mShaderFiles.clear();
+		gDeferredNonIndexedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredNonIndexedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredNonIndexedDiffuseProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredNonIndexedDiffuseProgram.createShader(NULL, NULL);
+	}
+		
+
 	if (success)
 	{
 		gDeferredSkinnedDiffuseProgram.mName = "Deferred Skinned Diffuse Shader";
@@ -1217,6 +1310,24 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredAlphaProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredAlphaProgram.createShader(NULL, NULL);
+		if (success)
+		{
+			setup_indexed_texture(gDeferredAlphaProgram);
+		}
+	}
+
+	if (success)
+	{
+		gDeferredAvatarEyesProgram.mName = "Deferred Avatar Eyes Shader";
+		gDeferredAvatarEyesProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredAvatarEyesProgram.mFeatures.hasGamma = true;
+		gDeferredAvatarEyesProgram.mFeatures.hasTransport = true;
+		gDeferredAvatarEyesProgram.mFeatures.isFullbright = true;
+		gDeferredAvatarEyesProgram.mShaderFiles.clear();
+		gDeferredAvatarEyesProgram.mShaderFiles.push_back(make_pair("deferred/avatarEyesV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredAvatarEyesProgram.mShaderFiles.push_back(make_pair("deferred/diffuseF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredAvatarEyesProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredAvatarEyesProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -1231,6 +1342,11 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredFullbrightProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredFullbrightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredFullbrightProgram.createShader(NULL, NULL);
+
+		if (success)
+		{
+			setup_indexed_texture(gDeferredFullbrightProgram);
+		}
 	}
 
 	if (success)
@@ -1490,6 +1606,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 BOOL LLViewerShaderMgr::loadShadersObject()
 {
 	BOOL success = TRUE;
+	bool batch_textures = mVertexShaderLevel[SHADER_OBJECT] > 1;
 
 	if (mVertexShaderLevel[SHADER_OBJECT] == 0)
 	{
@@ -1501,6 +1618,14 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectSimpleWaterProgram.unload();
 		gObjectFullbrightProgram.unload();
 		gObjectFullbrightWaterProgram.unload();
+		gObjectShinyNonIndexedProgram.unload();
+		gObjectFullbrightShinyNonIndexedProgram.unload();
+		gObjectFullbrightShinyNonIndexedWaterProgram.unload();
+		gObjectShinyNonIndexedWaterProgram.unload();
+		gObjectSimpleNonIndexedProgram.unload();
+		gObjectSimpleNonIndexedWaterProgram.unload();
+		gObjectFullbrightNonIndexedProgram.unload();
+		gObjectFullbrightNonIndexedWaterProgram.unload();
 		gSkinnedObjectSimpleProgram.unload();
 		gSkinnedObjectFullbrightProgram.unload();
 		gSkinnedObjectFullbrightShinyProgram.unload();
@@ -1513,6 +1638,137 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		return TRUE;
 	}
 
+	if (success)
+	{
+		gObjectSimpleNonIndexedProgram.mName = "Non indexed Shader";
+		gObjectSimpleNonIndexedProgram.mFeatures.calculatesLighting = true;
+		gObjectSimpleNonIndexedProgram.mFeatures.calculatesAtmospherics = true;
+		gObjectSimpleNonIndexedProgram.mFeatures.hasGamma = true;
+		gObjectSimpleNonIndexedProgram.mFeatures.hasAtmospherics = true;
+		gObjectSimpleNonIndexedProgram.mFeatures.hasLighting = true;
+		gObjectSimpleNonIndexedProgram.mFeatures.disableTextureIndex = true;
+		gObjectSimpleNonIndexedProgram.mShaderFiles.clear();
+		gObjectSimpleNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB));
+		gObjectSimpleNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gObjectSimpleNonIndexedProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		success = gObjectSimpleNonIndexedProgram.createShader(NULL, NULL);
+	}
+	
+	if (success)
+	{
+		gObjectSimpleNonIndexedWaterProgram.mName = "Non indexed Water Shader";
+		gObjectSimpleNonIndexedWaterProgram.mFeatures.calculatesLighting = true;
+		gObjectSimpleNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true;
+		gObjectSimpleNonIndexedWaterProgram.mFeatures.hasWaterFog = true;
+		gObjectSimpleNonIndexedWaterProgram.mFeatures.hasAtmospherics = true;
+		gObjectSimpleNonIndexedWaterProgram.mFeatures.hasLighting = true;
+		gObjectSimpleNonIndexedWaterProgram.mFeatures.disableTextureIndex = true;
+		gObjectSimpleNonIndexedWaterProgram.mShaderFiles.clear();
+		gObjectSimpleNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB));
+		gObjectSimpleNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gObjectSimpleNonIndexedWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		gObjectSimpleNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+		success = gObjectSimpleNonIndexedWaterProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gObjectFullbrightNonIndexedProgram.mName = "Non Indexed Fullbright Shader";
+		gObjectFullbrightNonIndexedProgram.mFeatures.calculatesAtmospherics = true;
+		gObjectFullbrightNonIndexedProgram.mFeatures.hasGamma = true;
+		gObjectFullbrightNonIndexedProgram.mFeatures.hasTransport = true;
+		gObjectFullbrightNonIndexedProgram.mFeatures.isFullbright = true;
+		gObjectFullbrightNonIndexedProgram.mFeatures.disableTextureIndex = true;
+		gObjectFullbrightNonIndexedProgram.mShaderFiles.clear();
+		gObjectFullbrightNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
+		gObjectFullbrightNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gObjectFullbrightNonIndexedProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		success = gObjectFullbrightNonIndexedProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gObjectFullbrightNonIndexedWaterProgram.mName = "Non Indexed Fullbright Water Shader";
+		gObjectFullbrightNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true;
+		gObjectFullbrightNonIndexedWaterProgram.mFeatures.isFullbright = true;
+		gObjectFullbrightNonIndexedWaterProgram.mFeatures.hasWaterFog = true;		
+		gObjectFullbrightNonIndexedWaterProgram.mFeatures.hasTransport = true;
+		gObjectFullbrightNonIndexedWaterProgram.mFeatures.disableTextureIndex = true;
+		gObjectFullbrightNonIndexedWaterProgram.mShaderFiles.clear();
+		gObjectFullbrightNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
+		gObjectFullbrightNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gObjectFullbrightNonIndexedWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		gObjectFullbrightNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+		success = gObjectFullbrightNonIndexedWaterProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gObjectShinyNonIndexedProgram.mName = "Non Indexed Shiny Shader";
+		gObjectShinyNonIndexedProgram.mFeatures.calculatesAtmospherics = true;
+		gObjectShinyNonIndexedProgram.mFeatures.calculatesLighting = true;
+		gObjectShinyNonIndexedProgram.mFeatures.hasGamma = true;
+		gObjectShinyNonIndexedProgram.mFeatures.hasAtmospherics = true;
+		gObjectShinyNonIndexedProgram.mFeatures.isShiny = true;
+		gObjectShinyNonIndexedProgram.mFeatures.disableTextureIndex = true;
+		gObjectShinyNonIndexedProgram.mShaderFiles.clear();
+		gObjectShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB));
+		gObjectShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB));		
+		gObjectShinyNonIndexedProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		success = gObjectShinyNonIndexedProgram.createShader(NULL, &mShinyUniforms);
+	}
+
+	if (success)
+	{
+		gObjectShinyNonIndexedWaterProgram.mName = "Non Indexed Shiny Water Shader";
+		gObjectShinyNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true;
+		gObjectShinyNonIndexedWaterProgram.mFeatures.calculatesLighting = true;
+		gObjectShinyNonIndexedWaterProgram.mFeatures.isShiny = true;
+		gObjectShinyNonIndexedWaterProgram.mFeatures.hasWaterFog = true;
+		gObjectShinyNonIndexedWaterProgram.mFeatures.hasAtmospherics = true;
+		gObjectShinyNonIndexedWaterProgram.mFeatures.disableTextureIndex = true;
+		gObjectShinyNonIndexedWaterProgram.mShaderFiles.clear();
+		gObjectShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gObjectShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB));
+		gObjectShinyNonIndexedWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		gObjectShinyNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+		success = gObjectShinyNonIndexedWaterProgram.createShader(NULL, &mShinyUniforms);
+	}
+	
+	if (success)
+	{
+		gObjectFullbrightShinyNonIndexedProgram.mName = "Non Indexed Fullbright Shiny Shader";
+		gObjectFullbrightShinyNonIndexedProgram.mFeatures.calculatesAtmospherics = true;
+		gObjectFullbrightShinyNonIndexedProgram.mFeatures.isFullbright = true;
+		gObjectFullbrightShinyNonIndexedProgram.mFeatures.isShiny = true;
+		gObjectFullbrightShinyNonIndexedProgram.mFeatures.hasGamma = true;
+		gObjectFullbrightShinyNonIndexedProgram.mFeatures.hasTransport = true;
+		gObjectFullbrightShinyNonIndexedProgram.mFeatures.disableTextureIndex = true;
+		gObjectFullbrightShinyNonIndexedProgram.mShaderFiles.clear();
+		gObjectFullbrightShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB));
+		gObjectFullbrightShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gObjectFullbrightShinyNonIndexedProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		success = gObjectFullbrightShinyNonIndexedProgram.createShader(NULL, &mShinyUniforms);
+	}
+
+	if (success)
+	{
+		gObjectFullbrightShinyNonIndexedWaterProgram.mName = "Non Indexed Fullbright Shiny Water Shader";
+		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true;
+		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.isFullbright = true;
+		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.isShiny = true;
+		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.hasGamma = true;
+		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.hasTransport = true;
+		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.hasWaterFog = true;
+		gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.disableTextureIndex = true;
+		gObjectFullbrightShinyNonIndexedWaterProgram.mShaderFiles.clear();
+		gObjectFullbrightShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB));
+		gObjectFullbrightShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gObjectFullbrightShinyNonIndexedWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		gObjectFullbrightShinyNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+		success = gObjectFullbrightShinyNonIndexedWaterProgram.createShader(NULL, &mShinyUniforms);
+	}
+
 	if (success)
 	{
 		gObjectSimpleProgram.mName = "Simple Shader";
@@ -1526,6 +1782,11 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectSimpleProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
 		success = gObjectSimpleProgram.createShader(NULL, NULL);
+
+		if (success && batch_textures)
+		{
+			setup_indexed_texture(gObjectSimpleProgram);
+		}
 	}
 	
 	if (success)
@@ -1542,6 +1803,11 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectSimpleWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
 		gObjectSimpleWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
 		success = gObjectSimpleWaterProgram.createShader(NULL, NULL);
+
+		if (success && batch_textures)
+		{
+			setup_indexed_texture(gObjectSimpleWaterProgram);
+		}
 	}
 	
 	if (success)
@@ -1556,6 +1822,10 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectFullbrightProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
 		success = gObjectFullbrightProgram.createShader(NULL, NULL);
+		if (success && batch_textures)
+		{
+			setup_indexed_texture(gObjectFullbrightProgram);
+		}
 	}
 
 	if (success)
@@ -1571,6 +1841,10 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
 		gObjectFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
 		success = gObjectFullbrightWaterProgram.createShader(NULL, NULL);
+		if (success && batch_textures)
+		{
+			setup_indexed_texture(gObjectFullbrightWaterProgram);
+		}
 	}
 
 	if (success)
@@ -1586,6 +1860,10 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectShinyProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB));		
 		gObjectShinyProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
 		success = gObjectShinyProgram.createShader(NULL, &mShinyUniforms);
+		if (success && batch_textures)
+		{
+			setup_indexed_texture_with_cubemap(gObjectShinyProgram);
+		}
 	}
 
 	if (success)
@@ -1602,6 +1880,10 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectShinyWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
 		gObjectShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
 		success = gObjectShinyWaterProgram.createShader(NULL, &mShinyUniforms);
+		if (success && batch_textures)
+		{
+			setup_indexed_texture_with_cubemap(gObjectShinyWaterProgram);
+		}
 	}
 	
 	if (success)
@@ -1617,6 +1899,10 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectFullbrightShinyProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
 		success = gObjectFullbrightShinyProgram.createShader(NULL, &mShinyUniforms);
+		if (success && batch_textures)
+		{
+			setup_indexed_texture_with_cubemap(gObjectFullbrightShinyProgram);
+		}
 	}
 
 	if (success)
@@ -1634,6 +1920,10 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightShinyWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
 		gObjectFullbrightShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
 		success = gObjectFullbrightShinyWaterProgram.createShader(NULL, &mShinyUniforms);
+		if (success && batch_textures)
+		{
+			setup_indexed_texture_with_cubemap(gObjectFullbrightShinyWaterProgram);
+		}
 	}
 
 	if (mVertexShaderLevel[SHADER_AVATAR] > 0)
@@ -1647,6 +1937,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 			gSkinnedObjectSimpleProgram.mFeatures.hasAtmospherics = true;
 			gSkinnedObjectSimpleProgram.mFeatures.hasLighting = true;
 			gSkinnedObjectSimpleProgram.mFeatures.hasObjectSkinning = true;
+			gSkinnedObjectSimpleProgram.mFeatures.disableTextureIndex = true;
 			gSkinnedObjectSimpleProgram.mShaderFiles.clear();
 			gSkinnedObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
 			gSkinnedObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB));
@@ -1662,6 +1953,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 			gSkinnedObjectFullbrightProgram.mFeatures.hasTransport = true;
 			gSkinnedObjectFullbrightProgram.mFeatures.isFullbright = true;
 			gSkinnedObjectFullbrightProgram.mFeatures.hasObjectSkinning = true;
+			gSkinnedObjectFullbrightProgram.mFeatures.disableTextureIndex = true;
 			gSkinnedObjectFullbrightProgram.mShaderFiles.clear();
 			gSkinnedObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
 			gSkinnedObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
@@ -1678,6 +1970,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 			gSkinnedObjectFullbrightShinyProgram.mFeatures.isShiny = true;
 			gSkinnedObjectFullbrightShinyProgram.mFeatures.isFullbright = true;
 			gSkinnedObjectFullbrightShinyProgram.mFeatures.hasObjectSkinning = true;
+			gSkinnedObjectFullbrightShinyProgram.mFeatures.disableTextureIndex = true;
 			gSkinnedObjectFullbrightShinyProgram.mShaderFiles.clear();
 			gSkinnedObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB));
 			gSkinnedObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
@@ -1694,6 +1987,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 			gSkinnedObjectShinySimpleProgram.mFeatures.hasAtmospherics = true;
 			gSkinnedObjectShinySimpleProgram.mFeatures.hasObjectSkinning = true;
 			gSkinnedObjectShinySimpleProgram.mFeatures.isShiny = true;
+			gSkinnedObjectShinySimpleProgram.mFeatures.disableTextureIndex = true;
 			gSkinnedObjectShinySimpleProgram.mShaderFiles.clear();
 			gSkinnedObjectShinySimpleProgram.mShaderFiles.push_back(make_pair("objects/shinySimpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
 			gSkinnedObjectShinySimpleProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB));
@@ -1709,9 +2003,11 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 			gSkinnedObjectSimpleWaterProgram.mFeatures.hasGamma = true;
 			gSkinnedObjectSimpleWaterProgram.mFeatures.hasAtmospherics = true;
 			gSkinnedObjectSimpleWaterProgram.mFeatures.hasLighting = true;
+			gSkinnedObjectSimpleWaterProgram.mFeatures.disableTextureIndex = true;
 			gSkinnedObjectSimpleWaterProgram.mFeatures.hasWaterFog = true;
 			gSkinnedObjectSimpleWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
 			gSkinnedObjectSimpleWaterProgram.mFeatures.hasObjectSkinning = true;
+			gSkinnedObjectSimpleWaterProgram.mFeatures.disableTextureIndex = true;
 			gSkinnedObjectSimpleWaterProgram.mShaderFiles.clear();
 			gSkinnedObjectSimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
 			gSkinnedObjectSimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
@@ -1728,6 +2024,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 			gSkinnedObjectFullbrightWaterProgram.mFeatures.isFullbright = true;
 			gSkinnedObjectFullbrightWaterProgram.mFeatures.hasObjectSkinning = true;
 			gSkinnedObjectFullbrightWaterProgram.mFeatures.hasWaterFog = true;
+			gSkinnedObjectFullbrightWaterProgram.mFeatures.disableTextureIndex = true;
 			gSkinnedObjectFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
 			gSkinnedObjectFullbrightWaterProgram.mShaderFiles.clear();
 			gSkinnedObjectFullbrightWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
@@ -1746,6 +2043,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.isFullbright = true;
 			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasObjectSkinning = true;
 			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasWaterFog = true;
+			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.disableTextureIndex = true;
 			gSkinnedObjectFullbrightShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
 			gSkinnedObjectFullbrightShinyWaterProgram.mShaderFiles.clear();
 			gSkinnedObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB));
@@ -1764,6 +2062,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 			gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasObjectSkinning = true;
 			gSkinnedObjectShinySimpleWaterProgram.mFeatures.isShiny = true;
 			gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasWaterFog = true;
+			gSkinnedObjectShinySimpleWaterProgram.mFeatures.disableTextureIndex = true;
 			gSkinnedObjectShinySimpleWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
 			gSkinnedObjectShinySimpleWaterProgram.mShaderFiles.clear();
 			gSkinnedObjectShinySimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/shinySimpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index f5371f06190d651efd4357d7ae57f3683e96f98a..6ecba65470c8705de9424ec8cea924c306c8160d 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -298,16 +298,25 @@ extern LLVector4			gShinyOrigin;
 //object shaders
 extern LLGLSLShader			gObjectSimpleProgram;
 extern LLGLSLShader			gObjectSimpleWaterProgram;
+extern LLGLSLShader			gObjectSimpleNonIndexedProgram;
+extern LLGLSLShader			gObjectSimpleNonIndexedWaterProgram;
 extern LLGLSLShader			gObjectFullbrightProgram;
 extern LLGLSLShader			gObjectFullbrightWaterProgram;
+extern LLGLSLShader			gObjectFullbrightNonIndexedProgram;
+extern LLGLSLShader			gObjectFullbrightNonIndexedWaterProgram;
 
 extern LLGLSLShader			gObjectSimpleLODProgram;
 extern LLGLSLShader			gObjectFullbrightLODProgram;
 
 extern LLGLSLShader			gObjectFullbrightShinyProgram;
 extern LLGLSLShader			gObjectFullbrightShinyWaterProgram;
+extern LLGLSLShader			gObjectFullbrightShinyNonIndexedProgram;
+extern LLGLSLShader			gObjectFullbrightShinyNonIndexedWaterProgram;
+
 extern LLGLSLShader			gObjectShinyProgram;
 extern LLGLSLShader			gObjectShinyWaterProgram;
+extern LLGLSLShader			gObjectShinyNonIndexedProgram;
+extern LLGLSLShader			gObjectShinyNonIndexedWaterProgram;
 
 extern LLGLSLShader			gSkinnedObjectSimpleProgram;
 extern LLGLSLShader			gSkinnedObjectFullbrightProgram;
@@ -349,6 +358,7 @@ extern LLGLSLShader			gDeferredImpostorProgram;
 extern LLGLSLShader			gDeferredEdgeProgram;
 extern LLGLSLShader			gDeferredWaterProgram;
 extern LLGLSLShader			gDeferredDiffuseProgram;
+extern LLGLSLShader			gDeferredNonIndexedDiffuseProgram;
 extern LLGLSLShader			gDeferredSkinnedDiffuseProgram;
 extern LLGLSLShader			gDeferredSkinnedBumpProgram;
 extern LLGLSLShader			gDeferredSkinnedAlphaProgram;
@@ -373,6 +383,7 @@ extern LLGLSLShader			gDeferredAvatarShadowProgram;
 extern LLGLSLShader			gDeferredAttachmentShadowProgram;
 extern LLGLSLShader			gDeferredAlphaProgram;
 extern LLGLSLShader			gDeferredFullbrightProgram;
+extern LLGLSLShader			gDeferredAvatarEyesProgram;
 extern LLGLSLShader			gDeferredAvatarAlphaProgram;
 extern LLGLSLShader			gDeferredWLSkyProgram;
 extern LLGLSLShader			gDeferredWLCloudProgram;
diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp
index 6f354b78b1e1fa953e105dc98fd1e6330cd9e3d7..a4b0910c926c0abb839fcc7f4d097e43077cfccf 100644
--- a/indra/newview/llvopartgroup.cpp
+++ b/indra/newview/llvopartgroup.cpp
@@ -324,10 +324,18 @@ void LLVOPartGroup::getGeometry(S32 idx,
 
 
 	LLVector3 normal = -LLViewerCamera::getInstance()->getXAxis();
-		
+
+	//HACK -- the verticesp->mV[3] = 0.f here are to set the texture index to 0 (particles don't use texture batching, maybe they should)
+	// this works because there is actually a 4th float stored after the vertex position which is used as a texture index
+	// also, somebody please VECTORIZE THIS
+
+	verticesp->mV[3] = 0.f;
 	*verticesp++ = part_pos_agent + up - right;
+	verticesp->mV[3] = 0.f;
 	*verticesp++ = part_pos_agent - up - right;
+	verticesp->mV[3] = 0.f;
 	*verticesp++ = part_pos_agent + up + right;
+	verticesp->mV[3] = 0.f;
 	*verticesp++ = part_pos_agent - up + right;
 
 	*colorsp++ = part.mColor;
@@ -360,7 +368,7 @@ U32 LLVOPartGroup::getPartitionType() const
 }
 
 LLParticlePartition::LLParticlePartition()
-: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK, TRUE, GL_STREAM_DRAW_ARB)
+: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, GL_STREAM_DRAW_ARB)
 {
 	mRenderPass = LLRenderPass::PASS_ALPHA;
 	mDrawableType = LLPipeline::RENDER_TYPE_PARTICLES;
@@ -418,6 +426,7 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co
 			mFaceList.push_back(facep);
 			vertex_count += facep->getGeomCount();
 			index_count += facep->getIndicesCount();
+			llassert(facep->getIndicesCount() < 65536);
 		}
 		
 		obj->mDepth /= count;
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index 6396bc042dba7fc9f4b01559b83adfb9fc25ae99..800af26b698c966f71926005ac293673a62f64fe 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -1483,6 +1483,8 @@ BOOL LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, const S32 f, cons
 		facep->setVertexBuffer(buff);
 	}
 
+	llassert(facep->getVertexBuffer()->getNumIndices() == 6);
+
 	index_offset = facep->getGeometry(verticesp,normalsp,texCoordsp, indicesp);
 
 	if (-1 == index_offset)
diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp
index dbcd4f50cadf6549509afcd1aee89ee4dd79601d..510525259f4c9a6f64fee619aafb1785880adf12 100644
--- a/indra/newview/llvosurfacepatch.cpp
+++ b/indra/newview/llvosurfacepatch.cpp
@@ -375,6 +375,8 @@ void LLVOSurfacePatch::updateMainGeometry(LLFace *facep,
 	S32 num_vertices, num_indices;
 	U32 index;
 
+	llassert(mLastStride > 0);
+
 	render_stride = mLastStride;
 	patch_size = mPatchp->getSurface()->getGridsPerPatchEdge();
 	S32 vert_size = patch_size / render_stride;
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index cc443d32fb84298e7a69864ae040a1c470c0f7c8..713724cf4633713e376962d5ca7bc8d91712cb08 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -73,6 +73,7 @@
 #include "llagent.h"
 #include "llviewermediafocus.h"
 #include "lldatapacker.h"
+#include "llviewershadermgr.h"
 #include "llvoavatar.h"
 #include "llvocache.h"
 
@@ -1247,17 +1248,7 @@ BOOL LLVOVolume::calcLOD()
 	{
 		//setDebugText(llformat("%.2f:%.2f, %d", debug_distance, radius, cur_detail));
 
-		F32 bin_radius = getBinRadius();
-		F32 node_size = 0.f; 
-
-		LLSpatialGroup* group = mDrawable->getSpatialGroup();
-		if (group)
-		{
-			LLSpatialGroup::OctreeNode* node = group->mOctreeNode;
-			node_size = node->getSize()[0];
-		}
-
-		setDebugText(llformat("%.2f:%.2f", bin_radius, node_size));
+		setDebugText(llformat("%d", mDrawable->getFace(0)->getTextureIndex()));
 	}
 
 	if (cur_detail != mLOD)
@@ -3734,6 +3725,21 @@ LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep)
 	mSlopRatio = 0.25f;
 }
 
+bool can_batch_texture(LLFace* facep)
+{
+	if (facep->getTextureEntry()->getBumpmap())
+	{ //bump maps aren't worked into texture batching yet
+		return false;
+	}
+
+	if (facep->isState(LLFace::TEXTURE_ANIM) && facep->getVirtualSize() > MIN_TEX_ANIM_SIZE)
+	{ //texture animation breaks batches
+		return false;
+	}
+	
+	return true;
+}
+
 void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type)
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
@@ -3784,12 +3790,36 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 	
 	LLViewerTexture* tex = facep->getTexture();
 
+	U8 index = facep->getTextureIndex();
+
+	bool batchable = false;
+
+	if (index < 255 && idx >= 0)
+	{
+		if (index < draw_vec[idx]->mTextureList.size())
+		{
+			if (draw_vec[idx]->mTextureList[index].isNull())
+			{
+				batchable = true;
+				draw_vec[idx]->mTextureList[index] = tex;
+			}
+			else if (draw_vec[idx]->mTextureList[index] == tex)
+			{ //this face's texture index can be used with this batch
+				batchable = true;
+			}
+		}
+		else
+		{ //texture list can be expanded to fit this texture index
+			batchable = true;
+		}
+	}
+	
 	U8 glow = (U8) (facep->getTextureEntry()->getGlow() * 255);
 
 	if (idx >= 0 && 
 		draw_vec[idx]->mVertexBuffer == facep->getVertexBuffer() &&
 		draw_vec[idx]->mEnd == facep->getGeomIndex()-1 &&
-		(LLPipeline::sTextureBindTest || draw_vec[idx]->mTexture == tex) &&
+		(LLPipeline::sTextureBindTest || draw_vec[idx]->mTexture == tex || batchable) &&
 #if LL_DARWIN
 		draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange &&
 		draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange &&
@@ -3803,6 +3833,12 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		draw_vec[idx]->mCount += facep->getIndicesCount();
 		draw_vec[idx]->mEnd += facep->getGeomCount();
 		draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, facep->getVirtualSize());
+
+		if (index >= draw_vec[idx]->mTextureList.size())
+		{
+			draw_vec[idx]->mTextureList.resize(index+1);
+			draw_vec[idx]->mTextureList[index] = tex;
+		}
 		draw_vec[idx]->validate();
 		update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[0]);
 		update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[1]);
@@ -3833,6 +3869,11 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 			draw_info->mDrawMode = LLRender::TRIANGLE_STRIP;
 		}
 
+		if (index < 255)
+		{ //initialize texture list for texture batching
+			draw_info->mTextureList.resize(index+1);
+			draw_info->mTextureList[index] = tex;
+		}
 		draw_info->validate();
 	}
 }
@@ -4255,15 +4296,24 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 	U32 bump_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR;
 	U32 fullbright_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR;
 
-	if (LLPipeline::sRenderDeferred)
+	bool batch_textures = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 1;
+
+	if (batch_textures)
 	{
 		bump_mask |= LLVertexBuffer::MAP_BINORMAL;
+		genDrawInfo(group, simple_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, simple_faces, FALSE, TRUE);
+		genDrawInfo(group, fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, fullbright_faces, FALSE, TRUE);
+		genDrawInfo(group, bump_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, bump_faces, FALSE, TRUE);
+		genDrawInfo(group, alpha_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, alpha_faces, TRUE, TRUE);
+	}
+	else
+	{
+		genDrawInfo(group, simple_mask, simple_faces);
+		genDrawInfo(group, fullbright_mask, fullbright_faces);
+		genDrawInfo(group, bump_mask, bump_faces, FALSE, TRUE);
+		genDrawInfo(group, alpha_mask, alpha_faces, TRUE);
 	}
 	
-	genDrawInfo(group, simple_mask, simple_faces);
-	genDrawInfo(group, bump_mask, bump_faces);
-	genDrawInfo(group, fullbright_mask, fullbright_faces);
-	genDrawInfo(group, alpha_mask, alpha_faces, TRUE);
 
 	if (!LLPipeline::sDelayVBUpdate)
 	{
@@ -4376,7 +4426,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 	llassert(!group || !group->isState(LLSpatialGroup::NEW_DRAWINFO));
 }
 
-void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort)
+void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort, BOOL batch_textures)
 {
 	//calculate maximum number of vertices to store in a single buffer
 	U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
@@ -4435,19 +4485,101 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 		std::vector<LLFace*>::iterator i = face_iter;
 		++i;
 		
-		while (i != faces.end() && 
-			(LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex)))
+		std::vector<LLViewerTexture*> texture_list;
+
+		if (batch_textures)
 		{
-			facep = *i;
-			
-			if (geom_count + facep->getGeomCount() > max_vertices)
-			{ //cut batches on geom count too big
-				break;
+			U8 cur_tex = 0;
+			facep->setTextureIndex(cur_tex);
+			texture_list.push_back(tex);
+
+			//if (can_batch_texture(facep))
+			{
+				while (i != faces.end())
+				{
+					facep = *i;
+					if (facep->getTexture() != tex)
+					{
+						if (distance_sort)
+						{ //textures might be out of order, see if texture exists in current batch
+							bool found = false;
+							for (U32 tex_idx = 0; tex_idx < texture_list.size(); ++tex_idx)
+							{
+								if (facep->getTexture() == texture_list[tex_idx])
+								{
+									cur_tex = tex_idx;
+									found = true;
+									break;
+								}
+							}
+
+							if (!found)
+							{
+								cur_tex = texture_list.size();
+							}
+						}
+						else
+						{
+							cur_tex++;
+
+							if (cur_tex >= 7 && facep->getTextureEntry()->getShiny())
+							{ //entry 7 is reserved for the environment map for shiny faces
+								break;
+							}
+						}
+
+						if (!can_batch_texture(facep))
+						{ //face is bump mapped or has an animated texture matrix -- can't 
+							//batch more than 1 texture at a time
+							break;
+						}
+
+						if (cur_tex >= 8)
+						{ //cut batches on every 8 textures
+							break;
+						}
+
+						tex = facep->getTexture();
+
+						texture_list.push_back(tex);
+					}
+
+					if (geom_count + facep->getGeomCount() > max_vertices)
+					{ //cut batches on geom count too big
+						break;
+					}
+
+					++i;
+					index_count += facep->getIndicesCount();
+					geom_count += facep->getGeomCount();
+
+					facep->setTextureIndex(cur_tex);
+				}
 			}
 
-			++i;
-			index_count += facep->getIndicesCount();
-			geom_count += facep->getGeomCount();
+			tex = texture_list[0];
+		}
+		else
+		{
+			while (i != faces.end() && 
+				(LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex)))
+			{
+				facep = *i;
+			
+
+				//face has no texture index
+				facep->mDrawInfo = NULL;
+				facep->setTextureIndex(255);
+
+				if (geom_count + facep->getGeomCount() > max_vertices)
+				{ //cut batches on geom count too big
+					break;
+				}
+
+				++i;
+				index_count += facep->getIndicesCount();
+				geom_count += facep->getGeomCount();
+			}
 		}
 	
 		//create/delete/resize vertex buffer if needed
@@ -4497,6 +4629,11 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 			facep->setGeomIndex(index_offset);
 			facep->setVertexBuffer(buffer);	
 			
+			if (batch_textures && facep->getTextureIndex() == 255)
+			{
+				llerrs << "Invalid texture index." << llendl;
+			}
+			
 			{
 				//for debugging, set last time face was updated vs moved
 				facep->updateRebuildFlags();
@@ -4695,7 +4832,7 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun
 			{
 				vertex_count += facep->getGeomCount();
 				index_count += facep->getIndicesCount();
-
+				llassert(facep->getIndicesCount() < 65536);
 				//remember face (for sorting)
 				mFaceList.push_back(facep);
 			}
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index fadae7c71e991d1d87d773dc527a06bbf47fe9b8..1489c033e25eee140ccb8ccd3dbb21e935e2c39a 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -3606,7 +3606,7 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
 					if (gDebugGL)
 					{
 						check_stack_depth(stack_depth);
-						std::string msg = llformat("%s pass %d", gPoolNames[cur_type].c_str(), i);
+						std::string msg = llformat("pass %d", i);
 						LLGLState::checkStates(msg);
 						LLGLState::checkTextureChannels(msg);
 						LLGLState::checkClientArrays(msg);
@@ -6568,8 +6568,6 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, LLRen
 		noise_map = mNoiseMap;
 	}
 
-	LLGLState::checkTextureChannels();
-
 	shader.bind();
 	S32 channel = 0;
 	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, mDeferredScreen.getUsage());
@@ -7852,8 +7850,6 @@ void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(0)->activate();
 	shader.unbind();
-
-	LLGLState::checkTextureChannels();
 }
 
 inline float sgn(float a)