From 2ae4b6976baf0556066d5a3b43b8f6148f18c1d8 Mon Sep 17 00:00:00 2001
From: Geenz <geenz@geenzo.com>
Date: Mon, 4 Feb 2013 11:32:05 -0500
Subject: Added a new draw pool specifically for faces with materials applied
 to them.  Removed materials rendering from the bump draw pool, and reverted
 it to its previous state.

---
 indra/llrender/llglslshader.cpp                    |   2 +-
 indra/llrender/llshadermgr.cpp                     |   7 -
 indra/newview/CMakeLists.txt                       |   2 +
 .../shaders/class1/deferred/bumpF.glsl             |  21 +-
 .../shaders/class1/deferred/materialF.glsl         |  89 ++++++++
 .../shaders/class1/deferred/materialV.glsl         |  57 +++++
 indra/newview/lldrawpool.cpp                       |   4 +
 indra/newview/lldrawpool.h                         |   2 +
 indra/newview/lldrawpoolbump.cpp                   |  29 +--
 indra/newview/lldrawpoolmaterials.cpp              | 237 +++++++++++++++++++++
 indra/newview/lldrawpoolmaterials.h                |  75 +++++++
 indra/newview/llviewerdisplay.cpp                  |   1 +
 indra/newview/llviewershadermgr.cpp                | 125 +++++++++++
 indra/newview/llviewershadermgr.h                  |  11 +
 indra/newview/llvovolume.cpp                       |  16 +-
 indra/newview/pipeline.cpp                         |  31 ++-
 indra/newview/pipeline.h                           |   4 +
 17 files changed, 657 insertions(+), 56 deletions(-)
 create mode 100644 indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/deferred/materialV.glsl
 create mode 100644 indra/newview/lldrawpoolmaterials.cpp
 create mode 100644 indra/newview/lldrawpoolmaterials.h

(limited to 'indra')

diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 39e81c4bfc..78fd4e98d7 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -386,7 +386,7 @@ void LLGLSLShader::removePermutation(std::string name)
 
 GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type)
 {
-	if (type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB ||
+	if ((type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB) ||
 		type == GL_SAMPLER_2D_MULTISAMPLE)
 	{	//this here is a texture
 		glUniform1iARB(location, mActiveTextureChannels);
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index 9b2874c79d..d4ddc6396b 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -650,13 +650,6 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 			text[count++] = strdup("#define shadow2DRect(a,b) vec2(texture(a,b))\n");
 		}
 	}
-
-	//copy preprocessor definitions into buffer
-	for (std::map<std::string,std::string>::iterator iter = mDefinitions.begin(); iter != mDefinitions.end(); ++iter)
-	{
-		std::string define = "#define " + iter->first + " " + iter->second + "\n";
-		text[count++] = (GLcharARB *) strdup(define.c_str());
-	}
 	
 	for (boost::unordered_map<std::string,std::string>::iterator iter = defines.begin(); iter != defines.end(); ++iter)
 	{
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 85262b55a8..ca2905e963 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -153,6 +153,7 @@ set(viewer_SOURCE_FILES
     lldrawpoolavatar.cpp
     lldrawpoolbump.cpp
     lldrawpoolground.cpp
+    lldrawpoolmaterials.cpp
     lldrawpoolsimple.cpp
     lldrawpoolsky.cpp
     lldrawpoolterrain.cpp
@@ -730,6 +731,7 @@ set(viewer_HEADER_FILES
     lldrawpoolalpha.h
     lldrawpoolavatar.h
     lldrawpoolbump.h
+    lldrawpoolmaterials.h
     lldrawpoolground.h
     lldrawpoolsimple.h
     lldrawpoolsky.h
diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
index 6e5cc69e39..aaf1e5e572 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
@@ -31,9 +31,6 @@ out vec4 frag_data[3];
 
 uniform sampler2D diffuseMap;
 uniform sampler2D bumpMap;
-uniform sampler2D specularMap;
-uniform float env_intensity;
-uniform vec4 specular_color;
 
 VARYING vec3 vary_mat0;
 VARYING vec3 vary_mat1;
@@ -45,17 +42,15 @@ VARYING vec2 vary_texcoord0;
 void main() 
 {
 	vec3 col = vertex_color.rgb * texture2D(diffuseMap, vary_texcoord0.xy).rgb;
-	vec4 spec = texture2D(specularMap, vary_texcoord0.xy);
-	vec4 norm = texture2D(bumpMap, vary_texcoord0.xy);
-	norm.xyz = norm.xyz * 2 - 1;
+	vec3 norm = texture2D(bumpMap, vary_texcoord0.xy).rgb * 2.0 - 1.0;
 
-	vec3 tnorm = vec3(dot(norm.xyz,vary_mat0),
-			  dot(norm.xyz,vary_mat1),
-			  dot(norm.xyz,vary_mat2));
-	
-	frag_data[0] = vec4(col * (1 - spec.a * env_intensity), 0);
-	frag_data[1] = vec4(spec.xyz * specular_color.xyz, specular_color.a * norm.a); // spec
+	vec3 tnorm = vec3(dot(norm,vary_mat0),
+			  dot(norm,vary_mat1),
+			  dot(norm,vary_mat2));
+						
+	frag_data[0] = vec4(col * (1 - vertex_color.a), 0.0);
+	frag_data[1] = vertex_color.aaaa; // spec
 	//frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested
 	vec3 nvn = normalize(tnorm);
-	frag_data[2] = vec4(nvn.xyz * 0.5 + 0.5, spec.a * env_intensity);
+	frag_data[2] = vec4(nvn.xyz * 0.5 + 0.5, vertex_color.a);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
new file mode 100644
index 0000000000..4f7fc6a411
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
@@ -0,0 +1,89 @@
+/** 
+ * @file materialF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+ 
+#ifdef DEFINE_GL_FRAGCOLOR
+out vec4 frag_data[3];
+#else
+#define frag_data gl_FragData
+#endif
+
+uniform sampler2D diffuseMap;
+
+uniform sampler2D bumpMap;
+
+uniform sampler2D specularMap;
+uniform float env_intensity;
+uniform vec4 specular_color;
+
+#ifdef ALPHA_TEST
+uniform float minimum_alpha;
+#endif
+
+VARYING vec3 vary_mat0;
+VARYING vec3 vary_mat1;
+VARYING vec3 vary_mat2;
+
+VARYING vec4 vertex_color;
+VARYING vec2 vary_texcoord0;
+
+void main() 
+{
+	vec4 col = texture2D(diffuseMap, vary_texcoord0.xy) * vertex_color;
+
+	#ifdef ALPHA_TEST
+	if (col.a < minimum_alpha)
+	{
+		discard;
+	}
+	#endif
+	
+	vec4 spec = texture2D(specularMap, vary_texcoord0.xy);
+
+	vec4 norm = texture2D(bumpMap, vary_texcoord0.xy);
+
+	norm.xyz = norm.xyz * 2 - 1;
+
+	vec3 tnorm = vec3(dot(norm.xyz,vary_mat0),
+			  dot(norm.xyz,vary_mat1),
+			  dot(norm.xyz,vary_mat2));
+
+	vec4 final_color = col;
+	final_color.rgb *= 1 - spec.a * env_intensity;
+
+	#ifndef EMISSIVE_MASK
+	final_color.a = 0;
+	#endif
+
+	vec4 final_specular = spec;
+	final_specular.rgb *= specular_color.rgb;
+	final_specular.a = specular_color.a * norm.a;
+
+	vec4 final_normal = vec4(normalize(tnorm), spec.a * env_intensity);
+	final_normal.xyz = final_normal.xyz * 0.5 + 0.5;
+	
+	frag_data[0] = final_color;
+	frag_data[1] = final_specular; // XYZ = Specular color. W = Specular exponent.
+	frag_data[2] = final_normal; // XYZ = Normal.  W = Env. intensity.
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl
new file mode 100644
index 0000000000..c8d38bb8f7
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl
@@ -0,0 +1,57 @@
+/** 
+ * @file bumpV.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+uniform mat3 normal_matrix;
+uniform mat4 texture_matrix0;
+uniform mat4 modelview_projection_matrix;
+
+ATTRIBUTE vec3 position;
+ATTRIBUTE vec4 diffuse_color;
+ATTRIBUTE vec3 normal;
+ATTRIBUTE vec2 texcoord0;
+ATTRIBUTE vec3 binormal;
+
+VARYING vec3 vary_mat0;
+VARYING vec3 vary_mat1;
+VARYING vec3 vary_mat2;
+VARYING vec4 vertex_color;
+VARYING vec2 vary_texcoord0;
+
+void main()
+{
+	//transform vertex
+	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); 
+	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
+	
+	vec3 n = normalize(normal_matrix * normal);
+	vec3 b = normalize(normal_matrix * binormal);
+	vec3 t = cross(b, n);
+	
+	vary_mat0 = vec3(t.x, b.x, n.x);
+	vary_mat1 = vec3(t.y, b.y, n.y);
+	vary_mat2 = vec3(t.z, b.z, n.z);
+	
+	vertex_color = diffuse_color;
+}
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index 94dd927d26..fc5571aa58 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -35,6 +35,7 @@
 #include "lldrawpoolalpha.h"
 #include "lldrawpoolavatar.h"
 #include "lldrawpoolbump.h"
+#include "lldrawpoolmaterials.h"
 #include "lldrawpoolground.h"
 #include "lldrawpoolsimple.h"
 #include "lldrawpoolsky.h"
@@ -98,6 +99,9 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerTexture *tex0)
 	case POOL_BUMP:
 		poolp = new LLDrawPoolBump();
 		break;
+	case POOL_MATERIALS:
+		poolp = new LLDrawPoolMaterials();
+		break;
 	case POOL_WL_SKY:
 		poolp = new LLDrawPoolWLSky();
 		break;
diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h
index ab9bb9e611..caa57ad583 100644
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -50,6 +50,7 @@ public:
 		POOL_GROUND,
 		POOL_FULLBRIGHT,
 		POOL_BUMP,
+		POOL_MATERIALS,
 		POOL_TERRAIN,	
 		POOL_SKY,
 		POOL_WL_SKY,
@@ -133,6 +134,7 @@ public:
 		PASS_SHINY,
 		PASS_BUMP,
 		PASS_POST_BUMP,
+		PASS_MATERIALS,
 		PASS_GLOW,
 		PASS_ALPHA,
 		PASS_ALPHA_MASK,
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 07384a136a..a264eae302 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -72,7 +72,7 @@ static LLGLSLShader* shader = NULL;
 static S32 cube_channel = -1;
 static S32 diffuse_channel = -1;
 static S32 bump_channel = -1;
-static S32 spec_channel = -1;
+
 // static 
 void LLStandardBumpmap::init()
 {
@@ -153,7 +153,7 @@ void LLStandardBumpmap::addstandard()
 		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mLabel = label;
 		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage = 
 			LLViewerTextureManager::getFetchedTexture(LLUUID(bump_image_id));	
-		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setBoostLevel(LLViewerTexture::BOOST_BUMP);
+		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setBoostLevel(LLViewerTexture::BOOST_BUMP) ;
 		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setLoadedCallback(LLBumpImageList::onSourceStandardLoaded, 0, TRUE, FALSE, NULL, NULL );
 		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->forceToSaveRawImage(0) ;
 		LLStandardBumpmap::sStandardBumpmapCount++;
@@ -632,11 +632,6 @@ void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL
 BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params, S32 channel)
 {
 	U8 bump_code = params.mBump;
-	if (params.mNormalMap.notNull())
-	{
-		bump_code = 99;
-		return bindBumpMap(bump_code, params.mNormalMap, params.mVSize, channel);
-	}
 
 	return bindBumpMap(bump_code, params.mTexture, params.mVSize, channel);
 }
@@ -675,10 +670,7 @@ BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsi
 	case BE_DARKNESS:
 		bump = gBumpImageList.getBrightnessDarknessImage( tex, bump_code );		
 		break;
-	case 99:
-		bump = tex;
-		bump->addTextureStats(vsize);
-		break;
+
 	default:
 		if( bump_code < LLStandardBumpmap::sStandardBumpmapCount )
 		{
@@ -828,7 +820,6 @@ void LLDrawPoolBump::beginDeferredPass(S32 pass)
 	gDeferredBumpProgram.bind();
 	diffuse_channel = gDeferredBumpProgram.enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 	bump_channel = gDeferredBumpProgram.enableTexture(LLViewerShaderMgr::BUMP_MAP);
-	spec_channel = gDeferredBumpProgram.enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
 	gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(bump_channel)->unbind(LLTexUnit::TT_TEXTURE);
 }
@@ -843,7 +834,6 @@ void LLDrawPoolBump::endDeferredPass(S32 pass)
 	mShiny = FALSE;
 	gDeferredBumpProgram.disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 	gDeferredBumpProgram.disableTexture(LLViewerShaderMgr::BUMP_MAP);
-	gDeferredBumpProgram.disableTexture(LLViewerShaderMgr::SPECULAR_MAP);
 	gDeferredBumpProgram.unbind();
 	gGL.getTexUnit(0)->activate();
 }
@@ -865,18 +855,7 @@ void LLDrawPoolBump::renderDeferred(S32 pass)
 	for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i)	
 	{
 		LLDrawInfo& params = **i;
-		
-		gDeferredBumpProgram.uniform4f(LLShaderMgr::SPECULAR_COLOR, params.mSpecColor.mV[0], params.mSpecColor.mV[1], params.mSpecColor.mV[2], params.mSpecColor.mV[3]);
-		gDeferredBumpProgram.uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, params.mEnvIntensity);
-		
-		if (params.mSpecularMap)
-		{
-			params.mSpecularMap->addTextureStats(params.mVSize);
-			gGL.getTexUnit(spec_channel)->bind(params.mSpecularMap);
-		} else {
-			gGL.getTexUnit(spec_channel)->bind(LLViewerFetchedTexture::sWhiteImagep);
-		}
-		
+
 		LLDrawPoolBump::bindBumpMap(params, bump_channel);
 		pushBatch(params, mask, TRUE);
 	}
diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp
new file mode 100644
index 0000000000..5eb3cb9629
--- /dev/null
+++ b/indra/newview/lldrawpoolmaterials.cpp
@@ -0,0 +1,237 @@
+/** 
+ * @file lldrawpool.cpp
+ * @brief LLDrawPoolMaterials class implementation
+ * @author Jonathan "Geenz" Goodman
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lldrawpoolmaterials.h"
+#include "llviewershadermgr.h"
+#include "pipeline.h"
+
+S32 diffuse_channel = -1;
+
+LLDrawPoolMaterials::LLDrawPoolMaterials()
+:  LLRenderPass(LLDrawPool::POOL_MATERIALS)
+{
+	
+}
+
+void LLDrawPoolMaterials::prerender()
+{
+	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); 
+}
+
+void LLDrawPoolMaterials::beginDeferredPass(S32 pass)
+{
+	LLFastTimer t(FTM_RENDER_MATERIALS);
+}
+
+void LLDrawPoolMaterials::endDeferredPass(S32 pass)
+{
+	LLFastTimer t(FTM_RENDER_MATERIALS);
+	LLRenderPass::endRenderPass(pass);
+}
+
+void LLDrawPoolMaterials::renderDeferred(S32 pass)
+{
+	U32 type = LLRenderPass::PASS_MATERIALS;
+	LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type);
+	LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type);
+	
+	for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i)
+	{
+		LLDrawInfo& params = **i;
+		
+		switch (params.mDiffuseAlphaMode)
+		{
+			case 0:
+				LL_INFOS("Asdf") << "Renderererererrerererrrr!!!~!!!~!~" << LL_ENDL;
+				mShader = &gDeferredMaterialShinyNormal;
+				break;
+			case 1: // Alpha blending not supported in the opaque draw pool.
+				return;
+			case 2:
+				mShader = &gDeferredMaterialShinyNormalAlphaTest;
+				break;
+			case 3:
+				mShader = &gDeferredMaterialShinyNormalEmissive;
+				break;
+		};
+		
+		mShader->bind();
+		
+		mShader->uniform4f(LLShaderMgr::SPECULAR_COLOR, params.mSpecColor.mV[0], params.mSpecColor.mV[1], params.mSpecColor.mV[2], params.mSpecColor.mV[3]);
+		mShader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, params.mEnvIntensity);
+		
+		params.mNormalMap->addTextureStats(params.mVSize);
+		bindNormalMap(params.mNormalMap);
+		
+		params.mSpecularMap->addTextureStats(params.mVSize);
+		bindSpecularMap(params.mNormalMap);
+		
+		diffuse_channel = mShader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
+		pushBatch(params, VERTEX_DATA_MASK, TRUE);
+		mShader->disableTexture(LLShaderMgr::DIFFUSE_MAP);
+		mShader->unbind();
+	}
+}
+
+void LLDrawPoolMaterials::bindSpecularMap(LLViewerTexture* tex)
+{
+	mShader->bindTexture(LLShaderMgr::SPECULAR_MAP, tex);
+}
+
+void LLDrawPoolMaterials::bindNormalMap(LLViewerTexture* tex)
+{
+	mShader->bindTexture(LLShaderMgr::BUMP_MAP, tex);
+}
+
+void LLDrawPoolMaterials::beginRenderPass(S32 pass)
+{
+	LLFastTimer t(FTM_RENDER_MATERIALS);
+	
+	// Materials isn't supported under forward rendering.
+	// Use the simple shaders to handle it instead.
+	// This is basically replicated from LLDrawPoolSimple.
+	
+	if (LLPipeline::sUnderWaterRender)
+	{
+		mShader = &gObjectSimpleWaterProgram;
+	}
+	else
+	{
+		mShader = &gObjectSimpleProgram;
+	}
+	
+	if (mVertexShaderLevel > 0)
+	{
+		mShader->bind();
+	}
+	else
+	{
+		// don't use shaders!
+		if (gGLManager.mHasShaderObjects)
+		{
+			LLGLSLShader::bindNoShader();
+		}
+	}
+}
+
+void LLDrawPoolMaterials::endRenderPass(S32 pass)
+{
+	LLFastTimer t(FTM_RENDER_MATERIALS);
+	stop_glerror();
+	LLRenderPass::endRenderPass(pass);
+	stop_glerror();
+	if (mVertexShaderLevel > 0)
+	{
+		mShader->unbind();
+	}
+}
+
+void LLDrawPoolMaterials::render(S32 pass)
+{
+	LLGLDisable blend(GL_BLEND);
+	
+	{ //render simple
+		LLFastTimer t(FTM_RENDER_MATERIALS);
+		gPipeline.enableLightsDynamic();
+		
+		if (mVertexShaderLevel > 0)
+		{
+			U32 mask = getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX;
+			
+			pushBatches(LLRenderPass::PASS_MATERIALS, mask, TRUE, TRUE);
+		}
+		else
+		{
+			LLGLDisable alpha_test(GL_ALPHA_TEST);
+			renderTexture(LLRenderPass::PASS_MATERIALS, getVertexDataMask());
+		}
+	}
+}
+
+
+void LLDrawPoolMaterials::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures)
+{
+	applyModelMatrix(params);
+	
+	bool tex_setup = false;
+	
+	if (batch_textures && params.mTextureList.size() > 1)
+	{
+		for (U32 i = 0; i < params.mTextureList.size(); ++i)
+		{
+			if (params.mTextureList[i].notNull())
+			{
+				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.mTextureMatrix)
+		{
+			//if (mShiny)
+			{
+				gGL.getTexUnit(0)->activate();
+				gGL.matrixMode(LLRender::MM_TEXTURE);
+			}
+			
+			gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix);
+			gPipeline.mTextureMatrixOps++;
+			
+			tex_setup = true;
+		}
+		
+		if (mVertexShaderLevel > 1 && 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();
+	}
+	params.mVertexBuffer->setBuffer(mask);
+	params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
+	gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode);
+	if (tex_setup)
+	{
+		gGL.getTexUnit(0)->activate();
+		gGL.loadIdentity();
+		gGL.matrixMode(LLRender::MM_MODELVIEW);
+	}
+}
diff --git a/indra/newview/lldrawpoolmaterials.h b/indra/newview/lldrawpoolmaterials.h
new file mode 100644
index 0000000000..e8838c64d6
--- /dev/null
+++ b/indra/newview/lldrawpoolmaterials.h
@@ -0,0 +1,75 @@
+/** 
+ * @file lldrawpoolmaterials.h
+ * @brief LLDrawPoolMaterials class definition
+ * @author Jonathan "Geenz" Goodman
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLDRAWPOOLMATERIALS_H
+#define LL_LLDRAWPOOLMATERIALS_H
+
+#include "v4coloru.h"
+#include "v2math.h"
+#include "v3math.h"
+#include "llvertexbuffer.h"
+#include "lldrawpool.h"
+
+class LLViewerTexture;
+class LLDrawInfo;
+class LLGLSLShader;
+
+class LLDrawPoolMaterials : public LLRenderPass
+{
+	LLGLSLShader *mShader;
+public:
+	LLDrawPoolMaterials();
+	
+	enum
+	{
+		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
+		LLVertexBuffer::MAP_NORMAL |
+		LLVertexBuffer::MAP_TEXCOORD0 |
+		LLVertexBuffer::MAP_COLOR |
+		LLVertexBuffer::MAP_BINORMAL
+	};
+	
+	/*virtual*/ U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
+	
+	/*virtual*/ void render(S32 pass = 0);
+	/*virtual*/ void beginRenderPass( S32 pass );
+	/*virtual*/ void endRenderPass( S32 pass );
+	/*virtual*/ S32	 getNumPasses() {return 1;}
+	/*virtual*/ void prerender();
+	
+	/*virtual*/ S32 getNumDeferredPasses() {return 1;}
+	/*virtual*/ void beginDeferredPass(S32 pass);
+	/*virtual*/ void endDeferredPass(S32 pass);
+	/*virtual*/ void renderDeferred(S32 pass);
+	
+	void bindSpecularMap(LLViewerTexture* tex);
+	void bindNormalMap(LLViewerTexture* tex);
+	
+	/*virtual*/ void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE);
+};
+
+#endif //LL_LLDRAWPOOLMATERIALS_H
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index feceee5709..face1608a0 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -1101,6 +1101,7 @@ void render_hud_attachments()
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_BUMP);
+		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_MATERIALS);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY);
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 43de7450c8..20e0448c1b 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -207,6 +207,17 @@ LLGLSLShader			gDeferredWLCloudProgram;
 LLGLSLShader			gDeferredStarProgram;
 LLGLSLShader			gNormalMapGenProgram;
 
