Microsoft windows builds

Index: /branches/shadow-draft/doc/asset_urls.txt
===================================================================
--- /branches/shadow-draft/doc/asset_urls.txt (revision 573)
+++ /branches/shadow-draft/doc/asset_urls.txt (revision 575)
@@ -2,7 +2,7 @@
 # https://wiki.secondlife.com/wiki/Get_source_and_compile
 
-SLASSET_MD5=http://secondlife.com/developers/opensource/downloads/2008/05/md5sums-shadow-draft-r87567.txt
-SLASSET_ART=http://secondlife.com/developers/opensource/downloads/2008/05/slviewer-artwork-shadow-draft-r87567.zip
-SLASSET_LIBS_DARWIN=http://secondlife.com/developers/opensource/downloads/2008/05/slviewer-darwin-libs-shadow-draft-r87567.tar.gz
-SLASSET_LIBS_WIN32=http://secondlife.com/developers/opensource/downloads/2008/05/slviewer-win32-libs-shadow-draft-r87567.zip
-SLASSET_LIBS_LINUXI386=http://secondlife.com/developers/opensource/downloads/2008/05/slviewer-linux-libs-shadow-draft-r87567.tar.gz
+SLASSET_MD5=http://secondlife.com/developers/opensource/downloads/2008/05/md5sums-shadow-draft-r87814.txt
+SLASSET_ART=http://secondlife.com/developers/opensource/downloads/2008/05/slviewer-artwork-shadow-draft-r87814.zip
+SLASSET_LIBS_DARWIN=http://secondlife.com/developers/opensource/downloads/2008/05/slviewer-darwin-libs-shadow-draft-r87814.tar.gz
+SLASSET_LIBS_WIN32=http://secondlife.com/developers/opensource/downloads/2008/05/slviewer-win32-libs-shadow-draft-r87814.zip
+SLASSET_LIBS_LINUXI386=http://secondlife.com/developers/opensource/downloads/2008/05/slviewer-linux-libs-shadow-draft-r87814.tar.gz
Index: /branches/shadow-draft/indra/llcommon/llfasttimer.h
===================================================================
--- /branches/shadow-draft/indra/llcommon/llfasttimer.h (revision 280)
+++ /branches/shadow-draft/indra/llcommon/llfasttimer.h (revision 575)
@@ -185,9 +185,11 @@
 	
 public:
+	static LLFastTimer::EFastTimerType sCurType;
+
 	LLFastTimer(EFastTimerType type)
 	{
 #if FAST_TIMER_ON
 		mType = type;
-
+		sCurType = type;
 		// These don't get counted, because they use CPU clockticks
 		//gTimerBins[gCurTimerBin]++;
Index: /branches/shadow-draft/indra/llcommon/llfasttimer.cpp
===================================================================
--- /branches/shadow-draft/indra/llcommon/llfasttimer.cpp (revision 173)
+++ /branches/shadow-draft/indra/llcommon/llfasttimer.cpp (revision 575)
@@ -49,4 +49,6 @@
 // statics
 
+
+LLFastTimer::EFastTimerType LLFastTimer::sCurType = LLFastTimer::FTM_OTHER;
 int LLFastTimer::sCurDepth = 0;
 U64 LLFastTimer::sStart[LLFastTimer::FTM_MAX_DEPTH];
Index: /branches/shadow-draft/indra/newview/lldrawpoolavatar.h
===================================================================
--- /branches/shadow-draft/indra/newview/lldrawpoolavatar.h (revision 280)
+++ /branches/shadow-draft/indra/newview/lldrawpoolavatar.h (revision 575)
@@ -74,4 +74,19 @@
 	/*virtual*/ void renderForSelect();
 
+	/*virtual*/ S32 getNumDeferredPasses();
+	/*virtual*/ void beginDeferredPass(S32 pass);
+	/*virtual*/ void endDeferredPass(S32 pass);
+	/*virtual*/ void renderDeferred(S32 pass);
+
+	/*virtual*/ S32 getNumPostDeferredPasses();
+	/*virtual*/ void beginPostDeferredPass(S32 pass);
+	/*virtual*/ void endPostDeferredPass(S32 pass);
+	/*virtual*/ void renderPostDeferred(S32 pass);
+
+	/*virtual*/ S32 getNumShadowPasses();
+	/*virtual*/ void beginShadowPass(S32 pass);
+	/*virtual*/ void endShadowPass(S32 pass);
+	/*virtual*/ void renderShadow(S32 pass);
+
 	void beginRigid();
 	void beginFootShadow();
@@ -81,4 +96,12 @@
 	void endFootShadow();
 	void endSkinned();
+
+	void beginDeferredImpostor();
+	void beginDeferredRigid();
+	void beginDeferredSkinned();
+	
+	void endDeferredImpostor();
+	void endDeferredRigid();
+	void endDeferredSkinned();
 		
 	/*virtual*/ LLViewerImage *getDebugTexture();
@@ -86,4 +109,6 @@
 
 	void renderAvatars(LLVOAvatar *single_avatar, S32 pass = -1); // renders only one avatar if single_avatar is not null.
+
+	static BOOL sSkipOpaque;
 };
 
Index: /branches/shadow-draft/indra/newview/lldrawpoolterrain.h
===================================================================
--- /branches/shadow-draft/indra/newview/lldrawpoolterrain.h (revision 280)
+++ /branches/shadow-draft/indra/newview/lldrawpoolterrain.h (revision 575)
@@ -48,5 +48,5 @@
 	};
 
-	virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
+	virtual U32 getVertexDataMask();
 	static S32 getDetailMode();
 
@@ -56,4 +56,13 @@
 	/*virtual*/ LLDrawPool *instancePool();
 
+	/*virtual*/ S32 getNumDeferredPasses() { return 1; }
+	/*virtual*/ void beginDeferredPass(S32 pass);
+	/*virtual*/ void endDeferredPass(S32 pass);
+	/*virtual*/ void renderDeferred(S32 pass);
+
+	/*virtual*/ S32 getNumShadowPasses() { return 1; }
+	/*virtual*/ void beginShadowPass(S32 pass);
+	/*virtual*/ void endShadowPass(S32 pass);
+	/*virtual*/ void renderShadow(S32 pass);
 
 	/*virtual*/ void render(S32 pass = 0);
Index: /branches/shadow-draft/indra/newview/llviewerjointmesh.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/llviewerjointmesh.cpp (revision 573)
+++ /branches/shadow-draft/indra/newview/llviewerjointmesh.cpp (revision 575)
@@ -459,9 +459,6 @@
 			{
 				F32* vector = gJointMatUnaligned[joint_num].mMatrix[axis];
-				//glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB, LL_CHARACTER_MAX_JOINTS_PER_MESH * axis + joint_num+5, (GLfloat*)vector);
 				U32 offset = LL_CHARACTER_MAX_JOINTS_PER_MESH*axis+joint_num;
 				memcpy(mat+offset*4, vector, sizeof(GLfloat)*4);
-				//glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB, LL_CHARACTER_MAX_JOINTS_PER_MESH * axis + joint_num+6, (GLfloat*)vector);
-				//cgGLSetParameterArray4f(gPipeline.mAvatarMatrix, offset, 1, vector);
 			}
 		}
Index: /branches/shadow-draft/indra/newview/llviewercontrol.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/llviewercontrol.cpp (revision 573)
+++ /branches/shadow-draft/indra/newview/llviewercontrol.cpp (revision 575)
@@ -355,5 +355,5 @@
 static bool handleRenderUseImpostorsChanged(const LLSD& newvalue)
 {
-	LLVOAvatar::sUseImpostors = FALSE; //newvalue.asBoolean();
+	LLVOAvatar::sUseImpostors = newvalue.asBoolean();
 	return true;
 }
Index: /branches/shadow-draft/indra/newview/lldrawpoolsimple.h
===================================================================
--- /branches/shadow-draft/indra/newview/lldrawpoolsimple.h (revision 280)
+++ /branches/shadow-draft/indra/newview/lldrawpoolsimple.h (revision 575)
@@ -49,8 +49,39 @@
 	LLDrawPoolSimple();
 	
+	/*virtual*/ S32 getNumDeferredPasses() { return 1; }
+	/*virtual*/ void beginDeferredPass(S32 pass);
+	/*virtual*/ void endDeferredPass(S32 pass);
+	/*virtual*/ void renderDeferred(S32 pass);
+
 	/*virtual*/ void beginRenderPass(S32 pass);
 	/*virtual*/ void endRenderPass(S32 pass);
 	/// We need two passes so we can handle emissive materials separately.
 	/*virtual*/ S32	 getNumPasses() { return 1; }
+	/*virtual*/ void render(S32 pass = 0);
+	/*virtual*/ void prerender();
+
+};
+
+class LLDrawPoolFullbright : public LLRenderPass
+{
+public:
+	enum
+	{
+		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
+							LLVertexBuffer::MAP_TEXCOORD |
+							LLVertexBuffer::MAP_COLOR
+	};
+	virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
+
+	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 beginRenderPass(S32 pass);
+	/*virtual*/ void endRenderPass(S32 pass);
+	/*virtual*/ S32	 getNumPasses();
 	/*virtual*/ void render(S32 pass = 0);
 	/*virtual*/ void prerender();
@@ -73,4 +104,9 @@
 	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); }
+
 	void render(S32 pass = 0);
 	void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture = TRUE);
Index: /branches/shadow-draft/indra/newview/lldrawpoolterrain.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/lldrawpoolterrain.cpp (revision 573)
+++ /branches/shadow-draft/indra/newview/lldrawpoolterrain.cpp (revision 575)
@@ -100,4 +100,16 @@
 
 
+U32 LLDrawPoolTerrain::getVertexDataMask() 
+{ 
+	if (LLPipeline::sShadowRender)
+	{
+		return LLVertexBuffer::MAP_VERTEX;
+	}
+	else
+	{
+		return VERTEX_DATA_MASK; 
+	}
+}
+
 void LLDrawPoolTerrain::prerender()
 {
@@ -217,4 +229,58 @@
 }
 
+void LLDrawPoolTerrain::beginDeferredPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN);
+	LLFacePool::beginRenderPass(pass);
+
+	sShader = &gDeferredTerrainProgram;
+
+	sShader->bind();
+}
+
+void LLDrawPoolTerrain::endDeferredPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN);
+	LLFacePool::endRenderPass(pass);
+	sShader->unbind();
+}
+
+void LLDrawPoolTerrain::renderDeferred(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN);
+	if (mDrawFace.empty())
+	{
+		return;
+	}
+	renderFullShader();
+}
+
+void LLDrawPoolTerrain::beginShadowPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN);
+	LLFacePool::beginRenderPass(pass);
+	LLViewerImage::unbindTexture(0);
+	gDeferredShadowProgram.bind();
+}
+
+void LLDrawPoolTerrain::endShadowPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN);
+	LLFacePool::endRenderPass(pass);
+	gDeferredShadowProgram.unbind();
+}
+
+void LLDrawPoolTerrain::renderShadow(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN);
+	if (mDrawFace.empty())
+	{
+		return;
+	}
+	//LLGLEnable offset(GL_POLYGON_OFFSET);
+	glCullFace(GL_FRONT);
+	drawLoop();
+	glCullFace(GL_BACK);
+}
 
 void LLDrawPoolTerrain::renderFullShader()
Index: /branches/shadow-draft/indra/newview/llvoavatar.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/llvoavatar.cpp (revision 573)
+++ /branches/shadow-draft/indra/newview/llvoavatar.cpp (revision 575)
@@ -3997,5 +3997,5 @@
 				mEyeLashLOD.updateGeometry();
 				mHeadLOD.updateGeometry();
-				mHairLOD.updateGeometry();				
+				mHairLOD.updateGeometry();
 			}
 			mNeedsSkin = FALSE;
@@ -4094,16 +4094,20 @@
 	{
 		BOOL first_pass = TRUE;
-		if (!mIsSelf || gAgent.needsRenderHead())
-		{
-			num_indices += mHeadLOD.render(mAdjustedPixelArea);
-			first_pass = FALSE;
-		}
-		num_indices += mUpperBodyLOD.render(mAdjustedPixelArea, first_pass);
-		num_indices += mLowerBodyLOD.render(mAdjustedPixelArea, FALSE);
-
+		if (!LLDrawPoolAvatar::sSkipOpaque)
+		{
+			if (!mIsSelf || gAgent.needsRenderHead())
+			{
+				num_indices += mHeadLOD.render(mAdjustedPixelArea);
+				first_pass = FALSE;
+			}
+			num_indices += mUpperBodyLOD.render(mAdjustedPixelArea, first_pass);
+			num_indices += mLowerBodyLOD.render(mAdjustedPixelArea, FALSE);
+		}
+
+		if (!LLPipeline::sRenderDeferred || LLPipeline::sImpostorRender)
 		{
 			LLGLEnable blend(GL_BLEND);
 			LLGLEnable test(GL_ALPHA_TEST);
-			num_indices += renderTransparent();
+			num_indices += renderTransparent(first_pass);
 		}
 	}
@@ -4118,8 +4122,7 @@
 }
 
-U32 LLVOAvatar::renderTransparent()
+U32 LLVOAvatar::renderTransparent(BOOL first_pass)
 {
 	U32 num_indices = 0;
-	BOOL first_pass = FALSE;
 	if( isWearingWearableType( WT_SKIRT ) )
 	{
@@ -9724,5 +9727,5 @@
 BOOL LLVOAvatar::needsImpostorUpdate() const
 {
-	return mNeedsImpostorUpdate ;
+	return mNeedsImpostorUpdate;
 }
 
Index: /branches/shadow-draft/indra/newview/lldrawpool.h
===================================================================
--- /branches/shadow-draft/indra/newview/lldrawpool.h (revision 515)
+++ /branches/shadow-draft/indra/newview/lldrawpool.h (revision 575)
@@ -53,4 +53,5 @@
 		// Correspond to LLPipeline render type
 		POOL_SIMPLE = 1,
+		POOL_FULLBRIGHT,
 		POOL_TERRAIN,	
 		POOL_TREE,
@@ -78,5 +79,21 @@
 	virtual void beginRenderPass( S32 pass );
 	virtual void endRenderPass( S32 pass );
-	virtual S32	 getNumPasses() { return 1; }
+	virtual S32	 getNumPasses();
+	
+	virtual void beginDeferredPass(S32 pass);
+	virtual void endDeferredPass(S32 pass);
+	virtual S32 getNumDeferredPasses();
+	virtual void renderDeferred(S32 pass = 0);
+
+	virtual void beginPostDeferredPass(S32 pass);
+	virtual void endPostDeferredPass(S32 pass);
+	virtual S32 getNumPostDeferredPasses();
+	virtual void renderPostDeferred(S32 pass = 0);
+
+	virtual void beginShadowPass(S32 pass);
+	virtual void endShadowPass(S32 pass);
+	virtual S32 getNumShadowPasses();
+	virtual void renderShadow(S32 pass = 0);
+
 	virtual void render(S32 pass = 0) = 0;
 	virtual void prerender() = 0;
Index: /branches/shadow-draft/indra/newview/llspatialpartition.h
===================================================================
--- /branches/shadow-draft/indra/newview/llspatialpartition.h (revision 280)
+++ /branches/shadow-draft/indra/newview/llspatialpartition.h (revision 575)
@@ -54,4 +54,7 @@
 S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad);
 
+// get index buffer for binary encoded axis vertex buffer given a box at center being viewed by given camera
+U8* get_box_fan_indices(LLCamera* camera, const LLVector3& center);
+
 class LLDrawInfo : public LLRefCount 
 {
Index: /branches/shadow-draft/indra/newview/llviewerjoint.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/llviewerjoint.cpp (revision 573)
+++ /branches/shadow-draft/indra/newview/llviewerjoint.cpp (revision 575)
@@ -260,4 +260,8 @@
 			triangle_count += drawShape( pixelArea, first_pass );
 		}
+		else if (LLPipeline::sShadowRender)
+		{
+			triangle_count += drawShape(pixelArea, first_pass);
+		}
 		else if ( isTransparent() && !LLPipeline::sReflectionRender)
 		{
@@ -278,5 +282,5 @@
 				}
 				// third past respects z buffer and writes color
-				gGL.setColorMask(true, false);
+				gGL.setColorMask(true, LLPipeline::sRenderDeferred);
 				{
 					LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
Index: /branches/shadow-draft/indra/newview/llvovolume.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/llvovolume.cpp (revision 515)
+++ /branches/shadow-draft/indra/newview/llvovolume.cpp (revision 575)
@@ -2425,4 +2425,5 @@
 				BOOL is_alpha = facep->getPoolType() == LLDrawPool::POOL_ALPHA ? TRUE : FALSE;
 
+			
 				if (!is_alpha 
 					&& gPipeline.canUseWindLightShadersOnObjects()
@@ -2434,4 +2435,8 @@
 						registerFace(group, facep, LLRenderPass::PASS_INVISI_SHINY);
 						registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
+					}
+					else if (LLPipeline::sRenderDeferred)
+					{
+						registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
 					}
 					else if (fullbright)
Index: /branches/shadow-draft/indra/newview/pipeline.h
===================================================================
--- /branches/shadow-draft/indra/newview/pipeline.h (revision 536)
+++ /branches/shadow-draft/indra/newview/pipeline.h (revision 575)
@@ -57,4 +57,5 @@
 class LLCullResult;
 class LLVOAvatar;
+class LLGLSLShader;
 
 typedef enum e_avatar_skinning_method
@@ -75,4 +76,5 @@
 glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar);
 glh::matrix4f gl_perspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar);
+glh::matrix4f gl_lookat(LLVector3 eye, LLVector3 center, LLVector3 up);
 
 class LLPipeline
@@ -88,4 +90,5 @@
 	void releaseGLBuffers();
 	void createGLBuffers();
+	void allocateScreenBuffer(U32 resX, U32 resY);
 
 	void resetVertexBuffers(LLDrawable* drawable);
@@ -182,8 +185,14 @@
 
 	void renderGeom(LLCamera& camera, BOOL forceVBOUpdate = FALSE);
-	void renderGeomDeferred();
-
+	void renderGeomDeferred(LLCamera& camera);
+	void renderGeomPostDeferred(LLCamera& camera);
+	void renderGeomShadow(LLCamera& camera);
+	void bindDeferredShader(LLGLSLShader& shader);
+	void unbindDeferredShader(LLGLSLShader& shader);
+	void renderDeferredLighting();
+	
 	void processImagery(LLCamera& camera);
 	void generateWaterReflection(LLCamera& camera);
+	void generateSunShadow(LLCamera& camera);
 	void renderHighlights();
 	void renderDebug();
@@ -286,4 +295,5 @@
 		RENDER_TYPE_TERRAIN		= LLDrawPool::POOL_TERRAIN,
 		RENDER_TYPE_SIMPLE		= LLDrawPool::POOL_SIMPLE,
+		RENDER_TYPE_FULLBRIGHT	= LLDrawPool::POOL_FULLBRIGHT,
 		RENDER_TYPE_BUMP		= LLDrawPool::POOL_BUMP,
 		RENDER_TYPE_AVATAR		= LLDrawPool::POOL_AVATAR,
@@ -371,4 +381,5 @@
 	static BOOL				sUseFBO;
 	static BOOL				sUseFarClip;
+	static BOOL				sShadowRender;
 	static BOOL				sSkipUpdate; //skip lod updates
 	static BOOL				sDynamicReflections;
@@ -381,8 +392,17 @@
 	static BOOL				sTextureBindTest;
 	static BOOL				sRenderFrameTest;
-	
+	static BOOL				sRenderDeferred;
+	static S32				sVisibleLightCount;
+
 	//screen texture
 	LLRenderTarget			mScreen;
-	
+	LLRenderTarget			mDeferredScreen;
+	LLRenderTarget			mDeferredLight;
+
+	//sun shadow map
+	LLRenderTarget			mSunShadow;
+	glh::matrix4f			mSunShadowMatrix[3];
+	LLVector3				mSunClipPlanes;
+
 	LLVector2				mScreenScale;
 
@@ -406,4 +426,7 @@
 	GLuint					mBlurCubeBuffer[3];
 	GLuint					mBlurCubeTexture[3];
+	
+	//noise map
+	GLuint					mNoiseMap;
 
 	//frambuffer object for rendering dynamic cube maps
@@ -517,4 +540,5 @@
 	LLDrawPool*					mGroundPool;
 	LLRenderPass*				mSimplePool;
+	LLRenderPass*				mFullbrightPool;
 	LLDrawPool*					mInvisiblePool;
 	LLDrawPool*					mGlowPool;
Index: /branches/shadow-draft/indra/newview/llviewermenu.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/llviewermenu.cpp (revision 543)
+++ /branches/shadow-draft/indra/newview/llviewermenu.cpp (revision 575)
@@ -1207,4 +1207,5 @@
 	menu->append(new LLMenuItemCheckGL("Show Time", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowTime"));
 	menu->append(new LLMenuItemCheckGL("Show Render Info", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowRenderInfo"));
+	menu->append(new LLMenuItemCheckGL("Show Matrices", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowRenderMatrices"));
 	menu->append(new LLMenuItemCheckGL("Show Color Under Cursor", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowColor"));
 	
Index: /branches/shadow-draft/indra/newview/llviewerwindow.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/llviewerwindow.cpp (revision 573)
+++ /branches/shadow-draft/indra/newview/llviewerwindow.cpp (revision 575)
@@ -584,7 +584,44 @@
 			ypos += y_inc;
 
+			addText(xpos,ypos, llformat("%d Lights visible", LLPipeline::sVisibleLightCount));
+			
+			ypos += y_inc;
+
 			LLVertexBuffer::sBindCount = LLImageGL::sBindCount = 
 				LLVertexBuffer::sSetCount = LLImageGL::sUniqueCount = 
-				gPipeline.mNumVisibleNodes = 0;
+				gPipeline.mNumVisibleNodes = LLPipeline::sVisibleLightCount = 0;
+		}
+		if (gSavedSettings.getBOOL("DebugShowRenderMatrices"))
+		{
+			addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[12], gGLProjection[13], gGLProjection[14], gGLProjection[15]));
+			ypos += y_inc;
+
+			addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[8], gGLProjection[9], gGLProjection[10], gGLProjection[11]));
+			ypos += y_inc;
+
+			addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[4], gGLProjection[5], gGLProjection[6], gGLProjection[7]));
+			ypos += y_inc;
+
+			addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[0], gGLProjection[1], gGLProjection[2], gGLProjection[3]));
+			ypos += y_inc;
+
+			addText(xpos, ypos, "Projection Matrix");
+			ypos += y_inc;
+
+
+			addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[12], gGLModelView[13], gGLModelView[14], gGLModelView[15]));
+			ypos += y_inc;
+
+			addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[8], gGLModelView[9], gGLModelView[10], gGLModelView[11]));
+			ypos += y_inc;
+
+			addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[4], gGLModelView[5], gGLModelView[6], gGLModelView[7]));
+			ypos += y_inc;
+
+			addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[0], gGLModelView[1], gGLModelView[2], gGLModelView[3]));
+			ypos += y_inc;
+
+			addText(xpos, ypos, "View Matrix");
+			ypos += y_inc;
 		}
 		if (gSavedSettings.getBOOL("DebugShowColor"))
