From aa1befd689703d9fea50399201911e0f8fca6ac6 Mon Sep 17 00:00:00 2001
From: Geenz <geenz@geenzo.com>
Date: Wed, 30 Jan 2013 12:17:04 -0500
Subject: [PATCH] Specular map support.  This is the vast majority of the
 material parameters implemented at this point for opaque geometry.

---
 indra/llrender/llshadermgr.cpp                |  1 +
 indra/llrender/llshadermgr.h                  |  1 +
 .../shaders/class1/deferred/bumpF.glsl        | 21 ++++++++++------
 .../shaders/class1/deferred/softenLightF.glsl |  6 ++---
 .../shaders/class2/deferred/softenLightF.glsl |  6 ++---
 indra/newview/lldrawpoolbump.cpp              | 19 +++++++++++---
 indra/newview/lldrawpoolbump.h                |  5 ++--
 indra/newview/llface.cpp                      |  6 +++--
 indra/newview/llspatialpartition.cpp          |  7 +++++-
 indra/newview/llviewerobject.cpp              | 11 +++-----
 indra/newview/llvovolume.cpp                  | 18 +++++++++++--
 indra/newview/pipeline.cpp                    | 25 ++++++++-----------
 12 files changed, 78 insertions(+), 48 deletions(-)

diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index b6b39028d3c..9b2874c79d9 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -1126,6 +1126,7 @@ void LLShaderMgr::initAttribsAndUniforms()
 	mReservedUniforms.push_back("texture_gamma");
 	
 	mReservedUniforms.push_back("specular_color");
+	mReservedUniforms.push_back("env_intensity");
 
 	llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS);
 
diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h
index a89e0319069..1c97ab4e609 100644
--- a/indra/llrender/llshadermgr.h
+++ b/indra/llrender/llshadermgr.h
@@ -169,6 +169,7 @@ class LLShaderMgr
 		TEXTURE_GAMMA,
 		
 		SPECULAR_COLOR,
+		ENVIRONMENT_INTENSITY,
 		
 		END_RESERVED_UNIFORMS
 	} eGLSLReservedUniforms;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
index 23c4ea2fffd..6e5cc69e393 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
@@ -31,6 +31,9 @@ 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;
@@ -42,15 +45,17 @@ VARYING vec2 vary_texcoord0;
 void main() 
 {
 	vec3 col = vertex_color.rgb * texture2D(diffuseMap, vary_texcoord0.xy).rgb;
-	vec3 norm = texture2D(bumpMap, vary_texcoord0.xy).rgb * 2.0 - 1.0;
+	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,vary_mat0),
-			  dot(norm,vary_mat1),
-			  dot(norm,vary_mat2));
-						
-	frag_data[0] = vec4(col, 0.0);
-	frag_data[1] = vertex_color.aaaa; // spec
+	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
 	//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, 0.0);
+	frag_data[2] = vec4(nvn.xyz * 0.5 + 0.5, spec.a * env_intensity);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
index 87cdf1026f4..2ec3fe4a52a 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
@@ -280,8 +280,8 @@ void main()
 	vec2 tc = vary_fragcoord.xy;
 	float depth = texture2DRect(depthMap, tc.xy).r;
 	vec3 pos = getPosition_d(tc, depth).xyz;
-	vec3 norm = texture2DRect(normalMap, tc).xyz;
-	norm = (norm.xyz-0.5)*2.0; // unpack norm
+	vec4 norm = texture2DRect(normalMap, tc);
+	norm.xyz = (norm.xyz-0.5)*2.0; // unpack norm
 		
 	float da = max(dot(norm.xyz, sun_dir.xyz), 0.0);
 	
@@ -315,7 +315,7 @@ void main()
 			//add environmentmap
 			vec3 env_vec = env_mat * refnormpersp;
 			col = mix(col.rgb, samplesRGB(textureCube(environmentMap, env_vec).rgb) * 2.2, 
-				max(spec.a-diffuse.a*2.0, 0.0)); 
+				max(norm.a-diffuse.a*2.0, 0.0)); 
 		}
 	
 		col = atmosLighting(col);
diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
index bf4c4761387..e95991a6356 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
@@ -283,8 +283,8 @@ void main()
 	vec2 tc = vary_fragcoord.xy;
 	float depth = texture2DRect(depthMap, tc.xy).r;
 	vec3 pos = getPosition_d(tc, depth).xyz;
-	vec3 norm = texture2DRect(normalMap, tc).xyz;
-	norm = (norm.xyz-0.5)*2.0; // unpack norm
+	vec4 norm = texture2DRect(normalMap, tc);
+	norm.xyz = (norm.xyz-0.5)*2.0; // unpack norm
 		
 	float da = max(dot(norm.xyz, sun_dir.xyz), 0.0);
 	
@@ -324,7 +324,7 @@ void main()
 			//add environmentmap
 			vec3 env_vec = env_mat * refnormpersp;
 			col = mix(col.rgb, samplesRGB(textureCube(environmentMap, env_vec).rgb) * 2.2, 
-				max(spec.a-diffuse.a*2.0, 0.0)); 
+				max(norm.a-diffuse.a*2.0, 0.0)); 
 		}
 			
 		col = atmosLighting(col);
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index fcc81dc723f..07384a136a8 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()
 {
@@ -634,7 +634,7 @@ BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params, S32 channel)
 	U8 bump_code = params.mBump;
 	if (params.mNormalMap.notNull())
 	{
-		bump_code = BE_CUSTOM;
+		bump_code = 99;
 		return bindBumpMap(bump_code, params.mNormalMap, params.mVSize, channel);
 	}
 
@@ -675,7 +675,7 @@ BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsi
 	case BE_DARKNESS:
 		bump = gBumpImageList.getBrightnessDarknessImage( tex, bump_code );		
 		break;
-	case BE_CUSTOM:
+	case 99:
 		bump = tex;
 		bump->addTextureStats(vsize);
 		break;
@@ -828,6 +828,7 @@ 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);
 }
@@ -842,6 +843,7 @@ 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();
 }
@@ -864,7 +866,16 @@ void LLDrawPoolBump::renderDeferred(S32 pass)
 	{
 		LLDrawInfo& params = **i;
 		
-		gDeferredBumpProgram.uniform4fv(LLShaderMgr::SPECULAR_COLOR, 4, (GLfloat*)params.mSpecColor.mV);
+		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/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index aaf0bdf36fa..476b1d41b7d 100644
--- a/indra/newview/lldrawpoolbump.h
+++ b/indra/newview/lldrawpoolbump.h
@@ -100,9 +100,8 @@ enum EBumpEffect
 	BE_NO_BUMP = 0,
 	BE_BRIGHTNESS = 1,
 	BE_DARKNESS = 2,
-	BE_CUSTOM = 3,
-	BE_STANDARD_0 = 4,  // Standard must always be the last one
-	BE_COUNT = 5
+	BE_STANDARD_0 = 3,  // Standard must always be the last one
+	BE_COUNT = 4
 };
 
 ////////////////////////////////////////////////////////////////
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 01cbfafe162..cd848152952 100755
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -2077,9 +2077,11 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			LLFastTimer t(FTM_FACE_GEOM_BINORMAL);
 			mVertexBuffer->getBinormalStrider(binorm, mGeomIndex, mGeomCount, map_range);
 			F32* binormals = (F32*) binorm.get();
-		
+			
+			mVObjp->getVolume()->genBinormals(f);
+			
 			for (S32 i = 0; i < num_vertices; i++)