+// Deferred materials shaders
+LLGLSLShader			gDeferredMaterialShiny;
+LLGLSLShader			gDeferredMaterialNormal;
+LLGLSLShader			gDeferredMaterialShinyNormal;
+LLGLSLShader			gDeferredMaterialShinyAlphaTest;
+LLGLSLShader			gDeferredMaterialNormalAlphaTest;
+LLGLSLShader			gDeferredMaterialShinyNormalAlphaTest;
+LLGLSLShader			gDeferredMaterialShinyEmissive;
+LLGLSLShader			gDeferredMaterialNormalEmissive;
+LLGLSLShader			gDeferredMaterialShinyNormalEmissive;
+
 LLViewerShaderMgr::LLViewerShaderMgr() :
 	mVertexShaderLevel(SHADER_COUNT, 0),
 	mMaxAvatarShaderLevel(0)
@@ -1105,6 +1116,12 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredWLCloudProgram.unload();
 		gDeferredStarProgram.unload();
 		gNormalMapGenProgram.unload();
+		gDeferredMaterialShiny.unload();
+		gDeferredMaterialNormal.unload();
+		gDeferredMaterialShinyAlphaTest.unload();
+		gDeferredMaterialNormalAlphaTest.unload();
+		gDeferredMaterialShinyEmissive.unload();
+		gDeferredMaterialNormalEmissive.unload();
 		return TRUE;
 	}
 