Index: /branches/shadow-draft/indra/newview/llviewercamera.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/llviewercamera.cpp (revision 431)
+++ /branches/shadow-draft/indra/newview/llviewercamera.cpp (revision 575)
@@ -86,4 +86,19 @@
 }
 
+glh::matrix4f gl_lookat(LLVector3 eye, LLVector3 center, LLVector3 up)
+{
+	LLVector3 f = center-eye;
+	f.normVec();
+	up.normVec();
+	LLVector3 s = f % up;
+	LLVector3 u = s % f;
+
+	return glh::matrix4f(s[0], s[1], s[2], 0,
+					 u[0], u[1], u[2], 0,
+					 -f[0], -f[1], -f[2], 0,
+					 0, 0, 0, 1);
+	
+}
+
 LLViewerCamera::LLViewerCamera() : LLCamera()
 {
@@ -192,5 +207,5 @@
 
 //static
-void LLViewerCamera::updateFrustumPlanes(LLCamera& camera, BOOL ortho, BOOL zflip)
+void LLViewerCamera::updateFrustumPlanes(LLCamera& camera, BOOL ortho, BOOL zflip, BOOL no_hacks)
 {
 	GLint* viewport = (GLint*) gGLViewport;
@@ -201,5 +216,25 @@
 	LLVector3 frust[8];
 
-	if (zflip)
+	if (no_hacks)
+	{
+		gluUnProject(viewport[0],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ);
+		frust[0].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0]+viewport[2],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ);
+		frust[1].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ);
+		frust[2].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ);
+		frust[3].setVec((F32)objX,(F32)objY,(F32)objZ);
+
+		gluUnProject(viewport[0],viewport[1],1,model,proj,viewport,&objX,&objY,&objZ);
+		frust[4].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0]+viewport[2],viewport[1],1,model,proj,viewport,&objX,&objY,&objZ);
+		frust[5].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],1,model,proj,viewport,&objX,&objY,&objZ);
+		frust[6].setVec((F32)objX,(F32)objY,(F32)objZ);
+		gluUnProject(viewport[0],viewport[1]+viewport[3],1,model,proj,viewport,&objX,&objY,&objZ);
+		frust[7].setVec((F32)objX,(F32)objY,(F32)objZ);
+	}
+	else if (zflip)
 	{
 		gluUnProject(viewport[0],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ);
@@ -241,5 +276,5 @@
 		if (ortho)
 		{
-			LLVector3 far_shift = LLVector3(camera.getFar()*2.0f,0,0);
+			LLVector3 far_shift = camera.getAtAxis()*camera.getFar()*2.f; 
 			for (U32 i = 0; i < 4; i++)
 			{
@@ -381,5 +416,5 @@
 	updateFrustumPlanes(*this);
 
-	if (gSavedSettings.getBOOL("CameraOffset"))
+	/*if (gSavedSettings.getBOOL("CameraOffset"))
 	{
 		glMatrixMode(GL_PROJECTION);
@@ -387,5 +422,5 @@
 		glRotatef(20.0,1,0,0);
 		glMatrixMode(GL_MODELVIEW);
-	}
+	}*/
 }
 
Index: /branches/shadow-draft/indra/newview/lldrawpoolwater.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/lldrawpoolwater.cpp (revision 573)
+++ /branches/shadow-draft/indra/newview/lldrawpoolwater.cpp (revision 575)
@@ -59,4 +59,6 @@
 static float sTime;
 
+BOOL deferred_render = FALSE;
+
 BOOL LLDrawPoolWater::sSkipScreenCopy = FALSE;
 BOOL LLDrawPoolWater::sNeedsReflectionUpdate = TRUE;
@@ -119,4 +121,16 @@
 
 	return 0;
+}
+
+void LLDrawPoolWater::beginPostDeferredPass(S32 pass)
+{
+	beginRenderPass(pass);
+	deferred_render = TRUE;
+}
+
+void LLDrawPoolWater::endPostDeferredPass(S32 pass)
+{
+	endRenderPass(pass);
+	deferred_render = FALSE;
 }
 
@@ -375,5 +389,9 @@
 	F32 eyedepth = LLViewerCamera::getInstance()->getOrigin().mV[2] - gAgent.getRegion()->getWaterHeight();
 	
-	if (eyedepth < 0.f && LLPipeline::sWaterReflections)
+	if (deferred_render)
+	{
+		shader = &gDeferredWaterProgram;
+	}
+	else if (eyedepth < 0.f && LLPipeline::sWaterReflections)
 	{
 		shader = &gUnderWaterProgram;
@@ -412,8 +430,4 @@
 	
 	S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX);	
-	stop_glerror();
-	
-	shader->bind();
-
 	if (screentex > -1)
 	{
@@ -421,7 +435,17 @@
 		shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, 
 			param_mgr->getFogDensity());
-	}
-	
-	gPipeline.mWaterDis.bindTexture();
+		gPipeline.mWaterDis.bindTexture();
+	}
+	
+	stop_glerror();
+	
+	if (deferred_render)
+	{
+		gPipeline.bindDeferredShader(*shader);
+	}
+	else
+	{
+		shader->bind();
+	}
 
 	if (mVertexShaderLevel == 1)
@@ -534,5 +558,13 @@
 	shader->disableTexture(LLShaderMgr::WATER_REFTEX);
 	shader->disableTexture(LLShaderMgr::WATER_SCREENDEPTH);
-	shader->unbind();
+
+	if (deferred_render)
+	{
+		gPipeline.unbindDeferredShader(*shader);
+	}
+	else
+	{
+		shader->unbind();
+	}
 
 	gGL.getTexUnit(0)->activate();
Index: /branches/shadow-draft/indra/newview/llviewercamera.h
===================================================================
--- /branches/shadow-draft/indra/newview/llviewercamera.h (revision 431)
+++ /branches/shadow-draft/indra/newview/llviewercamera.h (revision 575)
@@ -63,5 +63,5 @@
 								const LLVector3 &point_of_interest);
 
-	static void updateFrustumPlanes(LLCamera& camera, BOOL ortho = FALSE, BOOL zflip = FALSE);
+	static void updateFrustumPlanes(LLCamera& camera, BOOL ortho = FALSE, BOOL zflip = FALSE, BOOL no_hacks = FALSE);
 	void setPerspective(BOOL for_selection, S32 x, S32 y_from_bot, S32 width, S32 height, BOOL limit_select_distance, F32 z_near = 0, F32 z_far = 0);
 
Index: /branches/shadow-draft/indra/newview/lldrawpoolwater.h
===================================================================
--- /branches/shadow-draft/indra/newview/lldrawpoolwater.h (revision 387)
+++ /branches/shadow-draft/indra/newview/lldrawpoolwater.h (revision 575)
@@ -70,4 +70,9 @@
 	/*virtual*/ LLDrawPool *instancePool();
 	static void restoreGL();
+	
+	/*virtual*/ S32 getNumPostDeferredPasses() { return getNumPasses(); }
+	/*virtual*/ void beginPostDeferredPass(S32 pass);
+	/*virtual*/ void endPostDeferredPass(S32 pass);
+	/*virtual*/ void renderPostDeferred(S32 pass) { render(pass); }
 
 	/*virtual*/ S32 getNumPasses();
Index: /branches/shadow-draft/indra/newview/pipeline.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/pipeline.cpp (revision 573)
+++ /branches/shadow-draft/indra/newview/pipeline.cpp (revision 575)
@@ -219,4 +219,5 @@
 BOOL	LLPipeline::sRenderBump = TRUE;
 BOOL	LLPipeline::sUseFarClip = TRUE;
+BOOL	LLPipeline::sShadowRender = FALSE;
 BOOL	LLPipeline::sSkipUpdate = FALSE;
 BOOL	LLPipeline::sDynamicReflections = FALSE;
@@ -228,4 +229,6 @@
 BOOL	LLPipeline::sTextureBindTest = FALSE;
 BOOL	LLPipeline::sRenderFrameTest = FALSE;
+BOOL	LLPipeline::sRenderDeferred = FALSE;
+S32		LLPipeline::sVisibleLightCount = 0;
 
 static LLCullResult* sCull = NULL;
@@ -242,4 +245,11 @@
 
 void validate_framebuffer_object();
+
+void addDeferredAttachments(LLRenderTarget& target)
+{
+	target.addColorAttachment(GL_RGBA); //specular
+	target.addColorAttachment(GL_RGB16F_ARB); //normal		
+	target.addColorAttachment(GL_RGBA32F_ARB); //position
+}
 
 LLPipeline::LLPipeline() :
@@ -255,4 +265,5 @@
 	mGroundPool(NULL),
 	mSimplePool(NULL),
+	mFullbrightPool(NULL),
 	mInvisiblePool(NULL),
 	mGlowPool(NULL),
@@ -268,4 +279,5 @@
 	//mDepthbuffer[0] = mDepthbuffer[1] = 0;
 	mCubeFrameBuffer = 0;
+	mNoiseMap = 0;
 	mCubeDepth = 0;
 }
@@ -285,4 +297,5 @@
 	getPool(LLDrawPool::POOL_ALPHA);
 	getPool(LLDrawPool::POOL_SIMPLE);
+	getPool(LLDrawPool::POOL_FULLBRIGHT);
 	getPool(LLDrawPool::POOL_INVISIBLE);
 	getPool(LLDrawPool::POOL_BUMP);
@@ -362,4 +375,6 @@
 	delete mSimplePool;
 	mSimplePool = NULL;
+	delete mFullbrightPool;
+	mFullbrightPool = NULL;
 	delete mInvisiblePool;
 	mInvisiblePool = NULL;
@@ -419,6 +434,6 @@
 		}
 	
-		mScreen.release();
-		mScreen.allocate(resX, resY, GL_RGBA, TRUE, GL_TEXTURE_RECTANGLE_ARB);		
+
+		allocateScreenBuffer(resX,resY);
 
 		llinfos << "RESIZED SCREEN TEXTURE: " << resX << "x" << resY << llendl;
@@ -426,4 +441,15 @@
 }
 
+void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
+{
+	mScreen.allocate(resX, resY, GL_RGBA, TRUE, GL_TEXTURE_RECTANGLE_ARB);		
+	if (LLPipeline::sRenderDeferred)
+	{
+		//allocate deferred rendering color buffers
+		mDeferredScreen.allocate(resX, resY, GL_RGBA, TRUE, GL_TEXTURE_RECTANGLE_ARB);
+		addDeferredAttachments(mDeferredScreen);
+		mDeferredLight.allocate(resX, resY, GL_RGBA, FALSE, GL_TEXTURE_RECTANGLE_ARB);
+	}
+}
 
 void LLPipeline::releaseGLBuffers()
@@ -431,4 +457,10 @@
 	assertInitialized();
 	
+	if (mNoiseMap)
+	{
+		glDeleteTextures(1, &mNoiseMap);
+		mNoiseMap = 0;
+	}
+
 	if (mCubeBuffer)
 	{
@@ -464,4 +496,6 @@
 	mWaterDis.release();
 	mScreen.release();
+	mDeferredScreen.release();
+	mSunShadow.release();
 
 	for (U32 i = 0; i < 3; i++)
@@ -559,5 +593,30 @@
 	GLuint resY = gViewerWindow->getWindowDisplayHeight();
 	
-	mScreen.allocate(resX, resY, GL_RGBA, TRUE, GL_TEXTURE_RECTANGLE_ARB);
+	allocateScreenBuffer(resX,resY);
+
+	if (sRenderDeferred)
+	{
+		mSunShadow.allocate(1024,1024, GL_RGB32F_ARB, TRUE);
+
+		if (!mNoiseMap)
+		{
+			const U32 noiseRes = 128;
+			LLVector3 noise[noiseRes*noiseRes];
+
+			for (U32 i = 0; i < noiseRes*noiseRes; ++i)
+			{
+				noise[i] = LLVector3(ll_frand()-0.5f,
+									 ll_frand()-0.5f,
+									 ll_frand()-0.5f);
+				noise[i].normVec();
+			}
+
+			glGenTextures(1, &mNoiseMap);
+			glBindTexture(GL_TEXTURE_2D, mNoiseMap);
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F_ARB, noiseRes, noiseRes, 0, GL_RGB, GL_FLOAT, noise);
+		}
+	}
 }
 
@@ -747,4 +806,8 @@
 		break;
 
+	case LLDrawPool::POOL_FULLBRIGHT:
+		poolp = mFullbrightPool;
+		break;
+
 	case LLDrawPool::POOL_INVISIBLE:
 		poolp = mInvisiblePool;
@@ -1165,5 +1228,12 @@
 	if (to_texture)
 	{
-		mScreen.bindTarget();
+		if (LLPipeline::sRenderDeferred)
+		{
+			mDeferredScreen.bindTarget();
+		}
+		else
+		{
+			mScreen.bindTarget();
+		}
 	}
 
@@ -1177,5 +1247,9 @@
 	LLViewerImage::unbindTexture(0, GL_TEXTURE_2D);
 
-	gGL.setColorMask(false, false);
+	if (sUseOcclusion > 1)
+	{
+		gGL.setColorMask(false, false);
+	}
+
 	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 
@@ -1235,10 +1309,24 @@
 	}
 	
-	gGL.setColorMask(true, false);
+	
 	glPopMatrix();
 
+	if (sUseOcclusion > 1)
+	{
+		gGL.setColorMask(true, false);
+	}
+
 	if (to_texture)
 	{
 		mScreen.flush();
+
+		if (LLPipeline::sRenderDeferred)
+		{
+			mDeferredScreen.flush();
+		}
+		else
+		{
+			mScreen.flush();
+		}
 		LLRenderTarget::unbindTarget();
 	}
@@ -1310,4 +1398,5 @@
 {
 	LLVertexBuffer::unbind();
+
 	if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
 	{
@@ -2315,7 +2404,13 @@
 	//	
 	stop_glerror();
-	BOOL occlude = sUseOcclusion > 1;
-	
-	U32 cur_type = 0;
+	
+	for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+	{
+		LLDrawPool *poolp = *iter;
+		if (hasRenderType(poolp->getType()))
+		{
+			poolp->prerender();
+		}
+	}
 
 	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PICKING))
@@ -2323,21 +2418,13 @@
 		gObjectList.renderObjectsForSelect(camera);
 	}
-	else if (gSavedSettings.getBOOL("RenderDeferred"))
-	{
-		renderGeomDeferred();
+	else if (sRenderDeferred)
+	{
+		renderGeomDeferred(camera);
 	}
 	else
 	{
-		for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
-		{
-			LLDrawPool *poolp = *iter;
-			if (hasRenderType(poolp->getType()))
-			{
-				poolp->prerender();
-			}
-		}
-
-
 		LLFastTimer t(LLFastTimer::FTM_POOLS);
+		BOOL occlude = sUseOcclusion > 1;
+		U32 cur_type = 0;
 		calcNearbyLights(camera);
 		setupHWLights(NULL);
@@ -2368,4 +2455,5 @@
 				for( S32 i = 0; i < poolp->getNumPasses(); i++ )
 				{
+					LLVertexBuffer::unbind();
 					poolp->beginRenderPass(i);
 					for (iter2 = iter1; iter2 != mPools.end(); iter2++)
@@ -2410,4 +2498,16 @@
 			stop_glerror();
 		}
+	LLVertexBuffer::unbind();
+		
+		gGLLastMatrix = NULL;
+		glLoadMatrixd(gGLModelView);
+
+		if (occlude)
+		{
+			occlude = FALSE;
+			gGLLastMatrix = NULL;
+			glLoadMatrixd(gGLModelView);
+			doOcclusion(camera);
+		}
 	}
 
@@ -2417,6 +2517,218 @@
 	LLGLState::checkClientArrays();
 
+	
+
+	stop_glerror();
+		
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
+	LLGLState::checkClientArrays();
+
+	if (!sReflectionRender)
+	{
+		renderHighlights();
+	}
+
+	// Contains a list of the faces of objects that are physical or
+	// have touch-handlers.
+	mHighlightFaces.clear();
+
+	renderDebug();
+
+	LLVertexBuffer::unbind();
+	
+	if (!LLPipeline::sReflectionRender && !LLPipeline::sRenderDeferred && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+	{
+		// Render debugging beacons.
+		gObjectList.renderObjectBeacons();
+		LLHUDObject::renderAll();
+		gObjectList.resetObjectBeacons();
+	}
+
+	//HACK: preserve/restore matrices around HUD render
+	if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+	{
+		for (U32 i = 0; i < 16; i++)
+		{
+			gGLModelView[i] = saved_modelview[i];
+			gGLProjection[i] = saved_projection[i];
+		}
+	}
+
+	LLVertexBuffer::unbind();
+
+	LLGLState::checkStates();
+	LLGLState::checkTextureChannels();
+	LLGLState::checkClientArrays();
+}
+
+void LLPipeline::renderGeomDeferred(LLCamera& camera)
+{
+	LLFastTimer t(LLFastTimer::FTM_POOLS);
+	U32 cur_type = 0;
+
+	gGL.setColorMask(true, true);
+	
+	pool_set_t::iterator iter1 = mPools.begin();
+
+	while ( iter1 != mPools.end() )
+	{
+		LLDrawPool *poolp = *iter1;
+		
+		cur_type = poolp->getType();
+
+		pool_set_t::iterator iter2 = iter1;
+		if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0)
+		{
+			LLFastTimer t(LLFastTimer::FTM_POOLRENDER);
+
+			gGLLastMatrix = NULL;
+			glLoadMatrixd(gGLModelView);
+		
+			for( S32 i = 0; i < poolp->getNumDeferredPasses(); i++ )
+			{
+				LLVertexBuffer::unbind();
+				poolp->beginDeferredPass(i);
+				for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+				{
+					LLDrawPool *p = *iter2;
+					if (p->getType() != cur_type)
+					{
+						break;
+					}
+										
+					p->renderDeferred(i);
+				}
+				poolp->endDeferredPass(i);
+				LLVertexBuffer::unbind();
+
+				GLint depth;
+				glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
+				if (depth > 3)
+				{
+					llerrs << "GL matrix stack corrupted!" << llendl;
+				}
+				LLGLState::checkStates();
+				LLGLState::checkTextureChannels();
+				LLGLState::checkClientArrays();
+			}
+		}
+		else
+		{
+			// Skip all pools of this type
+			for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+			{
+				LLDrawPool *p = *iter2;
+				if (p->getType() != cur_type)
+				{
+					break;
+				}
+			}
+		}
+		iter1 = iter2;
+		stop_glerror();
+	}
+
 	gGLLastMatrix = NULL;
 	glLoadMatrixd(gGLModelView);
+
+	gGL.setColorMask(true, false);
+}
+
+void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
+{
+	LLFastTimer t(LLFastTimer::FTM_POOLS);
+	U32 cur_type = 0;
+
+	calcNearbyLights(camera);
+	setupHWLights(NULL);
+
+	pool_set_t::iterator iter1 = mPools.begin();
+	BOOL occlude = LLPipeline::sUseOcclusion > 1;
+
+	while ( iter1 != mPools.end() )
+	{
+		LLDrawPool *poolp = *iter1;
+		
+		cur_type = poolp->getType();
+
+		if (occlude && cur_type > LLDrawPool::POOL_AVATAR)
+		{
+			occlude = FALSE;
+			gGLLastMatrix = NULL;
+			glLoadMatrixd(gGLModelView);
+			doOcclusion(camera);
+			gGL.setColorMask(true, true);
+		}
+
+		pool_set_t::iterator iter2 = iter1;
+		if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0)
+		{
+			LLFastTimer t(LLFastTimer::FTM_POOLRENDER);
+
+			gGLLastMatrix = NULL;
+			glLoadMatrixd(gGLModelView);
+		
+			for( S32 i = 0; i < poolp->getNumPostDeferredPasses(); i++ )
+			{
+				LLVertexBuffer::unbind();
+				poolp->beginPostDeferredPass(i);
+				for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+				{
+					LLDrawPool *p = *iter2;
+					if (p->getType() != cur_type)
+					{
+						break;
+					}
+										
+					p->renderPostDeferred(i);
+				}
+				poolp->endPostDeferredPass(i);
+				LLVertexBuffer::unbind();
+
+				GLint depth;
+				glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
+				if (depth > 3)
+				{
+					llerrs << "GL matrix stack corrupted!" << llendl;
+				}
+				LLGLState::checkStates();
+				LLGLState::checkTextureChannels();
+				LLGLState::checkClientArrays();
+			}
+		}
+		else
+		{
+			// Skip all pools of this type
+			for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+			{
+				LLDrawPool *p = *iter2;
+				if (p->getType() != cur_type)
+				{
+					break;
+				}
+			}
+		}
+		iter1 = iter2;
+		stop_glerror();
+	}
+
+	gGLLastMatrix = NULL;
+	glLoadMatrixd(gGLModelView);
+
+	renderHighlights();
+	mHighlightFaces.clear();
+
+	renderDebug();
+
+	LLVertexBuffer::unbind();
+
+	if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+	{
+		// Render debugging beacons.
+		gObjectList.renderObjectBeacons();
+		LLHUDObject::renderAll();
+		gObjectList.resetObjectBeacons();
+	}
 
 	if (occlude)
@@ -2427,55 +2739,78 @@
 		doOcclusion(camera);
 	}