-			{	
+			{
 				LLVector4a binormal;
 				mat_normal.rotate(vf.mBinormals[i], binormal);
 				binormal.normalize3fast();
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 2083afdcf59..8a62f229851 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -4672,7 +4672,12 @@ LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset,
 	mGroup(NULL),
 	mFace(NULL),
 	mDistance(0.f),
-	mDrawMode(LLRender::TRIANGLES)
+	mDrawMode(LLRender::TRIANGLES),
+	mSpecColor(1.0f, 1.0f, 1.0f, 0.5f),
+	mEnvIntensity(0.0f),
+	mAlphaMaskCutoff(0.5f),
+	mDiffuseAlphaMode(0),
+	mMaterialID(NULL)
 {
 	mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
 	
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 78c5b3ac53c..b8de345a9a9 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -4108,12 +4108,10 @@ S32 LLViewerObject::setTETextureCore(const U8 te, const LLUUID& uuid, LLHost hos
 
 S32 LLViewerObject::setTENormalMapCore(const U8 te, const LLUUID& uuid, LLHost host)
 {
-	LL_INFOS("Materials") << "Maybe normal maps! " << uuid << LL_ENDL;
 	S32 retval = 0;
 	//if (uuid != getTE(te)->getMaterialParams()->getNormalID() ||
-		//uuid == LLUUID::null)
+	//	uuid == LLUUID::null)
 	{
-		LL_INFOS("Materials") << "Normal maps! " << uuid << LL_ENDL;
 		retval = TEM_CHANGE_TEXTURE;
 		getTE(te)->getMaterialParams()->setNormalID(uuid);
 		mTENormalMaps[te] = LLViewerTextureManager::getFetchedTexture(uuid, TRUE, LLViewerTexture::BOOST_BUMP, LLViewerTexture::LOD_TEXTURE, 0, 0, host);
@@ -4128,12 +4126,10 @@ S32 LLViewerObject::setTENormalMapCore(const U8 te, const LLUUID& uuid, LLHost h
 
 S32 LLViewerObject::setTESpecularMapCore(const U8 te, const LLUUID& uuid, LLHost host)
 {
-	LL_INFOS("Materials") << "Maybe specular maps! " << uuid << LL_ENDL;
 	S32 retval = 0;
-	if (uuid != getTE(te)->getMaterialParams()->getSpecularID()	||
-		uuid == LLUUID::null)
+	//if (uuid != getTE(te)->getMaterialParams()->getSpecularID()	||
+	//	uuid == LLUUID::null)
 	{
-		LL_INFOS("Materials") << "Specular maps! " << uuid << LL_ENDL;
 		retval = TEM_CHANGE_TEXTURE;
 		getTE(te)->getMaterialParams()->setSpecularID(uuid);
 		mTESpecularMaps[te] = LLViewerTextureManager::getFetchedTexture(uuid, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host);
@@ -4381,6 +4377,7 @@ S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMateri
 	{
 		retval = LLPrimitive::setTEMaterialParams(te, pMaterialParams);
 		setTENormalMap(te, tep->getMaterialParams()->getNormalID());
+		setTESpecularMap(te, tep->getMaterialParams()->getSpecularID());
 		setChanged(TEXTURE);
 		if (mDrawable.notNull() && retval)
 		{
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 8cf22d9808d..c9d6a34b8a0 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -4172,12 +4172,26 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 				specColor.mV[2] = facep->getTextureEntry()->getMaterialParams()->getSpecularLightColor().mV[2] * (1.0 / 255);
 				specColor.mV[3] = facep->getTextureEntry()->getMaterialParams()->getSpecularLightExponent() * (1.0 / 255);
 				draw_info->mSpecColor = specColor;
+				LL_INFOS("Materials") << "Specular Color: " << specColor << LL_ENDL;
 				draw_info->mEnvIntensity = facep->getTextureEntry()->getMaterialParams()->getEnvironmentIntensity() * (1.0 / 255);
 				draw_info->mAlphaMaskCutoff = facep->getTextureEntry()->getMaterialParams()->getAlphaMaskCutoff() * (1.0 / 255);
 				draw_info->mDiffuseAlphaMode = facep->getTextureEntry()->getMaterialParams()->getDiffuseAlphaMode();
 				draw_info->mNormalMap = facep->getViewerObject()->getTENormalMap(facep->getTextureIndex());
 				draw_info->mSpecularMap = facep->getViewerObject()->getTESpecularMap(facep->getTextureIndex());
 			}
+		} else {
+			U8 shiny = facep->getTextureEntry()->getShiny();
+			float alpha[4] =
+			{
+				0.00f,
+				0.25f,
+				0.5f,
+				0.75f
+			};
+			float spec = alpha[shiny];
+			LLVector4 specColor(spec, spec, spec, spec);
+			draw_info->mSpecColor = specColor;
+			draw_info->mEnvIntensity = spec;
 		}
 		
 		if (type == LLRenderPass::PASS_ALPHA)
@@ -4631,7 +4645,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 						if (gPipeline.canUseWindLightShadersOnObjects()
 							&& LLPipeline::sRenderBump)
 						{
-							if (te->getBumpmap())
+							if (te->getBumpmap() || te->getMaterialParams()	!= NULL)
 							{ //needs normal + binormal
 								bump_faces.push_back(facep);
 							}
@@ -5237,7 +5251,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 				}
 				else
 				{
-					if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && (te->getBumpmap() || te->getMaterialParams() != NULL))
+					if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && (te->getBumpmap() || te->getMaterialParams()))
 					{ //non-shiny or fullbright deferred bump
 						registerFace(group, facep, LLRenderPass::PASS_BUMP);
 					}
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 07246391e39..ea7de6f3993 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -1262,31 +1262,26 @@ void LLPipeline::createLUTBuffers()
 			U32 lightResY = gSavedSettings.getU32("RenderSpecularResY");
 			F32* ls = new F32[lightResX*lightResY];
 			//F32 specExp = gSavedSettings.getF32("RenderSpecularExponent"); // Note: only use this when creating new specular lighting functions.
-            // Calculate the (normalized) Gaussian specular lookup texture. (with a few tweaks)
+            // Calculate the (normalized) blinn-phong specular lookup texture. (with a few tweaks)
 			for (U32 y = 0; y < lightResY; ++y)
 			{
 				for (U32 x = 0; x < lightResX; ++x)
 				{
 					ls[y*lightResX+x] = 0;
 					F32 sa = (F32) x/(lightResX-1);
-					F32 spec = (F32) y/(lightResY);
-					F32 n = spec;
+					F32 spec = (F32) y/(lightResY-1);
+					F32 n = spec * spec * 368;
 					
-					float angleNormalHalf = acosf(sa);
-					float exponent = angleNormalHalf / ((1 - n));
-					exponent = -(exponent * exponent);
-					spec = expf(exponent);
+					// Nothing special here.  Just your typical blinn-phong term.
+					spec = powf(sa, n);
 					
 					// Apply our normalization function.
-					// This is based around the phong normalization function, trading n+2 for n+1 instead.
-					// Since we're using a gaussian model here, we actually don't really need as large of an exponent as blinn-phong shading.
-					// Instead, we assume that the correct exponent is 8 here.
-					// This was achieved through much tweaking to find a decent "middleground" with our specular highlights with the gaussian term.
-					// Bigger highlights don't look too soft, smaller highlights don't look too bright, and everything in the middle seems to have a well maintained highlight curvature.
-					// There isn't really much theory behind this one.  This was done purely to produce a nice and mostly customizable BRDF.
-					
-					spec = lerpf(spec, spec * (n * 8 + 1) / 4.5, n);
+					// Note: This is the full equation that applies the full normalization curve, not an approximation.
+					// This is fine, given we only need to create our LUT once per buffer initialization.
+					spec *= (((n + 2) * (n + 4)) / (8 * F_PI * (powf(2, -n/2) + n)));
 					
+					// Since we use R16F, we no longer have a dynamic range issue we need to work around here.
+					// Though some older drivers may not like this, newer drivers shouldn't have this problem.
 					ls[y*lightResX+x] = spec;
 				}
 			}
-- 
GitLab