@@ -1218,6 +1235,114 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredBumpProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredBumpProgram.createShader(NULL, NULL);
 	}
+	
+	if (success)
+	{
+		gDeferredMaterialShiny.mName = "Deferred Shiny Material Shader";
+		gDeferredMaterialShiny.mShaderFiles.clear();
+		gDeferredMaterialShiny.mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredMaterialShiny.mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredMaterialShiny.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		gDeferredMaterialShiny.addPermutation("SHINY_MATERIAL", "1");
+		success = gDeferredMaterialShiny.createShader(NULL, NULL);
+	}
+	
+	if (success)
+	{
+		gDeferredMaterialNormal.mName = "Deferred Normal Mapped Material Shader";
+		gDeferredMaterialNormal.mShaderFiles.clear();
+		gDeferredMaterialNormal.mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredMaterialNormal.mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredMaterialNormal.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		gDeferredMaterialNormal.addPermutation("NORMAL_MATERIAL", "1");
+		success = gDeferredMaterialNormal.createShader(NULL, NULL);
+	}
+	
+	if (success)
+	{
+		gDeferredMaterialShinyNormal.mName = "Deferred Normal Mapped Shiny Material Shader";
+		gDeferredMaterialShinyNormal.mShaderFiles.clear();
+		gDeferredMaterialShinyNormal.mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredMaterialShinyNormal.mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredMaterialShinyNormal.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		gDeferredMaterialShinyNormal.addPermutation("NORMAL_MATERIAL", "1");
+		gDeferredMaterialShinyNormal.addPermutation("SHINY_MATERIAL", "1");
+		success = gDeferredMaterialShinyNormal.createShader(NULL, NULL);
+	}
+	
+	if (success)
+	{
+		gDeferredMaterialShinyAlphaTest.mName = "Deferred Alpha Tested Shiny Material Shader";
+		gDeferredMaterialShinyAlphaTest.mShaderFiles.clear();
+		gDeferredMaterialShinyAlphaTest.mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredMaterialShinyAlphaTest.mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredMaterialShinyAlphaTest.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		gDeferredMaterialShinyAlphaTest.addPermutation("SHINY_MATERIAL", "1");
+		gDeferredMaterialShinyAlphaTest.addPermutation("ALPHA_TEST", "1");
+		success = gDeferredMaterialShinyAlphaTest.createShader(NULL, NULL);
+	}
+	
+	if (success)
+	{
+		gDeferredMaterialNormalAlphaTest.mName = "Deferred Alpha Tested Normal Mapped Material Shader";
+		gDeferredMaterialNormalAlphaTest.mShaderFiles.clear();
+		gDeferredMaterialNormalAlphaTest.mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredMaterialNormalAlphaTest.mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredMaterialNormalAlphaTest.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		gDeferredMaterialNormalAlphaTest.addPermutation("NORMAL_MATERIAL", "1");
+		gDeferredMaterialNormalAlphaTest.addPermutation("ALPHA_TEST", "1");
+		success = gDeferredMaterialNormalAlphaTest.createShader(NULL, NULL);
+	}
+	
+	if (success)
+	{
+		gDeferredMaterialNormalAlphaTest.mName = "Deferred Alpha Tested Shiny Normal Mapped Material Shader";
+		gDeferredMaterialShinyNormalAlphaTest.mShaderFiles.clear();
+		gDeferredMaterialShinyNormalAlphaTest.mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredMaterialShinyNormalAlphaTest.mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredMaterialShinyNormalAlphaTest.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		gDeferredMaterialShinyNormalAlphaTest.addPermutation("NORMAL_MATERIAL", "1");
+		gDeferredMaterialShinyNormalAlphaTest.addPermutation("SHINY_MATERIAL", "1");
+		gDeferredMaterialShinyNormalAlphaTest.addPermutation("ALPHA_TEST", "1");
+		success = gDeferredMaterialShinyNormalAlphaTest.createShader(NULL, NULL);
+	}
+	
+	if (success)
+	{
+		gDeferredMaterialShinyEmissive.mName = "Deferred Emissive Mask Shiny Material Shader";
+		gDeferredMaterialShinyEmissive.mShaderFiles.clear();
+		gDeferredMaterialShinyEmissive.mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredMaterialShinyEmissive.mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredMaterialShinyEmissive.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		gDeferredMaterialShinyEmissive.addPermutation("SHINY_MATERIAL", "1");
+		gDeferredMaterialShinyEmissive.addPermutation("EMISSIVE_MASK", "1");
+		success = gDeferredMaterialShinyEmissive.createShader(NULL, NULL);
+	}
+	
+	if (success)
+	{
+		gDeferredMaterialNormalEmissive.mName = "Deferred Emissive Mask Normal Mapped Material Shader";
+		gDeferredMaterialNormalEmissive.mShaderFiles.clear();
+		gDeferredMaterialNormalEmissive.mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredMaterialNormalEmissive.mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredMaterialNormalEmissive.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		gDeferredMaterialNormalEmissive.addPermutation("NORMAL_MATERIAL", "1");
+		gDeferredMaterialNormalEmissive.addPermutation("EMISSIVE_MASK", "1");
+		success = gDeferredMaterialNormalEmissive.createShader(NULL, NULL);
+	}
+	
+	if (success)
+	{
+		gDeferredMaterialShinyNormalEmissive.mName = "Deferred Emissive Mask Normal Mapped Material Shader";
+		gDeferredMaterialShinyNormalEmissive.mShaderFiles.clear();
+		gDeferredMaterialShinyNormalEmissive.mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredMaterialShinyNormalEmissive.mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredMaterialShinyNormalEmissive.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		gDeferredMaterialShinyNormalEmissive.addPermutation("NORMAL_MATERIAL", "1");
+		gDeferredMaterialShinyNormalEmissive.addPermutation("SHINY_MATERIAL", "1");
+		gDeferredMaterialShinyNormalEmissive.addPermutation("EMISSIVE_MASK", "1");
+		success = gDeferredMaterialShinyNormalEmissive.createShader(NULL, NULL);
+	}
 
 	if (success)
 	{
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index d6dd645e8c..15bff6882e 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -362,4 +362,15 @@ extern LLGLSLShader			gDeferredWLCloudProgram;
 extern LLGLSLShader			gDeferredStarProgram;
 extern LLGLSLShader			gNormalMapGenProgram;
 
+// Deferred materials shaders
+extern LLGLSLShader			gDeferredMaterialShiny;
+extern LLGLSLShader			gDeferredMaterialNormal;
+extern LLGLSLShader			gDeferredMaterialShinyNormal;
+extern LLGLSLShader			gDeferredMaterialShinyAlphaTest;
+extern LLGLSLShader			gDeferredMaterialNormalAlphaTest;
+extern LLGLSLShader			gDeferredMaterialShinyNormalAlphaTest;
+extern LLGLSLShader			gDeferredMaterialShinyEmissive;
+extern LLGLSLShader			gDeferredMaterialNormalEmissive;
+extern LLGLSLShader			gDeferredMaterialShinyNormalEmissive;
+
 #endif
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 6c073a8e20..324d3de499 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -1995,7 +1995,6 @@ void LLVOVolume::setTEMaterialParamsCallback(const LLMaterialID &pMaterialID, co
 	{
 		if (getTE(i)->getMaterialID() == pMaterialID)
 		{
-			LL_INFOS("Materials") << "Material params callback triggered!" << LL_ENDL;
 			setTEMaterialParams(i, pMaterialParams);
 		}
 	}
@@ -2005,13 +2004,10 @@ S32 LLVOVolume::setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID)
 {
 	if (!pMaterialID.isNull())
 	{
-		LL_INFOS("Materials") << "Oh god it's a material! " << pMaterialID.asString() << LL_ENDL;
 		S32 res = LLViewerObject::setTEMaterialID(te, pMaterialID);
 		if (res)
 		{
-			LL_INFOS("Materials") << "We have a material!" << LL_ENDL;
 			LLMaterialMgr::instance().get(getRegion()->getRegionID(), pMaterialID, boost::bind(&LLVOVolume::setTEMaterialParamsCallback, this, _1, _2));
-			//setTEMaterialParams(te, pMatParam);
 			gPipeline.markTextured(mDrawable);
 			mFaceMappingChanged = TRUE;
 		}
@@ -5215,10 +5211,14 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 							registerFace(group, facep, LLRenderPass::PASS_POST_BUMP);
 						}
 					}
-					else if (te->getBumpmap() || te->getMaterialParams() != NULL)
+					else if (te->getBumpmap() && !te->getMaterialParams())
 					{ //register in deferred bump pass
 						registerFace(group, facep, LLRenderPass::PASS_BUMP);
 					}
+					else if (te->getMaterialParams())
+					{
+						registerFace(group, facep, LLRenderPass::PASS_MATERIALS);
+					}
 					else
 					{ //register in deferred simple pass (deferred simple includes shiny)
 						llassert(mask & LLVertexBuffer::MAP_NORMAL);
@@ -5250,10 +5250,14 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 				}
 				else
 				{
-					if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && (te->getBumpmap() || te->getMaterialParams()))
+					if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && (te->getBumpmap() && !te->getMaterialParams()))
 					{ //non-shiny or fullbright deferred bump
 						registerFace(group, facep, LLRenderPass::PASS_BUMP);
 					}