-
-	stop_glerror();
-		
-	LLGLState::checkStates();
-	LLGLState::checkTextureChannels();
-	LLGLState::checkClientArrays();
-
-	if (!sReflectionRender)
-	{
-		renderHighlights();
-	}
-
-	// Contains a list of the faces of objects that are physical or
-	// have touch-handlers.
-	mHighlightFaces.clear();
-
-	renderDebug();
-
-	LLVertexBuffer::unbind();
-	
-	if (!LLPipeline::sReflectionRender && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
-	{
-		// Render debugging beacons.
-		gObjectList.renderObjectBeacons();
-		LLHUDObject::renderAll();
-		gObjectList.resetObjectBeacons();
-	}
-
-	//HACK: preserve/restore matrices around HUD render
-	if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
-	{
-		for (U32 i = 0; i < 16; i++)
-		{
-			gGLModelView[i] = saved_modelview[i];
-			gGLProjection[i] = saved_projection[i];
-		}
-	}
-
-	LLVertexBuffer::unbind();
-
-	LLGLState::checkStates();
-	LLGLState::checkTextureChannels();
-	LLGLState::checkClientArrays();
-}
-
-void LLPipeline::renderGeomDeferred()
-{
-	gDeferredDiffuseProgram.bind();
-	gPipeline.renderObjects(LLRenderPass::PASS_SIMPLE, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_NORMAL, TRUE);
-	gDeferredDiffuseProgram.unbind();
-}
+}
+
+void LLPipeline::renderGeomShadow(LLCamera& camera)
+{
+	LLFastTimer t(LLFastTimer::FTM_POOLS);
+	U32 cur_type = 0;
+
+	pool_set_t::iterator iter1 = mPools.begin();
+	
+	while ( iter1 != mPools.end() )
+	{
+		LLDrawPool *poolp = *iter1;
+		
+		cur_type = poolp->getType();
+
+		pool_set_t::iterator iter2 = iter1;
+		if (hasRenderType(poolp->getType()) && poolp->getNumShadowPasses() > 0)
+		{
+			LLFastTimer t(LLFastTimer::FTM_POOLRENDER);
+
+			gGLLastMatrix = NULL;
+			glLoadMatrixd(gGLModelView);
+		
+			for( S32 i = 0; i < poolp->getNumShadowPasses(); i++ )
+			{
+				LLVertexBuffer::unbind();
+				poolp->beginShadowPass(i);
+				for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+				{
+					LLDrawPool *p = *iter2;
+					if (p->getType() != cur_type)
+					{
+						break;
+					}
+										
+					p->renderShadow(i);
+				}
+				poolp->endShadowPass(i);
+				LLVertexBuffer::unbind();
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+#	if LL_DEBUG_GL
+				GLint depth;
+				glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
+				if (depth > 3)
+				{
+					llerrs << "GL matrix stack corrupted!" << llendl;
+				}
+				LLGLState::checkStates();
+				LLGLState::checkTextureChannels();
+				LLGLState::checkClientArrays();
+#	endif
+#endif
+			}
+		}
+		else
+		{
+			// Skip all pools of this type
+			for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+			{
+				LLDrawPool *p = *iter2;
+				if (p->getType() != cur_type)
+				{
+					break;
+				}
+			}
+		}
+		iter1 = iter2;
+		stop_glerror();
+	}
+
+	gGLLastMatrix = NULL;
+	glLoadMatrixd(gGLModelView);
+}
+
 
 void LLPipeline::addTrianglesDrawn(S32 count)
@@ -2807,4 +3142,16 @@
 		break;
 
+	case LLDrawPool::POOL_FULLBRIGHT:
+		if (mFullbrightPool)
+		{
+			llassert(0);
+			llwarns << "Ignoring duplicate simple pool." << llendl;
+		}
+		else
+		{
+			mFullbrightPool = (LLRenderPass*) new_poolp;
+		}
+		break;
+
 	case LLDrawPool::POOL_INVISIBLE:
 		if (mInvisiblePool)
@@ -2938,4 +3285,9 @@
 		llassert(mSimplePool == poolp);
 		mSimplePool = NULL;
+		break;
+
+	case LLDrawPool::POOL_FULLBRIGHT:
+		llassert(mFullbrightPool == poolp);
+		mFullbrightPool = NULL;
 		break;
 
@@ -4131,4 +4483,5 @@
 	
 	U32 cube_mask = (1 << LLPipeline::RENDER_TYPE_SIMPLE) |
+					(1 << LLPipeline::RENDER_TYPE_FULLBRIGHT) |
 					(1 << LLPipeline::RENDER_TYPE_WATER) |
 					//(1 << LLPipeline::RENDER_TYPE_BUMP) |
@@ -4641,68 +4994,4 @@
 	gViewerWindow->setupViewport();
 
-	/*mGlow[1].bindTexture();
-	{
-		LLGLEnable stencil(GL_STENCIL_TEST);
-		glStencilFunc(GL_NOTEQUAL, 255, 0xFFFFFFFF);
-		glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
-		LLGLDisable blend(GL_BLEND);
-			
-		gGL.begin(LLVertexBuffer::TRIANGLE_STRIP);
-		gGL.color4f(1,1,1,1);
-		gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
-		gGL.vertex2f(-1,-1);
-		
-		gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
-		gGL.vertex2f(-1,1);
-		
-		gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
-		gGL.vertex2f(1,-1);
-		
-		gGL.texCoord2f(tc2.mV[0], tc2.mV[1]);
-		gGL.vertex2f(1,1);
-		gGL.end();
-
-		gGL.flush();
-	}
-
-	if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_GLOW))
-	{
-		tc2.setVec((F32) gViewerWindow->getWindowDisplayWidth(),
-				(F32) gViewerWindow->getWindowDisplayHeight());
-
-		if (res_mod > 1)
-		{
-			tc2 /= (F32) res_mod;
-		}
-
-		LLGLEnable blend(GL_BLEND);
-		gGL.blendFunc(GL_ONE, GL_ONE);
-
-		glDisable(GL_TEXTURE_2D);
-		glEnable(GL_TEXTURE_RECTANGLE_ARB);
-		mScreen.bindTexture();
-		
-		gGL.begin(LLVertexBuffer::TRIANGLE_STRIP);
-		gGL.color4f(1,1,1,1);
-		gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
-		gGL.vertex2f(-1,-1);
-		
-		gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
-		gGL.vertex2f(-1,1);
-		
-		gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
-		gGL.vertex2f(1,-1);
-		
-		gGL.texCoord2f(tc2.mV[0], tc2.mV[1]);
-		gGL.vertex2f(1,1);
-		gGL.end();
-
-		gGL.flush();
-		
-		glEnable(GL_TEXTURE_2D);
-		glDisable(GL_TEXTURE_RECTANGLE_ARB);
-
-		gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-	}*/
 	gGL.flush();
 	
@@ -4789,4 +5078,353 @@
 }
 
+void LLPipeline::bindDeferredShader(LLGLSLShader& shader)
+{
+	shader.bind();
+	S32 channel = 0;
+	channel = shader.enableTexture(LLShaderMgr::DIFFUSE_MAP, GL_TEXTURE_RECTANGLE_ARB);
+	if (channel > -1)
+	{
+		mDeferredScreen.bindTexture(0);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	}
+
+	channel = shader.enableTexture(LLShaderMgr::SPECULAR_MAP, GL_TEXTURE_RECTANGLE_ARB);
+	if (channel > -1)
+	{
+		mDeferredScreen.bindTexture(1);
+	}
+
+	channel = shader.enableTexture(LLShaderMgr::DEFERRED_NORMAL, GL_TEXTURE_RECTANGLE_ARB);
+	if (channel > -1)
+	{
+		mDeferredScreen.bindTexture(2);
+	}
+
+	channel = shader.enableTexture(LLShaderMgr::DEFERRED_POSITION, GL_TEXTURE_RECTANGLE_ARB);
+	if (channel > -1)
+	{
+		mDeferredScreen.bindTexture(3);
+	}
+
+	channel = shader.enableTexture(LLShaderMgr::DEFERRED_DEPTH, GL_TEXTURE_RECTANGLE_ARB);
+	if (channel > -1)
+	{
+		mDeferredScreen.bindDepth();
+	}
+
+	channel = shader.enableTexture(LLShaderMgr::DEFERRED_NOISE);
+	if (channel > -1)
+	{
+		glBindTexture(GL_TEXTURE_2D, mNoiseMap);
+	}
+
+	channel = shader.enableTexture(LLShaderMgr::DEFERRED_LIGHT, GL_TEXTURE_RECTANGLE_ARB);
+	if (channel > -1)
+	{
+		mDeferredLight.bindTexture();
+	}
+
+	channel = shader.enableTexture(LLShaderMgr::DEFERRED_SHADOW);
+	if (channel > -1)
+	{
+		mSunShadow.bindTexture();
+		//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+		//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
+
+		F32 mat[48];
+		for (U32 i = 0; i < 16; i++)
+		{
+			mat[i] = mSunShadowMatrix[0].m[i];
+			mat[i+16] = mSunShadowMatrix[1].m[i];
+			mat[i+32] = mSunShadowMatrix[2].m[i];
+		}
+
+		shader.uniformMatrix4fv("shadow_matrix", 3, FALSE, mat);
+	}
+
+	channel = shader.enableTexture(LLShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB);
+	if (channel > -1)
+	{
+		LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
+		if (cube_map)
+		{
+			cube_map->enable(channel);
+			cube_map->bind();
+			F64* m = gGLModelView;
+
+			
+			F32 mat[] = { m[0], m[1], m[2],
+						 m[4], m[5], m[6],
+						 m[8], m[9], m[10] };
+		
+			shader.uniform3fv("env_mat", 3, mat);
+		}
+	}
+
+	shader.uniform3fv("shadow_clip", 1, mSunClipPlanes.mV);
+	shader.uniform1f("sun_wash", gSavedSettings.getF32("RenderDeferredSunWash"));
+	glActiveTextureARB(GL_TEXTURE0_ARB);
+}
+
+void LLPipeline::renderDeferredLighting()
+{
+	if (!sCull)
+	{
+		return;
+	}
+
+	if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+	{
+		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+	}
+
+	mDeferredLight.bindTarget();
+
+	gGL.setColorMask(true, true);
+	mDeferredLight.clear();
+	
+	//draw a cube around every light
+	LLVertexBuffer::unbind();
+
+	glClear(GL_COLOR_BUFFER_BIT);
+	glBlendFunc(GL_ONE, GL_ONE);
+	LLGLEnable cull(GL_CULL_FACE);
+	LLGLEnable blend(GL_BLEND);
+
+	glh::matrix4f mat = glh_copy_matrix(gGLModelView);
+
+	F32 vert[] = 
+	{
+		-1,1,
+		-1,-1,
+		1,1,
+		1,-1
+	};
+
+	bindDeferredShader(gDeferredSunProgram);
+
+	F32 aoBackground = gSavedSettings.getF32("RenderSSAOBackground");
+	F32 aoForeground = gSavedSettings.getF32("RenderSSAOForeground");
+	F32 aoScale = gSavedSettings.getF32("RenderSSAOScale");
+
+	glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose();
+
+	const U32 slice = 32;
+	F32 offset[slice*3];
+	for (U32 i = 0; i < 4; i++)
+	{
+		for (U32 j = 0; j < 8; j++)
+		{
+		
+			glh::vec3f v;
+			v.set_value(sinf(6.284f/8*j), cosf(6.284f/8*j), -(F32) i);
+			v.normalize();
+			inv_trans.mult_matrix_vec(v);
+			v.normalize();
+			offset[(i*8+j)*3+0] = v.v[0];
+			offset[(i*8+j)*3+1] = v.v[2];
+			offset[(i*8+j)*3+2] = v.v[1];
+		}
+	}
+
+	gDeferredSunProgram.uniform3fv("offset", slice, offset);
+	gDeferredSunProgram.uniform2f("screenRes", mDeferredLight.getWidth(), mDeferredLight.getHeight());
+
+	gDeferredSunProgram.uniform1f("aoScale", aoScale);
+	gDeferredSunProgram.uniform1f("aoBackground", aoBackground);
+	gDeferredSunProgram.uniform1f("aoForeground", aoForeground);
+
+	setupHWLights(NULL); //to set mSunDir;
+
+	glPushMatrix();
+	glLoadIdentity();
+	glMatrixMode(GL_PROJECTION);
+	glPushMatrix();
+	glLoadIdentity();
+
+	LLVector4 dir(mSunDir, 0.f);
+
+	glh::vec4f tc(dir.mV);
+	mat.mult_matrix_vec(tc);
+	glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], 0);
+	glColor3f(1,1,1);
+
+	glVertexPointer(2, GL_FLOAT, 0, vert);
+	{
+		LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS);
+		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+	}
+	glPopMatrix();
+	glMatrixMode(GL_MODELVIEW);
+	glPopMatrix();
+
+	unbindDeferredShader(gDeferredSunProgram);
+
+	mDeferredLight.flush();
+		
+	mScreen.bindTarget();
+	mScreen.clear();
+	gGL.setColorMask(true, false);
+	
+	bindDeferredShader(gDeferredSoftenProgram);	
+	{
+		LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS);
+		LLGLDisable blend(GL_BLEND);
+
+		//full screen blit
+		glPushMatrix();
+		glLoadIdentity();
+		glMatrixMode(GL_PROJECTION);
+		glPushMatrix();
+		glLoadIdentity();
+
+		glVertexPointer(2, GL_FLOAT, 0, vert);
+		
+		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+		
+		glPopMatrix();
+		glMatrixMode(GL_MODELVIEW);
+		glPopMatrix();
+	}
+
+	unbindDeferredShader(gDeferredSoftenProgram);
+
+	bindDeferredShader(gDeferredLightProgram);
+
+	F32 v[24];
+	glVertexPointer(3, GL_FLOAT, 0, v);
+	{
+		LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+		for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter)
+		{
+			LLDrawable* drawablep = *iter;
+			
+			LLVOVolume* volume = drawablep->getVOVolume();
+			if (!volume)
+			{
+				continue;
+			}
+
+			LLVector3 center = drawablep->getPositionAgent();
+			F32* c = center.mV;
+			F32 s = volume->getLightRadius()*1.5f;
+
+			if (LLViewerCamera::getInstance()->AABBInFrustumNoFarClip(center, LLVector3(s,s,s)) == 0)
+			{
+				continue;
+			}
+
+			sVisibleLightCount++;
+			glh::vec3f tc(c);
+			mat.mult_matrix_vec(tc);
+			glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
+
+			LLColor3 col = volume->getLightColor();
+			col *= volume->getLightIntensity();
+
+			glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
+			
+			//vertex positions are encoded so the 3 bits of their vertex index 
+			//correspond to their axis facing, with bit position 3,2,1 matching
+			//axis facing x,y,z, bit set meaning positive facing, bit clear 
+			//meaning negative facing
+			v[0] = c[0]-s; v[1] = c[1]-s; v[2] = c[2]-s; // 0 - 0000 
+			v[3] = c[0]-s; v[4] = c[1]-s; v[5] = c[2]+s; // 1 - 0001
+			v[6] = c[0]-s; v[7] = c[1]+s; v[8] = c[2]-s; // 2 - 0010
+			v[9] = c[0]-s; v[10] = c[1]+s; v[11] = c[2]+s; // 3 - 0011
+																							 
+			v[12] = c[0]+s; v[13] = c[1]-s; v[14] = c[2]-s; // 4 - 0100
+			v[15] = c[0]+s; v[16] = c[1]-s; v[17] = c[2]+s; // 5 - 0101
+			v[18] = c[0]+s; v[19] = c[1]+s; v[20] = c[2]-s; // 6 - 0110
+			v[21] = c[0]+s; v[22] = c[1]+s; v[23] = c[2]+s; // 7 - 0111
+
+			if (LLViewerCamera::getInstance()->getOrigin().mV[0] > c[0] + s + 0.2f ||
+				LLViewerCamera::getInstance()->getOrigin().mV[0] < c[0] - s - 0.2f ||
+				LLViewerCamera::getInstance()->getOrigin().mV[1] > c[1] + s + 0.2f ||
+				LLViewerCamera::getInstance()->getOrigin().mV[1] < c[1] - s - 0.2f ||
+				LLViewerCamera::getInstance()->getOrigin().mV[2] > c[2] + s + 0.2f ||
+				LLViewerCamera::getInstance()->getOrigin().mV[2] < c[2] - s - 0.2f)
+			{ //draw box if camera is outside box
+				glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
+					GL_UNSIGNED_BYTE, get_box_fan_indices(LLViewerCamera::getInstance(), center));
+			}
+			else
+			{	
+				LLGLDepthTest depth(GL_FALSE);
+				//full screen blit
+				glPushMatrix();
+				glLoadIdentity();
+				glMatrixMode(GL_PROJECTION);
+				glPushMatrix();
+				glLoadIdentity();
+
+				glVertexPointer(2, GL_FLOAT, 0, vert);
+				glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+				
+				glVertexPointer(3, GL_FLOAT, 0, v);
+
+				glPopMatrix();
+				glMatrixMode(GL_MODELVIEW);
+				glPopMatrix();
+			}
+		}
+	}
+
+	unbindDeferredShader(gDeferredLightProgram);
+
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+	{ //render non-deferred geometry
+		LLGLDisable blend(GL_BLEND);
+		U32 render_mask = mRenderTypeMask;
+		sRenderDeferred = FALSE;
+		mRenderTypeMask =	(1 << LLPipeline::RENDER_TYPE_SKY) |
+							(1 << LLPipeline::RENDER_TYPE_CLOUDS) |
+							(1 << LLPipeline::RENDER_TYPE_WL_SKY) |
+							(1 << LLPipeline::RENDER_TYPE_ALPHA) |
+							(1 << LLPipeline::RENDER_TYPE_AVATAR) |
+							(1 << LLPipeline::RENDER_TYPE_WATER) |
+							(1 << LLPipeline::RENDER_TYPE_FULLBRIGHT) |
+							(1 << LLPipeline::RENDER_TYPE_VOLUME) |
+							(1 << LLPipeline::RENDER_TYPE_GLOW);
+		
+		renderGeomPostDeferred(*LLViewerCamera::getInstance());
+		sRenderDeferred = TRUE;
+		mRenderTypeMask = render_mask;
+	}
+
+	mScreen.flush();
+						
+}
+
+void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
+{
+	shader.disableTexture(LLShaderMgr::DEFERRED_POSITION, GL_TEXTURE_RECTANGLE_ARB);
+	shader.disableTexture(LLShaderMgr::DEFERRED_NORMAL, GL_TEXTURE_RECTANGLE_ARB);
+	shader.disableTexture(LLShaderMgr::DIFFUSE_MAP, GL_TEXTURE_RECTANGLE_ARB);
+	shader.disableTexture(LLShaderMgr::SPECULAR_MAP, GL_TEXTURE_RECTANGLE_ARB);
+	shader.disableTexture(LLShaderMgr::DEFERRED_DEPTH, GL_TEXTURE_RECTANGLE_ARB);
+	shader.disableTexture(LLShaderMgr::DEFERRED_SHADOW);
+	shader.disableTexture(LLShaderMgr::DEFERRED_LIGHT);
+	shader.disableTexture(LLShaderMgr::DEFERRED_NOISE);
+
+	S32 channel = shader.disableTexture(LLShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB);
+	if (channel > -1)
+	{
+		LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
+		if (cube_map)
+		{
+			cube_map->disable();
+		}
+	}
+	LLImageGL::unbindTexture(0);
+	glActiveTextureARB(GL_TEXTURE0_ARB);
+	glEnable(GL_TEXTURE_2D);
+	shader.unbind();
+}
+
 void LLPipeline::processImagery(LLCamera& camera)
 {
@@ -4826,4 +5464,6 @@
 		S32 occlusion = LLPipeline::sUseOcclusion;
 		LLPipeline::sUseOcclusion = llmin(occlusion, 1);
+		BOOL deferred = LLPipeline::sRenderDeferred;
+
 		U32 type_mask = gPipeline.mRenderTypeMask;
 
@@ -4900,6 +5540,7 @@
 				updateCull(camera, result);
 				stateSort(camera, result);
+				LLPipeline::sRenderDeferred = FALSE;
 				renderGeom(camera, TRUE);
-
+				LLPipeline::sRenderDeferred = deferred;
 				mRenderTypeMask = tmp;
 			}
@@ -4935,5 +5576,7 @@
 					updateCull(camera, result, 1);
 					stateSort(camera, result);
+					LLPipeline::sRenderDeferred = FALSE;
 					renderGeom(camera);
+					LLPipeline::sRenderDeferred = deferred;
 					LLSpatialPartition::sFreezeState = FALSE;
 					LLPipeline::sSkipUpdate = FALSE;
@@ -4984,5 +5627,7 @@
 				updateCull(camera, result, water_clip);
 				stateSort(camera, result);
+				LLPipeline::sRenderDeferred = FALSE;
 				renderGeom(camera);
+				LLPipeline::sRenderDeferred = deferred;
 			}
 
@@ -4993,4 +5638,5 @@
 
 		LLRenderTarget::unbindTarget();
+
 		LLPipeline::sReflectionRender = FALSE;
 
@@ -5011,5 +5657,420 @@
 		LLGLState::checkTextureChannels();
 		LLGLState::checkClientArrays();
-	}
+		LLPipeline::sRenderDeferred = deferred;
+	}
+}
+
+glh::matrix4f look(const LLVector3 pos, const LLVector3 dir, const LLVector3 up)
+{
+	glh::matrix4f ret;
+
+	LLVector3 dirN;
+	LLVector3 upN;
+	LLVector3 lftN;
+
+	lftN = dir % up;
+	lftN.normVec();
+	
+	upN = lftN % dir;
+	upN.normVec();
+	
+	dirN = dir;
+	dirN.normVec();
+	
+
+	ret.m[ 0] = lftN[0];
+	ret.m[ 1] = upN[0];
+	ret.m[ 2] = -dirN[0];
+	ret.m[ 3] = 0.f;
+
+	ret.m[ 4] = lftN[1];
+	ret.m[ 5] = upN[1];
+	ret.m[ 6] = -dirN[1];
+	ret.m[ 7] = 0.f;
+
+	ret.m[ 8] = lftN[2];
+	ret.m[ 9] = upN[2];
+	ret.m[10] = -dirN[2];
+	ret.m[11] = 0.f;
+
+	ret.m[12] = -(lftN*pos);
+	ret.m[13] = -(upN*pos);
+	ret.m[14] = dirN*pos;
+	ret.m[15] = 1.f;
+
+	return ret;
+}
+
+glh::matrix4f scale_translate_to_fit(const LLVector3 min, const LLVector3 max)
+{
+	glh::matrix4f ret;
+	ret.m[ 0] = 2/(max[0]-min[0]);
+	ret.m[ 4] = 0;
+	ret.m[ 8] = 0;
+	ret.m[12] = -(max[0]+min[0])/(max[0]-min[0]);
+
+	ret.m[ 1] = 0;
+	ret.m[ 5] = 2/(max[1]-min[1]);
+	ret.m[ 9] = 0;
+	ret.m[13] = -(max[1]+min[1])/(max[1]-min[1]);
+
+	ret.m[ 2] = 0;
+	ret.m[ 6] = 0;
+	ret.m[10] = 2/(max[2]-min[2]);
+	ret.m[14] = -(max[2]+min[2])/(max[2]-min[2]);
+
+	ret.m[ 3] = 0;
+	ret.m[ 7] = 0;
+	ret.m[11] = 0;
+	ret.m[15] = 1;
+
+	return ret;
+}
+
+void LLPipeline::generateSunShadow(LLCamera& camera)
+{
+	if (!sRenderDeferred)
+	{
+		return;
+	}
+
+	mSunShadow.bindTarget();
+	mSunShadow.getViewport(gGLViewport);
+
+	//get sun view matrix
+	
+	F32 range = 128.f;
+
+	glh::matrix4f saved_proj = glh_get_current_projection();
+	glh::matrix4f saved_view = glh_get_current_modelview();
+	glh::matrix4f inv_view = saved_view.inverse();
+
+	glh::matrix4f view[3];
+	glh::matrix4f proj[3];
+	LLVector3 up;
+
+	mSunClipPlanes = gSavedSettings.getVector3("RenderShadowClipPlanes");
+	if (!gLastHitPosGlobal.isExactlyZero())
+	{
+		F32 focus_dist = (F32) (gLastHitPosGlobal + gLastHitObjectOffset - gAgent.getPosGlobalFromAgent(LLViewerCamera::getInstance()->getOrigin())).magVec();
+		mSunClipPlanes.mV[0] = llclamp(focus_dist*focus_dist, 2.f, mSunClipPlanes.mV[0]);
+	}
+		
+	F32 dist[] = { 0.1f, mSunClipPlanes.mV[0], mSunClipPlanes.mV[1], mSunClipPlanes.mV[2] };
+
+	for (S32 j = 2; j >= 0; j--)
+	{
+		glh_set_current_modelview(saved_view);
+		glh_set_current_projection(saved_proj);
+
+		LLVector3 center = camera.getOrigin() + camera.getAtAxis() * range;
+
+		LLVector3 eye = camera.getOrigin(); //center + LLVector3(0, 0, range);
+
+		LLCamera shadow_cam;
+
+		if (j > 2)
+		{ //uniform shadow mapping
+			glh::vec3f p[16];
+			glh::vec3f wp[16];
+
+			LLVector3 lightDir = -mSunDir; //(0, 0, -1.f);
+			glh::vec3f light_dir(lightDir.mV);
+
+			LLVector3 at = lightDir%camera.getLeftAxis();
+			LLVector3 left = lightDir%at;
+			up = left%lightDir;
+			up.normVec();
+			
+			shadow_cam = camera;
+			shadow_cam.setFar(camera.getFar());
+			F32 shadow_dist = camera.getFar()*2.f;
+
+			LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
+
+			view[j] = look(eye, lightDir, up);
+
+			LLVector3* frust = shadow_cam.mAgentFrustum;
+					
+			LLVector3 pn = shadow_cam.getAtAxis();
+
+			for (U32 i = 0; i < 4; i++)
+			{
+				LLVector3 delta = frust[i+4]-eye;
+				delta.normVec();
+				F32 dp = delta*pn;
+				wp[i] = glh::vec3f(( eye + (delta*dist[j])/dp ).mV);
+				wp[i+4] = glh::vec3f(( eye + (delta*dist[j+1])/dp ).mV);
+			}
+
+			for (U32 i = 0; i < 8; i++)
+			{
+				wp[i+8] = wp[i] - light_dir*shadow_dist;
+				view[j].mult_matrix_vec(wp[i], p[i]);
+				view[j].mult_matrix_vec(wp[i+8], p[i+8]);
+			}
+
+			LLVector3 min = LLVector3(p[0].v);
+			LLVector3 max = LLVector3(p[0].v);
+
+			for (U32 i = 1; i < 16; i++)
+			{
+				update_min_max(min, max, LLVector3(p[i].v));
+			}
+
+			proj[j] = gl_ortho(min.mV[0], max.mV[0], min.mV[1], max.mV[1], min.mV[2], max.mV[2]); 
+		}
+		else
+		{ // perspective shadow map
+			glh::vec3f p[16];
+			glh::vec3f wp[16];
+
+			LLVector3 lightDir = -mSunDir; //(0, 0, -1.f);
+			glh::vec3f light_dir(lightDir.mV);
+
+			LLVector3 at;
+			F32 dl = camera.getLeftAxis() * lightDir;
+			F32 du = camera.getUpAxis() * lightDir;
+
+			if (dl*dl < du*du)
+			{
+				at = lightDir%camera.getLeftAxis();
+			}
+			else
+			{
+				at = lightDir%camera.getUpAxis();
+			}
+
+			if (at * camera.getAtAxis() < 0)
+			{
+				at = -at;
+			}
+			
+			LLVector3 left = lightDir%at;
+			up = left%lightDir;
+			up.normVec();
+			view[j] = look(eye, lightDir, up);
+
+			shadow_cam = camera;
+			shadow_cam.setFar(16.f);
+			F32 shadow_dist = camera.getFar();
+
+			LLViewerCamera::updateFrustumPlanes(shadow_cam);
+
+			LLVector3* frust = shadow_cam.mAgentFrustum;
+					
+			LLVector3 pn = shadow_cam.getAtAxis();
+			
+			for (U32 i = 0; i < 4; i++)
+			{
+				LLVector3 delta = frust[i+4]-eye;
+				delta.normVec();
+				F32 dp = delta*pn;
+				wp[i] = glh::vec3f(( eye + (delta*dist[j])/dp ).mV);
+				wp[i+4] = glh::vec3f(( eye + (delta*dist[j+1])/dp ).mV);
+			}
+
+			for (U32 i = 0; i < 8; i++)
+			{
+				wp[i+8] = wp[i] - light_dir*shadow_dist;
+				view[j].mult_matrix_vec(wp[i], p[i]);
+				view[j].mult_matrix_vec(wp[i+8], p[i+8]);
+			}
+
+			LLVector3 min = LLVector3(p[0].v);
+			LLVector3 max = LLVector3(p[0].v);
+
+			for (U32 i = 1; i < 16; i++)
+			{
+				update_min_max(min, max, LLVector3(p[i].v));
+			}
+
+			F32 nearDist = gSavedSettings.getF32("RenderShadowNearDist");
+			//nearDist *= dist[j];
+			/*F32 dp = pn * lightDir;
+			dp *= dp;
+			nearDist += dist[j] * dp;*/
+
+			//use the formulas of the paper to get n (and f)
+			F32 dotProd = lightDir*camera.getAtAxis();
+			if (fabsf(dotProd) > 1.f)
+			{
+				llerrs << "WTF?" << llendl;
+			}
+
+			F32 sinGamma = sqrtf(1.f-dotProd*dotProd);
+
+			F32 factor = 1.f/sinGamma;
+			F32 z_n = factor*nearDist;
+			F32 d = fabsf(max[1]-min[1]); //perspective transform depth //light space y extents
+			F32 z_f = z_n + d*sinGamma;
+			F32 n = (z_n+sqrtf(z_f*z_n))/sinGamma;
+			F32 f = n+d;
+			
+			if (n > f)
+			{
+				llerrs << "WTF" << llendl;
+			}
+
+			LLVector3 pos = eye - up*(n-nearDist);
+			
+			view[j] = look(pos,lightDir,up);
+
+			//one possibility for a simple perspective transformation matrix
+			//with the two parameters n(near) and f(far) in y direction
+			glh::matrix4f lispMtx;
+			// a = (f+n)/(f-n); b = -2*f*n/(f-n);
+			lispMtx.m[ 5] = (f+n)/(f-n);	// [ 1 0 0 0] 
+			lispMtx.m[13] = -2*f*n/(f-n);	// [ 0 a 0 b]
+			lispMtx.m[ 7] = 1;				// [ 0 0 1 0]
+			lispMtx.m[15] = 0;				// [ 0 1 0 0]
+
+			//temporal arrangement for the transformation of the points to post-perspective space
+			proj[j] = lispMtx*view[j];
+					
+			for (U32 i = 0; i < 16; ++i)
+			{
+				proj[j].mult_matrix_vec(wp[i]);
+			}
+
+			min = LLVector3(wp[0].v);
+			max = min;
+			for (U32 i = 1; i < 16; ++i)
+			{
+				update_min_max(min, max, LLVector3(wp[i].v));
+			}
+
+			proj[j] = scale_translate_to_fit(min, max);
+
+			proj[j] = proj[j] * lispMtx;
+
+			glh::matrix4f rh2lh;
+			rh2lh.set_scale(glh::vec3f(1.f, 1.f, -1.f));
+			proj[j] = rh2lh * proj[j];
+		}
+
+		
+		//translate and scale to from [-1, 1] to [0, 1]
+		glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
+						0.f, 0.5f, 0.f, 0.5f,
+						0.f, 0.f, 0.5f, 0.5f,
+						0.f, 0.f, 0.f, 1.f);
+
+		mSunShadowMatrix[j] = trans*proj[j]*view[j]*inv_view;
+		
+		shadow_cam.setFar(128.f);
+		shadow_cam.setOriginAndLookAt(eye, up, center);
+
+		glh_set_current_modelview(view[j]);
+		glh_set_current_projection(proj[j]);
+
+		LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
+
+		//generate sun shadow map
+		glMatrixMode(GL_PROJECTION);
+		glPushMatrix();
+		glLoadMatrixf(proj[j].m);
+		glMatrixMode(GL_MODELVIEW);
+		glPushMatrix();
+		glLoadMatrixf(view[j].m);
+
+		gGLLastMatrix = NULL;
+
+		U32 type_mask = mRenderTypeMask;
+		mRenderTypeMask = type_mask & ((1<<LLPipeline::RENDER_TYPE_SIMPLE) |
+									 (1<<LLPipeline::RENDER_TYPE_ALPHA) |
+									 (1<<LLPipeline::RENDER_TYPE_FULLBRIGHT) |
+									 (1<<LLPipeline::RENDER_TYPE_BUMP) |
+									 (1<<LLPipeline::RENDER_TYPE_VOLUME) |
+									 (1<<LLPipeline::RENDER_TYPE_AVATAR) |
+									 (1<<LLPipeline::RENDER_TYPE_TREE) |
+									 (1<<LLPipeline::RENDER_TYPE_TERRAIN));	
+
+		LLViewerImage::unbindTexture(0, GL_TEXTURE_2D);
+		
+		switch (j)
+		{
+			case 0:
+				gGL.setColorMask(true, false, false, false);
+				break;
+			case 1:
+				gGL.setColorMask(false, true, false, false);
+				break;
+			case 2:
+				gGL.setColorMask(false, false, true, false);
+				break;
+		}
+		
+		{
+			LLGLDepthTest depth(GL_TRUE);
+			glClearColor(1,1,1,1);
+			mSunShadow.clear();
+			glClearColor(0,0,0,0);
+		}
+
+		//clip out geometry on the same side of water as the camera
+		static LLCullResult result;
+		S32 occlude = LLPipeline::sUseOcclusion;
+		BOOL deferred = LLPipeline::sRenderDeferred;
+		LLPipeline::sUseOcclusion = 0;
+		LLPipeline::sShadowRender = TRUE;
+		//hack to prevent LOD updates from using sun camera origin
+		shadow_cam.setOrigin(camera.getOrigin());
+		updateCull(shadow_cam, result);
+		stateSort(shadow_cam, result);
+		LLPipeline::sRenderDeferred = FALSE;
+		
+		U32 types[] = { LLRenderPass::PASS_SIMPLE, LLRenderPass::PASS_FULLBRIGHT, LLRenderPass::PASS_SHINY };
+		LLGLEnable cull(GL_CULL_FACE);
+		
+		glColor4f(1,1,1,1);
+		LLImageGL::unbindTexture(0);
+		gDeferredShadowProgram.bind();
+
+		for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i)
+		{
+			renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE);
+		}
+		
+		{
+			LLGLEnable test(GL_ALPHA_TEST);
+			gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.6f);
+			renderObjects(LLRenderPass::PASS_ALPHA, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD | LLVertexBuffer::MAP_COLOR, TRUE);
+			glColor4f(1,1,1,1);
+			gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+		}
+
+		gDeferredShadowProgram.unbind();
+
+		renderGeomShadow(shadow_cam);
+		LLPipeline::sRenderDeferred = deferred;
+		LLPipeline::sUseOcclusion = occlude;
+		LLPipeline::sShadowRender = FALSE;
+		mRenderTypeMask = type_mask;
+		
+		glMatrixMode(GL_PROJECTION);
+		glPopMatrix();
+		glMatrixMode(GL_MODELVIEW);
+		glPopMatrix();
+		gGLLastMatrix = NULL;
+	}
+
+	mSunShadow.flush();
+
+	if (!gSavedSettings.getBOOL("CameraOffset"))
+	{
+		glh_set_current_modelview(saved_view);
+		glh_set_current_projection(saved_proj);
+	}
+	else
+	{
+		glh_set_current_modelview(view[1]);
+		glh_set_current_projection(proj[1]);
+		glLoadMatrixf(view[1].m);
+		glMatrixMode(GL_PROJECTION);
+		glLoadMatrixf(proj[1].m);
+		glMatrixMode(GL_MODELVIEW);
+	}
+	gGL.setColorMask(true, false);
 }
 
@@ -5076,4 +6137,5 @@
 				(1<<LLPipeline::RENDER_TYPE_GRASS) |
 				(1<<LLPipeline::RENDER_TYPE_SIMPLE) |
+				(1<<LLPipeline::RENDER_TYPE_FULLBRIGHT) |
 				(1<<LLPipeline::RENDER_TYPE_ALPHA) | 
 				(1<<LLPipeline::RENDER_TYPE_INVISIBLE);
@@ -5086,5 +6148,5 @@
 	S32 occlusion = sUseOcclusion;
 	sUseOcclusion = 0;
-	sReflectionRender = TRUE;
+	sReflectionRender = sRenderDeferred ? FALSE : TRUE;
 	sImpostorRender = TRUE;
 
@@ -5164,4 +6226,8 @@
 	{
 		avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE);
+		if (LLPipeline::sRenderDeferred)
+		{
+			addDeferredAttachments(avatar->mImpostor);
+		}
 		avatar->mImpostor.bindTexture();
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -5174,6 +6240,5 @@
 		glScissor(0, 0, resX, resY);
 		avatar->mImpostor.bindTarget();
-		avatar->mImpostor.getViewport(gGLViewport);
-		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+		avatar->mImpostor.clear();
 	}
 	
@@ -5188,4 +6253,5 @@
 	glStencilFunc(GL_EQUAL, 1, 0xFFFFFF);
 
+	if (!sRenderDeferred || muted)
 	{
 		LLVector3 left = camera.getLeftAxis()*tdim.mV[0]*2.f;
@@ -5218,5 +6284,4 @@
 		gGL.flush();
 
-
 		gGL.setSceneBlendType(LLRender::BT_ALPHA);
 	}
Index: /branches/shadow-draft/indra/newview/llappviewer.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/llappviewer.cpp (revision 573)
+++ /branches/shadow-draft/indra/newview/llappviewer.cpp (revision 575)
@@ -3175,4 +3175,5 @@
 
 	 gFrameStats.start(LLFrameStats::IDLE_NETWORK);
+		stop_glerror();
 		idleNetwork();
 	 stop_glerror();
Index: /branches/shadow-draft/indra/newview/llvosky.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/llvosky.cpp (revision 543)
+++ /branches/shadow-draft/indra/newview/llvosky.cpp (revision 575)
@@ -2024,5 +2024,5 @@
 	LLColor4 target_fog(0.f, 0.2f, 0.5f, 0.f);
 
-	const F32 water_height = gAgent.getRegion()->getWaterHeight();
+	const F32 water_height = gAgent.getRegion() ? gAgent.getRegion()->getWaterHeight() : 0.f;
 	// LLWorld::getInstance()->getWaterHeight();
 	F32 camera_height = gAgent.getCameraPositionAgent().mV[2];
Index: /branches/shadow-draft/indra/newview/llviewerdisplay.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/llviewerdisplay.cpp (revision 573)
+++ /branches/shadow-draft/indra/newview/llviewerdisplay.cpp (revision 575)
@@ -556,7 +556,8 @@
 			if (!for_snapshot)
 			{
+				gPipeline.generateSunShadow(*LLViewerCamera::getInstance());
 				render_ui_and_swap_if_needed();
 				gDisplaySwapBuffers = TRUE;
-				
+								
 				glh::matrix4f proj = glh_get_current_projection();
 				glh::matrix4f mod = glh_get_current_modelview();
@@ -680,8 +681,19 @@
 		//}
 
+		LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE;
+		LLPipeline::sRenderDeferred = gSavedSettings.getBOOL("RenderDeferred") && LLRenderTarget::sUseFBO &&
+			!LLPipeline::sUnderWaterRender;
+
 		if (to_texture)
 		{
 			gGL.setColorMask(true, true);
-			gPipeline.mScreen.bindTarget();
+			if (LLPipeline::sRenderDeferred)
+			{
+				gPipeline.mDeferredScreen.bindTarget();
+			}
+			else
+			{
+				gPipeline.mScreen.bindTarget();
+			}
 			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 			gGL.setColorMask(true, false);
@@ -692,5 +704,4 @@
 		{
 			gGL.setColorMask(true, false);
-			LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE;
 			gPipeline.renderGeom(*LLViewerCamera::getInstance(), TRUE);
 			LLPipeline::sUnderWaterRender = FALSE;
@@ -708,5 +719,12 @@
 		if (to_texture)
 		{
-			gPipeline.mScreen.flush();
+			if (LLPipeline::sRenderDeferred)
+			{
+				gPipeline.mDeferredScreen.flush();
+			}
+			else
+			{
+				gPipeline.mScreen.flush();
+			}
 		}
 
@@ -716,7 +734,12 @@
 		/// grasp of their full display stack just yet.
 		// gPostProcess->apply(gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight());
+
+		if (LLPipeline::sRenderDeferred)
+		{
+			gPipeline.renderDeferredLighting();
+		}
 	}
 	gFrameStats.start(LLFrameStats::RENDER_UI);
-
+	
 	if (gHandleKeysAsync)
 	{
@@ -756,5 +779,8 @@
 		U32 mask = gPipeline.getRenderTypeMask();
 		gPipeline.setRenderTypeMask(0);
-		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+		if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+		{
+			gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+		}
 
 		BOOL has_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
@@ -776,4 +802,5 @@
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_VOLUME);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA);
+		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_FULLBRIGHT);
 		
 		gPipeline.stateSort(hud_cam, result);
Index: /branches/shadow-draft/indra/newview/llglslshader.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/llglslshader.cpp (revision 573)
+++ /branches/shadow-draft/indra/newview/llglslshader.cpp (revision 575)
@@ -117,5 +117,17 @@
 
 // Deferred rendering shaders
+LLGLSLShader			gDeferredImpostorProgram;
+LLGLSLShader			gDeferredWaterProgram;
 LLGLSLShader			gDeferredDiffuseProgram;
+LLGLSLShader			gDeferredTerrainProgram;
+LLGLSLShader			gDeferredTreeProgram;
+LLGLSLShader			gDeferredAvatarProgram;
+LLGLSLShader			gDeferredAvatarAlphaProgram;
+LLGLSLShader			gDeferredLightProgram;
+LLGLSLShader			gDeferredSunProgram;
+LLGLSLShader			gDeferredSoftenProgram;
+LLGLSLShader			gDeferredShadowProgram;
+LLGLSLShader			gDeferredAvatarShadowProgram;
+LLGLSLShader			gDeferredAlphaProgram;
 
 //current avatar shader parameter pointer
@@ -137,4 +149,5 @@
 vector<string> LLShaderMgr::sAvatarAttribs;
 vector<string> LLShaderMgr::sAvatarUniforms;
+
 //vector< GLhandleARB > LLShaderMgr::sBaseObjects;
 
@@ -158,4 +171,9 @@
 	&gObjectShinyWaterProgram,
 	&gUnderWaterProgram,
+	&gDeferredSunProgram,
+	&gDeferredLightProgram,
+	&gDeferredAlphaProgram,
+	&gDeferredWaterProgram,
+	&gDeferredAvatarAlphaProgram,
 };
 const size_t LLShaderMgr::sNumShaders = sizeof(sShaderList) / sizeof(sShaderList[0]);
@@ -235,4 +253,10 @@
 		sReservedUniforms.push_back("gamma");
 		sReservedUniforms.push_back("scene_light_strength");
+		sReservedUniforms.push_back("depthMap");
+		sReservedUniforms.push_back("shadowMap");
+		sReservedUniforms.push_back("normalMap");
+		sReservedUniforms.push_back("positionMap");
+		sReservedUniforms.push_back("noiseMap");
+		sReservedUniforms.push_back("lightMap");
 
 		sWLUniforms.push_back("camPosLocal");
@@ -271,4 +295,5 @@
 		sWaterUniforms.push_back("refScale");
 		sWaterUniforms.push_back("waterHeight");
+
 	}	
 }
@@ -739,4 +764,5 @@
 		LLPipeline::sWaterReflections = gGLManager.mHasCubeMap;
 		LLPipeline::sRenderGlow = gSavedSettings.getBOOL("RenderGlow"); 
+		LLPipeline::sRenderDeferred = gSavedSettings.getBOOL("RenderDeferred") && LLRenderTarget::sUseFBO;
 	}
 	else
@@ -799,11 +825,6 @@
 		}
 
-		if (gSavedSettings.getBOOL("RenderDeferred"))
-		{
-			light_class = 1;
-			env_class = 0;
-			obj_class = 0;
-			water_class = 1;
-			effect_class = 1;
+		if (LLPipeline::sRenderDeferred)
+		{
 			deferred_class = 1;
 		}
@@ -844,10 +865,10 @@
 			loadShadersEffects();
 			loadShadersInterface();
-			loadShadersDeferred();
-
+			
 			// Load max avatar shaders to set the max level
 			sVertexShaderLevel[SHADER_AVATAR] = 3;
 			sMaxAvatarShaderLevel = 3;
 			loadShadersAvatar();
+					
 			
 #if 0 && LL_DARWIN // force avatar shaders off for mac
@@ -892,4 +913,6 @@
 				loadShadersAvatar(); // unloads
 			}
+
+			loadShadersDeferred();
 #endif
 		}
@@ -955,5 +978,17 @@
 	gPostNightVisionProgram.unload();
 
+	gDeferredAvatarProgram.unload();
+	gDeferredAvatarAlphaProgram.unload();
 	gDeferredDiffuseProgram.unload();
+	gDeferredTreeProgram.unload();
+	gDeferredImpostorProgram.unload();
+	gDeferredTerrainProgram.unload();
+	gDeferredLightProgram.unload();
+	gDeferredSunProgram.unload();
+	gDeferredSoftenProgram.unload();
+	gDeferredShadowProgram.unload();
+	gDeferredAvatarShadowProgram.unload();
+	gDeferredAlphaProgram.unload();
+	gDeferredWaterProgram.unload();
 
 	sVertexShaderLevel[SHADER_LIGHTING] = 0;
@@ -1261,7 +1296,21 @@
 	if (sVertexShaderLevel[SHADER_DEFERRED] == 0)
 	{
+		gDeferredTreeProgram.unload();
 		gDeferredDiffuseProgram.unload();
+		gDeferredImpostorProgram.unload();
+		gDeferredTerrainProgram.unload();
+		gDeferredLightProgram.unload();
+		gDeferredSunProgram.unload();
+		gDeferredSoftenProgram.unload();
+		gDeferredShadowProgram.unload();
+		gDeferredAvatarShadowProgram.unload();
+		gDeferredAvatarProgram.unload();
+		gDeferredAvatarAlphaProgram.unload();
+		gDeferredAlphaProgram.unload();
+		gDeferredWaterProgram.unload();
 		return FALSE;
 	}
+
+	sVertexShaderLevel[SHADER_AVATAR] = 1;
 
 	BOOL success = TRUE;