+					else if (te->getMaterialParams())
+					{
+						registerFace(group, facep, LLRenderPass::PASS_MATERIALS);
+					}
 					else
 					{ //all around simple
 						llassert(mask & LLVertexBuffer::MAP_NORMAL);
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index ea7de6f399..8ee4cd7713 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -233,6 +233,7 @@ LLFastTimer::DeclareTimer FTM_RENDER_WL_SKY("Windlight Sky");
 LLFastTimer::DeclareTimer FTM_RENDER_ALPHA("Alpha Objects");
 LLFastTimer::DeclareTimer FTM_RENDER_CHARACTERS("Avatars");
 LLFastTimer::DeclareTimer FTM_RENDER_BUMP("Bump");
+LLFastTimer::DeclareTimer FTM_RENDER_MATERIALS("Materials");
 LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT("Fullbright");
 LLFastTimer::DeclareTimer FTM_RENDER_GLOW("Glow");
 LLFastTimer::DeclareTimer FTM_GEO_UPDATE("Geo Update");
@@ -262,6 +263,7 @@ std::string gPoolNames[] =
 	"POOL_GROUND",
 	"POOL_FULLBRIGHT",
 	"POOL_BUMP",
+	"POOL_MATERIALS",
 	"POOL_TERRAIN,"	
 	"POOL_SKY",
 	"POOL_WL_SKY",
@@ -490,6 +492,7 @@ void LLPipeline::init()
 	getPool(LLDrawPool::POOL_FULLBRIGHT);
 	getPool(LLDrawPool::POOL_INVISIBLE);
 	getPool(LLDrawPool::POOL_BUMP);
+	getPool(LLDrawPool::POOL_MATERIALS);
 	getPool(LLDrawPool::POOL_GLOW);
 
 	LLViewerStats::getInstance()->mTrianglesDrawnStat.reset();
@@ -1520,7 +1523,9 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0)
 	case LLDrawPool::POOL_BUMP:
 		poolp = mBumpPool;
 		break;