@@ -1275,4 +1324,141 @@
 		gDeferredDiffuseProgram.mShaderLevel = sVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredDiffuseProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredTreeProgram.mName = "Deffered Tree Shader";
+		gDeferredTreeProgram.mShaderFiles.clear();
+		gDeferredTreeProgram.mShaderFiles.push_back(make_pair("deferred/treeV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredTreeProgram.mShaderFiles.push_back(make_pair("deferred/treeF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredTreeProgram.mShaderLevel = sVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredTreeProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredImpostorProgram.mName = "Deffered Impostor Shader";
+		gDeferredImpostorProgram.mShaderFiles.clear();
+		gDeferredImpostorProgram.mShaderFiles.push_back(make_pair("deferred/impostorV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredImpostorProgram.mShaderFiles.push_back(make_pair("deferred/impostorF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredImpostorProgram.mShaderLevel = sVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredImpostorProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredLightProgram.mName = "Deffered Light Shader";
+		gDeferredLightProgram.mShaderFiles.clear();
+		gDeferredLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredLightProgram.mShaderLevel = sVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredLightProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredSunProgram.mName = "Deffered Sun Shader";
+		gDeferredSunProgram.mShaderFiles.clear();
+		gDeferredSunProgram.mShaderFiles.push_back(make_pair("deferred/sunLightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredSunProgram.mShaderFiles.push_back(make_pair("deferred/sunLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredSunProgram.mShaderLevel = sVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredSunProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredAlphaProgram.mName = "Deffered Alpha Shader";
+		gDeferredAlphaProgram.mFeatures.calculatesLighting = true;
+		gDeferredAlphaProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredAlphaProgram.mFeatures.hasGamma = true;
+		gDeferredAlphaProgram.mFeatures.hasAtmospherics = true;
+		gDeferredAlphaProgram.mFeatures.hasLighting = true;
+		gDeferredAlphaProgram.mShaderFiles.clear();
+		gDeferredAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredAlphaProgram.mShaderLevel = sVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredAlphaProgram.createShader(NULL, NULL);
+	}
+
+		if (success)
+	{
+		// load water shader
+		gDeferredWaterProgram.mName = "Deferred Water Shader";
+		gDeferredWaterProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredWaterProgram.mFeatures.hasGamma = true;
+		gDeferredWaterProgram.mFeatures.hasTransport = true;
+		gDeferredWaterProgram.mShaderFiles.clear();
+		gDeferredWaterProgram.mShaderFiles.push_back(make_pair("deferred/waterV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredWaterProgram.mShaderFiles.push_back(make_pair("deferred/waterF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredWaterProgram.mShaderLevel = sVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredWaterProgram.createShader(NULL, &sWaterUniforms);
+	}
+
+	if (success)
+	{
+		gDeferredSoftenProgram.mName = "Deffered Soften Shader";
+		gDeferredSoftenProgram.mShaderFiles.clear();
+		gDeferredSoftenProgram.mShaderFiles.push_back(make_pair("deferred/softenLightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredSoftenProgram.mShaderFiles.push_back(make_pair("deferred/softenLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredSoftenProgram.mShaderLevel = sVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredSoftenProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredShadowProgram.mName = "Deffered Shadow Shader";
+		gDeferredShadowProgram.mShaderFiles.clear();
+		gDeferredShadowProgram.mShaderFiles.push_back(make_pair("deferred/shadowV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredShadowProgram.mShaderFiles.push_back(make_pair("deferred/shadowF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredShadowProgram.mShaderLevel = sVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredShadowProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredAvatarShadowProgram.mName = "Deffered Avatar Shadow Shader";
+		gDeferredAvatarShadowProgram.mFeatures.hasSkinning = true;
+		gDeferredAvatarShadowProgram.mShaderFiles.clear();
+		gDeferredAvatarShadowProgram.mShaderFiles.push_back(make_pair("deferred/avatarShadowV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredAvatarShadowProgram.mShaderFiles.push_back(make_pair("deferred/avatarShadowF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredAvatarShadowProgram.mShaderLevel = sVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredAvatarShadowProgram.createShader(&sAvatarAttribs, &sAvatarUniforms);
+	}
+
+	if (success)
+	{
+		gTerrainProgram.mName = "Deferred Terrain Shader";
+		gDeferredTerrainProgram.mShaderFiles.clear();
+		gDeferredTerrainProgram.mShaderFiles.push_back(make_pair("deferred/terrainV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredTerrainProgram.mShaderFiles.push_back(make_pair("deferred/terrainF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredTerrainProgram.mShaderLevel = sVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredTerrainProgram.createShader(NULL, &sTerrainUniforms);
+	}
+
+	if (success)
+	{
+		gDeferredAvatarProgram.mName = "Avatar Shader";
+		gDeferredAvatarProgram.mFeatures.hasSkinning = true;
+		gDeferredAvatarProgram.mShaderFiles.clear();
+		gDeferredAvatarProgram.mShaderFiles.push_back(make_pair("deferred/avatarV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredAvatarProgram.mShaderFiles.push_back(make_pair("deferred/avatarF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredAvatarProgram.mShaderLevel = sVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredAvatarProgram.createShader(&sAvatarAttribs, &sAvatarUniforms);
+	}
+
+	if (success)
+	{
+		gDeferredAvatarAlphaProgram.mName = "Avatar Alpha Shader";
+		gDeferredAvatarAlphaProgram.mFeatures.hasSkinning = true;
+		gDeferredAvatarAlphaProgram.mFeatures.calculatesLighting = true;
+		gDeferredAvatarAlphaProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredAvatarAlphaProgram.mFeatures.hasGamma = true;
+		gDeferredAvatarAlphaProgram.mFeatures.hasAtmospherics = true;
+		gDeferredAvatarAlphaProgram.mFeatures.hasLighting = true;
+		gDeferredAvatarAlphaProgram.mShaderFiles.clear();
+		gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/avatarAlphaV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/avatarAlphaF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredAvatarAlphaProgram.mShaderLevel = sVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredAvatarAlphaProgram.createShader(&sAvatarAttribs, &sAvatarUniforms);
 	}
 
Index: /branches/shadow-draft/indra/newview/lldrawpoolsky.h
===================================================================
--- /branches/shadow-draft/indra/newview/lldrawpoolsky.h (revision 280)
+++ /branches/shadow-draft/indra/newview/lldrawpoolsky.h (revision 575)
@@ -59,4 +59,9 @@
 	/*virtual*/ LLDrawPool *instancePool();
 
+	/*virtual*/ S32 getNumPostDeferredPasses() { return getNumPasses(); }
+	/*virtual*/ void beginPostDeferredPass(S32 pass) { beginRenderPass(pass); }
+	/*virtual*/ void endPostDeferredPass(S32 pass) { endRenderPass(pass); }
+	/*virtual*/ void renderPostDeferred(S32 pass) { render(pass); }
+
 	/*virtual*/ void prerender();
 	/*virtual*/ void render(S32 pass = 0);
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl (revision 575)
@@ -0,0 +1,20 @@
+/** 
+ * @file impostorF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+uniform sampler2D normalMap;
+uniform sampler2D specularMap;
+
+varying vec4 vary_position;
+
+void main() 
+{
+	gl_FragData[0] = texture2D(diffuseMap, gl_TexCoord[0].xy);
+	gl_FragData[1] = texture2D(specularMap, gl_TexCoord[0].xy);
+	gl_FragData[2].xyz = texture2D(normalMap, gl_TexCoord[0].xy).xyz;
+	gl_FragData[3] = vary_position;
+}
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/sunLightV.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/sunLightV.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/sunLightV.glsl (revision 575)
@@ -0,0 +1,21 @@
+/** 
+ * @file sunLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec4 vary_light;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	
+	vec4 tex = gl_MultiTexCoord0;
+	tex.w = 1.0;
+	
+	vary_light = gl_MultiTexCoord0;
+		
+	gl_FrontColor = gl_Color;
+}
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl (revision 575)
@@ -0,0 +1,20 @@
+/** 
+ * @file avatarF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+
+varying vec3 vary_normal;
+varying vec4 vary_position;
+
+void main() 
+{
+	gl_FragData[0] = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].xy);
+	gl_FragData[1] = vec4(0,0,0,0);
+	gl_FragData[2].xyz = normalize(vary_normal);
+	gl_FragData[3] = vary_position;
+}
+
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl (revision 575)
@@ -0,0 +1,22 @@
+/** 
+ * @file treeV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec3 vary_normal;
+varying vec4 vary_position;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+	
+	vary_position = gl_ModelViewMatrix * gl_Vertex;
+	
+	vary_normal = normalize(gl_NormalMatrix * gl_Normal);
+
+	gl_FrontColor = gl_Color;
+}
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl (revision 575)
@@ -0,0 +1,63 @@
+/** 
+ * @file pointLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2DRect diffuseMap;
+uniform sampler2DRect specularMap;
+uniform sampler2DRect positionMap;
+uniform sampler2DRect normalMap;
+uniform samplerCube environmentMap;
+uniform sampler2DRect lightMap;
+
+uniform vec3 env_mat[3];
+uniform float sun_wash;
+
+varying vec4 vary_light;
+
+void main() 
+{
+	vec3 pos = texture2DRect(positionMap, gl_FragCoord.xy).xyz;
+	vec3 lv = vary_light.xyz-pos;
+	float dist2 = dot(lv,lv);
+	if (dist2 > vary_light.w)
+	{
+		discard;
+	}
+	
+	vec3 norm = texture2DRect(normalMap, gl_FragCoord.xy).xyz;
+	vec4 spec = texture2DRect(specularMap, gl_FragCoord.xy);
+	
+	if (dot(norm, lv) < 0.0 && spec.a == 0.0)
+	{
+		discard;
+	}
+	
+	
+	lv = normalize(lv);
+	float da = dot(norm, lv);
+	
+	vec3 col = texture2DRect(diffuseMap, gl_FragCoord.xy).rgb;
+	float fa = gl_Color.a+1.0;
+	float dist_atten = clamp(1.0-(dist2-vary_light.w*(1.0-fa))/(vary_light.w*fa), 0.0, 1.0);
+	float lit = da * dist_atten;
+	
+	col = gl_Color.rgb*lit*col;
+	
+	if (spec.a > 0.0)
+	{
+		vec3 ref = reflect(normalize(pos), norm);
+		da = dot(ref,lv);
+		da = max(da, 0.0);
+		da = pow(da, 128.0 * spec.a*spec.a/dist_atten)*min(dist_atten*4.0, 1.0);
+		col += da*gl_Color.rgb*spec.rgb;
+	}
+	
+	vec3 light = texture2DRect(lightMap, gl_FragCoord.xy);
+	light *= sun_wash;
+			
+	gl_FragColor = vec4(col*(1.0-light), 1.0);	
+	//gl_FragColor.rgb = vec3(spec.a);
+}
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl (revision 575)
@@ -0,0 +1,165 @@
+/** 
+ * @file waterF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+vec3 scaleSoftClip(vec3 inColor);
+vec3 atmosTransport(vec3 inColor);
+
+uniform sampler2D bumpMap; 
+uniform sampler2D screenTex;
+uniform sampler2D refTex;
+uniform sampler2D shadowMap;
+uniform sampler2D noiseMap;
+
+uniform mat4 shadow_matrix[3];
+uniform vec3 shadow_clip;
+
+uniform float sunAngle;
+uniform float sunAngle2;
+uniform vec3 lightDir;
+uniform vec3 specular;
+uniform float lightExp;
+uniform float refScale;
+uniform float kd;
+uniform vec2 screenRes;
+uniform vec3 normScale;
+uniform float fresnelScale;
+uniform float fresnelOffset;
+uniform float blurMultiplier;
+
+
+//bigWave is (refCoord.w, view.w);
+varying vec4 refCoord;
+varying vec4 littleWave;
+varying vec4 view;
+varying vec4 vary_position;
+varying vec3 vary_normal;
+
+void main() 
+{
+	vec4 color;
+	float dist = length(view.xy);
+	
+	//normalize view vector
+	vec3 viewVec = normalize(view.xyz);
+	
+	//get wave normals
+	vec3 wave1 = texture2D(bumpMap, vec2(refCoord.w, view.w)).xyz*2.0-1.0;
+	vec3 wave2 = texture2D(bumpMap, littleWave.xy).xyz*2.0-1.0;
+	vec3 wave3 = texture2D(bumpMap, littleWave.zw).xyz*2.0-1.0;
+	//get base fresnel components	
+	
+	vec3 df = vec3(
+					dot(viewVec, wave1),
+					dot(viewVec, (wave2 + wave3) * 0.5),
+					dot(viewVec, wave3)
+				 ) * fresnelScale + fresnelOffset;
+	df *= df;
+		 
+	vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5;
+	
+	float dist2 = dist;
+	dist = max(dist, 5.0);
+	
+	float dmod = sqrt(dist);
+	
+	vec2 dmod_scale = vec2(dmod*dmod, dmod);
+	
+	//get reflected color
+	vec2 refdistort1 = wave1.xy*normScale.x;
+	vec2 refvec1 = distort+refdistort1/dmod_scale;
+	vec4 refcol1 = texture2D(refTex, refvec1);
+	
+	vec2 refdistort2 = wave2.xy*normScale.y;
+	vec2 refvec2 = distort+refdistort2/dmod_scale;
+	vec4 refcol2 = texture2D(refTex, refvec2);
+	
+	vec2 refdistort3 = wave3.xy*normScale.z;
+	vec2 refvec3 = distort+refdistort3/dmod_scale;
+	vec4 refcol3 = texture2D(refTex, refvec3);
+
+	vec4 refcol = refcol1 + refcol2 + refcol3;
+	float df1 = df.x + df.y + df.z;
+	refcol *= df1 * 0.333;
+	
+	vec3 wavef = (wave1 + wave2 * 0.4 + wave3 * 0.6) * 0.5;
+	wavef.z *= max(-viewVec.z, 0.1);
+	wavef = normalize(wavef);
+	
+	float df2 = dot(viewVec, wavef) * fresnelScale+fresnelOffset;
+	
+	vec2 refdistort4 = wavef.xy*0.125;
+	refdistort4.y -= abs(refdistort4.y);
+	vec2 refvec4 = distort+refdistort4/dmod;
+	float dweight = min(dist2*blurMultiplier, 1.0);
+	vec4 baseCol = texture2D(refTex, refvec4);
+	refcol = mix(baseCol*df2, refcol, dweight);
+
+	//get specular component
+	float spec = clamp(dot(lightDir, (reflect(viewVec,wavef))),0.0,1.0);
+		
+	//harden specular
+	spec = pow(spec, 128.0);
+
+	//figure out distortion vector (ripply) 
+	vec2 distort2 = distort+wavef.xy*refScale/max(dmod*df1, 1.0);
+		
+	vec4 fb = texture2D(screenTex, distort2);
+	
+	//mix with reflection
+	// Note we actually want to use just df1, but multiplying by 0.999999 gets around and nvidia compiler bug
+	color.rgb = mix(fb.rgb, refcol.rgb, df1 * 0.99999);
+	
+	float shadow = 1.0;
+	vec4 pos = vary_position;
+	vec3 norm = normalize(vary_normal);
+	
+	int i = 0;
+	if (pos.z < -shadow_clip.x)
+	{
+		i++;
+	}
+	if (pos.z < -shadow_clip.y)
+	{
+		i++;
+	}
+
+	vec4 lpos;
+	if (pos.z > -shadow_clip.z)
+	{	
+		dist = sqrt(-pos.z)*0.1;
+		vec4 spos = pos;
+		spos.xyz += norm*dist;
+	
+		lpos = (shadow_matrix[i]*spos);
+		vec3 depth = texture2DProj(shadowMap, lpos).xyz;
+		float d[3];
+		d[0] = depth.x; d[1] = depth.y; d[2] = depth.z;
+			
+		float sdist = lpos.z/lpos.w - d[i];
+		if (sdist > 0)
+		{
+			vec3 nz = norm * max(length(pos)/8.0, 1.0) +
+				texture2D(noiseMap, gl_FragCoord.xy/128.0).xyz;
+			lpos = (shadow_matrix[i]*
+				 (spos + vec4(nz*0.5, 0.0)));
+			depth = texture2DProj(shadowMap, lpos).xyz;
+			d[0] = depth.x; d[1] = depth.y; d[2] = depth.z;
+			float shadow2 = d[i] < lpos.z/lpos.w ? 0.0 : 1.0;
+			
+			shadow = shadow2*0.5;
+		}
+	}
+	
+	spec *= shadow;
+	color.rgb += spec * specular;
+	
+	color.rgb = atmosTransport(color.rgb);
+	color.rgb = scaleSoftClip(color.rgb);
+	color.a = spec * sunAngle2;
+
+	gl_FragColor = color;
+}
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl (revision 575)
@@ -0,0 +1,16 @@
+/** 
+ * @file avatarShadowF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+
+
+void main() 
+{
+	gl_FragColor.rgb = vec3(gl_FragCoord.z);
+	gl_FragColor.a = gl_Color.a * texture2D(diffuseMap, gl_TexCoord[0].xy);
+}
+
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaF.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaF.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaF.glsl (revision 575)
@@ -0,0 +1,73 @@
+/** 
+ * @file avatarAlphaF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+uniform sampler2D shadowMap;
+uniform sampler2D noiseMap;
+
+uniform mat4 shadow_matrix[3];
+uniform vec3 shadow_clip;
+
+vec3 atmosLighting(vec3 light);
+vec3 scaleSoftClip(vec3 light);
+
+varying vec3 vary_ambient;
+varying vec3 vary_directional;
+varying vec4 vary_position;
+varying vec3 vary_normal;
+
+void main() 
+{
+	float shadow = 1.0;
+	vec4 pos = vary_position;
+	vec3 norm = normalize(vary_normal);
+	float dist = sqrt(-pos.z)*0.1;
+	
+	int i = 0;
+	if (pos.z < -shadow_clip.x)
+	{
+		i++;
+	}
+	if (pos.z < -shadow_clip.y)
+	{
+		i++;
+	}
+
+	if (pos.z > -shadow_clip.z)
+	{	
+		vec4 spos = pos;
+		spos.xyz += norm*dist;
+	
+		vec4 lpos = (shadow_matrix[i]*spos);
+		vec3 depth = texture2DProj(shadowMap, lpos).xyz;
+		float d[3];
+		d[0] = depth.x; d[1] = depth.y; d[2] = depth.z;
+			
+		float sdist = lpos.z/lpos.w - d[i];
+		if (sdist > 0)
+		{
+			vec3 nz = norm * max(length(pos)/8.0, 1.0) +
+				texture2D(noiseMap, gl_FragCoord.xy/128.0).xyz;
+			lpos = (shadow_matrix[i]*
+				 (spos + vec4(nz*0.01, 0.0)));
+			depth = texture2DProj(shadowMap, lpos).xyz;
+			d[0] = depth.x; d[1] = depth.y; d[2] = depth.z;
+			float shadow2 = d[i] < lpos.z/lpos.w ? 0.0 : 1.0;
+			
+			shadow = shadow2*0.5;
+		}
+	}
+	
+	vec4 col = vec4(vary_ambient + vary_directional*shadow, gl_Color.a);	
+	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * col;
+	
+	color.rgb = atmosLighting(color.rgb);
+
+	color.rgb = scaleSoftClip(color.rgb);
+
+	gl_FragColor = color;
+}
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl (revision 575)
@@ -0,0 +1,41 @@
+/** 
+ * @file terrainV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec3 vary_normal;
+varying vec4 vary_position;
+
+vec4 texgen_object(vec4 vpos, vec4 tc, mat4 mat, vec4 tp0, vec4 tp1)
+{
+	vec4 tcoord;
+	
+	tcoord.x = dot(vpos, tp0);
+	tcoord.y = dot(vpos, tp1);
+	tcoord.z = tc.z;
+	tcoord.w = tc.w;
+	
+	tcoord = mat * tcoord; 
+	
+	return tcoord; 
+}
+
+void main()
+{
+	//transform vertex
+	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
+			
+	vary_position = gl_ModelViewMatrix * gl_Vertex;
+	vary_normal = normalize(gl_NormalMatrix * gl_Normal);
+	
+	// Transform and pass tex coords
+ 	gl_TexCoord[0].xy = texgen_object(gl_Vertex, gl_MultiTexCoord0, gl_TextureMatrix[0], gl_ObjectPlaneS[0], gl_ObjectPlaneT[0]).xy;
+	
+	vec4 t = gl_MultiTexCoord1;
+	
+	gl_TexCoord[0].zw = t.xy;
+	gl_TexCoord[1].xy = t.xy-vec2(2.0, 0.0);
+	gl_TexCoord[1].zw = t.xy-vec2(1.0, 0.0);
+}
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl (revision 575)
@@ -0,0 +1,15 @@
+/** 
+ * @file shadowF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+
+
+void main() 
+{
+	gl_FragColor.rgb = vec3(gl_FragCoord.z);
+	gl_FragColor.a = texture2D(diffuseMap, gl_TexCoord[0].xy).a * gl_Color.a;
+}
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl (revision 387)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl (revision 575)
@@ -9,8 +9,12 @@
 
 varying vec3 vary_normal;
+varying vec4 vary_position;
 
 void main() 
 {
-	gl_FragColor = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].xy);
-	gl_FragColor.rgb = vary_normal*0.5+0.5;
+	vec3 col = texture2D(diffuseMap, gl_TexCoord[0].xy).rgb;
+	gl_FragData[0] = vec4(gl_Color.rgb*col, 1.0);
+	gl_FragData[1] = vec4(col*(gl_Color.a*1.5), gl_Color.a);
+	gl_FragData[2].xyz = normalize(vary_normal);
+	gl_FragData[3] = vary_position;
 }
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl (revision 575)
@@ -0,0 +1,75 @@
+/** 
+ * @file alphaF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+uniform sampler2D shadowMap;
+uniform sampler2D noiseMap;
+
+uniform mat4 shadow_matrix[3];
+uniform vec3 shadow_clip;
+
+vec3 atmosLighting(vec3 light);
+vec3 scaleSoftClip(vec3 light);
+
+varying vec3 vary_ambient;
+varying vec3 vary_directional;
+varying vec4 vary_position;
+varying vec3 vary_normal;
+
+void main() 
+{
+	float shadow = 1.0;
+	vec4 pos = vary_position;
+	vec3 norm = normalize(vary_normal);
+	float dist = sqrt(-pos.z)*0.1;
+	
+	int i = 0;
+	if (pos.z < -shadow_clip.x)
+	{
+		i++;
+	}
+	if (pos.z < -shadow_clip.y)
+	{
+		i++;
+	}
+
+	if (pos.z > -shadow_clip.z)
+	{	
+		vec4 spos = pos;
+		spos.xyz += norm*dist;
+	
+		vec4 lpos = (shadow_matrix[i]*spos);
+		vec3 depth = texture2DProj(shadowMap, lpos).xyz;
+		float d[3];
+		d[0] = depth.x; d[1] = depth.y; d[2] = depth.z;
+			
+		float sdist = lpos.z/lpos.w - d[i];
+		if (sdist > 0)
+		{
+			vec3 nz = norm * max(length(pos)/8.0, 1.0) +
+				texture2D(noiseMap, gl_FragCoord.xy/128.0).xyz;
+			lpos = (shadow_matrix[i]*
+				 (spos + vec4(nz*0.01, 0.0)));
+			depth = texture2DProj(shadowMap, lpos).xyz;
+			d[0] = depth.x; d[1] = depth.y; d[2] = depth.z;
+			float shadow2 = d[i] < lpos.z/lpos.w ? 0.0 : 1.0;
+			
+			shadow = shadow2*0.5;
+		}
+	}
+	
+	vec4 col = vec4(vary_ambient + vary_directional*shadow, gl_Color.a);
+	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * col;
+	
+	color.rgb = atmosLighting(color.rgb);
+
+	color.rgb = scaleSoftClip(color.rgb);
+
+	//gl_FragColor = gl_Color;
+	gl_FragColor = color;
+}
+
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl (revision 575)
@@ -0,0 +1,106 @@
+/** 
+ * @file softenLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2DRect diffuseMap;
+uniform sampler2DRect specularMap;
+uniform sampler2DRect positionMap;
+uniform sampler2DRect normalMap;
+uniform sampler2DRect depthMap;
+uniform sampler2DRect lightMap;
+uniform samplerCube environmentMap;
+
+uniform vec3 env_mat[3];
+
+uniform vec4 gamma;
+
+vec3 scaleSoftClip(vec3 light)
+{
+	//soft clip effect:
+	light = 1. - clamp(light, vec3(0.), vec3(1.));
+	light = 1. - pow(light, gamma.xxx);
+
+	return light;
+}
+
+vec2 kern[] = 
+{
+	16*vec2(0.7, 0.7),
+	15*vec2(-0.7, -0.7),
+	14*vec2(-0.7, 0.7),
+	13*vec2(0.7, -0.7),
+	12*vec2(1.0, 0.0),
+	11*vec2(-1.0, 0.0),
+	10*vec2(0.0, 1.0),
+	9*vec2(0.0, -1.0),
+
+	8*vec2(0.7, 0.7),
+	7*vec2(-0.7, -0.7),
+	6*vec2(-0.7, 0.7),
+	5*vec2(0.7, -0.7),
+	4*vec2(1.0, 0.0),
+	3*vec2(-1.0, 0.0),
+	2*vec2(0.0, 1.0),
+	1*vec2(0.0, -1.0)
+};
+
+void main() 
+{
+	vec3 pos = texture2DRect(positionMap, gl_FragCoord.xy).xyz;
+	vec3 norm = texture2DRect(normalMap, gl_FragCoord.xy).xyz;
+	
+	float dist = clamp(16.0/sqrt(-pos.z), 1.0/8.0, 1.0)*0.5;
+	vec2 nd = dist/(norm.xy*norm.xy*4.0+1.0);
+	
+	vec4 diffuse = vec4(texture2DRect(diffuseMap, gl_FragCoord.xy).rgb, 1.0);
+	vec4 spec = texture2DRect(specularMap, gl_FragCoord.xy);
+	
+	vec4 col = texture2DRect(lightMap, gl_FragCoord.xy);
+	vec4 centcol = col;
+
+	int count = 1;
+
+	for (int i = 0; i < 16; i++) {	
+		vec2 coord = gl_FragCoord.xy+kern[i]*nd;
+		//vec3 cpos = texture2DRect(positionMap, coord).xyz;
+		vec3 cnorm = texture2DRect(normalMap, coord).xyz;	
+		
+		if (dot(cnorm, norm) > 0.9) {
+			count++;
+			col += texture2DRect(lightMap, coord);
+
+			vec4 delta = centcol-col/count;
+			if (count==5 &&
+			 dot(delta, delta) < 0.001) {
+				// first four coarsest surrounding samples were
+				// fairly identical to centre; don't bother
+				// taking any more (quite expensive) samples.
+				break;
+			}
+		}
+	}
+	
+	col = diffuse*col/count;
+	
+	spec *= col.a*0.5+0.5;
+	if (spec.a > 0.2)
+	{
+		vec3 ref = reflect(pos.xyz, norm);
+		vec3 rc;
+		rc.x = dot(ref, env_mat[0]);
+		rc.y = dot(ref, env_mat[1]);
+		rc.z = dot(ref, env_mat[2]);
+		
+		vec3 refcol = textureCube(environmentMap, rc).rgb;
+		col.rgb += refcol * spec.rgb; 
+	}
+					
+	gl_FragColor.rgb = col;
+	//gl_FragColor.rgb = pos/8.0*0.5+0.5;
+	//gl_FragColor.rgb = vec3(diffuse.a);
+	gl_FragColor.a = 1.0;
+	gl_FragDepth = texture2DRect(depthMap, gl_FragCoord.xy).x;
+}
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/impostorV.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/impostorV.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/impostorV.glsl (revision 575)
@@ -0,0 +1,19 @@
+/** 
+ * @file impostorV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec4 vary_position;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+	
+	vary_position = gl_ModelViewMatrix * gl_Vertex;
+
+	gl_FrontColor = gl_Color;
+}
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl (revision 575)
@@ -0,0 +1,294 @@
+/** 
+ * @file sunLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+//uniform sampler2DRect diffuseMap;
+uniform sampler2DRect specularMap;
+uniform sampler2DRect positionMap;
+uniform sampler2DRect normalMap;
+uniform sampler2DRect depthMap;
+uniform sampler2D shadowMap;
+uniform sampler2D noiseMap;
+
+// Inputs
+uniform vec4 morphFactor;
+uniform vec3 camPosLocal;
+//uniform vec4 camPosWorld;
+uniform vec4 gamma;
+uniform vec4 lightnorm;
+uniform vec4 sunlight_color;
+uniform vec4 ambient;
+uniform vec4 blue_horizon;
+uniform vec4 blue_density;
+uniform vec4 haze_horizon;
+uniform vec4 haze_density;
+uniform vec4 cloud_shadow;
+uniform vec4 density_multiplier;
+uniform vec4 distance_multiplier;
+uniform vec4 max_y;
+uniform vec4 glow;
+uniform float scene_light_strength;
+uniform vec3 env_mat[3];
+uniform mat4 shadow_matrix[3];
+uniform vec3 shadow_clip;
+varying vec4 vary_light;
+
+vec3 vary_PositionEye;
+
+vec3 vary_SunlitColor;
+vec3 vary_AmblitColor;
+vec3 vary_AdditiveColor;
+vec3 vary_AtmosAttenuation;
+
+vec3 getPositionEye()
+{
+	return vary_PositionEye;
+}
+vec3 getSunlitColor()
+{
+	return vary_SunlitColor;
+}
+vec3 getAmblitColor()
+{
+	return vary_AmblitColor;
+}
+vec3 getAdditiveColor()
+{
+	return vary_AdditiveColor;
+}
+vec3 getAtmosAttenuation()
+{
+	return vary_AtmosAttenuation;
+}
+
+
+void setPositionEye(vec3 v)
+{
+	vary_PositionEye = v;
+}
+
+void setSunlitColor(vec3 v)
+{
+	vary_SunlitColor = v;
+}
+
+void setAmblitColor(vec3 v)
+{
+	vary_AmblitColor = v;
+}
+
+void setAdditiveColor(vec3 v)
+{
+	vary_AdditiveColor = v;
+}
+
+void setAtmosAttenuation(vec3 v)
+{
+	vary_AtmosAttenuation = v;
+}
+
+void calcAtmospherics(vec3 inPositionEye) {
+
+	vec3 P = inPositionEye;
+	setPositionEye(P);
+	
+	//(TERRAIN) limit altitude
+	if (P.y > max_y.x) P *= (max_y.x / P.y);
+	if (P.y < -max_y.x) P *= (-max_y.x / P.y);
+
+	vec3 tmpLightnorm = lightnorm.xyz;
+
+	vec3 Pn = normalize(P);
+	float Plen = length(P);
+
+	vec4 temp1 = vec4(0);
+	vec3 temp2 = vec3(0);
+	vec4 blue_weight;
+	vec4 haze_weight;
+	vec4 sunlight = sunlight_color;
+	vec4 light_atten;
+
+	//sunlight attenuation effect (hue and brightness) due to atmosphere
+	//this is used later for sunlight modulation at various altitudes
+	light_atten = (blue_density * 1.0 + vec4(haze_density.r) * 0.25) * (density_multiplier.x * max_y.x);
+		//I had thought blue_density and haze_density should have equal weighting,
+		//but attenuation due to haze_density tends to seem too strong
+
+	temp1 = blue_density + vec4(haze_density.r);
+	blue_weight = blue_density / temp1;
+	haze_weight = vec4(haze_density.r) / temp1;
+
+	//(TERRAIN) compute sunlight from lightnorm only (for short rays like terrain)
+	temp2.y = max(0.0, tmpLightnorm.y);
+	temp2.y = 1. / temp2.y;
+	sunlight *= exp( - light_atten * temp2.y);
+
+	// main atmospheric scattering line integral
+	temp2.z = Plen * density_multiplier.x;
+
+	// Transparency (-> temp1)
+	// ATI Bugfix -- can't store temp1*temp2.z*distance_multiplier.x in a variable because the ati
+	// compiler gets confused.
+	temp1 = exp(-temp1 * temp2.z * distance_multiplier.x);
+
+	//final atmosphere attenuation factor
+	setAtmosAttenuation(temp1.rgb);
+	
+	//compute haze glow
+	//(can use temp2.x as temp because we haven't used it yet)
+	temp2.x = dot(Pn, tmpLightnorm.xyz);
+	temp2.x = 1. - temp2.x;
+		//temp2.x is 0 at the sun and increases away from sun
+	temp2.x = max(temp2.x, .03);	//was glow.y
+		//set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot)
+	temp2.x *= glow.x;
+		//higher glow.x gives dimmer glow (because next step is 1 / "angle")
+	temp2.x = pow(temp2.x, glow.z);
+		//glow.z should be negative, so we're doing a sort of (1 / "angle") function
+
+	//add "minimum anti-solar illumination"
+	temp2.x += .25;
+
+
+	//increase ambient when there are more clouds
+	vec4 tmpAmbient = ambient + (vec4(1.) - ambient) * cloud_shadow.x * 0.5;
+
+	//haze color
+	setAdditiveColor(
+		vec3(blue_horizon * blue_weight * (sunlight*(1.-cloud_shadow.x) + tmpAmbient)
+	 + (haze_horizon.r * haze_weight) * (sunlight*(1.-cloud_shadow.x) * temp2.x
+		 + tmpAmbient)));
+
+	//brightness of surface both sunlight and ambient
+	setSunlitColor(vec3(sunlight * .5));
+	setAmblitColor(vec3(tmpAmbient * .25));
+	setAdditiveColor(getAdditiveColor() * vec3(1.0 - temp1));
+}
+
+vec3 atmosLighting(vec3 light)
+{
+	light *= getAtmosAttenuation().r;
+	light += getAdditiveColor();
+	return (2.0 * light);
+}
+
+vec3 atmosTransport(vec3 light) {
+	light *= getAtmosAttenuation().r;
+	light += getAdditiveColor() * 2.0;
+	return light;
+}
+vec3 atmosGetDiffuseSunlightColor()
+{
+	return getSunlitColor();
+}
+
+vec3 scaleDownLight(vec3 light)
+{
+	return (light / scene_light_strength );
+}
+
+vec3 scaleUpLight(vec3 light)
+{
+	return (light * scene_light_strength);
+}
+
+vec3 atmosAmbient(vec3 light)
+{
+	return getAmblitColor() + light / 2.0;
+}
+
+vec3 atmosAffectDirectionalLight(float lightIntensity)
+{
+	return getSunlitColor() * lightIntensity;
+}
+
+vec3 scaleSoftClip(vec3 light)
+{
+	//soft clip effect:
+	light = 1. - clamp(light, vec3(0.), vec3(1.));
+	light = 1. - pow(light, gamma.xxx);
+
+	return light;
+}
+
+vec2 kern[] = 
+{
+	vec2(-1.0, -1.0),
+	vec2(1.0, -1.0),
+	vec2(1.0, 1.0),
+	vec2(-1.0, 1.0),
+	vec2(0.0, -2.0),
+	vec2(2.0, 0.0),
+	vec2(0.0, 2.0),
+	vec2(-2.0, 0.0)
+};
+
+void main() 
+{
+	vec3 norm = texture2DRect(normalMap, gl_FragCoord.xy).xyz;
+	//vec3 diffuse = texture2DRect(diffuseMap, gl_FragCoord.xy).rgb;
+	vec3 nz = texture2D(noiseMap, gl_FragCoord.xy/128.0).xyz;
+		
+	vec4 spec = texture2DRect(specularMap, gl_FragCoord.xy);
+	
+	float da = max(dot(norm, vary_light.xyz), 0.0);
+	vec4 pos = texture2DRect(positionMap, gl_FragCoord.xy).xyzw;
+	nz += norm * max(length(pos)/8.0, 1.0);
+	calcAtmospherics(pos.xyz);
+	
+	float dist = sqrt(-pos.z)*0.05;
+		
+	vec3 col = atmosAmbient(vec3(0));
+	int i = 0;
+	if (pos.z < -shadow_clip.x)
+	{
+		i++;
+	}
+	if (pos.z < -shadow_clip.y)
+	{
+		i++;
+	}
+
+	float shadow = 1.0;
+	
+	if (pos.z > -shadow_clip.z)
+	{	
+		vec4 spos = pos;
+		spos.xyz += norm*dist;
+	
+		vec4 lpos = (shadow_matrix[i]*spos);
+		vec3 depth = texture2DProj(shadowMap, lpos).xyz;
+		float d[3];
+		d[0] = depth.x; d[1] = depth.y; d[2] = depth.z;
+			
+		float sdist = lpos.z/lpos.w - d[i];
+		if (sdist > 0)
+		{
+			lpos = (shadow_matrix[i]*
+				 (spos + vec4(nz*0.01, 0.0)));
+			depth = texture2DProj(shadowMap, lpos).xyz;
+			d[0] = depth.x; d[1] = depth.y; d[2] = depth.z;
+			float shadow2 = d[i] < lpos.z/lpos.w ? 0.0 : 1.0;
+			
+			shadow = shadow2*0.5;
+		}
+	}
+		
+	col.rgb += atmosAffectDirectionalLight(da) * shadow;
+	
+	//col *= diffuse;
+	
+	col = atmosLighting(col);	
+	
+	gl_FragColor.rgb = scaleSoftClip(col);
+	//gl_FragColor.g = i/3.0;
+	gl_FragColor.a = shadow;
+	//lpos.xy /= lpos.w;
+	//gl_FragColor.rgb = vec3(lpos.x, lpos.y, d[i]);
+	//gl_FragColor.rgb = vec3((d[i]-lpos.z)/256.0);
+	//gl_FragColor = texture2D(shadowMap, gl_FragCoord.xy/512.0).x;
+	gl_FragDepth = texture2DRect(depthMap, gl_FragCoord.xy).x;
+}
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl (revision 575)
@@ -0,0 +1,42 @@
+/** 
+ * @file avatarV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+mat4 getSkinnedTransform();
+
+attribute vec4 weight;
+
+varying vec3 vary_normal;
+varying vec4 vary_position;
+
+void main()
+{
+	gl_TexCoord[0] = gl_MultiTexCoord0;
+				
+	vec4 pos;
+	vec3 norm;
+	
+	mat4 trans = getSkinnedTransform();
+	pos.x = dot(trans[0], gl_Vertex);
+	pos.y = dot(trans[1], gl_Vertex);
+	pos.z = dot(trans[2], gl_Vertex);
+	pos.w = 1.0;
+	
+	norm.x = dot(trans[0].xyz, gl_Normal);
+	norm.y = dot(trans[1].xyz, gl_Normal);
+	norm.z = dot(trans[2].xyz, gl_Normal);
+	norm = normalize(norm);
+	
+	vary_position = pos;
+	vary_normal = norm;
+	
+	gl_Position = gl_ProjectionMatrix * pos;
+	//gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;	
+	
+	gl_FrontColor = gl_Color;
+}
+
+
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl (revision 575)
@@ -0,0 +1,20 @@
+/** 
+ * @file treeF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+
+varying vec3 vary_normal;
+varying vec4 vary_position;
+
+void main() 
+{
+	vec4 col = texture2D(diffuseMap, gl_TexCoord[0].xy);
+	gl_FragData[0] = gl_Color*col;
+	gl_FragData[1] = vec4(0,0,0,0);
+	gl_FragData[2].xyz = normalize(vary_normal);
+	gl_FragData[3] = vary_position;
+}
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl (revision 575)
@@ -0,0 +1,21 @@
+/** 
+ * @file pointLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec4 vary_light;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	
+	vec4 tex = gl_MultiTexCoord0;
+	tex.w = 1.0;
+	
+	vary_light = gl_MultiTexCoord0;
+		
+	gl_FrontColor = gl_Color;
+}
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl (revision 575)
@@ -0,0 +1,78 @@
+/** 
+ * @file waterV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+void calcAtmospherics(vec3 inPositionEye);
+
+uniform vec2 d1;
+uniform vec2 d2;
+uniform float time;
+uniform vec3 eyeVec;
+uniform float waterHeight;
+
+varying vec4 refCoord;
+varying vec4 littleWave;
+varying vec4 view;
+
+varying vec4 vary_position;
+varying vec3 vary_normal;
+
+float wave(vec2 v, float t, float f, vec2 d, float s) 
+{
+ return (dot(d, v)*f + t*s)*f;
+}
+
+void main()
+{
+	//transform vertex
+	vec4 position = gl_Vertex;
+	mat4 modelViewProj = gl_ModelViewProjectionMatrix;
+	
+	vec4 oPosition;
+		 
+	//get view vector
+	vec3 oEyeVec;
+	oEyeVec.xyz = position.xyz-eyeVec;
+		
+	float d = length(oEyeVec.xy);
+	float ld = min(d, 2560.0);
+	
+	position.xy = eyeVec.xy + oEyeVec.xy/d*ld;
+	view.xyz = oEyeVec;
+		
+	d = clamp(ld/1536.0-0.5, 0.0, 1.0);	
+	d *= d;
+		
+	oPosition = position;
+	oPosition.z = mix(oPosition.z, max(eyeVec.z*0.75, 0.0), d);
+	vary_position = gl_ModelViewMatrix * oPosition;
+	vary_normal = normalize(gl_NormalMatrix * vec3(0, 0, 1));
+	oPosition = modelViewProj * oPosition;
+	
+	refCoord.xyz = oPosition.xyz + vec3(0,0,0.2);
+	
+	//get wave position parameter (create sweeping horizontal waves)
+	vec3 v = position.xyz;
+	v.x += (cos(v.x*0.08/*+time*0.01*/)+sin(v.y*0.02))*6.0;
+	 
+	//push position for further horizon effect.
+	position.xyz = oEyeVec.xyz*(waterHeight/oEyeVec.z);
+	position.w = 1.0;
+	position = position*gl_ModelViewMatrix;
+	
+	calcAtmospherics((gl_ModelViewMatrix * gl_Vertex).xyz);
+	
+	
+	//pass wave parameters to pixel shader
+	vec2 bigWave = (v.xy) * vec2(0.04,0.04) + d1 * time * 0.055;
+	//get two normal map (detail map) texture coordinates
+	littleWave.xy = (v.xy) * vec2(0.45, 0.9) + d2 * time * 0.13;
+	littleWave.zw = (v.xy) * vec2(0.1, 0.2) + d1 * time * 0.1;
+	view.w = bigWave.y;
+	refCoord.w = bigWave.x;
+	
+	gl_Position = oPosition;
+}
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl (revision 575)
@@ -0,0 +1,35 @@
+/** 
+ * @file avatarShadowV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+mat4 getSkinnedTransform();
+
+attribute vec4 weight;
+
+void main()
+{
+	gl_TexCoord[0] = gl_MultiTexCoord0;
+				
+	vec4 pos;
+	vec3 norm;
+	
+	mat4 trans = getSkinnedTransform();
+	pos.x = dot(trans[0], gl_Vertex);
+	pos.y = dot(trans[1], gl_Vertex);
+	pos.z = dot(trans[2], gl_Vertex);
+	pos.w = 1.0;
+	
+	norm.x = dot(trans[0].xyz, gl_Normal);
+	norm.y = dot(trans[1].xyz, gl_Normal);
+	norm.z = dot(trans[2].xyz, gl_Normal);
+	norm = normalize(norm);
+	
+	gl_Position = gl_ProjectionMatrix * pos;
+	
+		gl_FrontColor = gl_Color;
+}
+
+
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl (revision 575)
@@ -0,0 +1,78 @@
+/** 
+ * @file avatarAlphaV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
+mat4 getSkinnedTransform();
+void calcAtmospherics(vec3 inPositionEye);
+
+float calcDirectionalLight(vec3 n, vec3 l);
+float calcPointLight(vec3 v, vec3 n, vec4 lp, float la);
+
+vec3 atmosAmbient(vec3 light);
+vec3 atmosAffectDirectionalLight(float lightIntensity);
+vec3 scaleDownLight(vec3 light);
+vec3 scaleUpLight(vec3 light);
+
+varying vec4 vary_position;
+varying vec3 vary_ambient;
+varying vec3 vary_directional;
+varying vec3 vary_normal;
+
+void main()
+{
+	gl_TexCoord[0] = gl_MultiTexCoord0;
+				
+	vec4 pos;
+	vec3 norm;
+	
+	mat4 trans = getSkinnedTransform();
+	pos.x = dot(trans[0], gl_Vertex);
+	pos.y = dot(trans[1], gl_Vertex);
+	pos.z = dot(trans[2], gl_Vertex);
+	pos.w = 1.0;
+	
+	norm.x = dot(trans[0].xyz, gl_Normal);
+	norm.y = dot(trans[1].xyz, gl_Normal);
+	norm.z = dot(trans[2].xyz, gl_Normal);
+	norm = normalize(norm);
+		
+	gl_Position = gl_ProjectionMatrix * pos;
+	vary_position = pos;
+	vary_normal = norm;	
+	
+	calcAtmospherics(pos.xyz);
+
+	//vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.));
+	vec4 col;
+	col.a = gl_Color.a;
+	
+	// Add windlight lights
+	col.rgb = atmosAmbient(vec4(0.));
+	col.rgb = scaleUpLight(col.rgb);
+
+	// Collect normal lights (need to be divided by two, as we later multiply by 2)
+	col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].linearAttenuation);
+	col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].linearAttenuation);
+	col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].linearAttenuation);
+	col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].linearAttenuation);
+ 	col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].linearAttenuation);
+ 	col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].linearAttenuation);
+	col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
+	col.rgb = scaleDownLight(col.rgb);
+	
+	vary_ambient = col.rgb*gl_Color.rgb;
+	vary_directional = gl_Color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, gl_LightSource[0].position.xyz), (1.0-gl_Color.a)*(1.0-gl_Color.a)));
+	
+	col.rgb = min(col.rgb*gl_Color.rgb, 1.0);
+	
+	gl_FrontColor = col;
+
+	gl_FogFragCoord = pos.z;
+
+}
+
+
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl (revision 575)
@@ -0,0 +1,36 @@
+/** 
+ * @file terrainF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D detail_0;
+uniform sampler2D detail_1;
+uniform sampler2D detail_2;
+uniform sampler2D detail_3;
+uniform sampler2D alpha_ramp;
+
+varying vec3 vary_normal;
+varying vec4 vary_position;
+
+void main()
+{
+	/// Note: This should duplicate the blending functionality currently used for the terrain rendering.
+	
+	vec4 color0 = texture2D(detail_0, gl_TexCoord[0].xy);
+	vec4 color1 = texture2D(detail_1, gl_TexCoord[0].xy);
+	vec4 color2 = texture2D(detail_2, gl_TexCoord[0].xy);
+	vec4 color3 = texture2D(detail_3, gl_TexCoord[0].xy);
+
+	float alpha1 = texture2D(alpha_ramp, gl_TexCoord[0].zw).a;
+	float alpha2 = texture2D(alpha_ramp,gl_TexCoord[1].xy).a;
+	float alphaFinal = texture2D(alpha_ramp, gl_TexCoord[1].zw).a;
+	vec4 outColor = mix( mix(color3, color2, alpha2), mix(color1, color0, alpha1), alphaFinal );
+	
+	gl_FragData[0] = vec4(outColor.rgb, 1.0);
+	gl_FragData[1] = vec4(outColor.rgb*0.2, 0.2);
+	gl_FragData[2].xyz = normalize(vary_normal);
+	gl_FragData[3] = vary_position;
+}
+
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl (revision 575)
@@ -0,0 +1,14 @@
+/** 
+ * @file shadowV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+	gl_FrontColor = gl_Color;
+}
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl (revision 387)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl (revision 575)
@@ -7,5 +7,5 @@
 
 varying vec3 vary_normal;
-varying vec3 vary_position;
+varying vec4 vary_position;
 
 void main()
@@ -15,5 +15,5 @@
 	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
 	
-	vary_position = (gl_ModelViewMatrix * gl_Vertex).xyz;
+	vary_position = gl_ModelViewMatrix * gl_Vertex;
 	
 	vary_normal = normalize(gl_NormalMatrix * gl_Normal);
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl (revision 575)
@@ -0,0 +1,65 @@
+/** 
+ * @file alphaV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
+void calcAtmospherics(vec3 inPositionEye);
+
+float calcDirectionalLight(vec3 n, vec3 l);
+float calcPointLight(vec3 v, vec3 n, vec4 lp, float la);
+
+vec3 atmosAmbient(vec3 light);
+vec3 atmosAffectDirectionalLight(float lightIntensity);
+vec3 scaleDownLight(vec3 light);
+vec3 scaleUpLight(vec3 light);
+
+varying vec4 vary_position;
+varying vec3 vary_ambient;
+varying vec3 vary_directional;
+varying vec3 vary_normal;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	
+	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+	
+	vec4 pos = (gl_ModelViewMatrix * gl_Vertex);
+	vary_position = pos;
+	
+	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
+	vary_normal = norm;
+	
+	calcAtmospherics(pos.xyz);
+
+	//vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.));
+	vec4 col;
+	col.a = gl_Color.a;
+	
+	// Add windlight lights
+	col.rgb = atmosAmbient(vec4(0.));
+	col.rgb = scaleUpLight(col.rgb);
+
+	// Collect normal lights (need to be divided by two, as we later multiply by 2)
+	col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].linearAttenuation);
+	col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].linearAttenuation);
+	col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].linearAttenuation);
+	col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].linearAttenuation);
+ 	col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].linearAttenuation);
+ 	col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].linearAttenuation);
+	col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
+	col.rgb = scaleDownLight(col.rgb);
+	
+	vary_ambient = col.rgb*gl_Color.rgb;
+	vary_directional = gl_Color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, gl_LightSource[0].position.xyz), (1.0-gl_Color.a)*(1.0-gl_Color.a)));
+	
+	col.rgb = min(col.rgb*gl_Color.rgb, 1.0);
+	
+	gl_FrontColor = col;
+
+	gl_FogFragCoord = pos.z;
+}
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl (revision 575)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl (revision 575)
@@ -0,0 +1,12 @@
+/** 
+ * @file softenLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+}
Index: /branches/shadow-draft/indra/newview/app_settings/shaders/class1/environment/waterF.glsl
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/shaders/class1/environment/waterF.glsl (revision 487)
+++ /branches/shadow-draft/indra/newview/app_settings/shaders/class1/environment/waterF.glsl (revision 575)
@@ -8,4 +8,5 @@
 vec3 scaleSoftClip(vec3 inColor);
 vec3 atmosTransport(vec3 inColor);
+vec3 applyWaterFog(vec4 inColor);
 
 uniform sampler2D diffuseMap;
Index: /branches/shadow-draft/indra/newview/app_settings/settings.xml
===================================================================
--- /branches/shadow-draft/indra/newview/app_settings/settings.xml (revision 543)
+++ /branches/shadow-draft/indra/newview/app_settings/settings.xml (revision 575)
@@ -1715,4 +1715,15 @@
 <integer>0</integer>
 </map>
+ <key>DebugShowRenderMatrices</key>
+ <map>
+ <key>Comment</key>
+ <string>Display values of current view and projection matrices.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
 <key>DebugShowTime</key>
 <map>
@@ -5291,5 +5302,73 @@
 <integer>1</integer>
 </map>
- <key>RenderBumpmapMinDistanceSquared</key>
+
+
+ <key>RenderShadowNearDist</key>
+ <map>
+ <key>Comment</key>
+ <string>Near clip plane of shadow camera (affects precision of depth shadows).</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>10</real>
+ </map>
+
+ <key>RenderShadowClipPlanes</key>
+ <map>
+ <key>Comment</key>
+ <string>Near clip plane split distances for shadow map frusta.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Vector3</string>
+ <key>Value</key>
+ <array>
+ <real>8.0</real>
+ <real>24.0</real>
+ <real>128.0</real>
+ </array>
+ </map>
+ 
+ 
+ <key>RenderSSAOScale</key>
+ <map>
+ <key>Comment</key>
+ <string>Currently unused</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>100</real>
+ </map>
+
+ <key>RenderSSAOBackground</key>
+ <map>
+ <key>Comment</key>
+ <string>Currently unused</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>100</real>
+ </map>
+
+ <key>RenderSSAOForeground</key>
+ <map>
+ <key>Comment</key>
+ <string>Currently unused</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>100</real>
+ </map>
+
+
+ <key>RenderBumpmapMinDistanceSquared</key>
 <map>
 <key>Comment</key>
@@ -9857,6 +9936,17 @@
 			<string>Boolean</string>
 		<key>Value</key>
-			<integer>0</integer>
+			<integer>1</integer>
 		</map>
+ <key>RenderDeferredSunWash</key>
+ <map>
+ <key>Comment</key>
+ <string>Amount local lights are washed out by sun.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.5</real>
+ </map>
 <key>RenderFSAASamples</key>
 		<map>
Index: /branches/shadow-draft/indra/newview/lldrawpoolsimple.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/lldrawpoolsimple.cpp (revision 573)
+++ /branches/shadow-draft/indra/newview/lldrawpoolsimple.cpp (revision 575)
@@ -158,20 +158,108 @@
 	}			
 
-	{ //render fullbright
-		if (mVertexShaderLevel > 0)
-		{
-			fullbright_shader->bind();
-			fullbright_shader->uniform1f(LLShaderMgr::FULLBRIGHT, 1.f);
-		}
-		else
-		{
-			gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
-		}
-		LLFastTimer t(LLFastTimer::FTM_RENDER_FULLBRIGHT);
-		U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD | LLVertexBuffer::MAP_COLOR;
-		renderTexture(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask);
-	}
-
 	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 }
 
+//===============================
+//DEFERRED IMPLEMENTATION
+//===============================
+
+void LLDrawPoolSimple::beginDeferredPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE);
+	gDeferredDiffuseProgram.bind();
+}
+
+void LLDrawPoolSimple::endDeferredPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE);
+	LLRenderPass::endRenderPass(pass);
+
+	gDeferredDiffuseProgram.unbind();
+}
+
+void LLDrawPoolSimple::renderDeferred(S32 pass)
+{
+	LLGLDisable blend(GL_BLEND);
+	LLGLState alpha_test(GL_ALPHA_TEST, gPipeline.canUseWindLightShadersOnObjects());
+
+	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
+
+	{ //render simple
+		LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE);
+		renderTexture(LLRenderPass::PASS_SIMPLE, getVertexDataMask());
+	}
+
+	{
+		LLFastTimer t(LLFastTimer::FTM_RENDER_GRASS);
+		gDeferredTreeProgram.bind();
+		LLGLEnable test(GL_ALPHA_TEST);
+		//render grass
+		LLRenderPass::renderTexture(LLRenderPass::PASS_GRASS, getVertexDataMask());
+	}			
+
+	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+}
+
+// Fullbright drawpool
+LLDrawPoolFullbright::LLDrawPoolFullbright() :
+	LLRenderPass(POOL_FULLBRIGHT)
+{
+}
+
+void LLDrawPoolFullbright::prerender()
+{
+	mVertexShaderLevel = LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_OBJECT);
+}
+
+void LLDrawPoolFullbright::beginRenderPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_FULLBRIGHT);
+	
+	if (LLPipeline::sUnderWaterRender)
+	{
+		fullbright_shader = &gObjectFullbrightWaterProgram;
+	}
+	else
+	{
+		fullbright_shader = &gObjectFullbrightProgram;
+	}
+}
+
+void LLDrawPoolFullbright::endRenderPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_FULLBRIGHT);
+	LLRenderPass::endRenderPass(pass);
+
+	if (mVertexShaderLevel > 0)
+	{
+		fullbright_shader->unbind();
+	}
+}
+
+void LLDrawPoolFullbright::render(S32 pass)
+{ //render fullbright
+	LLFastTimer t(LLFastTimer::FTM_RENDER_FULLBRIGHT);
+	if (mVertexShaderLevel > 0)
+	{
+		fullbright_shader->bind();
+		fullbright_shader->uniform1f(LLShaderMgr::FULLBRIGHT, 1.f);
+	}
+	else
+	{
+		gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
+	}
+	
+	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
+	
+	U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD | LLVertexBuffer::MAP_COLOR;
+	renderTexture(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask);
+
+	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+}
+
+S32 LLDrawPoolFullbright::getNumPasses()
+{ 
+	return 1;
+}
+
Index: /branches/shadow-draft/indra/newview/lldrawpooltree.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/lldrawpooltree.cpp (revision 573)
+++ /branches/shadow-draft/indra/newview/lldrawpooltree.cpp (revision 575)
@@ -114,4 +114,52 @@
 	}
 }
+
+//============================================
+// deferred implementation
+//============================================
+void LLDrawPoolTree::beginDeferredPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_TREES);
+	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
+		
+	shader = &gDeferredTreeProgram;
+	shader->bind();
+}
+
+void LLDrawPoolTree::renderDeferred(S32 pass)
+{
+	render(pass);
+}
+
+void LLDrawPoolTree::endDeferredPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_TREES);
+	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+	
+	shader->unbind();
+}
+
+//============================================
+// shadow implementation
+//============================================
+void LLDrawPoolTree::beginShadowPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_TREES);
+	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
+	gDeferredShadowProgram.bind();
+}
+
+void LLDrawPoolTree::renderShadow(S32 pass)
+{
+	render(pass);
+}
+
+void LLDrawPoolTree::endShadowPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_TREES);
+	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+	gDeferredShadowProgram.unbind();
+}
+
 
 void LLDrawPoolTree::renderForSelect()
Index: /branches/shadow-draft/indra/newview/lldrawpoolalpha.h
===================================================================
--- /branches/shadow-draft/indra/newview/lldrawpoolalpha.h (revision 543)
+++ /branches/shadow-draft/indra/newview/lldrawpoolalpha.h (revision 575)
@@ -55,4 +55,9 @@
 	/*virtual*/ ~LLDrawPoolAlpha();
 
+	/*virtual*/ S32 getNumPostDeferredPasses();
+	/*virtual*/ void beginPostDeferredPass(S32 pass);
+	/*virtual*/ void endPostDeferredPass(S32 pass);
+	/*virtual*/ void renderPostDeferred(S32 pass);
+
 	/*virtual*/ void beginRenderPass(S32 pass = 0);
 	/*virtual*/ void endRenderPass( S32 pass );
Index: /branches/shadow-draft/indra/newview/llglslshader.h
===================================================================
--- /branches/shadow-draft/indra/newview/llglslshader.h (revision 573)
+++ /branches/shadow-draft/indra/newview/llglslshader.h (revision 575)
@@ -262,4 +262,10 @@
 		GAMMA,
 		SCENE_LIGHT_STRENGTH,
+		DEFERRED_DEPTH,
+		DEFERRED_SHADOW,
+		DEFERRED_NORMAL,
+		DEFERRED_POSITION,
+		DEFERRED_NOISE,
+		DEFERRED_LIGHT,
 		END_RESERVED_UNIFORMS
 	} eGLSLReservedUniforms;
@@ -413,5 +419,17 @@
 
 // Deferred rendering shaders
+extern LLGLSLShader			gDeferredImpostorProgram;
+extern LLGLSLShader			gDeferredWaterProgram;
 extern LLGLSLShader			gDeferredDiffuseProgram;
+extern LLGLSLShader			gDeferredTerrainProgram;
+extern LLGLSLShader			gDeferredTreeProgram;
+extern LLGLSLShader			gDeferredLightProgram;
+extern LLGLSLShader			gDeferredSunProgram;
+extern LLGLSLShader			gDeferredAvatarProgram;
+extern LLGLSLShader			gDeferredSoftenProgram;
+extern LLGLSLShader			gDeferredShadowProgram;
+extern LLGLSLShader			gDeferredAvatarShadowProgram;
+extern LLGLSLShader			gDeferredAlphaProgram;
+extern LLGLSLShader			gDeferredAvatarAlphaProgram;
 
 //current avatar shader parameter pointer
Index: /branches/shadow-draft/indra/newview/llvoavatar.h
===================================================================
--- /branches/shadow-draft/indra/newview/llvoavatar.h (revision 521)
+++ /branches/shadow-draft/indra/newview/llvoavatar.h (revision 575)
@@ -295,5 +295,5 @@
 	U32 renderRigid();
 	U32 renderSkinned(EAvatarRenderPass pass);
-	U32 renderTransparent();
+	U32 renderTransparent(BOOL first_pass);
 	void renderCollisionVolumes();
 	
Index: /branches/shadow-draft/indra/newview/lldrawpoolalpha.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/lldrawpoolalpha.cpp (revision 573)
+++ /branches/shadow-draft/indra/newview/lldrawpoolalpha.cpp (revision 575)
@@ -76,4 +76,38 @@
 }
 
+S32 LLDrawPoolAlpha::getNumPostDeferredPasses() 
+{ 
+	return 1; 
+}
+
+void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass) 
+{ 
+	LLFastTimer t(LLFastTimer::FTM_RENDER_ALPHA);
+
+	simple_shader = &gDeferredAlphaProgram;
+	gPipeline.bindDeferredShader(*simple_shader);
+	fullbright_shader = &gObjectFullbrightProgram;
+	
+	if (mVertexShaderLevel > 0)
+	{
+		// Start out with no shaders.
+		current_shader = target_shader = NULL;
+		glUseProgramObjectARB(0);
+	}
+	gPipeline.enableLightsDynamic();
+}
+
+void LLDrawPoolAlpha::endPostDeferredPass(S32 pass) 
+{ 
+	endRenderPass(pass); 
+	simple_shader->bind();
+	gPipeline.unbindDeferredShader(*simple_shader);
+}
+
+void LLDrawPoolAlpha::renderPostDeferred(S32 pass) 
+{ 
+	render(pass); 
+}
+
 void LLDrawPoolAlpha::beginRenderPass(S32 pass)
 {
Index: /branches/shadow-draft/indra/newview/lldrawpoolavatar.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/lldrawpoolavatar.cpp (revision 573)
+++ /branches/shadow-draft/indra/newview/lldrawpoolavatar.cpp (revision 575)
@@ -54,4 +54,6 @@
 static LLGLSLShader* sVertexProgram = NULL;
 
+BOOL	LLDrawPoolAvatar::sSkipOpaque = FALSE;
+
 extern BOOL gUseGLPick;
 
@@ -87,4 +89,6 @@
 BOOL gAvatarEmbossBumpMap = FALSE;
 static BOOL sRenderingSkinned = FALSE;
+S32 normal_channel = -1;
+S32 specular_channel = -1;
 
 LLDrawPoolAvatar::LLDrawPoolAvatar() :
@@ -114,4 +118,5 @@
 {
 	mVertexShaderLevel = LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_AVATAR);
+	
 	sShaderLevel = mVertexShaderLevel;
 	
@@ -142,4 +147,178 @@
 //-----------------------------------------------------------------------------
 
+
+S32 LLDrawPoolAvatar::getNumDeferredPasses()
+{
+	return getNumPasses();
+}
+
+void LLDrawPoolAvatar::beginDeferredPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_CHARACTERS);
+	
+	if (LLPipeline::sImpostorRender)
+	{
+		beginDeferredSkinned();
+		return;
+	}
+
+	switch (pass)
+	{
+	case 0:
+		beginDeferredImpostor();
+		break;
+	case 1:
+		beginDeferredRigid();
+		break;
+	case 2:
+		beginDeferredSkinned();
+		break;
+	}
+}
+
+void LLDrawPoolAvatar::endDeferredPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_CHARACTERS);
+
+	if (LLPipeline::sImpostorRender)
+	{
+		endDeferredSkinned();
+		return;
+	}
+
+	switch (pass)
+	{
+	case 0:
+		endDeferredImpostor();
+		break;
+	case 1:
+		endDeferredRigid();
+		break;
+	case 2:
+		endDeferredSkinned();
+		break;
+	}
+}
+
+void LLDrawPoolAvatar::renderDeferred(S32 pass)
+{
+	render(pass);
+}
+
+S32 LLDrawPoolAvatar::getNumPostDeferredPasses()
+{
+	return 1;
+}
+
+void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass)
+{
+	sSkipOpaque = TRUE;
+	sShaderLevel = mVertexShaderLevel;
+	sVertexProgram = &gDeferredAvatarAlphaProgram;
+
+	sRenderingSkinned = TRUE;
+
+	gPipeline.bindDeferredShader(*sVertexProgram);
+	
+	enable_vertex_weighting(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_WEIGHT]);
+
+	glActiveTextureARB(GL_TEXTURE0_ARB);
+}
+
+void LLDrawPoolAvatar::endPostDeferredPass(S32 pass)
+{
+	// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
+	sRenderingSkinned = FALSE;
+	sSkipOpaque = FALSE;
+	disable_vertex_weighting(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_WEIGHT]);
+	
+	gPipeline.unbindDeferredShader(*sVertexProgram);
+
+	sShaderLevel = mVertexShaderLevel;
+
+	glActiveTextureARB(GL_TEXTURE0_ARB);
+}
+
+void LLDrawPoolAvatar::renderPostDeferred(S32 pass)
+{
+	render(2); //pass 2 = skinned
+}
+
+
+S32 LLDrawPoolAvatar::getNumShadowPasses()
+{
+	return 1;
+}
+
+void LLDrawPoolAvatar::beginShadowPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_CHARACTERS);
+	
+	sVertexProgram = &gDeferredAvatarShadowProgram;
+	if (sShaderLevel > 0)
+	{
+		gAvatarMatrixParam = sVertexProgram->mUniform[LLShaderMgr::AVATAR_MATRIX];
+	}
+	gGL.setAlphaRejectSettings(LLRender::CF_GREATER_EQUAL, 0.2f);
+	
+	glColor4f(1,1,1,1);
+
+	if ((sShaderLevel > 0)) // for hardware blending
+	{
+		sRenderingSkinned = TRUE;
+		sVertexProgram->bind();
+		enable_vertex_weighting(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_WEIGHT]);
+	}
+
+}
+
+void LLDrawPoolAvatar::endShadowPass(S32 pass)
+{
+	LLFastTimer t(LLFastTimer::FTM_RENDER_CHARACTERS);
+
+	if (sShaderLevel > 0)
+	{
+		sRenderingSkinned = FALSE;
+		sVertexProgram->unbind();
+		disable_vertex_weighting(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_WEIGHT]);
+	}
+
+	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+}
+
+void LLDrawPoolAvatar::renderShadow(S32 pass)
+{
+	if (!gRenderAvatar)
+	{
+		return;
+	}
+
+	if (mDrawFace.empty())
+	{
+		return;
+	}
+
+	const LLFace *facep = mDrawFace[0];
+	if (!facep->getDrawable())
+	{
+		return;
+	}
+	LLVOAvatar *avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
+
+	if (avatarp->isDead() || avatarp->mIsDummy || avatarp->mDrawable.isNull())
+	{
+		return;
+	}
+
+	BOOL impostor = avatarp->isImpostor();
+	if (impostor)
+	{
+		return;
+	}
+	
+	avatarp->renderSkinned(AVATAR_RENDER_PASS_SINGLE);
+
+}
+
 S32 LLDrawPoolAvatar::getNumPasses()
 {
@@ -257,4 +436,45 @@
 }
 
+void LLDrawPoolAvatar::beginDeferredImpostor()
+{
+	if (!LLPipeline::sReflectionRender)
+	{
+		LLVOAvatar::sRenderDistance = llclamp(LLVOAvatar::sRenderDistance, 16.f, 256.f);
+		LLVOAvatar::sNumVisibleAvatars = 0;
+	}
+
+	sVertexProgram = &gDeferredImpostorProgram;
+
+	normal_channel = sVertexProgram->enableTexture(LLShaderMgr::DEFERRED_NORMAL);
+	specular_channel = sVertexProgram->enableTexture(LLShaderMgr::SPECULAR_MAP);
+	glActiveTextureARB(GL_TEXTURE0_ARB);
+				
+	sVertexProgram->bind();
+}
+
+void LLDrawPoolAvatar::endDeferredImpostor()
+{
+	sShaderLevel = mVertexShaderLevel;
+	sVertexProgram->disableTexture(LLShaderMgr::DEFERRED_NORMAL);
+	sVertexProgram->disableTexture(LLShaderMgr::SPECULAR_MAP);
+	glActiveTextureARB(GL_TEXTURE0_ARB);
+	glEnable(GL_TEXTURE_2D);
+	sVertexProgram->unbind();
+}
+
+void LLDrawPoolAvatar::beginDeferredRigid()
+{
+	sVertexProgram = &gDeferredDiffuseProgram;
+				
+	sVertexProgram->bind();
+}
+
+void LLDrawPoolAvatar::endDeferredRigid()
+{
+	sShaderLevel = mVertexShaderLevel;
+	sVertexProgram->unbind();
+}
+
+
 void LLDrawPoolAvatar::beginSkinned()
 {
@@ -286,5 +506,5 @@
 	{
 		sRenderingSkinned = TRUE;
-		
+
 		sVertexProgram->bind();
 		if (sShaderLevel >= SHADER_LEVEL_CLOTH)
@@ -321,4 +541,5 @@
 		sVertexProgram->disableTexture(LLShaderMgr::BUMP_MAP);
 		gGL.getTexUnit(0)->activate();
+
 		disable_vertex_weighting(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_WEIGHT]);
 		if (sShaderLevel >= SHADER_LEVEL_BUMP)
@@ -345,4 +566,30 @@
 
 	gGL.getTexUnit(0)->activate();
+}
+
+void LLDrawPoolAvatar::beginDeferredSkinned()
+{
+	sShaderLevel = mVertexShaderLevel;
+	sVertexProgram = &gDeferredAvatarProgram;
+
+	sRenderingSkinned = TRUE;
+
+	sVertexProgram->bind();
+	
+	enable_vertex_weighting(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_WEIGHT]);
+
+	glActiveTextureARB(GL_TEXTURE0_ARB);
+}
+
+void LLDrawPoolAvatar::endDeferredSkinned()
+{
+	// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
+	sRenderingSkinned = FALSE;
+	disable_vertex_weighting(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_WEIGHT]);
+	sVertexProgram->unbind();
+
+	sShaderLevel = mVertexShaderLevel;
+
+	glActiveTextureARB(GL_TEXTURE0_ARB);
 }
 
@@ -444,7 +691,21 @@
 		if (impostor)
 		{
+			if (LLPipeline::sRenderDeferred && avatarp->mImpostor.isComplete()) 
+			{
+				if (normal_channel > -1)
+				{
+					glActiveTextureARB(GL_TEXTURE0_ARB+normal_channel);
+					avatarp->mImpostor.bindTexture(2);
+				}
+				if (specular_channel > -1)
+				{
+					glActiveTextureARB(GL_TEXTURE0_ARB+specular_channel);
+					avatarp->mImpostor.bindTexture(1);
+				}
+				glActiveTextureARB(GL_TEXTURE0_ARB);
+			}
 			avatarp->renderImpostor();
 		}
-		else if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS))
+		else if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS) && !LLPipeline::sRenderDeferred)
 		{
 			avatarp->renderFootShadows();	
@@ -687,8 +948,4 @@
 		glVertexPointer(3,GL_FLOAT, mStride, (void*)(base + 0));
 		glNormalPointer(GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_NORMAL]));
-	
-		glClientActiveTextureARB(GL_TEXTURE1_ARB);
-		glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD2]));
-		glClientActiveTextureARB(GL_TEXTURE0_ARB);
 		glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD]));
 		
Index: /branches/shadow-draft/indra/newview/lldrawpooltree.h
===================================================================
--- /branches/shadow-draft/indra/newview/lldrawpooltree.h (revision 280)
+++ /branches/shadow-draft/indra/newview/lldrawpooltree.h (revision 575)
@@ -53,4 +53,15 @@
 
 	/*virtual*/ void prerender();