-
+	case LLDrawPool::POOL_MATERIALS:
+		poolp = mMaterialsPool;
+		break;
 	case LLDrawPool::POOL_ALPHA:
 		poolp = mAlphaPool;
 		break;
@@ -1598,9 +1603,12 @@ U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerTexture* ima
 	{
 		return LLDrawPool::POOL_ALPHA;
 	}
-	else if ((te->getBumpmap() || te->getShiny()))
+	else if ((te->getBumpmap() || te->getShiny()) && te->getMaterialID().isNull())
 	{
 		return LLDrawPool::POOL_BUMP;
+	} else if (!te->getMaterialID().isNull() && !alpha)
+	{
+		return LLDrawPool::POOL_MATERIALS;
 	}
 	else
 	{
@@ -5421,7 +5429,17 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp )
 			mBumpPool = new_poolp;
 		}
 		break;
-
+	case LLDrawPool::POOL_MATERIALS:
+		if (mMaterialsPool)
+		{
+			llassert(0);
+			llwarns << "Ignorning duplicate materials pool." << llendl;
+		}
+		else
+		{
+			mMaterialsPool = new_poolp;
+		}
+		break;
 	case LLDrawPool::POOL_ALPHA:
 		if( mAlphaPool )
 		{
@@ -5562,7 +5580,12 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
 		llassert( poolp == mBumpPool );
 		mBumpPool = NULL;
 		break;
-	
+			
+	case LLDrawPool::POOL_MATERIALS:
+		llassert(poolp == mMaterialsPool);
+		mMaterialsPool = NULL;
+		break;
+			
 	case LLDrawPool::POOL_ALPHA:
 		llassert( poolp == mAlphaPool );
 		mAlphaPool = NULL;
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index e264081910..22a0ca6a2f 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -95,6 +95,7 @@ extern LLFastTimer::DeclareTimer FTM_RENDER_WL_SKY;
 extern LLFastTimer::DeclareTimer FTM_RENDER_ALPHA;
 extern LLFastTimer::DeclareTimer FTM_RENDER_CHARACTERS;
 extern LLFastTimer::DeclareTimer FTM_RENDER_BUMP;
+extern LLFastTimer::DeclareTimer FTM_RENDER_MATERIALS;
 extern LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT;
 extern LLFastTimer::DeclareTimer FTM_RENDER_GLOW;
 extern LLFastTimer::DeclareTimer FTM_STATESORT;
@@ -419,6 +420,7 @@ public:
 		RENDER_TYPE_GRASS						= LLDrawPool::POOL_GRASS,
 		RENDER_TYPE_FULLBRIGHT					= LLDrawPool::POOL_FULLBRIGHT,
 		RENDER_TYPE_BUMP						= LLDrawPool::POOL_BUMP,
+		RENDER_TYPE_MATERIALS					= LLDrawPool::POOL_MATERIALS,
 		RENDER_TYPE_AVATAR						= LLDrawPool::POOL_AVATAR,
 		RENDER_TYPE_TREE						= LLDrawPool::POOL_TREE,
 		RENDER_TYPE_INVISIBLE					= LLDrawPool::POOL_INVISIBLE,
@@ -435,6 +437,7 @@ public:
 		RENDER_TYPE_PASS_SHINY					= LLRenderPass::PASS_SHINY,
 		RENDER_TYPE_PASS_BUMP					= LLRenderPass::PASS_BUMP,
 		RENDER_TYPE_PASS_POST_BUMP				= LLRenderPass::PASS_POST_BUMP,
+		RENDER_TYPE_PASS_MATERIALS				= LLRenderPass::PASS_MATERIALS,
 		RENDER_TYPE_PASS_GLOW					= LLRenderPass::PASS_GLOW,
 		RENDER_TYPE_PASS_ALPHA					= LLRenderPass::PASS_ALPHA,
 		RENDER_TYPE_PASS_ALPHA_MASK				= LLRenderPass::PASS_ALPHA_MASK,
@@ -776,6 +779,7 @@ protected:
 	LLDrawPool*					mInvisiblePool;
 	LLDrawPool*					mGlowPool;
 	LLDrawPool*					mBumpPool;
+	LLDrawPool*					mMaterialsPool;
 	LLDrawPool*					mWLSkyPool;
 	// Note: no need to keep an quick-lookup to avatar pools, since there's only one per avatar
 	
-- 
cgit v1.2.3