+
+	/*virtual*/ S32 getNumDeferredPasses() { return 1; }
+	/*virtual*/ void beginDeferredPass(S32 pass);
+	/*virtual*/ void endDeferredPass(S32 pass);
+	/*virtual*/ void renderDeferred(S32 pass);
+
+	/*virtual*/ S32 getNumShadowPasses() { return 1; }
+	/*virtual*/ void beginShadowPass(S32 pass);
+	/*virtual*/ void endShadowPass(S32 pass);
+	/*virtual*/ void renderShadow(S32 pass);
+
 	/*virtual*/ void beginRenderPass( S32 pass );
 	/*virtual*/ void render(S32 pass = 0);
Index: /branches/shadow-draft/indra/newview/lldrawable.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/lldrawable.cpp (revision 521)
+++ /branches/shadow-draft/indra/newview/lldrawable.cpp (revision 575)
@@ -1191,5 +1191,6 @@
 	LLVector3 size = (mExtents[1]-mExtents[0]) * 0.5f;
 
-	if (LLPipeline::sImpostorRender ||
+	if ((LLPipeline::sShadowRender && camera_in.AABBInFrustum(center, size)) ||
+		LLPipeline::sImpostorRender ||
 		(camera_in.AABBInFrustumNoFarClip(center, size) && 
 		AABBSphereIntersect(mExtents[0], mExtents[1], camera_in.getOrigin(), camera_in.mFrustumCornerDist)))
Index: /branches/shadow-draft/indra/newview/lldrawpoolwlsky.h
===================================================================
--- /branches/shadow-draft/indra/newview/lldrawpoolwlsky.h (revision 280)
+++ /branches/shadow-draft/indra/newview/lldrawpoolwlsky.h (revision 575)
@@ -50,4 +50,9 @@
 	/*virtual*/ BOOL isDead() { return FALSE; }
 
+	/*virtual*/ S32 getNumPostDeferredPasses() { return getNumPasses(); }
+	/*virtual*/ void beginPostDeferredPass(S32 pass) { beginRenderPass(pass); }
+	/*virtual*/ void endPostDeferredPass(S32 pass) { endRenderPass(pass); }
+	/*virtual*/ void renderPostDeferred(S32 pass) { render(pass); }
+
 	/*virtual*/ LLViewerImage *getDebugTexture();
 	/*virtual*/ void beginRenderPass( S32 pass );
Index: /branches/shadow-draft/indra/newview/llface.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/llface.cpp (revision 573)
+++ /branches/shadow-draft/indra/newview/llface.cpp (revision 575)
@@ -178,18 +178,27 @@
 void LLFace::destroy()
 {
+	if (mDrawPoolp)
+	{
+		mDrawPoolp->removeFace(this);
+		mDrawPoolp = NULL;
+	}
+
+	if (mTextureMatrix)
+	{
+		delete mTextureMatrix;
+		mTextureMatrix = NULL;
+
+		if (mDrawablep.notNull())
+		{
+			LLSpatialGroup* group = mDrawablep->getSpatialGroup();
+			if (group)
+			{
+				group->dirtyGeom();
+			}
+		}
+	}
+
 	mDrawablep = NULL;
 	mVObjp = NULL;
-
-	if (mDrawPoolp)
-	{
-		mDrawPoolp->removeFace(this);
-		mDrawPoolp = NULL;
-	}
-
-	if (mTextureMatrix)
-	{
-		delete mTextureMatrix;
-		mTextureMatrix = NULL;
-	}
 }
 
@@ -943,5 +952,5 @@
 		};
 
-		if (getPoolType() != LLDrawPool::POOL_ALPHA && LLPipeline::sRenderBump && tep->getShiny())
+		if (getPoolType() != LLDrawPool::POOL_ALPHA && (LLPipeline::sRenderDeferred || LLPipeline::sRenderBump && tep->getShiny()))
 		{
 			color.mV[3] = U8 (alpha[tep->getShiny()] * 255);
Index: /branches/shadow-draft/indra/newview/lldrawpool.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/lldrawpool.cpp (revision 573)
+++ /branches/shadow-draft/indra/newview/lldrawpool.cpp (revision 575)
@@ -68,4 +68,7 @@
 		poolp = new LLDrawPoolSimple();
 		break;
+	case POOL_FULLBRIGHT:
+		poolp = new LLDrawPoolFullbright();
+		break;
 	case POOL_INVISIBLE:
 		poolp = new LLDrawPoolInvisible();
@@ -133,7 +136,85 @@
 }
 
+//virtual 
+S32	 LLDrawPool::getNumPasses()
+{
+	return 1;
+}
+	
+//virtual 
+void LLDrawPool::beginDeferredPass(S32 pass)
+{
+
+}
+
+//virtual 
+void LLDrawPool::endDeferredPass(S32 pass)
+{
+
+}
+
+//virtual 
+S32 LLDrawPool::getNumDeferredPasses()
+{
+	return 0;
+}
+
+//virtual 
+void LLDrawPool::renderDeferred(S32 pass)
+{
+
+}
+
+//virtual 
+void LLDrawPool::beginPostDeferredPass(S32 pass)
+{
+
+}
+
+//virtual 
+void LLDrawPool::endPostDeferredPass(S32 pass)
+{
+
+}
+
+//virtual 
+S32 LLDrawPool::getNumPostDeferredPasses()
+{
+	return 0;
+}
+
+//virtual 
+void LLDrawPool::renderPostDeferred(S32 pass)
+{
+
+}
+
 //virtual
 void LLDrawPool::endRenderPass( S32 pass )
 {
+}
+
+//virtual 
+void LLDrawPool::beginShadowPass(S32 pass)
+{
+
+}
+
+//virtual 
+void LLDrawPool::endShadowPass(S32 pass)
+{
+
+}
+
+//virtual 
+S32 LLDrawPool::getNumShadowPasses()
+{
+	return 0;
+}
+
+//virtual 
+void LLDrawPool::renderShadow(S32 pass)
+{
+
 }
 
Index: /branches/shadow-draft/indra/newview/llspatialpartition.cpp
===================================================================
--- /branches/shadow-draft/indra/newview/llspatialpartition.cpp (revision 573)
+++ /branches/shadow-draft/indra/newview/llspatialpartition.cpp (revision 575)
@@ -184,5 +184,5 @@
 };
 
-U8* get_occlusion_indices(LLCamera* camera, const LLVector3& center)
+U8* get_box_fan_indices(LLCamera* camera, const LLVector3& center)
 {
 	LLVector3 d = center - camera->getOrigin();
@@ -1320,5 +1320,5 @@
 				glVertexPointer(3, GL_FLOAT, 0, mOcclusionVerts);
 				glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
-							GL_UNSIGNED_BYTE, get_occlusion_indices(camera, mBounds[0]));
+							GL_UNSIGNED_BYTE, get_box_fan_indices(camera, mBounds[0]));
 				glEndQueryARB(GL_SAMPLES_PASSED_ARB);
 			}
@@ -1610,4 +1610,22 @@
 	}
 };
+
+class LLOctreeCullShadow : public LLOctreeCull
+{
+public:
+	LLOctreeCullShadow(LLCamera* camera)
+		: LLOctreeCull(camera) { }
+
+	virtual S32 frustumCheck(const LLSpatialGroup* group)
+	{
+		return mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]);
+	}
+
+	virtual S32 frustumCheckObjects(const LLSpatialGroup* group)
+	{
+		return mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]);
+	}
+};
+
 
 class LLOctreeSelect : public LLOctreeCull
@@ -1788,4 +1806,10 @@
 		LLOctreeSelect selecter(&camera, results);
 		selecter.traverse(mOctree);
+	}
+	else if (LLPipeline::sShadowRender)
+	{
+		LLFastTimer ftm(LLFastTimer::FTM_FRUSTUM_CULL);
+		LLOctreeCullShadow culler(&camera);
+		culler.traverse(mOctree);
 	}
 	else if (mInfiniteFarClip || !LLPipeline::sUseFarClip)
@@ -2158,9 +2182,9 @@
 
 			glColor4f(1.0f, 0.f, 0.f, 0.5f);
-			glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, GL_UNSIGNED_BYTE, get_occlusion_indices(camera, group->mBounds[0]));
+			glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, GL_UNSIGNED_BYTE, get_box_fan_indices(camera, group->mBounds[0]));
 			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 			
 			glColor4f(1.0f, 1.f, 1.f, 1.0f);
-			glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, GL_UNSIGNED_BYTE, get_occlusion_indices(camera, group->mBounds[0]));
+			glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, GL_UNSIGNED_BYTE, get_box_fan_indices(camera, group->mBounds[0]));
 			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 		}
Index: /branches/shadow-draft/indra/llwindow/llgl.h
===================================================================
--- /branches/shadow-draft/indra/llwindow/llgl.h (revision 543)
+++ /branches/shadow-draft/indra/llwindow/llgl.h (revision 575)
@@ -78,5 +78,5 @@
 	BOOL mHasCompressedTextures;
 	BOOL mHasFramebufferObject;
-
+	
 	// ARB Extensions
 	BOOL mHasVertexBufferObject;
@@ -87,4 +87,5 @@
 	BOOL mHasOcclusionQuery;
 	BOOL mHasPointParameters;
+	BOOL mHasDrawBuffers;
 
 	// Other extensions.
Index: /branches/shadow-draft/indra/llwindow/llgl.cpp
===================================================================
--- /branches/shadow-draft/indra/llwindow/llgl.cpp (revision 573)
+++ /branches/shadow-draft/indra/llwindow/llgl.cpp (revision 575)
@@ -130,4 +130,7 @@
 PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT = NULL;
 PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = NULL;
+
+// GL_ARB_draw_buffers
+PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB = NULL;
 
 //shader object prototypes
@@ -542,4 +545,9 @@
 	mHasFramebufferObject = FALSE;
 # endif
+# if GL_ARB_draw_buffers
+	mHasDrawBuffers = TRUE;
+#else
+	mHasDrawBuffers = FALSE;
+# endif
 	mHasMipMapGeneration = FALSE;
 	mHasPalettedTextures = FALSE;
@@ -567,4 +575,5 @@
 	mHasFramebufferObject = ExtensionExists("GL_EXT_framebuffer_object", gGLHExts.mSysExts)
 		&& ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts);
+	mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts);
 #if !LL_DARWIN
 	mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
@@ -586,4 +595,5 @@
 		mHasVertexBufferObject = FALSE;
 		mHasFramebufferObject = FALSE;
+		mHasDrawBuffers = FALSE;
 		mHasMipMapGeneration = FALSE;
 		mHasPalettedTextures = FALSE;
@@ -640,4 +650,6 @@
 		if (strchr(blacklist,'p')) mHasPointParameters = FALSE;//S
 		if (strchr(blacklist,'q')) mHasFramebufferObject = FALSE;//S
+		if (strchr(blacklist,'r')) mHasDrawBuffers = FALSE;//S
+
 	}
 #endif // LL_LINUX
@@ -757,4 +769,8 @@
 		glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGetFramebufferAttachmentParameterivEXT");
 		glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenerateMipmapEXT");
+	}
+	if (mHasDrawBuffers)
+	{
+		glDrawBuffersARB = (PFNGLDRAWBUFFERSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDrawBuffersARB");
 	}
 #if !LL_LINUX
@@ -1588,4 +1604,19 @@
 {
 	std::sort(mNameList.begin(), mNameList.end(), CompareUsed());
+	/*for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter)
+	{
+		if (iter->used == FALSE)
+		{
+			releaseName(iter->name);
+		}
+		else 
+		{
+			mNameList.erase(mNameList.begin(), iter);
+			return;
+		}
+	}
+
+	//if we hit this point, whole pool has been released
+	mNameList.clear();*/
 }
 
Index: /branches/shadow-draft/indra/llwindow/llglheaders.h
===================================================================
--- /branches/shadow-draft/indra/llwindow/llglheaders.h (revision 280)
+++ /branches/shadow-draft/indra/llwindow/llglheaders.h (revision 575)
@@ -261,4 +261,6 @@
 extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT;
 
+//GL_ARB_draw_buffers
+extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
 
 #elif LL_WINDOWS
@@ -449,4 +451,6 @@
 extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT;
 
+//GL_ARB_draw_buffers
+extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
 
 #elif LL_DARWIN
@@ -485,4 +489,6 @@
 extern void glGenerateMipmapEXT(GLenum target) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
 
+// GL_ARB_draw_buffers
+extern void glDrawBuffersARB(GLsizei n, const GLenum* bufs) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
 
 #ifdef __cplusplus
Index: /branches/shadow-draft/indra/llrender/llvertexbuffer.cpp
===================================================================
--- /branches/shadow-draft/indra/llrender/llvertexbuffer.cpp (revision 573)
+++ /branches/shadow-draft/indra/llrender/llvertexbuffer.cpp (revision 575)
@@ -123,5 +123,5 @@
 					glDisableClientState(array[i]);
 				}
-				else
+				else if (gDebugGL)
 				{ //needs to be enabled, make sure it was (DEBUG TEMPORARY)
 					if (i > 0 && !glIsEnabled(array[i]))
@@ -137,5 +137,5 @@
 					glEnableClientState(array[i]);
 				}
-				else if (glIsEnabled(array[i]))
+				else if (gDebugGL && glIsEnabled(array[i]))
 				{ //needs to be disabled, make sure it was (DEBUG TEMPORARY)
 					llerrs << "Bad client state! " << array[i] << " enabled." << llendl;
@@ -762,9 +762,5 @@
 		mMappedIndexData = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
 		stop_glerror();
-		/*if (sMapped)
-		{
-			llerrs << "Mapped two VBOs at the same time!" << llendl;
-		}
-		sMapped = TRUE;*/
+
 		if (!mMappedData)
 		{
Index: /branches/shadow-draft/indra/llrender/llrendertarget.cpp
===================================================================
--- /branches/shadow-draft/indra/llrender/llrendertarget.cpp (revision 573)
+++ /branches/shadow-draft/indra/llrender/llrendertarget.cpp (revision 575)
@@ -67,10 +67,65 @@
 	release();
 
-	glGenTextures(1, (GLuint *) &mTex);
-	glBindTexture(mUsage, mTex);
-	glTexImage2D(mUsage, 0, color_fmt, mResX, mResY, 0, color_fmt, GL_UNSIGNED_BYTE, NULL);
-
-	glTexParameteri(mUsage, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-	glTexParameteri(mUsage, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	stop_glerror();
+
+	if ((sUseFBO || use_fbo) && gGLManager.mHasFramebufferObject)
+	{
+
+		if (depth)
+		{
+			stop_glerror();
+			allocateDepth();
+			stop_glerror();
+		}
+
+		glGenFramebuffersEXT(1, (GLuint *) &mFBO);
+
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
+
+		if (mDepth)
+		{
+			glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, mUsage, mDepth, 0);
+			glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, mUsage, mDepth, 0);
+			stop_glerror();
+		}
+		
+		stop_glerror();
+
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+		stop_glerror();
+	}
+
+	addColorAttachment(color_fmt);
+}
+
+void LLRenderTarget::addColorAttachment(U32 color_fmt)
+{
+	if (color_fmt == 0)
+	{
+		return;
+	}
+
+	U32 offset = mTex.size();
+	if (offset >= 4 ||
+		offset > 0 && (mFBO == 0 || !gGLManager.mHasDrawBuffers))
+	{
+		llerrs << "Too many color attachments!" << llendl;
+	}
+
+	U32 tex;
+	glGenTextures(1, (GLuint *) &tex);
+	glBindTexture(mUsage, tex);
+	glTexImage2D(mUsage, 0, color_fmt, mResX, mResY, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+	if (offset == 0)
+	{
+		glTexParameteri(mUsage, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+		glTexParameteri(mUsage, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	}
+	else
+	{ //don't filter data attachments
+		glTexParameteri(mUsage, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+		glTexParameteri(mUsage, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	}
 
 	if (mUsage != GL_TEXTURE_RECTANGLE_ARB)
@@ -86,34 +141,28 @@
 	}
 
-	stop_glerror();
-
-	if ((sUseFBO || use_fbo) && gGLManager.mHasFramebufferObject)
-	{
-
-		if (depth)
-		{
-			stop_glerror();
-			allocateDepth();
-			stop_glerror();
-		}
-
-		glGenFramebuffersEXT(1, (GLuint *) &mFBO);
-
+	if (mFBO)
+	{
 		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
-
-		if (mDepth)
-		{
-			glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, mUsage, mDepth, 0);
-			glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, mUsage, mDepth, 0);
-			stop_glerror();
-		}
-
-		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
-						mUsage, mTex, 0);
-		stop_glerror();
-
-		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
-		stop_glerror();
-	}
+		glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+offset,
+						mUsage, tex, 0);
+
+
+		GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+		switch (status)
+		{
+		case GL_FRAMEBUFFER_COMPLETE_EXT:
+			break;
+		case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
+			llerrs << "WTF?" << llendl;
+			break;
+		default:
+			llerrs << "WTF?" << llendl;
+		}
+
+		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+	}
+
+	mTex.push_back(tex);
+
 }
 
@@ -135,8 +184,8 @@
 	}
 
-	if (mTex)
-	{
-		glDeleteTextures(1, (GLuint *) &mTex);
-		mTex = 0;
+	if (mTex.size() > 0)
+	{
+		glDeleteTextures(mTex.size(), (GLuint *) &mTex[0]);
+		mTex.clear();
 	}
 
@@ -153,4 +202,12 @@
 	{
 		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO);
+		if (gGLManager.mHasDrawBuffers)
+		{ //setup multiple render targets
+			GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0_EXT,
+									GL_COLOR_ATTACHMENT1_EXT,
+									GL_COLOR_ATTACHMENT2_EXT,
+									GL_COLOR_ATTACHMENT3_EXT};
+			glDrawBuffersARB(mTex.size(), drawbuffers);
+		}
 	}
 
@@ -187,7 +244,11 @@
 }
 
-void LLRenderTarget::bindTexture()
-{
-	glBindTexture(mUsage, mTex);
+void LLRenderTarget::bindTexture(U32 attachment)
+{
+	if (attachment > mTex.size()-1)
+	{
+		llerrs << "Invalid attachment index." << llendl;
+	}
+	glBindTexture(mUsage, mTex[attachment]);
 }
 
@@ -225,5 +286,5 @@
 BOOL LLRenderTarget::isComplete() const
 {
-	return (mTex || mDepth) ? TRUE : FALSE;
+	return (!mTex.empty() || mDepth) ? TRUE : FALSE;
 }
 
Index: /branches/shadow-draft/indra/llrender/llrendertarget.h
===================================================================
--- /branches/shadow-draft/indra/llrender/llrendertarget.h (revision 531)
+++ /branches/shadow-draft/indra/llrender/llrendertarget.h (revision 575)
@@ -74,4 +74,8 @@
 	void allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, U32 usage = GL_TEXTURE_2D, BOOL use_fbo = FALSE);
 
+	//add color buffer attachment
+	//limit of 4 color attachments per render target
+	void addColorAttachment(U32 color_fmt);
+
 	//allocate a depth texture
 	void allocateDepth();
@@ -102,5 +106,5 @@
 
 	//bind results of render for sampling
-	void bindTexture();
+	void bindTexture(U32 attachment = 0);
 
 	//bind results of render for sampling depth buffer
@@ -123,5 +127,5 @@
 	U32 mResX;
 	U32 mResY;
-	U32 mTex;
+	std::vector<U32> mTex;
 	U32 mFBO;
 	U32 mDepth;