From 939a506569433db7bff96c12200f03b3f85f40de Mon Sep 17 00:00:00 2001
From: Eric Tulla <tulla@lindenlab.com>
Date: Mon, 30 Jun 2008 17:57:00 +0000
Subject: [PATCH] Merging in file-move-merge ( QAR-649 ) Result of "svn merge
 -r 90669:90786 $tulla/file-move-merge ."

Be careful of future merges involving changes to any of these moved files as SVN usually does the wrong thing:
newview/llglslshader.* -> llrender/llglslshader.*, llrender/llshadermgr.*, newview/llviewershadermgr.* (gets split into 3 separate files)
newview/llpostprocess.* -> llrender/llpostprocess.*
newview/llrendersphere.* -> llrender/llrendersphere.*
newview/llcubemap.* -> llrender/llcubemap.*
llwindow/llgl.* -> llrender/llgl.*
llwindow/llglstates.h -> llrender/llglstates.h
llwindow/llgltypes.h -> llrender/llgltypes.h
llwindow/llglheaders.h -> llrender/llglheaders.h
---
 indra/cmake/LLRender.cmake            |   21 +
 indra/llrender/CMakeLists.txt         |   34 +
 indra/llrender/llcubemap.cpp          |  532 ++++++++
 indra/llrender/llcubemap.h            |   89 ++
 indra/llrender/llgl.cpp               | 1726 +++++++++++++++++++++++++
 indra/llrender/llgl.h                 |  377 ++++++
 indra/llrender/llglheaders.h          |  588 +++++++++
 indra/llrender/llglslshader.cpp       |  823 ++++++++++++
 indra/llrender/llglslshader.h         |  139 ++
 indra/llrender/llglstates.h           |  302 +++++
 indra/llrender/llgltypes.h            |   44 +
 indra/llrender/llpostprocess.cpp      |  574 ++++++++
 indra/llrender/llpostprocess.h        |  268 ++++
 indra/llrender/llrender.cpp           |    6 +
 indra/llrender/llrender.h             |    5 +-
 indra/llrender/llrendersphere.cpp     |  159 +++
 indra/llrender/llrendersphere.h       |   34 +
 indra/llrender/llshadermgr.cpp        |  513 ++++++++
 indra/llrender/llshadermgr.h          |   75 ++
 indra/llrender/llvertexbuffer.h       |    1 +
 indra/llwindow/CMakeLists.txt         |   18 +-
 indra/newview/CMakeLists.txt          |   10 +-
 indra/newview/llappviewer.cpp         |    6 +-
 indra/newview/lldrawpoolalpha.cpp     |    4 +-
 indra/newview/lldrawpoolavatar.cpp    |   44 +-
 indra/newview/lldrawpoolbump.cpp      |   30 +-
 indra/newview/lldrawpoolground.cpp    |    4 +-
 indra/newview/lldrawpoolsimple.cpp    |   10 +-
 indra/newview/lldrawpoolsky.cpp       |    4 +-
 indra/newview/lldrawpoolterrain.cpp   |   24 +-
 indra/newview/lldrawpooltree.cpp      |    4 +-
 indra/newview/lldrawpoolwater.cpp     |   52 +-
 indra/newview/llhudrender.cpp         |    1 +
 indra/newview/llviewercamera.cpp      |   12 -
 indra/newview/llviewercamera.h        |    7 -
 indra/newview/llviewercontrol.cpp     |    4 +-
 indra/newview/llviewerdisplay.cpp     |    3 +-
 indra/newview/llviewerjointmesh.cpp   |    4 +-
 indra/newview/llviewershadermgr.cpp   | 1094 ++++++++++++++++
 indra/newview/llviewershadermgr.h     |  313 +++++
 indra/newview/llvoavatar.cpp          |   10 +-
 indra/newview/llvosky.cpp             |    4 +-
 indra/newview/llwaterparammanager.cpp |   16 +-
 indra/newview/llwaterparamset.h       |    2 +-
 indra/newview/llwlparammanager.cpp    |   16 +-
 indra/newview/llwlparamset.h          |    2 +-
 indra/newview/pipeline.cpp            |   26 +-
 47 files changed, 7857 insertions(+), 177 deletions(-)
 create mode 100644 indra/llrender/llcubemap.cpp
 create mode 100644 indra/llrender/llcubemap.h
 create mode 100644 indra/llrender/llgl.cpp
 create mode 100644 indra/llrender/llgl.h
 create mode 100644 indra/llrender/llglheaders.h
 create mode 100644 indra/llrender/llglslshader.cpp
 create mode 100644 indra/llrender/llglslshader.h
 create mode 100644 indra/llrender/llglstates.h
 create mode 100644 indra/llrender/llgltypes.h
 create mode 100644 indra/llrender/llpostprocess.cpp
 create mode 100644 indra/llrender/llpostprocess.h
 create mode 100644 indra/llrender/llrendersphere.cpp
 create mode 100644 indra/llrender/llrendersphere.h
 create mode 100644 indra/llrender/llshadermgr.cpp
 create mode 100644 indra/llrender/llshadermgr.h
 create mode 100644 indra/newview/llviewershadermgr.cpp
 create mode 100644 indra/newview/llviewershadermgr.h

diff --git a/indra/cmake/LLRender.cmake b/indra/cmake/LLRender.cmake
index 8fda6c1d6a2..bbcf4cd57d7 100644
--- a/indra/cmake/LLRender.cmake
+++ b/indra/cmake/LLRender.cmake
@@ -6,6 +6,27 @@ set(LLRENDER_INCLUDE_DIRS
     ${LIBS_OPEN_DIR}/llrender
     )
 
+if (SERVER AND LINUX)
+  set(LLRENDER_LIBRARIES
+      llrenderheadless
+      )
+else (SERVER AND LINUX)
 set(LLRENDER_LIBRARIES
     llrender
     )
+endif (SERVER AND LINUX)
+
+# mapserver requires certain files to be copied so LL_MESA_HEADLESS can be set
+# differently for different object files.
+macro (copy_server_sources _copied_SOURCES)
+  foreach (PREFIX ${_copied_SOURCES})
+    add_custom_command(
+        OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${PREFIX}_server.cpp
+        COMMAND ${CMAKE_COMMAND}
+        ARGS -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${PREFIX}.cpp
+             ${CMAKE_CURRENT_BINARY_DIR}/${PREFIX}_server.cpp
+        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${PREFIX}.cpp
+        )
+    list(APPEND server_SOURCE_FILES ${PREFIX}_server.cpp)
+  endforeach (PREFIX ${_copied_SOURCES})
+endmacro (copy_server_sources _copied_SOURCES)
diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt
index 2dba8ef60dd..76858d98395 100644
--- a/indra/llrender/CMakeLists.txt
+++ b/indra/llrender/CMakeLists.txt
@@ -20,24 +20,38 @@ include_directories(
     )
 
 set(llrender_SOURCE_FILES
+    llcubemap.cpp
     llfont.cpp
     llfontgl.cpp
     llgldbg.cpp
+    llglslshader.cpp
     llimagegl.cpp
+    llpostprocess.cpp
     llrender.cpp
+    llrendersphere.cpp
     llrendertarget.cpp
+    llshadermgr.cpp
     llvertexbuffer.cpp
     )
     
 set(llrender_HEADER_FILES
     CMakeLists.txt
 
+    llcubemap.h
     llfontgl.h
     llfont.h
+    llgl.h
     llgldbg.h
+    llglheaders.h
+    llglslshader.h
+    llglstates.h
+    llgltypes.h
     llimagegl.h
+    llpostprocess.h
     llrender.h
+    llrendersphere.h
     llrendertarget.h
+    llshadermgr.h
     llvertexbuffer.h
     )
 
@@ -46,4 +60,24 @@ set_source_files_properties(${llrender_HEADER_FILES}
 
 list(APPEND llrender_SOURCE_FILES ${llrender_HEADER_FILES})
 
+if (SERVER AND NOT WINDOWS AND NOT DARWIN)
+  copy_server_sources(
+      llgl
+      )
+
+
+  set_source_files_properties(
+    ${server_SOURCE_FILES}
+    PROPERTIES
+    COMPILE_FLAGS "-DLL_MESA=1 -DLL_MESA_HEADLESS=1"
+    )
+  add_library (llrenderheadless
+    ${llrender_SOURCE_FILES}
+    ${server_SOURCE_FILES}
+    )
+else (SERVER AND NOT WINDOWS AND NOT DARWIN)
+  list(APPEND llrender_SOURCE_FILES
+      llgl.cpp
+      )
+endif (SERVER AND NOT WINDOWS AND NOT DARWIN)
 add_library (llrender ${llrender_SOURCE_FILES})
diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp
new file mode 100644
index 00000000000..f19992eeabe
--- /dev/null
+++ b/indra/llrender/llcubemap.cpp
@@ -0,0 +1,532 @@
+/** 
+ * @file llcubemap.cpp
+ * @brief LLCubeMap class implementation
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ * 
+ * Copyright (c) 2002-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+#include "linden_common.h"
+
+#include "llworkerthread.h"
+
+#include "llcubemap.h"
+
+#include "v4coloru.h"
+#include "v3math.h"
+#include "v3dmath.h"
+#include "m3math.h"
+#include "m4math.h"
+#include "llcamera.h"
+
+#include "llrender.h"
+
+#include "llglheaders.h"
+
+const F32 epsilon = 1e-7f;
+const U16 RESOLUTION = 64;
+
+#if LL_DARWIN
+// mipmap generation on cubemap textures seems to be broken on the Mac for at least some cards.
+// Since the cubemap is small (64x64 per face) and doesn't have any fine detail, turning off mipmaps is a usable workaround.
+const BOOL use_cube_mipmaps = FALSE;
+#else
+const BOOL use_cube_mipmaps = FALSE;  //current build works best without cube mipmaps
+#endif
+
+bool LLCubeMap::sUseCubeMaps = true;
+
+LLCubeMap::LLCubeMap()
+	: mTextureStage(0),
+	  mTextureCoordStage(0),
+	  mMatrixStage(0)
+{
+}
+
+LLCubeMap::~LLCubeMap()
+{
+}
+
+void LLCubeMap::initGL()
+{
+	llassert(gGLManager.mInited);
+
+	if (gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps)
+	{
+		mTargets[0] = GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB;
+		mTargets[1] = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB;
+		mTargets[2] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB;
+		mTargets[3] = GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB;
+		mTargets[4] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB;
+		mTargets[5] = GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB;
+		
+		// Not initialized, do stuff.
+		if (mImages[0].isNull())
+		{
+			GLuint texname = 0;
+			
+			glGenTextures(1, &texname);
+
+			for (int i = 0; i < 6; i++)
+			{
+				mImages[i] = new LLImageGL(64, 64, 4, (use_cube_mipmaps? TRUE : FALSE));
+				mImages[i]->setTarget(mTargets[i], GL_TEXTURE_CUBE_MAP_ARB);
+				mRawImages[i] = new LLImageRaw(64, 64, 4);
+				mImages[i]->createGLTexture(0, mRawImages[i], texname);
+				
+				glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, texname);
+				mImages[i]->setClampCubemap (TRUE, TRUE, TRUE);
+				stop_glerror();
+			}
+		}
+		disable();
+	}
+	else
+	{
+		llwarns << "Using cube map without extension!" << llendl
+	}
+}
+
+void LLCubeMap::initRawData(const std::vector<LLPointer<LLImageRaw> >& rawimages)
+{
+	bool flip_x[6] =	{ false, true,  false, false, true,  false };
+	bool flip_y[6] = 	{ true,  true,  true,  false, true,  true  };
+	bool transpose[6] = { false, false, false, false, true,  true  };
+	
+	// Yes, I know that this is inefficient! - djs 08/08/02
+	for (int i = 0; i < 6; i++)
+	{
+		const U8 *sd = rawimages[i]->getData();
+		U8 *td = mRawImages[i]->getData();
+
+		S32 offset = 0;
+		S32 sx, sy, so;
+		for (int y = 0; y < 64; y++)
+		{
+			for (int x = 0; x < 64; x++)
+			{
+				sx = x;
+				sy = y;
+				if (flip_y[i])
+				{
+					sy = 63 - y;
+				}
+				if (flip_x[i])
+				{
+					sx = 63 - x;
+				}
+				if (transpose[i])
+				{
+					S32 temp = sx;
+					sx = sy;
+					sy = temp;
+				}
+
+				so = 64*sy + sx;
+				so *= 4;
+				*(td + offset++) = *(sd + so++);
+				*(td + offset++) = *(sd + so++);
+				*(td + offset++) = *(sd + so++);
+				*(td + offset++) = *(sd + so++);
+			}
+		}
+	}
+}
+
+void LLCubeMap::initGLData()
+{
+	for (int i = 0; i < 6; i++)
+	{
+		mImages[i]->setSubImage(mRawImages[i], 0, 0, 64, 64);
+	}
+}
+
+void LLCubeMap::init(const std::vector<LLPointer<LLImageRaw> >& rawimages)
+{
+	if (!gGLManager.mIsDisabled)
+	{
+		initGL();
+		initRawData(rawimages);
+		initGLData();
+	}
+}
+
+GLuint LLCubeMap::getGLName()
+{
+	return mImages[0]->getTexName();
+}
+
+void LLCubeMap::bind()
+{
+	if (gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps)
+	{
+		// We assume that if they have cube mapping, they have multitexturing.
+		if (mTextureStage > 0)
+		{
+			gGL.getTexUnit(mTextureStage)->activate();
+		}
+		glEnable(GL_TEXTURE_CUBE_MAP_ARB);
+		glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mImages[0]->getTexName());
+
+		mImages[0]->setMipFilterNearest (FALSE, FALSE);
+		if (mTextureStage > 0)
+		{
+			gGL.getTexUnit(0)->activate();
+		}
+	}
+	else
+	{
+		llwarns << "Using cube map without extension!" << llendl
+	}
+}
+
+void LLCubeMap::enable(S32 stage)
+{
+	enableTexture(stage);
+	enableTextureCoords(stage);
+}
+
+void LLCubeMap::enableTexture(S32 stage)
+{
+	mTextureStage = stage;
+	if (gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps)
+	{
+		if (stage > 0)
+		{
+			gGL.getTexUnit(stage)->activate();
+		}
+		
+		glEnable(GL_TEXTURE_CUBE_MAP_ARB);
+		
+		if (stage > 0)
+		{
+			gGL.getTexUnit(0)->activate();
+		}
+	}
+}
+
+void LLCubeMap::enableTextureCoords(S32 stage)
+{
+	mTextureCoordStage = stage;
+	if (gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps)
+	{
+		if (stage > 0)
+		{
+			gGL.getTexUnit(stage)->activate();
+		}
+		
+		glEnable(GL_TEXTURE_GEN_R);
+		glEnable(GL_TEXTURE_GEN_S);
+		glEnable(GL_TEXTURE_GEN_T);
+
+		glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
+		glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
+		glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
+		
+		if (stage > 0)
+		{
+			gGL.getTexUnit(0)->activate();
+		}
+	}
+}
+
+void LLCubeMap::disable(void)
+{
+	disableTexture();
+	disableTextureCoords();
+}
+
+void LLCubeMap::disableTexture(void)
+{
+	if (gGLManager.mHasCubeMap && mTextureStage >= 0 && LLCubeMap::sUseCubeMaps)
+	{
+		if (mTextureStage > 0)
+		{
+			gGL.getTexUnit(mTextureStage)->activate();
+		}
+		glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);
+		glDisable(GL_TEXTURE_CUBE_MAP_ARB);
+		if (mTextureStage > 0)
+		{
+			gGL.getTexUnit(0)->activate();
+		}
+	}
+}
+
+void LLCubeMap::disableTextureCoords(void)
+{
+	if (gGLManager.mHasCubeMap && mTextureCoordStage >= 0 && LLCubeMap::sUseCubeMaps)
+	{
+		if (mTextureCoordStage > 0)
+		{
+			gGL.getTexUnit(mTextureCoordStage)->activate();
+		}
+		glDisable(GL_TEXTURE_GEN_S);
+		glDisable(GL_TEXTURE_GEN_T);
+		glDisable(GL_TEXTURE_GEN_R);
+		if (mTextureCoordStage > 0)
+		{
+			gGL.getTexUnit(0)->activate();
+		}
+	}
+}
+
+void LLCubeMap::setMatrix(S32 stage)
+{
+	mMatrixStage = stage;
+	
+	if (stage > 0)
+	{
+		gGL.getTexUnit(stage)->activate();
+	}
+
+	LLVector3 x(LLVector3d(gGLModelView+0));
+	LLVector3 y(LLVector3d(gGLModelView+4));
+	LLVector3 z(LLVector3d(gGLModelView+8));
+
+	LLMatrix3 mat3;
+	mat3.setRows(x,y,z);
+	LLMatrix4 trans(mat3);
+	trans.transpose();
+
+	glMatrixMode(GL_TEXTURE);
+	glPushMatrix();
+	glLoadMatrixf((F32 *)trans.mMatrix);
+	glMatrixMode(GL_MODELVIEW);
+	
+	if (stage > 0)
+	{
+		gGL.getTexUnit(0)->activate();
+	}
+}
+
+void LLCubeMap::restoreMatrix()
+{
+	if (mMatrixStage > 0)
+	{
+		gGL.getTexUnit(mMatrixStage)->activate();
+	}
+	glMatrixMode(GL_TEXTURE);
+	glPopMatrix();
+	glMatrixMode(GL_MODELVIEW);
+	
+	if (mMatrixStage > 0)
+	{
+		gGL.getTexUnit(0)->activate();
+	}
+}
+
+void LLCubeMap::setReflection (void)
+{
+	glBindTexture (GL_TEXTURE_CUBE_MAP_ARB, getGLName());
+	mImages[0]->setMipFilterNearest (FALSE, FALSE);
+	mImages[0]->setClampCubemap (TRUE, TRUE);
+}
+
+LLVector3 LLCubeMap::map(U8 side, U16 v_val, U16 h_val) const
+{
+	LLVector3 dir;
+
+	const U8 curr_coef = side >> 1; // 0/1 = X axis, 2/3 = Y, 4/5 = Z
+	const S8 side_dir = (((side & 1) << 1) - 1);  // even = -1, odd = 1
+	const U8 i_coef = (curr_coef + 1) % 3;
+	const U8 j_coef = (i_coef + 1) % 3;
+
+	dir.mV[curr_coef] = side_dir;
+
+	switch (side)
+	{
+	case 0: // negative X
+		dir.mV[i_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1;
+		dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1;
+		break;
+	case 1: // positive X
+		dir.mV[i_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1;
+		dir.mV[j_coef] = -F32((h_val<<1) + 1) / RESOLUTION + 1;
+		break;
+	case 2:	// negative Y
+		dir.mV[i_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1;
+		dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1;
+		break;
+	case 3:	// positive Y
+		dir.mV[i_coef] = F32((v_val<<1) + 1) / RESOLUTION - 1;
+		dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1;
+		break;
+	case 4:	// negative Z
+		dir.mV[i_coef] = -F32((h_val<<1) + 1) / RESOLUTION + 1;
+		dir.mV[j_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1;
+		break;
+	case 5: // positive Z
+		dir.mV[i_coef] = -F32((h_val<<1) + 1) / RESOLUTION + 1;
+		dir.mV[j_coef] = F32((v_val<<1) + 1) / RESOLUTION - 1;
+		break;
+	default:
+		dir.mV[i_coef] = F32((v_val<<1) + 1) / RESOLUTION - 1;
+		dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1;
+	}
+
+	dir.normVec();
+	return dir;
+}
+
+
+BOOL LLCubeMap::project(F32& v_val, F32& h_val, BOOL& outside,
+						U8 side, const LLVector3& dir) const
+{
+	const U8 curr_coef = side >> 1; // 0/1 = X axis, 2/3 = Y, 4/5 = Z
+	const S8 side_dir = (((side & 1) << 1) - 1);  // even = -1, odd = 1
+	const U8 i_coef = (curr_coef + 1) % 3;
+	const U8 j_coef = (i_coef + 1) % 3;
+
+	outside = TRUE;
+	if (side_dir * dir.mV[curr_coef] < 0)
+		return FALSE;
+
+	LLVector3 ray;
+
+	F32 norm_val = fabs(dir.mV[curr_coef]);
+
+	if (norm_val < epsilon)
+		norm_val = 1e-5f;
+
+	ray.mV[curr_coef] = side_dir;
+	ray.mV[i_coef] = dir.mV[i_coef] / norm_val;
+	ray.mV[j_coef] = dir.mV[j_coef] / norm_val;
+
+
+	const F32 i_val = (ray.mV[i_coef] + 1) * 0.5f * RESOLUTION;
+	const F32 j_val = (ray.mV[j_coef] + 1) * 0.5f * RESOLUTION;
+
+	switch (side)
+	{
+	case 0: // negative X
+		v_val = RESOLUTION - i_val;
+		h_val = j_val;
+		break;
+	case 1: // positive X
+		v_val = RESOLUTION - i_val;
+		h_val = RESOLUTION - j_val;
+		break;
+	case 2:	// negative Y
+		v_val = RESOLUTION - i_val;
+		h_val = j_val;
+		break;
+	case 3:	// positive Y
+		v_val = i_val;
+		h_val = j_val;
+		break;
+	case 4:	// negative Z
+		v_val = RESOLUTION - j_val;
+		h_val = RESOLUTION - i_val;
+		break;
+	case 5: // positive Z
+		v_val = RESOLUTION - j_val;
+		h_val = i_val;
+		break;
+	default:
+		v_val = i_val;
+		h_val = j_val;
+	}
+
+	outside =  ((v_val < 0) || (v_val > RESOLUTION) ||
+		(h_val < 0) || (h_val > RESOLUTION));
+
+	return TRUE;
+}
+
+BOOL LLCubeMap::project(F32& v_min, F32& v_max, F32& h_min, F32& h_max, 
+						U8 side, LLVector3 dir[4]) const
+{
+	v_min = h_min = RESOLUTION;
+	v_max = h_max = 0;
+
+	BOOL fully_outside = TRUE;
+	for (U8 vtx = 0; vtx < 4; ++vtx)
+	{
+		F32 v_val, h_val;
+		BOOL outside;
+		BOOL consider = project(v_val, h_val, outside, side, dir[vtx]);
+		if (!outside)
+			fully_outside = FALSE;
+		if (consider)
+		{
+			if (v_val < v_min) v_min = v_val;
+			if (v_val > v_max) v_max = v_val;
+			if (h_val < h_min) h_min = h_val;
+			if (h_val > h_max) h_max = h_val;
+		}
+	}
+
+	v_min = llmax(0.0f, v_min);
+	v_max = llmin(RESOLUTION - epsilon, v_max);
+	h_min = llmax(0.0f, h_min);
+	h_max = llmin(RESOLUTION - epsilon, h_max);
+
+	return !fully_outside;
+}
+
+
+void LLCubeMap::paintIn(LLVector3 dir[4], const LLColor4U& col)
+{
+	F32 v_min, v_max, h_min, h_max;
+	LLVector3 center = dir[0] + dir[1] + dir[2] + dir[3];
+	center.normVec();
+
+	for (U8 side = 0; side < 6; ++side)
+	{
+		if (!project(v_min, v_max, h_min, h_max, side, dir))
+			continue;
+
+		U8 *td = mRawImages[side]->getData();
+		
+		U16 v_minu = (U16) v_min;
+		U16 v_maxu = (U16) (ceil(v_max) + 0.5);
+		U16 h_minu = (U16) h_min;
+		U16 h_maxu = (U16) (ceil(h_max) + 0.5);
+
+		for (U16 v = v_minu; v < v_maxu; ++v)
+			for (U16 h = h_minu; h < h_maxu; ++h)
+		//for (U16 v = 0; v < RESOLUTION; ++v)
+		//	for (U16 h = 0; h < RESOLUTION; ++h)
+			{
+				const LLVector3 ray = map(side, v, h);
+				if (ray * center > 0.999)
+				{
+					const U32 offset = (RESOLUTION * v + h) * 4;
+					for (U8 cc = 0; cc < 3; ++cc)
+						td[offset + cc] = U8((td[offset + cc] + col.mV[cc]) * 0.5);
+				}
+			}
+		mImages[side]->setSubImage(mRawImages[side], 0, 0, 64, 64);
+	}
+}
+
+void LLCubeMap::destroyGL()
+{
+	for (S32 i = 0; i < 6; i++)
+	{
+		mImages[i] = NULL;
+	}
+}
diff --git a/indra/llrender/llcubemap.h b/indra/llrender/llcubemap.h
new file mode 100644
index 00000000000..c273ab40ec7
--- /dev/null
+++ b/indra/llrender/llcubemap.h
@@ -0,0 +1,89 @@
+/** 
+ * @file llcubemap.h
+ * @brief LLCubeMap class definition
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ * 
+ * Copyright (c) 2002-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLCUBEMAP_H
+#define LL_LLCUBEMAP_H
+
+#include "llgl.h"
+
+#include <vector>
+
+class LLVector3;
+
+// Environment map hack!
+class LLCubeMap : public LLRefCount
+{
+public:
+	LLCubeMap();
+	void init(const std::vector<LLPointer<LLImageRaw> >& rawimages);
+	void initGL();
+	void initRawData(const std::vector<LLPointer<LLImageRaw> >& rawimages);
+	void initGLData();
+
+	void bind();
+	void enable(S32 stage);
+	
+	void enableTexture(S32 stage);
+	void enableTextureCoords(S32 stage);
+	
+	void disable(void);
+	void disableTexture(void);
+	void disableTextureCoords(void);
+	void setMatrix(S32 stage);
+	void restoreMatrix();
+	void setReflection (void);
+
+	void finishPaint();
+
+	GLuint getGLName();
+
+	LLVector3 map(U8 side, U16 v_val, U16 h_val) const;
+	BOOL project(F32& v_val, F32& h_val, BOOL& outside,
+						U8 side, const LLVector3& dir) const;
+	BOOL project(F32& v_min, F32& v_max, F32& h_min, F32& h_max, 
+						U8 side, LLVector3 dir[4]) const;
+	void paintIn(LLVector3 dir[4], const LLColor4U& col);
+	void destroyGL();
+
+public:
+	static bool sUseCubeMaps;
+
+protected:
+	~LLCubeMap();
+	LLGLenum mTargets[6];
+	LLPointer<LLImageGL> mImages[6];
+	LLPointer<LLImageRaw> mRawImages[6];
+	S32 mTextureStage;
+	S32 mTextureCoordStage;
+	S32 mMatrixStage;
+};
+
+#endif
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
new file mode 100644
index 00000000000..8c63122cb8e
--- /dev/null
+++ b/indra/llrender/llgl.cpp
@@ -0,0 +1,1726 @@
+/** 
+ * @file llgl.cpp
+ * @brief LLGL implementation
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+// This file sets some global GL parameters, and implements some 
+// useful functions for GL operations.
+
+#define GLH_EXT_SINGLE_FILE
+
+#include "linden_common.h"
+
+#include "boost/tokenizer.hpp"
+
+#include "llsys.h"
+
+#include "llgl.h"
+#include "llrender.h"
+
+#include "llerror.h"
+#include "llquaternion.h"
+#include "llmath.h"
+#include "m4math.h"
+#include "llstring.h"
+
+#include "llglheaders.h"
+
+#ifdef _DEBUG
+//#define GL_STATE_VERIFY
+#endif
+
+BOOL gDebugGL = FALSE;
+BOOL gClothRipple = FALSE;
+BOOL gNoRender = FALSE;
+LLMatrix4 gGLObliqueProjectionInverse;
+
+LLGLNamePool::pool_list_t LLGLNamePool::sInstances;
+
+#if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS
+// ATI prototypes
+// vertex blending prototypes
+PFNGLWEIGHTPOINTERARBPROC			glWeightPointerARB = NULL;
+PFNGLVERTEXBLENDARBPROC				glVertexBlendARB = NULL;
+PFNGLWEIGHTFVARBPROC				glWeightfvARB = NULL;
+
+// Vertex buffer object prototypes
+PFNGLBINDBUFFERARBPROC				glBindBufferARB = NULL;
+PFNGLDELETEBUFFERSARBPROC			glDeleteBuffersARB = NULL;
+PFNGLGENBUFFERSARBPROC				glGenBuffersARB = NULL;
+PFNGLISBUFFERARBPROC				glIsBufferARB = NULL;
+PFNGLBUFFERDATAARBPROC				glBufferDataARB = NULL;
+PFNGLBUFFERSUBDATAARBPROC			glBufferSubDataARB = NULL;
+PFNGLGETBUFFERSUBDATAARBPROC		glGetBufferSubDataARB = NULL;
+PFNGLMAPBUFFERARBPROC				glMapBufferARB = NULL;
+PFNGLUNMAPBUFFERARBPROC				glUnmapBufferARB = NULL;
+PFNGLGETBUFFERPARAMETERIVARBPROC	glGetBufferParameterivARB = NULL;
+PFNGLGETBUFFERPOINTERVARBPROC		glGetBufferPointervARB = NULL;
+
+// vertex object prototypes
+PFNGLNEWOBJECTBUFFERATIPROC			glNewObjectBufferATI = NULL;
+PFNGLISOBJECTBUFFERATIPROC			glIsObjectBufferATI = NULL;
+PFNGLUPDATEOBJECTBUFFERATIPROC		glUpdateObjectBufferATI = NULL;
+PFNGLGETOBJECTBUFFERFVATIPROC		glGetObjectBufferfvATI = NULL;
+PFNGLGETOBJECTBUFFERIVATIPROC		glGetObjectBufferivATI = NULL;
+PFNGLFREEOBJECTBUFFERATIPROC		glFreeObjectBufferATI = NULL;
+PFNGLARRAYOBJECTATIPROC				glArrayObjectATI = NULL;
+PFNGLVERTEXATTRIBARRAYOBJECTATIPROC	glVertexAttribArrayObjectATI = NULL;
+PFNGLGETARRAYOBJECTFVATIPROC		glGetArrayObjectfvATI = NULL;
+PFNGLGETARRAYOBJECTIVATIPROC		glGetArrayObjectivATI = NULL;
+PFNGLVARIANTARRAYOBJECTATIPROC		glVariantObjectArrayATI = NULL;
+PFNGLGETVARIANTARRAYOBJECTFVATIPROC	glGetVariantArrayObjectfvATI = NULL;
+PFNGLGETVARIANTARRAYOBJECTIVATIPROC	glGetVariantArrayObjectivATI = NULL;
+
+// GL_ARB_occlusion_query
+PFNGLGENQUERIESARBPROC glGenQueriesARB = NULL;
+PFNGLDELETEQUERIESARBPROC glDeleteQueriesARB = NULL;
+PFNGLISQUERYARBPROC glIsQueryARB = NULL;
+PFNGLBEGINQUERYARBPROC glBeginQueryARB = NULL;
+PFNGLENDQUERYARBPROC glEndQueryARB = NULL;
+PFNGLGETQUERYIVARBPROC glGetQueryivARB = NULL;
+PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB = NULL;
+PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB = NULL;
+
+// GL_ARB_point_parameters
+PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB = NULL;
+PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB = NULL;
+
+// GL_EXT_framebuffer_object
+PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT = NULL;
+PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT = NULL;
+PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT = NULL;
+PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT = NULL;
+PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT = NULL;
+PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT = NULL;
+PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT = NULL;
+PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = NULL;
+PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT = NULL;
+PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = NULL;
+PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = NULL;
+PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT = NULL;
+PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = NULL;
+PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT = NULL;
+PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = NULL;
+PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT = NULL;
+PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = NULL;
+
+//shader object prototypes
+PFNGLDELETEOBJECTARBPROC glDeleteObjectARB = NULL;
+PFNGLGETHANDLEARBPROC glGetHandleARB = NULL;
+PFNGLDETACHOBJECTARBPROC glDetachObjectARB = NULL;
+PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB = NULL;
+PFNGLSHADERSOURCEARBPROC glShaderSourceARB = NULL;
+PFNGLCOMPILESHADERARBPROC glCompileShaderARB = NULL;
+PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB = NULL;
+PFNGLATTACHOBJECTARBPROC glAttachObjectARB = NULL;
+PFNGLLINKPROGRAMARBPROC glLinkProgramARB = NULL;
+PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB = NULL;
+PFNGLVALIDATEPROGRAMARBPROC glValidateProgramARB = NULL;
+PFNGLUNIFORM1FARBPROC glUniform1fARB = NULL;
+PFNGLUNIFORM2FARBPROC glUniform2fARB = NULL;
+PFNGLUNIFORM3FARBPROC glUniform3fARB = NULL;
+PFNGLUNIFORM4FARBPROC glUniform4fARB = NULL;
+PFNGLUNIFORM1IARBPROC glUniform1iARB = NULL;
+PFNGLUNIFORM2IARBPROC glUniform2iARB = NULL;
+PFNGLUNIFORM3IARBPROC glUniform3iARB = NULL;
+PFNGLUNIFORM4IARBPROC glUniform4iARB = NULL;
+PFNGLUNIFORM1FVARBPROC glUniform1fvARB = NULL;
+PFNGLUNIFORM2FVARBPROC glUniform2fvARB = NULL;
+PFNGLUNIFORM3FVARBPROC glUniform3fvARB = NULL;
+PFNGLUNIFORM4FVARBPROC glUniform4fvARB = NULL;
+PFNGLUNIFORM1IVARBPROC glUniform1ivARB = NULL;
+PFNGLUNIFORM2IVARBPROC glUniform2ivARB = NULL;
+PFNGLUNIFORM3IVARBPROC glUniform3ivARB = NULL;
+PFNGLUNIFORM4IVARBPROC glUniform4ivARB = NULL;
+PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB = NULL;
+PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB = NULL;
+PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB = NULL;
+PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB = NULL;
+PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB = NULL;
+PFNGLGETINFOLOGARBPROC glGetInfoLogARB = NULL;
+PFNGLGETATTACHEDOBJECTSARBPROC glGetAttachedObjectsARB = NULL;
+PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB = NULL;
+PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniformARB = NULL;
+PFNGLGETUNIFORMFVARBPROC glGetUniformfvARB = NULL;
+PFNGLGETUNIFORMIVARBPROC glGetUniformivARB = NULL;
+PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB = NULL;
+
+// vertex shader prototypes
+#if LL_LINUX
+PFNGLVERTEXATTRIB1DARBPROC glVertexAttrib1dARB = NULL;
+PFNGLVERTEXATTRIB1DVARBPROC glVertexAttrib1dvARB = NULL;
+PFNGLVERTEXATTRIB1FARBPROC glVertexAttrib1fARB = NULL;
+PFNGLVERTEXATTRIB1FVARBPROC glVertexAttrib1fvARB = NULL;
+PFNGLVERTEXATTRIB1SARBPROC glVertexAttrib1sARB = NULL;
+PFNGLVERTEXATTRIB1SVARBPROC glVertexAttrib1svARB = NULL;
+PFNGLVERTEXATTRIB2DARBPROC glVertexAttrib2dARB = NULL;
+PFNGLVERTEXATTRIB2DVARBPROC glVertexAttrib2dvARB = NULL;
+PFNGLVERTEXATTRIB2FARBPROC glVertexAttrib2fARB = NULL;
+PFNGLVERTEXATTRIB2FVARBPROC glVertexAttrib2fvARB = NULL;
+PFNGLVERTEXATTRIB2SARBPROC glVertexAttrib2sARB = NULL;
+PFNGLVERTEXATTRIB2SVARBPROC glVertexAttrib2svARB = NULL;
+PFNGLVERTEXATTRIB3DARBPROC glVertexAttrib3dARB = NULL;
+PFNGLVERTEXATTRIB3DVARBPROC glVertexAttrib3dvARB = NULL;
+PFNGLVERTEXATTRIB3FARBPROC glVertexAttrib3fARB = NULL;
+PFNGLVERTEXATTRIB3FVARBPROC glVertexAttrib3fvARB = NULL;
+PFNGLVERTEXATTRIB3SARBPROC glVertexAttrib3sARB = NULL;
+PFNGLVERTEXATTRIB3SVARBPROC glVertexAttrib3svARB = NULL;
+#endif // LL_LINUX
+PFNGLVERTEXATTRIB4NBVARBPROC glVertexAttrib4nbvARB = NULL;
+PFNGLVERTEXATTRIB4NIVARBPROC glVertexAttrib4nivARB = NULL;
+PFNGLVERTEXATTRIB4NSVARBPROC glVertexAttrib4nsvARB = NULL;
+PFNGLVERTEXATTRIB4NUBARBPROC glVertexAttrib4nubARB = NULL;
+PFNGLVERTEXATTRIB4NUBVARBPROC glVertexAttrib4nubvARB = NULL;
+PFNGLVERTEXATTRIB4NUIVARBPROC glVertexAttrib4nuivARB = NULL;
+PFNGLVERTEXATTRIB4NUSVARBPROC glVertexAttrib4nusvARB = NULL;
+#if LL_LINUX
+PFNGLVERTEXATTRIB4BVARBPROC glVertexAttrib4bvARB = NULL;
+PFNGLVERTEXATTRIB4DARBPROC glVertexAttrib4dARB = NULL;
+PFNGLVERTEXATTRIB4DVARBPROC glVertexAttrib4dvARB = NULL;
+PFNGLVERTEXATTRIB4FARBPROC glVertexAttrib4fARB = NULL;
+PFNGLVERTEXATTRIB4FVARBPROC glVertexAttrib4fvARB = NULL;
+PFNGLVERTEXATTRIB4IVARBPROC glVertexAttrib4ivARB = NULL;
+PFNGLVERTEXATTRIB4SARBPROC glVertexAttrib4sARB = NULL;
+PFNGLVERTEXATTRIB4SVARBPROC glVertexAttrib4svARB = NULL;
+PFNGLVERTEXATTRIB4UBVARBPROC glVertexAttrib4ubvARB = NULL;
+PFNGLVERTEXATTRIB4UIVARBPROC glVertexAttrib4uivARB = NULL;
+PFNGLVERTEXATTRIB4USVARBPROC glVertexAttrib4usvARB = NULL;
+PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB = NULL;
+PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB = NULL;
+PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB = NULL;
+PFNGLPROGRAMSTRINGARBPROC glProgramStringARB = NULL;
+PFNGLBINDPROGRAMARBPROC glBindProgramARB = NULL;
+PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB = NULL;
+PFNGLGENPROGRAMSARBPROC glGenProgramsARB = NULL;
+PFNGLPROGRAMENVPARAMETER4DARBPROC glProgramEnvParameter4dARB = NULL;
+PFNGLPROGRAMENVPARAMETER4DVARBPROC glProgramEnvParameter4dvARB = NULL;
+PFNGLPROGRAMENVPARAMETER4FARBPROC glProgramEnvParameter4fARB = NULL;
+PFNGLPROGRAMENVPARAMETER4FVARBPROC glProgramEnvParameter4fvARB = NULL;
+PFNGLPROGRAMLOCALPARAMETER4DARBPROC glProgramLocalParameter4dARB = NULL;
+PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glProgramLocalParameter4dvARB = NULL;
+PFNGLPROGRAMLOCALPARAMETER4FARBPROC glProgramLocalParameter4fARB = NULL;
+PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB = NULL;
+PFNGLGETPROGRAMENVPARAMETERDVARBPROC glGetProgramEnvParameterdvARB = NULL;
+PFNGLGETPROGRAMENVPARAMETERFVARBPROC glGetProgramEnvParameterfvARB = NULL;
+PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glGetProgramLocalParameterdvARB = NULL;
+PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glGetProgramLocalParameterfvARB = NULL;
+PFNGLGETPROGRAMIVARBPROC glGetProgramivARB = NULL;
+PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB = NULL;
+PFNGLGETVERTEXATTRIBDVARBPROC glGetVertexAttribdvARB = NULL;
+PFNGLGETVERTEXATTRIBFVARBPROC glGetVertexAttribfvARB = NULL;
+PFNGLGETVERTEXATTRIBIVARBPROC glGetVertexAttribivARB = NULL;
+PFNGLGETVERTEXATTRIBPOINTERVARBPROC glGetVertexAttribPointervARB = NULL;
+PFNGLISPROGRAMARBPROC glIsProgramARB = NULL;
+#endif // LL_LINUX
+PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB = NULL;
+PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB = NULL;
+PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB = NULL;
+
+#if LL_WINDOWS
+PFNWGLSWAPINTERVALEXTPROC			wglSwapIntervalEXT = NULL;
+#endif
+
+#if LL_LINUX
+PFNGLCOLORTABLEEXTPROC glColorTableEXT = NULL;
+#endif // LL_LINUX
+
+#endif
+
+LLGLManager gGLManager;
+
+LLGLManager::LLGLManager() :
+	mInited(FALSE),
+	mIsDisabled(FALSE),
+
+	mHasMultitexture(FALSE),
+	mNumTextureUnits(1),
+	mHasMipMapGeneration(FALSE),
+	mHasPalettedTextures(FALSE),
+	mHasCompressedTextures(FALSE),
+	mHasFramebufferObject(FALSE),
+
+	mHasVertexBufferObject(FALSE),
+	mHasPBuffer(FALSE),
+	mHasShaderObjects(FALSE),
+	mHasVertexShader(FALSE),
+	mHasFragmentShader(FALSE),
+	mHasOcclusionQuery(FALSE),
+	mHasPointParameters(FALSE),
+
+	mHasAnisotropic(FALSE),
+	mHasARBEnvCombine(FALSE),
+	mHasCubeMap(FALSE),
+
+	mIsATI(FALSE),
+	mIsNVIDIA(FALSE),
+	mIsIntel(FALSE),
+	mIsGF2or4MX(FALSE),
+	mIsGF3(FALSE),
+	mIsGFFX(FALSE),
+	mATIOffsetVerticalLines(FALSE),
+
+	mHasRequirements(TRUE),
+
+	mHasSeparateSpecularColor(FALSE),
+
+	mDriverVersionMajor(1),
+	mDriverVersionMinor(0),
+	mDriverVersionRelease(0),
+	mGLVersion(1.0f),
+		
+	mVRAM(0),
+	mGLMaxVertexRange(0),
+	mGLMaxIndexRange(0)
+{
+}
+
+//---------------------------------------------------------------------
+// Global initialization for GL
+//---------------------------------------------------------------------
+void LLGLManager::initWGL()
+{
+	mHasPBuffer = FALSE;
+#if LL_WINDOWS && !LL_MESA_HEADLESS
+	if (!glh_init_extensions("WGL_ARB_pixel_format"))
+	{
+		LL_WARNS("RenderInit") << "No ARB pixel format extensions" << LL_ENDL;
+	}
+
+	if (ExtensionExists("WGL_EXT_swap_control", gGLHExts.mSysExts))
+	{
+        GLH_EXT_NAME(wglSwapIntervalEXT) = (PFNWGLSWAPINTERVALEXTPROC)GLH_EXT_GET_PROC_ADDRESS("wglSwapIntervalEXT");
+	}
+
+	if( !glh_init_extensions("WGL_ARB_pbuffer") )
+	{
+		LL_WARNS("RenderInit") << "No ARB WGL PBuffer extensions" << LL_ENDL;
+	}
+
+	if( !glh_init_extensions("WGL_ARB_render_texture") )
+	{
+		LL_WARNS("RenderInit") << "No ARB WGL render texture extensions" << LL_ENDL;
+	}
+
+	mHasPBuffer = ExtensionExists("WGL_ARB_pbuffer", gGLHExts.mSysExts) &&
+					ExtensionExists("WGL_ARB_render_texture", gGLHExts.mSysExts) &&
+					ExtensionExists("WGL_ARB_pixel_format", gGLHExts.mSysExts);
+#endif
+}
+
+// return false if unable (or unwilling due to old drivers) to init GL
+bool LLGLManager::initGL()
+{
+	if (mInited)
+	{
+		LL_ERRS("RenderInit") << "Calling init on LLGLManager after already initialized!" << LL_ENDL;
+	}
+
+	GLint alpha_bits;
+	glGetIntegerv( GL_ALPHA_BITS, &alpha_bits );
+	if( 8 != alpha_bits )
+	{
+		LL_WARNS("RenderInit") << "Frame buffer has less than 8 bits of alpha.  Avatar texture compositing will fail." << LL_ENDL;
+	}
+
+	// Extract video card strings and convert to upper case to
+	// work around driver-to-driver variation in capitalization.
+	mGLVendor = std::string((const char *)glGetString(GL_VENDOR));
+	LLStringUtil::toUpper(mGLVendor);
+
+	mGLRenderer = std::string((const char *)glGetString(GL_RENDERER));
+	LLStringUtil::toUpper(mGLRenderer);
+
+	parse_gl_version( &mDriverVersionMajor, 
+		&mDriverVersionMinor, 
+		&mDriverVersionRelease, 
+		&mDriverVersionVendorString );
+
+	mGLVersion = mDriverVersionMajor + mDriverVersionMinor * .1f;
+	
+	// Trailing space necessary to keep "nVidia Corpor_ati_on" cards
+	// from being recognized as ATI.
+	if (mGLVendor.substr(0,4) == "ATI ")
+	{
+		mGLVendorShort = "ATI";
+		BOOL mobile = FALSE;
+		if (mGLRenderer.find("MOBILITY") != std::string::npos)
+		{
+			mobile = TRUE;
+		}
+		mIsATI = TRUE;
+
+#if LL_WINDOWS && !LL_MESA_HEADLESS
+		if (mDriverVersionRelease < 3842)
+		{
+			mATIOffsetVerticalLines = TRUE;
+		}
+#endif // LL_WINDOWS
+	}
+	else if (mGLVendor.find("NVIDIA ") != std::string::npos)
+	{
+		mGLVendorShort = "NVIDIA";
+		mIsNVIDIA = TRUE;
+		if (   mGLRenderer.find("GEFORCE4 MX") != std::string::npos
+			|| mGLRenderer.find("GEFORCE2") != std::string::npos
+			|| mGLRenderer.find("GEFORCE 2") != std::string::npos
+			|| mGLRenderer.find("GEFORCE4 460 GO") != std::string::npos
+			|| mGLRenderer.find("GEFORCE4 440 GO") != std::string::npos
+			|| mGLRenderer.find("GEFORCE4 420 GO") != std::string::npos)
+		{
+			mIsGF2or4MX = TRUE;
+		}
+		else if (mGLRenderer.find("GEFORCE FX") != std::string::npos
+				 || mGLRenderer.find("QUADRO FX") != std::string::npos
+				 || mGLRenderer.find("NV34") != std::string::npos)
+		{
+			mIsGFFX = TRUE;
+		}
+		else if(mGLRenderer.find("GEFORCE3") != std::string::npos)
+		{
+			mIsGF3 = TRUE;
+		}
+
+	}
+	else if (mGLVendor.find("INTEL") != std::string::npos
+#if LL_LINUX
+		 // The Mesa-based drivers put this in the Renderer string,
+		 // not the Vendor string.
+		 || mGLRenderer.find("INTEL") != std::string::npos
+#endif //LL_LINUX
+		 )
+	{
+		mGLVendorShort = "INTEL";
+		mIsIntel = TRUE;
+	}
+	else
+	{
+		mGLVendorShort = "MISC";
+	}
+	
+	// This is called here because it depends on the setting of mIsGF2or4MX, and sets up mHasMultitexture.
+	initExtensions();
+
+	if (mHasMultitexture)
+	{
+		GLint num_tex_units;		
+		glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &num_tex_units);
+		mNumTextureUnits = llmin(num_tex_units, (GLint)MAX_GL_TEXTURE_UNITS);
+		if (mIsIntel)
+		{
+			mNumTextureUnits = llmin(mNumTextureUnits, 2);
+		}
+	}
+	else
+	{
+		mHasRequirements = FALSE;
+
+		// We don't support cards that don't support the GL_ARB_multitexture extension
+		LL_WARNS("RenderInit") << "GL Drivers do not support GL_ARB_multitexture" << LL_ENDL;
+		return false;
+	}
+	
+
+	initGLStates();
+	return true;
+}
+
+void LLGLManager::getGLInfo(LLSD& info)
+{
+	info["GLInfo"]["GLVendor"] = std::string((const char *)glGetString(GL_VENDOR));
+	info["GLInfo"]["GLRenderer"] = std::string((const char *)glGetString(GL_RENDERER));
+	info["GLInfo"]["GLVersion"] = std::string((const char *)glGetString(GL_VERSION));
+
+#if !LL_MESA_HEADLESS
+	std::string all_exts = ll_safe_string((const char *)gGLHExts.mSysExts);
+	boost::char_separator<char> sep(" ");
+	boost::tokenizer<boost::char_separator<char> > tok(all_exts, sep);
+	for(boost::tokenizer<boost::char_separator<char> >::iterator i = tok.begin(); i != tok.end(); ++i)
+	{
+		info["GLInfo"]["GLExtensions"].append(*i);
+	}
+#endif
+}
+
+std::string LLGLManager::getGLInfoString()
+{
+	std::string info_str;
+	std::string all_exts, line;
+
+	info_str += std::string("GL_VENDOR      ") + ll_safe_string((const char *)glGetString(GL_VENDOR)) + std::string("\n");
+	info_str += std::string("GL_RENDERER    ") + ll_safe_string((const char *)glGetString(GL_RENDERER)) + std::string("\n");
+	info_str += std::string("GL_VERSION     ") + ll_safe_string((const char *)glGetString(GL_VERSION)) + std::string("\n");
+
+#if !LL_MESA_HEADLESS
+	all_exts = (const char *)gGLHExts.mSysExts;
+	LLStringUtil::replaceChar(all_exts, ' ', '\n');
+	info_str += std::string("GL_EXTENSIONS:\n") + all_exts + std::string("\n");
+#endif
+	
+	return info_str;
+}
+
+void LLGLManager::printGLInfoString()
+{
+	std::string info_str;
+	std::string all_exts, line;
+	
+	LL_INFOS("RenderInit") << "GL_VENDOR:     " << ((const char *)glGetString(GL_VENDOR)) << LL_ENDL;
+	LL_INFOS("RenderInit") << "GL_RENDERER:   " << ((const char *)glGetString(GL_RENDERER)) << LL_ENDL;
+	LL_INFOS("RenderInit") << "GL_VERSION:    " << ((const char *)glGetString(GL_VERSION)) << LL_ENDL;
+
+#if !LL_MESA_HEADLESS
+	all_exts = std::string(gGLHExts.mSysExts);
+	LLStringUtil::replaceChar(all_exts, ' ', '\n');
+	LL_DEBUGS("RenderInit") << "GL_EXTENSIONS:\n" << all_exts << LL_ENDL;
+#endif
+}
+
+std::string LLGLManager::getRawGLString()
+{
+	std::string gl_string;
+	gl_string = ll_safe_string((char*)glGetString(GL_VENDOR)) + " " + ll_safe_string((char*)glGetString(GL_RENDERER));
+	return gl_string;
+}
+
+void LLGLManager::shutdownGL()
+{
+	if (mInited)
+	{
+		glFinish();
+		stop_glerror();
+		mInited = FALSE;
+	}
+}
+
+// these are used to turn software blending on. They appear in the Debug/Avatar menu
+// presence of vertex skinning/blending or vertex programs will set these to FALSE by default.
+
+extern LLCPUInfo gSysCPU;
+
+void LLGLManager::initExtensions()
+{
+#if LL_MESA_HEADLESS
+# if GL_ARB_multitexture
+	mHasMultitexture = TRUE;
+# else
+	mHasMultitexture = FALSE;
+# endif
+# if GL_ARB_texture_env_combine
+	mHasARBEnvCombine = TRUE;	
+# else
+	mHasARBEnvCombine = FALSE;
+# endif
+# if GL_ARB_texture_compression
+	mHasCompressedTextures = TRUE;
+# else
+	mHasCompressedTextures = FALSE;
+# endif
+# if GL_ARB_vertex_buffer_object
+	mHasVertexBufferObject = TRUE;
+# else
+	mHasVertexBufferObject = FALSE;
+# endif
+# if GL_EXT_framebuffer_object
+	mHasFramebufferObject = TRUE;
+# else
+	mHasFramebufferObject = FALSE;
+# endif
+	mHasMipMapGeneration = FALSE;
+	mHasPalettedTextures = FALSE;
+	mHasSeparateSpecularColor = FALSE;
+	mHasAnisotropic = FALSE;
+	mHasCubeMap = FALSE;
+	mHasOcclusionQuery = FALSE;
+	mHasPointParameters = FALSE;
+	mHasShaderObjects = FALSE;
+	mHasVertexShader = FALSE;
+	mHasFragmentShader = FALSE;
+#else // LL_MESA_HEADLESS
+	mHasMultitexture = glh_init_extensions("GL_ARB_multitexture");
+	mHasMipMapGeneration = glh_init_extensions("GL_SGIS_generate_mipmap");
+	mHasPalettedTextures = glh_init_extension("GL_EXT_paletted_texture");
+	mHasSeparateSpecularColor = glh_init_extensions("GL_EXT_separate_specular_color");
+	mHasAnisotropic = glh_init_extensions("GL_EXT_texture_filter_anisotropic");
+	glh_init_extensions("GL_ARB_texture_cube_map");
+	mHasCubeMap = ExtensionExists("GL_ARB_texture_cube_map", gGLHExts.mSysExts);
+	mHasARBEnvCombine = ExtensionExists("GL_ARB_texture_env_combine", gGLHExts.mSysExts);
+	mHasCompressedTextures = glh_init_extensions("GL_ARB_texture_compression");
+	mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_query", gGLHExts.mSysExts);
+	mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", gGLHExts.mSysExts);
+	// mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad
+	mHasFramebufferObject = ExtensionExists("GL_EXT_framebuffer_object", gGLHExts.mSysExts)
+		&& ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts);
+#if !LL_DARWIN
+	mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
+#endif
+	mHasShaderObjects = ExtensionExists("GL_ARB_shader_objects", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts);
+	mHasVertexShader = ExtensionExists("GL_ARB_vertex_program", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_vertex_shader", gGLHExts.mSysExts)
+						&& ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts);
+	mHasFragmentShader = ExtensionExists("GL_ARB_fragment_shader", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts);
+#endif
+
+#if LL_LINUX
+	// Our extension support for the Linux Client is very young with some
+	// potential driver gotchas, so offer a semi-secret way to turn it off.
+	if (getenv("LL_GL_NOEXT"))	/* Flawfinder: ignore */
+	{
+		//mHasMultitexture = FALSE; // NEEDED!
+		mHasARBEnvCombine = FALSE;
+		mHasCompressedTextures = FALSE;
+		mHasVertexBufferObject = FALSE;
+		mHasFramebufferObject = FALSE;
+		mHasMipMapGeneration = FALSE;
+		mHasPalettedTextures = FALSE;
+		mHasSeparateSpecularColor = FALSE;
+		mHasAnisotropic = FALSE;
+		mHasCubeMap = FALSE;
+		mHasOcclusionQuery = FALSE;
+		mHasPointParameters = FALSE;
+		mHasShaderObjects = FALSE;
+		mHasVertexShader = FALSE;
+		mHasFragmentShader = FALSE;
+		LL_WARNS("RenderInit") << "GL extension support DISABLED via LL_GL_NOEXT" << LL_ENDL;
+	}
+	else if (getenv("LL_GL_BASICEXT"))	/* Flawfinder: ignore */
+	{
+		// This switch attempts to turn off all support for exotic
+		// extensions which I believe correspond to fatal driver
+		// bug reports.  This should be the default until we get a
+		// proper blacklist/whitelist on Linux.
+		mHasMipMapGeneration = FALSE;
+		mHasPalettedTextures = FALSE;
+		mHasAnisotropic = FALSE;
+		//mHasCubeMap = FALSE; // apparently fatal on Intel 915 & similar
+		//mHasOcclusionQuery = FALSE; // source of many ATI system hangs
+		mHasShaderObjects = FALSE;
+		mHasVertexShader = FALSE;
+		mHasFragmentShader = FALSE;
+		LL_WARNS("RenderInit") << "GL extension support forced to SIMPLE level via LL_GL_BASICEXT" << LL_ENDL;
+	}
+	if (getenv("LL_GL_BLACKLIST"))	/* Flawfinder: ignore */
+	{
+		// This lets advanced troubleshooters disable specific
+		// GL extensions to isolate problems with their hardware.
+		// SL-28126
+		const char *const blacklist = getenv("LL_GL_BLACKLIST");	/* Flawfinder: ignore */
+		LL_WARNS("RenderInit") << "GL extension support partially disabled via LL_GL_BLACKLIST: " << blacklist << LL_ENDL;
+		if (strchr(blacklist,'a')) mHasARBEnvCombine = FALSE;
+		if (strchr(blacklist,'b')) mHasCompressedTextures = FALSE;
+		if (strchr(blacklist,'c')) mHasVertexBufferObject = FALSE;
+		if (strchr(blacklist,'d')) mHasMipMapGeneration = FALSE;//S
+		if (strchr(blacklist,'e')) mHasPalettedTextures = FALSE;//S
+// 		if (strchr(blacklist,'f')) mHasNVVertexArrayRange = FALSE;//S
+// 		if (strchr(blacklist,'g')) mHasNVFence = FALSE;//S
+		if (strchr(blacklist,'h')) mHasSeparateSpecularColor = FALSE;
+		if (strchr(blacklist,'i')) mHasAnisotropic = FALSE;//S
+		if (strchr(blacklist,'j')) mHasCubeMap = FALSE;//S
+// 		if (strchr(blacklist,'k')) mHasATIVAO = FALSE;//S
+		if (strchr(blacklist,'l')) mHasOcclusionQuery = FALSE;
+		if (strchr(blacklist,'m')) mHasShaderObjects = FALSE;//S
+		if (strchr(blacklist,'n')) mHasVertexShader = FALSE;//S
+		if (strchr(blacklist,'o')) mHasFragmentShader = FALSE;//S
+		if (strchr(blacklist,'p')) mHasPointParameters = FALSE;//S
+		if (strchr(blacklist,'q')) mHasFramebufferObject = FALSE;//S
+	}
+#endif // LL_LINUX
+
+#if LL_DARWIN || LL_LINUX
+	// MBW -- 12/4/2003 -- Using paletted textures causes a bunch of avatar rendering problems on the Mac.
+	// Not sure if this is due to driver problems or incorrect use of the extension, but I'm disabling it for now.
+	// Tofu - 2006-10-03 -- Same problem on Linux.
+	mHasPalettedTextures = false;
+#endif
+	
+	if (!mHasMultitexture)
+	{
+		LL_INFOS("RenderInit") << "Couldn't initialize multitexturing" << LL_ENDL;
+	}
+	if (!mHasMipMapGeneration)
+	{
+		LL_INFOS("RenderInit") << "Couldn't initialize mipmap generation" << LL_ENDL;
+	}
+	if (!mHasARBEnvCombine)
+	{
+		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_texture_env_combine" << LL_ENDL;
+	}
+	if (!mHasPalettedTextures)
+	{
+		LL_INFOS("RenderInit") << "Couldn't initialize GL_EXT_paletted_texture" << LL_ENDL;
+	}
+	if (!mHasSeparateSpecularColor)
+	{
+		LL_INFOS("RenderInit") << "Couldn't initialize separate specular color" << LL_ENDL;
+	}
+	if (!mHasAnisotropic)
+	{
+		LL_INFOS("RenderInit") << "Couldn't initialize anisotropic filtering" << LL_ENDL;
+	}
+	if (!mHasCompressedTextures)
+	{
+		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_texture_compression" << LL_ENDL;
+	}
+	if (!mHasOcclusionQuery)
+	{
+		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_occlusion_query" << LL_ENDL;
+	}
+	if (!mHasPointParameters)
+	{
+		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_point_parameters" << LL_ENDL;
+	}
+	if (!mHasShaderObjects)
+	{
+		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_shader_objects" << LL_ENDL;
+	}
+	if (!mHasVertexShader)
+	{
+		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_vertex_shader" << LL_ENDL;
+	}
+	if (!mHasFragmentShader)
+	{
+		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_fragment_shader" << LL_ENDL;
+	}
+
+	// Disable certain things due to known bugs
+	if (mIsIntel && mHasMipMapGeneration)
+	{
+		LL_INFOS("RenderInit") << "Disabling mip-map generation for Intel GPUs" << LL_ENDL;
+		mHasMipMapGeneration = FALSE;
+	}
+	if (mIsATI && mHasMipMapGeneration)
+	{
+		LL_INFOS("RenderInit") << "Disabling mip-map generation for ATI GPUs (performance opt)" << LL_ENDL;
+		mHasMipMapGeneration = FALSE;
+	}
+	
+	// Misc
+	glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, (GLint*) &mGLMaxVertexRange);
+	glGetIntegerv(GL_MAX_ELEMENTS_INDICES, (GLint*) &mGLMaxIndexRange);
+	
+#if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS
+	LL_DEBUGS("RenderInit") << "GL Probe: Getting symbols" << LL_ENDL;
+	if (mHasVertexBufferObject)
+	{
+		glBindBufferARB = (PFNGLBINDBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBindBufferARB");
+		if (glBindBufferARB)
+		{
+			glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteBuffersARB");
+			glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGenBuffersARB");
+			glIsBufferARB = (PFNGLISBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glIsBufferARB");
+			glBufferDataARB = (PFNGLBUFFERDATAARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBufferDataARB");
+			glBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBufferSubDataARB");
+			glGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetBufferSubDataARB");
+			glMapBufferARB = (PFNGLMAPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMapBufferARB");
+			glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glUnmapBufferARB");
+			glGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetBufferParameterivARB");
+			glGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetBufferPointervARB");
+		}
+		else
+		{
+			mHasVertexBufferObject = FALSE;
+		}
+	}
+	if (mHasFramebufferObject)
+	{
+		glIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glIsRenderbufferEXT");
+		glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBindRenderbufferEXT");
+		glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteRenderbuffersEXT");
+		glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenRenderbuffersEXT");
+		glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glRenderbufferStorageEXT");
+		glGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGetRenderbufferParameterivEXT");
+		glIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glIsFramebufferEXT");
+		glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBindFramebufferEXT");
+		glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteFramebuffersEXT");
+		glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenFramebuffersEXT");
+		glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glCheckFramebufferStatusEXT");
+		glFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture1DEXT");
+		glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture2DEXT");
+		glFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferTexture3DEXT");
+		glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) GLH_EXT_GET_PROC_ADDRESS("glFramebufferRenderbufferEXT");
+		glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGetFramebufferAttachmentParameterivEXT");
+		glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glGenerateMipmapEXT");
+	}
+#if !LL_LINUX
+	// This is expected to be a static symbol on Linux GL implementations
+	glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements");
+	if (!glDrawRangeElements)
+	{
+		mGLMaxVertexRange = 0;
+		mGLMaxIndexRange = 0;
+	}
+#endif // !LL_LINUX
+#if LL_LINUX
+	// On Linux we need to get glColorTableEXT dynamically.
+	if (mHasPalettedTextures)
+	{
+		glColorTableEXT = (PFNGLCOLORTABLEEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTableEXT");
+	}
+#endif // LL_LINUX
+	if (mHasOcclusionQuery)
+	{
+		glGenQueriesARB = (PFNGLGENQUERIESARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGenQueriesARB");
+		glDeleteQueriesARB = (PFNGLDELETEQUERIESARBPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteQueriesARB");
+		glIsQueryARB = (PFNGLISQUERYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glIsQueryARB");
+		glBeginQueryARB = (PFNGLBEGINQUERYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBeginQueryARB");
+		glEndQueryARB = (PFNGLENDQUERYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glEndQueryARB");
+		glGetQueryivARB = (PFNGLGETQUERYIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetQueryivARB");
+		glGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjectivARB");
+		glGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjectuivARB");
+	}
+	if (mHasPointParameters)
+	{
+		glPointParameterfARB = (PFNGLPOINTPARAMETERFARBPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfARB");
+		glPointParameterfvARB = (PFNGLPOINTPARAMETERFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfvARB");
+	}
+	if (mHasShaderObjects)
+	{
+		glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteObjectARB");
+		glGetHandleARB = (PFNGLGETHANDLEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetHandleARB");
+		glDetachObjectARB = (PFNGLDETACHOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDetachObjectARB");
+		glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCreateShaderObjectARB");
+		glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glShaderSourceARB");
+		glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCompileShaderARB");
+		glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCreateProgramObjectARB");
+		glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glAttachObjectARB");
+		glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glLinkProgramARB");
+		glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUseProgramObjectARB");
+		glValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glValidateProgramARB");
+		glUniform1fARB = (PFNGLUNIFORM1FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1fARB");
+		glUniform2fARB = (PFNGLUNIFORM2FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2fARB");
+		glUniform3fARB = (PFNGLUNIFORM3FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3fARB");
+		glUniform4fARB = (PFNGLUNIFORM4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4fARB");
+		glUniform1iARB = (PFNGLUNIFORM1IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1iARB");
+		glUniform2iARB = (PFNGLUNIFORM2IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2iARB");
+		glUniform3iARB = (PFNGLUNIFORM3IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3iARB");
+		glUniform4iARB = (PFNGLUNIFORM4IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4iARB");
+		glUniform1fvARB = (PFNGLUNIFORM1FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1fvARB");
+		glUniform2fvARB = (PFNGLUNIFORM2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2fvARB");
+		glUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3fvARB");
+		glUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4fvARB");
+		glUniform1ivARB = (PFNGLUNIFORM1IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1ivARB");
+		glUniform2ivARB = (PFNGLUNIFORM2IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2ivARB");
+		glUniform3ivARB = (PFNGLUNIFORM3IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3ivARB");
+		glUniform4ivARB = (PFNGLUNIFORM4IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4ivARB");
+		glUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix2fvARB");
+		glUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix3fvARB");
+		glUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix4fvARB");
+		glGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetObjectParameterfvARB");
+		glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetObjectParameterivARB");
+		glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetInfoLogARB");
+		glGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetAttachedObjectsARB");
+		glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformLocationARB");
+		glGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetActiveUniformARB");
+		glGetUniformfvARB = (PFNGLGETUNIFORMFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformfvARB");
+		glGetUniformivARB = (PFNGLGETUNIFORMIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformivARB");
+		glGetShaderSourceARB = (PFNGLGETSHADERSOURCEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetShaderSourceARB");
+	}
+	if (mHasVertexShader)
+	{
+		glGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetAttribLocationARB");
+		glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glBindAttribLocationARB");
+		glGetActiveAttribARB = (PFNGLGETACTIVEATTRIBARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetActiveAttribARB");
+		glVertexAttrib1dARB = (PFNGLVERTEXATTRIB1DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dARB");
+		glVertexAttrib1dvARB = (PFNGLVERTEXATTRIB1DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dvARB");
+		glVertexAttrib1fARB = (PFNGLVERTEXATTRIB1FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fARB");
+		glVertexAttrib1fvARB = (PFNGLVERTEXATTRIB1FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fvARB");
+		glVertexAttrib1sARB = (PFNGLVERTEXATTRIB1SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1sARB");
+		glVertexAttrib1svARB = (PFNGLVERTEXATTRIB1SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1svARB");
+		glVertexAttrib2dARB = (PFNGLVERTEXATTRIB2DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dARB");
+		glVertexAttrib2dvARB = (PFNGLVERTEXATTRIB2DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dvARB");
+		glVertexAttrib2fARB = (PFNGLVERTEXATTRIB2FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fARB");
+		glVertexAttrib2fvARB = (PFNGLVERTEXATTRIB2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fvARB");
+		glVertexAttrib2sARB = (PFNGLVERTEXATTRIB2SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2sARB");
+		glVertexAttrib2svARB = (PFNGLVERTEXATTRIB2SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2svARB");
+		glVertexAttrib3dARB = (PFNGLVERTEXATTRIB3DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dARB");
+		glVertexAttrib3dvARB = (PFNGLVERTEXATTRIB3DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dvARB");
+		glVertexAttrib3fARB = (PFNGLVERTEXATTRIB3FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fARB");
+		glVertexAttrib3fvARB = (PFNGLVERTEXATTRIB3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fvARB");
+		glVertexAttrib3sARB = (PFNGLVERTEXATTRIB3SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3sARB");
+		glVertexAttrib3svARB = (PFNGLVERTEXATTRIB3SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3svARB");
+		glVertexAttrib4nbvARB = (PFNGLVERTEXATTRIB4NBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nbvARB");
+		glVertexAttrib4nivARB = (PFNGLVERTEXATTRIB4NIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nivARB");
+		glVertexAttrib4nsvARB = (PFNGLVERTEXATTRIB4NSVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nsvARB");
+		glVertexAttrib4nubARB = (PFNGLVERTEXATTRIB4NUBARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nubARB");
+		glVertexAttrib4nubvARB = (PFNGLVERTEXATTRIB4NUBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nubvARB");
+		glVertexAttrib4nuivARB = (PFNGLVERTEXATTRIB4NUIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nuivARB");
+		glVertexAttrib4nusvARB = (PFNGLVERTEXATTRIB4NUSVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nusvARB");
+		glVertexAttrib4bvARB = (PFNGLVERTEXATTRIB4BVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4bvARB");
+		glVertexAttrib4dARB = (PFNGLVERTEXATTRIB4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dARB");
+		glVertexAttrib4dvARB = (PFNGLVERTEXATTRIB4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dvARB");
+		glVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fARB");
+		glVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fvARB");
+		glVertexAttrib4ivARB = (PFNGLVERTEXATTRIB4IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ivARB");
+		glVertexAttrib4sARB = (PFNGLVERTEXATTRIB4SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4sARB");
+		glVertexAttrib4svARB = (PFNGLVERTEXATTRIB4SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4svARB");
+		glVertexAttrib4ubvARB = (PFNGLVERTEXATTRIB4UBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ubvARB");
+		glVertexAttrib4uivARB = (PFNGLVERTEXATTRIB4UIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4uivARB");
+		glVertexAttrib4usvARB = (PFNGLVERTEXATTRIB4USVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4usvARB");
+		glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttribPointerARB");
+		glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) GLH_EXT_GET_PROC_ADDRESS("glEnableVertexAttribArrayARB");
+		glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDisableVertexAttribArrayARB");
+		glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramStringARB");
+		glBindProgramARB = (PFNGLBINDPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glBindProgramARB");
+		glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteProgramsARB");
+		glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGenProgramsARB");
+		glProgramEnvParameter4dARB = (PFNGLPROGRAMENVPARAMETER4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dARB");
+		glProgramEnvParameter4dvARB = (PFNGLPROGRAMENVPARAMETER4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dvARB");
+		glProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fARB");
+		glProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fvARB");
+		glProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dARB");
+		glProgramLocalParameter4dvARB = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dvARB");
+		glProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fARB");
+		glProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fvARB");
+		glGetProgramEnvParameterdvARB = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterdvARB");
+		glGetProgramEnvParameterfvARB = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterfvARB");
+		glGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterdvARB");
+		glGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterfvARB");
+		glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramivARB");
+		glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramStringARB");
+		glGetVertexAttribdvARB = (PFNGLGETVERTEXATTRIBDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribdvARB");
+		glGetVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribfvARB");
+		glGetVertexAttribivARB = (PFNGLGETVERTEXATTRIBIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribivARB");
+		glGetVertexAttribPointervARB = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glgetVertexAttribPointervARB");
+		glIsProgramARB = (PFNGLISPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glIsProgramARB");
+	}
+	LL_DEBUGS("RenderInit") << "GL Probe: Got symbols" << LL_ENDL;
+#endif
+
+	mInited = TRUE;
+}
+
+void rotate_quat(LLQuaternion& rotation)
+{
+	F32 angle_radians, x, y, z;
+	rotation.getAngleAxis(&angle_radians, &x, &y, &z);
+	glRotatef(angle_radians * RAD_TO_DEG, x, y, z);
+}
+
+void flush_glerror()
+{
+	glGetError();
+}
+
+void assert_glerror()
+{
+	if (gNoRender || !gDebugGL) 
+	{
+		return;
+	}
+	if (!gGLManager.mInited)
+	{
+		LL_ERRS("RenderInit") << "GL not initialized" << LL_ENDL;
+	}
+	//  Create or update texture to be used with this data 
+	GLenum error;
+	error = glGetError();
+	BOOL quit = FALSE;
+	while (error)
+	{
+		quit = TRUE;
+#ifndef LL_LINUX // *FIX: !  This should be an error for linux as well.
+		GLubyte const * gl_error_msg = gluErrorString(error);
+		if (NULL != gl_error_msg)
+		{
+			LL_WARNS("RenderState") << "GL Error:" << gl_error_msg << LL_ENDL;
+		}
+		else
+		{
+			// gluErrorString returns NULL for some extensions' error codes.
+			// you'll probably have to grep for the number in glext.h.
+			LL_WARNS("RenderState") << "GL Error: UNKNOWN 0x" << std::hex << error << LL_ENDL;
+		}
+		error = glGetError();
+#endif
+	}
+
+	if (quit)
+	{
+		llerrs << "One or more unhandled GL errors." << llendl;
+	}
+}
+
+void clear_glerror()
+{
+	//  Create or update texture to be used with this data 
+	GLenum error;
+	error = glGetError();
+}
+
+///////////////////////////////////////////////////////////////
+//
+// LLGLState
+//
+
+// Static members
+std::map<LLGLenum, LLGLboolean> LLGLState::sStateMap;
+
+GLboolean LLGLDepthTest::sDepthEnabled = GL_FALSE; // OpenGL default
+GLenum LLGLDepthTest::sDepthFunc = GL_LESS; // OpenGL default
+GLboolean LLGLDepthTest::sWriteEnabled = GL_TRUE; // OpenGL default
+
+//static
+void LLGLState::initClass() 
+{
+	sStateMap[GL_DITHER] = GL_TRUE;
+	sStateMap[GL_TEXTURE_2D] = GL_TRUE;
+}
+
+//static
+void LLGLState::restoreGL()
+{
+	sStateMap.clear();
+	initClass();
+}
+
+//static
+// Really shouldn't be needed, but seems we sometimes do.
+void LLGLState::resetTextureStates()
+{
+	gGL.flush();
+	GLint maxTextureUnits;
+	
+	glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxTextureUnits);
+	for (S32 j = maxTextureUnits-1; j >=0; j--)
+	{
+		gGL.getTexUnit(j)->activate();
+		glClientActiveTextureARB(GL_TEXTURE0_ARB+j);
+		j == 0 ? glEnable(GL_TEXTURE_2D) : glDisable(GL_TEXTURE_2D);
+	}
+}
+
+void LLGLState::dumpStates() 
+{
+	LL_INFOS("RenderState") << "GL States:" << LL_ENDL;
+	for (std::map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin();
+		 iter != sStateMap.end(); ++iter)
+	{
+		LL_INFOS("RenderState") << llformat(" 0x%04x : %s",(S32)iter->first,iter->second?"TRUE":"FALSE") << LL_ENDL;
+	}
+}
+
+void LLGLState::checkStates()  
+{
+	if (!gDebugGL)
+	{
+		return;
+	}
+
+	stop_glerror();
+
+	GLint activeTexture;
+	glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &activeTexture);
+	
+	if (activeTexture != GL_TEXTURE0_ARB)
+	{
+		LL_GL_ERRS << "Texture channel corrupted. " << LL_ENDL;
+	}
+	
+	GLint src;
+	GLint dst;
+	glGetIntegerv(GL_BLEND_SRC, &src);
+	glGetIntegerv(GL_BLEND_DST, &dst);
+	
+	if (src != GL_SRC_ALPHA || dst != GL_ONE_MINUS_SRC_ALPHA)
+	{
+		LL_GL_ERRS << "Blend function corrupted: " << std::hex << src << " " << std::hex << dst << LL_ENDL;
+	}
+	
+	for (std::map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin();
+		 iter != sStateMap.end(); ++iter)
+	{
+		LLGLenum state = iter->first;
+		LLGLboolean cur_state = iter->second;
+		LLGLboolean gl_state = glIsEnabled(state);
+		if(cur_state != gl_state)
+		{
+			dumpStates();
+			LL_GL_ERRS << llformat("LLGLState error. State: 0x%04x",state) << LL_ENDL;
+		}
+	}
+	
+	stop_glerror();
+}
+
+void LLGLState::checkTextureChannels()
+{
+	if (!gDebugGL)
+	{
+		return;
+	}
+
+	GLint activeTexture;
+	glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &activeTexture);
+	
+	BOOL error = FALSE;
+
+	if (activeTexture != GL_TEXTURE0_ARB)
+	{
+		error = TRUE;
+ 		LL_WARNS("RenderState") << "Active texture channel corrupted. " << LL_ENDL;
+	}
+	else if (!glIsEnabled(GL_TEXTURE_2D))
+	{
+		error = TRUE;
+		LL_WARNS("RenderState") << "GL_TEXTURE_2D not enabled on texture channel 0." << LL_ENDL;
+	}
+	else 
+	{
+		GLint tex_env_mode = 0;
+
+		glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &tex_env_mode);
+		if (tex_env_mode != GL_MODULATE)
+		{
+			error = TRUE;
+			LL_WARNS("RenderState") << "GL_TEXTURE_ENV_MODE invalid: " << std::hex << tex_env_mode << LL_ENDL;
+		}
+	}
+
+	GLint maxTextureUnits;
+	glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxTextureUnits);
+
+	static const char* label[] =
+	{
+		"GL_TEXTURE_2D",
+		"GL_TEXTURE_COORD_ARRAY",
+		"GL_TEXTURE_1D",
+		"GL_TEXTURE_CUBE_MAP_ARB",
+		"GL_TEXTURE_GEN_S",
+		"GL_TEXTURE_GEN_T",
+		"GL_TEXTURE_GEN_Q",
+		"GL_TEXTURE_GEN_R"
+	};
+
+	static GLint value[] =
+	{
+		GL_TEXTURE_2D,
+		GL_TEXTURE_COORD_ARRAY,
+		GL_TEXTURE_1D,
+		GL_TEXTURE_CUBE_MAP_ARB,
+		GL_TEXTURE_GEN_S,
+		GL_TEXTURE_GEN_T,
+		GL_TEXTURE_GEN_Q,
+		GL_TEXTURE_GEN_R
+	};
+
+	GLint stackDepth = 0;
+	LLMatrix4 identity;
+	LLMatrix4 matrix;
+
+	for (GLint i = 0; i < maxTextureUnits; i++)
+	{
+		gGL.getTexUnit(i)->activate();
+		glClientActiveTextureARB(GL_TEXTURE0_ARB+i);
+
+		glGetIntegerv(GL_TEXTURE_STACK_DEPTH, &stackDepth);
+
+		if (stackDepth != 1)
+		{
+			error = TRUE;
+			LL_WARNS("RenderState") << "Texture matrix stack corrupted." << LL_ENDL;
+		}
+
+		glGetFloatv(GL_TEXTURE_MATRIX, (GLfloat*) matrix.mMatrix);
+
+		if (matrix != identity)
+		{
+			error = TRUE;
+			LL_WARNS("RenderState") << "Texture matrix in channel " << i << " corrupt." << LL_ENDL;
+		}
+
+		for (S32 j = (i == 0 ? 1 : 0); j < 8; j++)
+		{
+			if (glIsEnabled(value[j]))
+			{
+				error = TRUE;
+				LL_WARNS("RenderState") << "Texture channel " << i << " still has " << label[j] << " enabled." << LL_ENDL;
+			}
+		}
+	}
+
+	gGL.getTexUnit(0)->activate();
+	glClientActiveTextureARB(GL_TEXTURE0_ARB);
+
+	if (error)
+	{
+		LL_GL_ERRS << "GL texture state corruption detected." << LL_ENDL;
+	}
+}
+
+void LLGLState::checkClientArrays(U32 data_mask)
+{
+	if (!gDebugGL)
+	{
+		return;
+	}
+
+	stop_glerror();
+	BOOL error = FALSE;
+
+	GLint active_texture;
+	glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE_ARB, &active_texture);
+
+	if (active_texture != GL_TEXTURE0_ARB)
+	{
+		llwarns << "Client active texture corrupted: " << active_texture << llendl;
+		error = TRUE;
+	}
+
+	glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &active_texture);
+	if (active_texture != GL_TEXTURE0_ARB)
+	{
+		llwarns << "Active texture corrupted: " << active_texture << llendl;
+		error = TRUE;
+	}
+
+	static const char* label[] =
+	{
+		"GL_VERTEX_ARRAY",
+		"GL_NORMAL_ARRAY",
+		"GL_COLOR_ARRAY",
+		"GL_TEXTURE_COORD_ARRAY"
+	};
+
+	static GLint value[] =
+	{
+		GL_VERTEX_ARRAY,
+		GL_NORMAL_ARRAY,
+		GL_COLOR_ARRAY,
+		GL_TEXTURE_COORD_ARRAY
+	};
+
+	 U32 mask[] = 
+	{ //copied from llvertexbuffer.h
+		0x0001, //MAP_VERTEX,
+		0x0002, //MAP_NORMAL,
+		0x0010, //MAP_COLOR,
+		0x0004, //MAP_TEXCOORD
+	};
+
+
+	for (S32 j = 0; j < 4; j++)
+	{
+		if (glIsEnabled(value[j]))
+		{
+			if (!(mask[j] & data_mask))
+			{
+				error = TRUE;
+				LL_WARNS("RenderState") << "GL still has " << label[j] << " enabled." << LL_ENDL;
+			}
+		}
+		else
+		{
+			if (mask[j] & data_mask)
+			{
+				error = TRUE;
+				LL_WARNS("RenderState") << "GL does not have " << label[j] << " enabled." << LL_ENDL;
+			}
+		}
+	}
+
+	glClientActiveTextureARB(GL_TEXTURE1_ARB);
+	gGL.getTexUnit(1)->activate();
+	if (glIsEnabled(GL_TEXTURE_COORD_ARRAY))
+	{
+		if (!(data_mask & 0x0008))
+		{
+			error = TRUE;
+			LL_WARNS("RenderState") << "GL still has GL_TEXTURE_COORD_ARRAY enabled on channel 1." << LL_ENDL;
+		}
+	}
+	else
+	{
+		if (data_mask & 0x0008)
+		{
+			error = TRUE;
+			LL_WARNS("RenderState") << "GL does not have GL_TEXTURE_COORD_ARRAY enabled on channel 1." << LL_ENDL;
+		}
+	}
+
+	if (glIsEnabled(GL_TEXTURE_2D))
+	{
+		if (!(data_mask & 0x0008))
+		{
+			error = TRUE;
+			LL_WARNS("RenderState") << "GL still has GL_TEXTURE_2D enabled on channel 1." << LL_ENDL;
+		}
+	}
+	else
+	{
+		if (data_mask & 0x0008)
+		{
+			error = TRUE;
+			LL_WARNS("RenderState") << "GL does not have GL_TEXTURE_2D enabled on channel 1." << LL_ENDL;
+		}
+	}
+
+	glClientActiveTextureARB(GL_TEXTURE0_ARB);
+	gGL.getTexUnit(0)->activate();
+
+	if (error)
+	{
+		LL_GL_ERRS << "GL client array corruption detected." << LL_ENDL;
+	}
+}
+
+///////////////////////////////////////////////////////////////////////
+
+LLGLState::LLGLState(LLGLenum state, S32 enabled) :
+	mState(state), mWasEnabled(FALSE), mIsEnabled(FALSE)
+{
+	stop_glerror();
+	if (state)
+	{
+		mWasEnabled = sStateMap[state];
+		llassert(mWasEnabled == glIsEnabled(state));
+		setEnabled(enabled);
+		stop_glerror();
+	}
+}
+
+void LLGLState::setEnabled(S32 enabled)
+{
+	if (!mState)
+	{
+		return;
+	}
+	if (enabled == CURRENT_STATE)
+	{
+		enabled = sStateMap[mState] == GL_TRUE ? TRUE : FALSE;
+	}
+	else if (enabled == TRUE && sStateMap[mState] != GL_TRUE)
+	{
+		gGL.flush();
+		glEnable(mState);
+		sStateMap[mState] = GL_TRUE;
+	}
+	else if (enabled == FALSE && sStateMap[mState] != GL_FALSE)
+	{
+		gGL.flush();
+		glDisable(mState);
+		sStateMap[mState] = GL_FALSE;
+	}
+	mIsEnabled = enabled;
+}
+
+LLGLState::~LLGLState() 
+{
+	stop_glerror();
+	if (mState)
+	{
+		if (gDebugGL)
+		{
+			llassert_always(sStateMap[mState] == glIsEnabled(mState));
+		}
+
+		if (mIsEnabled != mWasEnabled)
+		{
+			gGL.flush();
+			if (mWasEnabled)
+			{
+				glEnable(mState);
+				sStateMap[mState] = GL_TRUE;
+			}
+			else
+			{
+				glDisable(mState);
+				sStateMap[mState] = GL_FALSE;
+			}
+		}
+	}
+	stop_glerror();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void LLGLManager::initGLStates()
+{
+	//gl states moved to classes in llglstates.h
+	LLGLState::initClass();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void enable_vertex_weighting(const S32 index)
+{
+#if GL_ARB_vertex_program
+	if (index > 0) glEnableVertexAttribArrayARB(index);	// vertex weights
+#endif
+}
+
+void disable_vertex_weighting(const S32 index)
+{
+#if GL_ARB_vertex_program
+	if (index > 0) glDisableVertexAttribArrayARB(index);	// vertex weights
+#endif
+}
+
+void enable_binormals(const S32 index)
+{
+#if GL_ARB_vertex_program
+	if (index > 0)
+	{
+		glEnableVertexAttribArrayARB(index);	// binormals
+	}
+#endif
+}
+
+void disable_binormals(const S32 index)
+{
+#if GL_ARB_vertex_program
+	if (index > 0)
+	{
+		glDisableVertexAttribArrayARB(index);	// binormals
+	}
+#endif
+}
+
+
+void enable_cloth_weights(const S32 index)
+{
+#if GL_ARB_vertex_program
+	if (index > 0)	glEnableVertexAttribArrayARB(index);
+#endif
+}
+
+void disable_cloth_weights(const S32 index)
+{
+#if GL_ARB_vertex_program
+	if (index > 0) glDisableVertexAttribArrayARB(index);
+#endif
+}
+
+void set_vertex_weights(const S32 index, const U32 stride, const F32 *weights)
+{
+#if GL_ARB_vertex_program
+	if (index > 0) glVertexAttribPointerARB(index, 1, GL_FLOAT, FALSE, stride, weights);
+	stop_glerror();
+#endif
+}
+
+void set_vertex_clothing_weights(const S32 index, const U32 stride, const LLVector4 *weights)
+{
+#if GL_ARB_vertex_program
+	if (index > 0) glVertexAttribPointerARB(index, 4, GL_FLOAT, TRUE, stride, weights);
+	stop_glerror();
+#endif
+}
+
+void set_binormals(const S32 index, const U32 stride,const LLVector3 *binormals)
+{
+#if GL_ARB_vertex_program
+	if (index > 0) glVertexAttribPointerARB(index, 3, GL_FLOAT, FALSE, stride, binormals);
+	stop_glerror();
+#endif
+}
+
+
+void set_palette(U8 *palette_data)
+{
+	if (gGLManager.mHasPalettedTextures)
+	{
+		glColorTableEXT(GL_TEXTURE_2D, GL_RGBA8, 256, GL_RGBA, GL_UNSIGNED_BYTE, palette_data);
+	}
+}
+
+
+void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific )
+{
+	// GL_VERSION returns a null-terminated string with the format: 
+	// <major>.<minor>[.<release>] [<vendor specific>]
+
+	const char* version = (const char*) glGetString(GL_VERSION);
+	*major = 0;
+	*minor = 0;
+	*release = 0;
+	vendor_specific->assign("");
+
+	if( !version )
+	{
+		return;
+	}
+
+	std::string ver_copy( version );
+	S32 len = (S32)strlen( version );	/* Flawfinder: ignore */
+	S32 i = 0;
+	S32 start;
+	// Find the major version
+	start = i;
+	for( ; i < len; i++ )
+	{
+		if( '.' == version[i] )
+		{
+			break;
+		}
+	}
+	std::string major_str = ver_copy.substr(start,i-start);
+	LLStringUtil::convertToS32(major_str, *major);
+
+	if( '.' == version[i] )
+	{
+		i++;
+	}
+
+	// Find the minor version
+	start = i;
+	for( ; i < len; i++ )
+	{
+		if( ('.' == version[i]) || isspace(version[i]) )
+		{
+			break;
+		}
+	}
+	std::string minor_str = ver_copy.substr(start,i-start);
+	LLStringUtil::convertToS32(minor_str, *minor);
+
+	// Find the release number (optional)
+	if( '.' == version[i] )
+	{
+		i++;
+
+		start = i;
+		for( ; i < len; i++ )
+		{
+			if( isspace(version[i]) )
+			{
+				break;
+			}
+		}
+
+		std::string release_str = ver_copy.substr(start,i-start);
+		LLStringUtil::convertToS32(release_str, *release);
+	}
+
+	// Skip over any white space
+	while( version[i] && isspace( version[i] ) )
+	{
+		i++;
+	}
+
+	// Copy the vendor-specific string (optional)
+	if( version[i] )
+	{
+		vendor_specific->assign( version + i );
+	}
+}
+
+LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const glh::matrix4f& modelview, const glh::matrix4f& projection)
+{
+	mModelview = modelview;
+	mProjection = projection;
+
+	setPlane(p.mV[0], p.mV[1], p.mV[2], p.mV[3]);
+}
+
+void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d)
+{
+	glh::matrix4f& P = mProjection;
+	glh::matrix4f& M = mModelview;
+    
+	glh::matrix4f invtrans_MVP = (P * M).inverse().transpose();
+    glh::vec4f oplane(a,b,c,d);
+    glh::vec4f cplane;
+    invtrans_MVP.mult_matrix_vec(oplane, cplane);
+
+    cplane /= fabs(cplane[2]); // normalize such that depth is not scaled
+    cplane[3] -= 1;
+
+    if(cplane[2] < 0)
+        cplane *= -1;
+
+    glh::matrix4f suffix;
+    suffix.set_row(2, cplane);
+    glh::matrix4f newP = suffix * P;
+    glMatrixMode(GL_PROJECTION);
+	glPushMatrix();
+    glLoadMatrixf(newP.m);
+	gGLObliqueProjectionInverse = LLMatrix4(newP.inverse().transpose().m);
+    glMatrixMode(GL_MODELVIEW);
+}
+
+LLGLUserClipPlane::~LLGLUserClipPlane()
+{
+	glMatrixMode(GL_PROJECTION);
+	glPopMatrix();
+	glMatrixMode(GL_MODELVIEW);
+}
+
+LLGLNamePool::LLGLNamePool()
+{
+}
+
+void LLGLNamePool::registerPool(LLGLNamePool* pool)
+{
+	pool_list_t::iterator iter = std::find(sInstances.begin(), sInstances.end(), pool);
+	if (iter == sInstances.end())
+	{
+		sInstances.push_back(pool);
+	}
+}
+
+LLGLNamePool::~LLGLNamePool()
+{
+	pool_list_t::iterator iter = std::find(sInstances.begin(), sInstances.end(), this);
+	if (iter != sInstances.end())
+	{
+		sInstances.erase(iter);
+	}
+}
+
+void LLGLNamePool::upkeep()
+{
+	std::sort(mNameList.begin(), mNameList.end(), CompareUsed());
+}
+
+void LLGLNamePool::cleanup()
+{
+	for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter)
+	{
+		releaseName(iter->name);
+	}
+
+	mNameList.clear();
+}
+
+GLuint LLGLNamePool::allocate()
+{
+	for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter)
+	{
+		if (!iter->used)
+		{
+			iter->used = TRUE;
+			return iter->name;
+		}
+	}
+
+	NameEntry entry;
+	entry.name = allocateName();
+	entry.used = TRUE;
+	mNameList.push_back(entry);
+
+	return entry.name;
+}
+
+void LLGLNamePool::release(GLuint name)
+{
+	for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter)
+	{
+		if (iter->name == name)
+		{
+			iter->used = FALSE;
+			return;
+		}
+	}
+}
+
+//static
+void LLGLNamePool::upkeepPools()
+{
+	for (pool_list_t::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
+	{
+		LLGLNamePool* pool = *iter;
+		pool->upkeep();
+	}
+}
+
+//static
+void LLGLNamePool::cleanupPools()
+{
+	for (pool_list_t::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
+	{
+		LLGLNamePool* pool = *iter;
+		pool->cleanup();
+	}
+}
+
+LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, GLenum depth_func)
+: mPrevDepthEnabled(sDepthEnabled), mPrevDepthFunc(sDepthFunc), mPrevWriteEnabled(sWriteEnabled)
+{
+	if (depth_enabled != sDepthEnabled)
+	{
+		gGL.flush();
+		if (depth_enabled) glEnable(GL_DEPTH_TEST);
+		else glDisable(GL_DEPTH_TEST);
+		sDepthEnabled = depth_enabled;
+	}
+	if (depth_func != sDepthFunc)
+	{
+		gGL.flush();
+		glDepthFunc(depth_func);
+		sDepthFunc = depth_func;
+	}
+	if (write_enabled != sWriteEnabled)
+	{
+		gGL.flush();
+		glDepthMask(write_enabled);
+		sWriteEnabled = write_enabled;
+	}
+}
+
+LLGLDepthTest::~LLGLDepthTest()
+{
+	if (sDepthEnabled != mPrevDepthEnabled )
+	{
+		gGL.flush();
+		if (mPrevDepthEnabled) glEnable(GL_DEPTH_TEST);
+		else glDisable(GL_DEPTH_TEST);
+		sDepthEnabled = mPrevDepthEnabled;
+	}
+	if (sDepthFunc != mPrevDepthFunc)
+	{
+		gGL.flush();
+		glDepthFunc(mPrevDepthFunc);
+		sDepthFunc = mPrevDepthFunc;
+	}
+	if (sWriteEnabled != mPrevWriteEnabled )
+	{
+		gGL.flush();
+		glDepthMask(mPrevWriteEnabled);
+		sWriteEnabled = mPrevWriteEnabled;
+	}
+}
+
+LLGLClampToFarClip::LLGLClampToFarClip(glh::matrix4f P)
+{
+	for (U32 i = 0; i < 4; i++)
+	{
+		P.element(2, i) = P.element(3, i) * 0.99999f;
+	}
+
+	glMatrixMode(GL_PROJECTION);
+	glPushMatrix();
+	glLoadMatrixf(P.m);
+	glMatrixMode(GL_MODELVIEW);
+}
+
+LLGLClampToFarClip::~LLGLClampToFarClip()
+{
+	glMatrixMode(GL_PROJECTION);
+	glPopMatrix();
+	glMatrixMode(GL_MODELVIEW);
+}
+
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
new file mode 100644
index 00000000000..e9b4c7929e5
--- /dev/null
+++ b/indra/llrender/llgl.h
@@ -0,0 +1,377 @@
+/** 
+ * @file llgl.h
+ * @brief LLGL definition
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLGL_H
+#define LL_LLGL_H
+
+// This file contains various stuff for handling gl extensions and other gl related stuff.
+
+#include <string>
+#include <map>
+
+#include "llerror.h"
+#include "v4color.h"
+#include "llstring.h"
+#include "stdtypes.h"
+#include "v4math.h"
+#include "llplane.h"
+#include "llgltypes.h"
+
+#include "llglheaders.h"
+#include "glh/glh_linear.h"
+
+extern BOOL gDebugGL;
+
+#define LL_GL_ERRS LL_ERRS("RenderState")
+
+class LLSD;
+
+// Manage GL extensions...
+class LLGLManager
+{
+public:
+	LLGLManager();
+
+	bool initGL();
+	void shutdownGL();
+
+	void initWGL(); // Initializes stupid WGL extensions
+
+	std::string getRawGLString(); // For sending to simulator
+
+	BOOL mInited;
+	BOOL mIsDisabled;
+
+	// Extensions used by everyone
+	BOOL mHasMultitexture;
+	S32	 mNumTextureUnits;
+	BOOL mHasMipMapGeneration;
+	BOOL mHasPalettedTextures;
+	BOOL mHasCompressedTextures;
+	BOOL mHasFramebufferObject;
+
+	// ARB Extensions
+	BOOL mHasVertexBufferObject;
+	BOOL mHasPBuffer;
+	BOOL mHasShaderObjects;
+	BOOL mHasVertexShader;
+	BOOL mHasFragmentShader;
+	BOOL mHasOcclusionQuery;
+	BOOL mHasPointParameters;
+
+	// Other extensions.
+	BOOL mHasAnisotropic;
+	BOOL mHasARBEnvCombine;
+	BOOL mHasCubeMap;
+
+	// Vendor-specific extensions
+	BOOL mIsATI;
+	BOOL mIsNVIDIA;
+	BOOL mIsIntel;
+	BOOL mIsGF2or4MX;
+	BOOL mIsGF3;
+	BOOL mIsGFFX;
+	BOOL mATIOffsetVerticalLines;
+
+	// Whether this version of GL is good enough for SL to use
+	BOOL mHasRequirements;
+
+	// Misc extensions
+	BOOL mHasSeparateSpecularColor;
+	
+	S32 mDriverVersionMajor;
+	S32 mDriverVersionMinor;
+	S32 mDriverVersionRelease;
+	F32 mGLVersion; // e.g = 1.4
+	std::string mDriverVersionVendorString;
+
+	S32 mVRAM; // VRAM in MB
+	S32 mGLMaxVertexRange;
+	S32 mGLMaxIndexRange;
+	
+	void getPixelFormat(); // Get the best pixel format
+
+	std::string getGLInfoString();
+	void printGLInfoString();
+	void getGLInfo(LLSD& info);
+
+	// In ALL CAPS
+	std::string mGLVendor;
+	std::string mGLVendorShort;
+
+	// In ALL CAPS
+	std::string mGLRenderer;
+
+private:
+	void initExtensions();
+	void initGLStates();
+	void initGLImages();
+};
+
+extern LLGLManager gGLManager;
+
+class LLQuaternion;
+class LLMatrix4;
+
+void rotate_quat(LLQuaternion& rotation);
+
+void flush_glerror(); // Flush GL errors when we know we're handling them correctly.
+
+void assert_glerror();
+
+void clear_glerror();
+
+//#if LL_DEBUG
+# define stop_glerror() assert_glerror()
+# define llglassertok() assert_glerror()
+//#else
+//# define stop_glerror()
+//# define llglassertok()
+//#endif
+
+#define llglassertok_always() assert_glerror()
+
+////////////////////////
+//
+// Note: U32's are GLEnum's...
+//
+
+// This is a class for GL state management
+
+/*
+	GL STATE MANAGEMENT DESCRIPTION
+
+	LLGLState and its two subclasses, LLGLEnable and LLGLDisable, manage the current 
+	enable/disable states of the GL to prevent redundant setting of state within a 
+	render path or the accidental corruption of what state the next path expects.
+
+	Essentially, wherever you would call glEnable set a state and then
+	subsequently reset it by calling glDisable (or vice versa), make an instance of 
+	LLGLEnable with the state you want to set, and assume it will be restored to its
+	original state when that instance of LLGLEnable is destroyed.  It is good practice
+	to exploit stack frame controls for optimal setting/unsetting and readability of 
+	code.  In llglstates.h, there are a collection of helper classes that define groups
+	of enables/disables that can cause multiple states to be set with the creation of
+	one instance.  
+
+	Sample usage:
+
+	//disable lighting for rendering hud objects
+	//INCORRECT USAGE
+	LLGLEnable lighting(GL_LIGHTING);
+	renderHUD();
+	LLGLDisable lighting(GL_LIGHTING);
+
+	//CORRECT USAGE
+	{
+		LLGLEnable lighting(GL_LIGHTING);
+		renderHUD();
+	}
+
+	If a state is to be set on a conditional, the following mechanism
+	is useful:
+
+	{
+		LLGLEnable lighting(light_hud ? GL_LIGHTING : 0);
+		renderHUD();
+	}
+
+	A LLGLState initialized with a parameter of 0 does nothing.
+
+	LLGLState works by maintaining a map of the current GL states, and ignoring redundant
+	enables/disables.  If a redundant call is attempted, it becomes a noop, otherwise,
+	it is set in the constructor and reset in the destructor.  
+
+	For debugging GL state corruption, running with debug enabled will trigger asserts
+	if the existing GL state does not match the expected GL state.
+
+*/
+class LLGLState
+{
+public:
+	static void initClass();
+	static void restoreGL();
+
+	static void resetTextureStates();
+	static void dumpStates();
+	static void checkStates();
+	static void checkTextureChannels();
+	static void checkClientArrays(U32 data_mask = 0x0001);
+	
+protected:
+	static std::map<LLGLenum, LLGLboolean> sStateMap;
+	
+public:
+	enum { CURRENT_STATE = -2 };
+	LLGLState(LLGLenum state, S32 enabled = CURRENT_STATE);
+	~LLGLState();
+	void setEnabled(S32 enabled);
+	void enable() { setEnabled(TRUE); }
+	void disable() { setEnabled(FALSE); }
+protected:
+	LLGLenum mState;
+	BOOL mWasEnabled;
+	BOOL mIsEnabled;
+};
+
+// New LLGLState class wrappers that don't depend on actual GL flags.
+class LLGLEnableBlending : public LLGLState
+{
+public:
+	LLGLEnableBlending(bool enable);
+};
+
+class LLGLEnableAlphaReject : public LLGLState
+{
+public:
+	LLGLEnableAlphaReject(bool enable);
+};
+
+/// TODO: Being deprecated.
+class LLGLEnable : public LLGLState
+{
+public:
+	LLGLEnable(LLGLenum state) : LLGLState(state, TRUE) {}
+};
+
+/// TODO: Being deprecated.
+class LLGLDisable : public LLGLState
+{
+public:
+	LLGLDisable(LLGLenum state) : LLGLState(state, FALSE) {}
+};
+
+/*
+  Store and modify projection matrix to create an oblique
+  projection that clips to the specified plane.  Oblique
+  projections alter values in the depth buffer, so this
+  class should not be used mid-renderpass.  
+
+  Restores projection matrix on destruction.
+  GL_MODELVIEW_MATRIX is active whenever program execution
+  leaves this class.
+  Does not stack.
+  Caches inverse of projection matrix used in gGLObliqueProjectionInverse
+*/
+class LLGLUserClipPlane 
+{
+public:
+	
+	LLGLUserClipPlane(const LLPlane& plane, const glh::matrix4f& modelview, const glh::matrix4f& projection);
+	~LLGLUserClipPlane();
+
+	void setPlane(F32 a, F32 b, F32 c, F32 d);
+
+private:
+	glh::matrix4f mProjection;
+	glh::matrix4f mModelview;
+};
+
+/*
+  Modify and load projection matrix to push depth values to far clip plane.
+
+  Restores projection matrix on destruction.
+  GL_MODELVIEW_MATRIX is active whenever program execution
+  leaves this class.
+  Does not stack.
+*/
+class LLGLClampToFarClip
+{
+public:
+	LLGLClampToFarClip(glh::matrix4f projection);
+	~LLGLClampToFarClip();
+};
+
+/*
+	Generic pooling scheme for things which use GL names (used for occlusion queries and vertex buffer objects).
+	Prevents thrashing of GL name caches by avoiding calls to glGenFoo and glDeleteFoo.
+*/
+class LLGLNamePool
+{
+public:
+	typedef struct
+	{
+		GLuint name;
+		BOOL used;
+	} NameEntry;
+
+	struct CompareUsed
+	{
+		bool operator()(const NameEntry& lhs, const NameEntry& rhs)
+		{
+			return lhs.used < rhs.used;  //FALSE entries first
+		}
+	};
+
+	typedef std::vector<NameEntry> name_list_t;
+	name_list_t mNameList;
+
+	LLGLNamePool();
+	virtual ~LLGLNamePool();
+	
+	void upkeep();
+	void cleanup();
+	
+	GLuint allocate();
+	void release(GLuint name);
+	
+	static void registerPool(LLGLNamePool* pool);
+	static void upkeepPools();
+	static void cleanupPools();
+
+protected:
+	typedef std::vector<LLGLNamePool*> pool_list_t;
+	static pool_list_t sInstances;
+	
+	virtual GLuint allocateName() = 0;
+	virtual void releaseName(GLuint name) = 0;
+};
+
+extern LLMatrix4 gGLObliqueProjectionInverse;
+
+#include "llglstates.h"
+
+void init_glstates();
+void enable_vertex_weighting(const S32 index);
+void disable_vertex_weighting(const S32 index);
+void enable_binormals(const S32 index);
+void disable_binormals(const S32 index);
+void enable_cloth_weights(const S32 index);
+void disable_cloth_weights(const S32 index);
+void set_vertex_weights(const S32 index, const U32 stride, const F32 *weights);
+void set_vertex_clothing_weights(const S32 index, const U32 stride, const LLVector4 *weights);
+void set_binormals(const S32 index, const U32 stride, const LLVector3 *binormals);
+void set_palette(U8* palette_data);
+void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific );
+
+extern BOOL gClothRipple;
+extern BOOL gNoRender;
+#endif // LL_LLGL_H
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
new file mode 100644
index 00000000000..01578245ac6
--- /dev/null
+++ b/indra/llrender/llglheaders.h
@@ -0,0 +1,588 @@
+/** 
+ * @file llglheaders.h
+ * @brief LLGL definitions
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLGLHEADERS_H
+#define LL_LLGLHEADERS_H
+
+#if LL_MESA
+//----------------------------------------------------------------------------
+// MESA headers
+// quotes so we get libraries/.../GL/ version
+#define GL_GLEXT_PROTOTYPES
+#include "GL/gl.h"
+#include "GL/glext.h"
+#include "GL/glu.h"
+
+// The __APPLE__ kludge is to make glh_extensions.h not symbol-clash horribly
+# define __APPLE__
+# include "GL/glh_extensions.h"
+# undef __APPLE__
+
+#elif LL_LINUX
+//----------------------------------------------------------------------------
+// Linux, MESA headers, but not necessarily assuming MESA runtime.
+// quotes so we get libraries/.../GL/ version
+#include "GL/gl.h"
+#include "GL/glext.h"
+#include "GL/glu.h"
+
+
+#if LL_LINUX && !LL_MESA_HEADLESS
+// The __APPLE__ kludge is to make glh_extensions.h not symbol-clash horribly
+# define __APPLE__
+# include "GL/glh_extensions.h"
+# undef __APPLE__
+
+/* Although SDL very likely ends up calling glXGetProcAddress() itself,
+   if we use SDL_GL_GetProcAddress() then we get bogus addresses back on
+   some systems.  Weird. */
+/*# include "SDL/SDL.h"
+  # define GLH_EXT_GET_PROC_ADDRESS(p) SDL_GL_GetProcAddress(p) */
+#define GLX_GLXEXT_PROTOTYPES 1
+# include "GL/glx.h"
+# include "GL/glxext.h"
+// Use glXGetProcAddressARB instead of glXGetProcAddress - the ARB symbol
+// is considered 'legacy' but works on more machines.
+# define GLH_EXT_GET_PROC_ADDRESS(p) glXGetProcAddressARB((const GLubyte*)(p))
+// Whee, the X headers define 'Status'.  Undefine to avoid confusion.
+#undef Status
+#endif // LL_LINUX && !LL_MESA_HEADLESS
+
+
+// GL_ARB_vertex_buffer_object
+extern PFNGLBINDBUFFERARBPROC		glBindBufferARB;
+extern PFNGLDELETEBUFFERSARBPROC	glDeleteBuffersARB;
+extern PFNGLGENBUFFERSARBPROC		glGenBuffersARB;
+extern PFNGLISBUFFERARBPROC			glIsBufferARB;
+extern PFNGLBUFFERDATAARBPROC		glBufferDataARB;
+extern PFNGLBUFFERSUBDATAARBPROC	glBufferSubDataARB;
+extern PFNGLGETBUFFERSUBDATAARBPROC glGetBufferSubDataARB;
+extern PFNGLMAPBUFFERARBPROC		glMapBufferARB;
+extern PFNGLUNMAPBUFFERARBPROC		glUnmapBufferARB;
+extern PFNGLGETBUFFERPARAMETERIVARBPROC	glGetBufferParameterivARB;
+extern PFNGLGETBUFFERPOINTERVARBPROC	glGetBufferPointervARB;
+
+// GL_ATI_vertex_array_object
+extern PFNGLNEWOBJECTBUFFERATIPROC			glNewObjectBufferATI;
+extern PFNGLISOBJECTBUFFERATIPROC			glIsObjectBufferATI;
+extern PFNGLUPDATEOBJECTBUFFERATIPROC		glUpdateObjectBufferATI;
+extern PFNGLGETOBJECTBUFFERFVATIPROC		glGetObjectBufferfvATI;
+extern PFNGLGETOBJECTBUFFERIVATIPROC		glGetObjectBufferivATI;
+extern PFNGLFREEOBJECTBUFFERATIPROC		    glFreeObjectBufferATI;
+extern PFNGLARRAYOBJECTATIPROC				glArrayObjectATI;
+extern PFNGLVERTEXATTRIBARRAYOBJECTATIPROC	glVertexAttribArrayObjectATI;
+extern PFNGLGETARRAYOBJECTFVATIPROC			glGetArrayObjectfvATI;
+extern PFNGLGETARRAYOBJECTIVATIPROC			glGetArrayObjectivATI;
+extern PFNGLVARIANTARRAYOBJECTATIPROC		glVariantObjectArrayATI;
+extern PFNGLGETVARIANTARRAYOBJECTFVATIPROC	glGetVariantArrayObjectfvATI;
+extern PFNGLGETVARIANTARRAYOBJECTIVATIPROC	glGetVariantArrayObjectivATI;
+
+// GL_ARB_occlusion_query
+extern PFNGLGENQUERIESARBPROC glGenQueriesARB;
+extern PFNGLDELETEQUERIESARBPROC glDeleteQueriesARB;
+extern PFNGLISQUERYARBPROC glIsQueryARB;
+extern PFNGLBEGINQUERYARBPROC glBeginQueryARB;
+extern PFNGLENDQUERYARBPROC glEndQueryARB;
+extern PFNGLGETQUERYIVARBPROC glGetQueryivARB;
+extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB;
+extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB;
+
+// GL_ARB_point_parameters
+extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB;
+extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB;
+
+// GL_ARB_shader_objects
+extern PFNGLDELETEOBJECTARBPROC glDeleteObjectARB;
+extern PFNGLGETHANDLEARBPROC glGetHandleARB;
+extern PFNGLDETACHOBJECTARBPROC glDetachObjectARB;
+extern PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB;
+extern PFNGLSHADERSOURCEARBPROC glShaderSourceARB;
+extern PFNGLCOMPILESHADERARBPROC glCompileShaderARB;
+extern PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB;
+extern PFNGLATTACHOBJECTARBPROC glAttachObjectARB;
+extern PFNGLLINKPROGRAMARBPROC glLinkProgramARB;
+extern PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB;
+extern PFNGLVALIDATEPROGRAMARBPROC glValidateProgramARB;
+extern PFNGLUNIFORM1FARBPROC glUniform1fARB;
+extern PFNGLUNIFORM2FARBPROC glUniform2fARB;
+extern PFNGLUNIFORM3FARBPROC glUniform3fARB;
+extern PFNGLUNIFORM4FARBPROC glUniform4fARB;
+extern PFNGLUNIFORM1IARBPROC glUniform1iARB;
+extern PFNGLUNIFORM2IARBPROC glUniform2iARB;
+extern PFNGLUNIFORM3IARBPROC glUniform3iARB;
+extern PFNGLUNIFORM4IARBPROC glUniform4iARB;
+extern PFNGLUNIFORM1FVARBPROC glUniform1fvARB;
+extern PFNGLUNIFORM2FVARBPROC glUniform2fvARB;
+extern PFNGLUNIFORM3FVARBPROC glUniform3fvARB;
+extern PFNGLUNIFORM4FVARBPROC glUniform4fvARB;
+extern PFNGLUNIFORM1IVARBPROC glUniform1ivARB;
+extern PFNGLUNIFORM2IVARBPROC glUniform2ivARB;
+extern PFNGLUNIFORM3IVARBPROC glUniform3ivARB;
+extern PFNGLUNIFORM4IVARBPROC glUniform4ivARB;
+extern PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB;
+extern PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB;
+extern PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB;
+extern PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB;
+extern PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB;
+extern PFNGLGETINFOLOGARBPROC glGetInfoLogARB;
+extern PFNGLGETATTACHEDOBJECTSARBPROC glGetAttachedObjectsARB;
+extern PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB;
+extern PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniformARB;
+extern PFNGLGETUNIFORMFVARBPROC glGetUniformfvARB;
+extern PFNGLGETUNIFORMIVARBPROC glGetUniformivARB;
+extern PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB;
+
+// GL_ARB_vertex_shader
+extern PFNGLVERTEXATTRIB1DARBPROC glVertexAttrib1dARB;
+extern PFNGLVERTEXATTRIB1DVARBPROC glVertexAttrib1dvARB;
+extern PFNGLVERTEXATTRIB1FARBPROC glVertexAttrib1fARB;
+extern PFNGLVERTEXATTRIB1FVARBPROC glVertexAttrib1fvARB;
+extern PFNGLVERTEXATTRIB1SARBPROC glVertexAttrib1sARB;
+extern PFNGLVERTEXATTRIB1SVARBPROC glVertexAttrib1svARB;
+extern PFNGLVERTEXATTRIB2DARBPROC glVertexAttrib2dARB;
+extern PFNGLVERTEXATTRIB2DVARBPROC glVertexAttrib2dvARB;
+extern PFNGLVERTEXATTRIB2FARBPROC glVertexAttrib2fARB;
+extern PFNGLVERTEXATTRIB2FVARBPROC glVertexAttrib2fvARB;
+extern PFNGLVERTEXATTRIB2SARBPROC glVertexAttrib2sARB;
+extern PFNGLVERTEXATTRIB2SVARBPROC glVertexAttrib2svARB;
+extern PFNGLVERTEXATTRIB3DARBPROC glVertexAttrib3dARB;
+extern PFNGLVERTEXATTRIB3DVARBPROC glVertexAttrib3dvARB;
+extern PFNGLVERTEXATTRIB3FARBPROC glVertexAttrib3fARB;
+extern PFNGLVERTEXATTRIB3FVARBPROC glVertexAttrib3fvARB;
+extern PFNGLVERTEXATTRIB3SARBPROC glVertexAttrib3sARB;
+extern PFNGLVERTEXATTRIB3SVARBPROC glVertexAttrib3svARB;
+extern PFNGLVERTEXATTRIB4NBVARBPROC glVertexAttrib4nbvARB;
+extern PFNGLVERTEXATTRIB4NIVARBPROC glVertexAttrib4nivARB;
+extern PFNGLVERTEXATTRIB4NSVARBPROC glVertexAttrib4nsvARB;
+extern PFNGLVERTEXATTRIB4NUBARBPROC glVertexAttrib4nubARB;
+extern PFNGLVERTEXATTRIB4NUBVARBPROC glVertexAttrib4nubvARB;
+extern PFNGLVERTEXATTRIB4NUIVARBPROC glVertexAttrib4nuivARB;
+extern PFNGLVERTEXATTRIB4NUSVARBPROC glVertexAttrib4nusvARB;
+extern PFNGLVERTEXATTRIB4BVARBPROC glVertexAttrib4bvARB;
+extern PFNGLVERTEXATTRIB4DARBPROC glVertexAttrib4dARB;
+extern PFNGLVERTEXATTRIB4DVARBPROC glVertexAttrib4dvARB;
+extern PFNGLVERTEXATTRIB4FARBPROC glVertexAttrib4fARB;
+extern PFNGLVERTEXATTRIB4FVARBPROC glVertexAttrib4fvARB;
+extern PFNGLVERTEXATTRIB4IVARBPROC glVertexAttrib4ivARB;
+extern PFNGLVERTEXATTRIB4SARBPROC glVertexAttrib4sARB;
+extern PFNGLVERTEXATTRIB4SVARBPROC glVertexAttrib4svARB;
+extern PFNGLVERTEXATTRIB4UBVARBPROC glVertexAttrib4ubvARB;
+extern PFNGLVERTEXATTRIB4UIVARBPROC glVertexAttrib4uivARB;
+extern PFNGLVERTEXATTRIB4USVARBPROC glVertexAttrib4usvARB;
+extern PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB;
+extern PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB;
+extern PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB;
+extern PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
+extern PFNGLBINDPROGRAMARBPROC glBindProgramARB;
+extern PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB;
+extern PFNGLGENPROGRAMSARBPROC glGenProgramsARB;
+extern PFNGLPROGRAMENVPARAMETER4DARBPROC glProgramEnvParameter4dARB;
+extern PFNGLPROGRAMENVPARAMETER4DVARBPROC glProgramEnvParameter4dvARB;
+extern PFNGLPROGRAMENVPARAMETER4FARBPROC glProgramEnvParameter4fARB;
+extern PFNGLPROGRAMENVPARAMETER4FVARBPROC glProgramEnvParameter4fvARB;
+extern PFNGLPROGRAMLOCALPARAMETER4DARBPROC glProgramLocalParameter4dARB;
+extern PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glProgramLocalParameter4dvARB;
+extern PFNGLPROGRAMLOCALPARAMETER4FARBPROC glProgramLocalParameter4fARB;
+extern PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB;
+extern PFNGLGETPROGRAMENVPARAMETERDVARBPROC glGetProgramEnvParameterdvARB;
+extern PFNGLGETPROGRAMENVPARAMETERFVARBPROC glGetProgramEnvParameterfvARB;
+extern PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glGetProgramLocalParameterdvARB;
+extern PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glGetProgramLocalParameterfvARB;
+extern PFNGLGETPROGRAMIVARBPROC glGetProgramivARB;
+extern PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB;
+extern PFNGLGETVERTEXATTRIBDVARBPROC glGetVertexAttribdvARB;
+extern PFNGLGETVERTEXATTRIBFVARBPROC glGetVertexAttribfvARB;
+extern PFNGLGETVERTEXATTRIBIVARBPROC glGetVertexAttribivARB;
+extern PFNGLGETVERTEXATTRIBPOINTERVARBPROC glGetVertexAttribPointervARB;
+extern PFNGLISPROGRAMARBPROC glIsProgramARB;
+extern PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB;
+extern PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB;
+extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB;
+
+extern PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB;
+extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB;
+
+extern PFNGLCOLORTABLEEXTPROC glColorTableEXT;
+
+//GL_EXT_framebuffer_object
+extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT;
+extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;
+extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT;
+extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT;
+extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT;
+extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT;
+extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT;
+extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
+extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT;
+extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
+extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
+extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT;
+extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
+extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT;
+extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT;
+extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT;
+extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT;
+
+
+#elif LL_WINDOWS
+
+// windows gl headers depend on things like APIENTRY, so include windows.
+#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <windows.h>
+
+//----------------------------------------------------------------------------
+#include <GL/gl.h>
+#include <GL/glu.h>
+
+// quotes so we get libraries/.../GL/ version
+#include "GL/glext.h"
+#include "GL/glh_extensions.h"
+
+
+// GL_ARB_vertex_buffer_object
+extern PFNGLBINDBUFFERARBPROC		glBindBufferARB;
+extern PFNGLDELETEBUFFERSARBPROC	glDeleteBuffersARB;
+extern PFNGLGENBUFFERSARBPROC		glGenBuffersARB;
+extern PFNGLISBUFFERARBPROC			glIsBufferARB;
+extern PFNGLBUFFERDATAARBPROC		glBufferDataARB;
+extern PFNGLBUFFERSUBDATAARBPROC	glBufferSubDataARB;
+extern PFNGLGETBUFFERSUBDATAARBPROC glGetBufferSubDataARB;
+extern PFNGLMAPBUFFERARBPROC		glMapBufferARB;
+extern PFNGLUNMAPBUFFERARBPROC		glUnmapBufferARB;
+extern PFNGLGETBUFFERPARAMETERIVARBPROC	glGetBufferParameterivARB;
+extern PFNGLGETBUFFERPOINTERVARBPROC	glGetBufferPointervARB;
+
+// GL_ATI_vertex_array_object
+extern PFNGLNEWOBJECTBUFFERATIPROC			glNewObjectBufferATI;
+extern PFNGLISOBJECTBUFFERATIPROC			glIsObjectBufferATI;
+extern PFNGLUPDATEOBJECTBUFFERATIPROC		glUpdateObjectBufferATI;
+extern PFNGLGETOBJECTBUFFERFVATIPROC		glGetObjectBufferfvATI;
+extern PFNGLGETOBJECTBUFFERIVATIPROC		glGetObjectBufferivATI;
+extern PFNGLFREEOBJECTBUFFERATIPROC		    glFreeObjectBufferATI;
+extern PFNGLARRAYOBJECTATIPROC				glArrayObjectATI;
+extern PFNGLVERTEXATTRIBARRAYOBJECTATIPROC	glVertexAttribArrayObjectATI;
+extern PFNGLGETARRAYOBJECTFVATIPROC			glGetArrayObjectfvATI;
+extern PFNGLGETARRAYOBJECTIVATIPROC			glGetArrayObjectivATI;
+extern PFNGLVARIANTARRAYOBJECTATIPROC		glVariantObjectArrayATI;
+extern PFNGLGETVARIANTARRAYOBJECTFVATIPROC	glGetVariantArrayObjectfvATI;
+extern PFNGLGETVARIANTARRAYOBJECTIVATIPROC	glGetVariantArrayObjectivATI;
+
+extern PFNWGLSWAPINTERVALEXTPROC			wglSwapIntervalEXT;
+
+// GL_ARB_occlusion_query
+extern PFNGLGENQUERIESARBPROC glGenQueriesARB;
+extern PFNGLDELETEQUERIESARBPROC glDeleteQueriesARB;
+extern PFNGLISQUERYARBPROC glIsQueryARB;
+extern PFNGLBEGINQUERYARBPROC glBeginQueryARB;
+extern PFNGLENDQUERYARBPROC glEndQueryARB;
+extern PFNGLGETQUERYIVARBPROC glGetQueryivARB;
+extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB;
+extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB;
+
+// GL_ARB_point_parameters
+extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB;
+extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB;
+
+// GL_ARB_shader_objects
+extern PFNGLDELETEOBJECTARBPROC glDeleteObjectARB;
+extern PFNGLGETHANDLEARBPROC glGetHandleARB;
+extern PFNGLDETACHOBJECTARBPROC glDetachObjectARB;
+extern PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB;
+extern PFNGLSHADERSOURCEARBPROC glShaderSourceARB;
+extern PFNGLCOMPILESHADERARBPROC glCompileShaderARB;
+extern PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB;
+extern PFNGLATTACHOBJECTARBPROC glAttachObjectARB;
+extern PFNGLLINKPROGRAMARBPROC glLinkProgramARB;
+extern PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB;
+extern PFNGLVALIDATEPROGRAMARBPROC glValidateProgramARB;
+extern PFNGLUNIFORM1FARBPROC glUniform1fARB;
+extern PFNGLUNIFORM2FARBPROC glUniform2fARB;
+extern PFNGLUNIFORM3FARBPROC glUniform3fARB;
+extern PFNGLUNIFORM4FARBPROC glUniform4fARB;
+extern PFNGLUNIFORM1IARBPROC glUniform1iARB;
+extern PFNGLUNIFORM2IARBPROC glUniform2iARB;
+extern PFNGLUNIFORM3IARBPROC glUniform3iARB;
+extern PFNGLUNIFORM4IARBPROC glUniform4iARB;
+extern PFNGLUNIFORM1FVARBPROC glUniform1fvARB;
+extern PFNGLUNIFORM2FVARBPROC glUniform2fvARB;
+extern PFNGLUNIFORM3FVARBPROC glUniform3fvARB;
+extern PFNGLUNIFORM4FVARBPROC glUniform4fvARB;
+extern PFNGLUNIFORM1IVARBPROC glUniform1ivARB;
+extern PFNGLUNIFORM2IVARBPROC glUniform2ivARB;
+extern PFNGLUNIFORM3IVARBPROC glUniform3ivARB;
+extern PFNGLUNIFORM4IVARBPROC glUniform4ivARB;
+extern PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB;
+extern PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB;
+extern PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB;
+extern PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB;
+extern PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB;
+extern PFNGLGETINFOLOGARBPROC glGetInfoLogARB;
+extern PFNGLGETATTACHEDOBJECTSARBPROC glGetAttachedObjectsARB;
+extern PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB;
+extern PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniformARB;
+extern PFNGLGETUNIFORMFVARBPROC glGetUniformfvARB;
+extern PFNGLGETUNIFORMIVARBPROC glGetUniformivARB;
+extern PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB;
+
+// GL_ARB_vertex_shader
+extern PFNGLVERTEXATTRIB1DARBPROC glVertexAttrib1dARB;
+extern PFNGLVERTEXATTRIB1DVARBPROC glVertexAttrib1dvARB;
+extern PFNGLVERTEXATTRIB1FARBPROC glVertexAttrib1fARB;
+extern PFNGLVERTEXATTRIB1FVARBPROC glVertexAttrib1fvARB;
+extern PFNGLVERTEXATTRIB1SARBPROC glVertexAttrib1sARB;
+extern PFNGLVERTEXATTRIB1SVARBPROC glVertexAttrib1svARB;
+extern PFNGLVERTEXATTRIB2DARBPROC glVertexAttrib2dARB;
+extern PFNGLVERTEXATTRIB2DVARBPROC glVertexAttrib2dvARB;
+extern PFNGLVERTEXATTRIB2FARBPROC glVertexAttrib2fARB;
+extern PFNGLVERTEXATTRIB2FVARBPROC glVertexAttrib2fvARB;
+extern PFNGLVERTEXATTRIB2SARBPROC glVertexAttrib2sARB;
+extern PFNGLVERTEXATTRIB2SVARBPROC glVertexAttrib2svARB;
+extern PFNGLVERTEXATTRIB3DARBPROC glVertexAttrib3dARB;
+extern PFNGLVERTEXATTRIB3DVARBPROC glVertexAttrib3dvARB;
+extern PFNGLVERTEXATTRIB3FARBPROC glVertexAttrib3fARB;
+extern PFNGLVERTEXATTRIB3FVARBPROC glVertexAttrib3fvARB;
+extern PFNGLVERTEXATTRIB3SARBPROC glVertexAttrib3sARB;
+extern PFNGLVERTEXATTRIB3SVARBPROC glVertexAttrib3svARB;
+extern PFNGLVERTEXATTRIB4NBVARBPROC glVertexAttrib4nbvARB;
+extern PFNGLVERTEXATTRIB4NIVARBPROC glVertexAttrib4nivARB;
+extern PFNGLVERTEXATTRIB4NSVARBPROC glVertexAttrib4nsvARB;
+extern PFNGLVERTEXATTRIB4NUBARBPROC glVertexAttrib4nubARB;
+extern PFNGLVERTEXATTRIB4NUBVARBPROC glVertexAttrib4nubvARB;
+extern PFNGLVERTEXATTRIB4NUIVARBPROC glVertexAttrib4nuivARB;
+extern PFNGLVERTEXATTRIB4NUSVARBPROC glVertexAttrib4nusvARB;
+extern PFNGLVERTEXATTRIB4BVARBPROC glVertexAttrib4bvARB;
+extern PFNGLVERTEXATTRIB4DARBPROC glVertexAttrib4dARB;
+extern PFNGLVERTEXATTRIB4DVARBPROC glVertexAttrib4dvARB;
+extern PFNGLVERTEXATTRIB4FARBPROC glVertexAttrib4fARB;
+extern PFNGLVERTEXATTRIB4FVARBPROC glVertexAttrib4fvARB;
+extern PFNGLVERTEXATTRIB4IVARBPROC glVertexAttrib4ivARB;
+extern PFNGLVERTEXATTRIB4SARBPROC glVertexAttrib4sARB;
+extern PFNGLVERTEXATTRIB4SVARBPROC glVertexAttrib4svARB;
+extern PFNGLVERTEXATTRIB4UBVARBPROC glVertexAttrib4ubvARB;
+extern PFNGLVERTEXATTRIB4UIVARBPROC glVertexAttrib4uivARB;
+extern PFNGLVERTEXATTRIB4USVARBPROC glVertexAttrib4usvARB;
+extern PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB;
+extern PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB;
+extern PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB;
+extern PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
+extern PFNGLBINDPROGRAMARBPROC glBindProgramARB;
+extern PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB;
+extern PFNGLGENPROGRAMSARBPROC glGenProgramsARB;
+extern PFNGLPROGRAMENVPARAMETER4DARBPROC glProgramEnvParameter4dARB;
+extern PFNGLPROGRAMENVPARAMETER4DVARBPROC glProgramEnvParameter4dvARB;
+extern PFNGLPROGRAMENVPARAMETER4FARBPROC glProgramEnvParameter4fARB;
+extern PFNGLPROGRAMENVPARAMETER4FVARBPROC glProgramEnvParameter4fvARB;
+extern PFNGLPROGRAMLOCALPARAMETER4DARBPROC glProgramLocalParameter4dARB;
+extern PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glProgramLocalParameter4dvARB;
+extern PFNGLPROGRAMLOCALPARAMETER4FARBPROC glProgramLocalParameter4fARB;
+extern PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB;
+extern PFNGLGETPROGRAMENVPARAMETERDVARBPROC glGetProgramEnvParameterdvARB;
+extern PFNGLGETPROGRAMENVPARAMETERFVARBPROC glGetProgramEnvParameterfvARB;
+extern PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glGetProgramLocalParameterdvARB;
+extern PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glGetProgramLocalParameterfvARB;
+extern PFNGLGETPROGRAMIVARBPROC glGetProgramivARB;
+extern PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB;
+extern PFNGLGETVERTEXATTRIBDVARBPROC glGetVertexAttribdvARB;
+extern PFNGLGETVERTEXATTRIBFVARBPROC glGetVertexAttribfvARB;
+extern PFNGLGETVERTEXATTRIBIVARBPROC glGetVertexAttribivARB;
+extern PFNGLGETVERTEXATTRIBPOINTERVARBPROC glGetVertexAttribPointervARB;
+extern PFNGLISPROGRAMARBPROC glIsProgramARB;
+extern PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB;
+extern PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB;
+extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB;
+
+//GL_EXT_framebuffer_object
+extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT;
+extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;
+extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT;
+extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT;
+extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT;
+extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT;
+extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT;
+extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
+extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT;
+extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
+extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
+extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT;
+extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
+extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT;
+extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT;
+extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT;
+extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT;
+
+
+#elif LL_DARWIN
+//----------------------------------------------------------------------------
+// LL_DARWIN
+
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+
+#define GL_EXT_separate_specular_color 1
+#include <OpenGL/glext.h>
+
+#include "GL/glh_extensions.h"
+
+// These symbols don't exist on 10.3.9, so they have to be declared weak.  Redeclaring them here fixes the problem.
+// Note that they also must not be called on 10.3.9.  This should be taken care of by a runtime check for the existence of the GL extension.
+#include <AvailabilityMacros.h>
+
+// GL_EXT_framebuffer_object
+extern GLboolean glIsRenderbufferEXT(GLuint renderbuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+extern void glBindRenderbufferEXT(GLenum target, GLuint renderbuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+extern void glDeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+extern void glGenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+extern void glRenderbufferStorageEXT(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+extern void glGetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+extern GLboolean glIsFramebufferEXT(GLuint framebuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+extern void glBindFramebufferEXT(GLenum target, GLuint framebuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+extern void glDeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+extern void glGenFramebuffersEXT(GLsizei n, GLuint *framebuffers) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+extern GLenum glCheckFramebufferStatusEXT(GLenum target) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+extern void glFramebufferTexture1DEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+extern void glFramebufferTexture2DEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+extern void glFramebufferTexture3DEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+extern void glFramebufferRenderbufferEXT(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+extern void glGetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, GLenum pname, GLint *params) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+extern void glGenerateMipmapEXT(GLenum target) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+//
+// Define vertex buffer object headers on Mac
+//
+#ifndef GL_ARB_vertex_buffer_object
+#define GL_BUFFER_SIZE_ARB                0x8764
+#define GL_BUFFER_USAGE_ARB               0x8765
+#define GL_ARRAY_BUFFER_ARB               0x8892
+#define GL_ELEMENT_ARRAY_BUFFER_ARB       0x8893
+#define GL_ARRAY_BUFFER_BINDING_ARB       0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895
+#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896
+#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897
+#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898
+#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899
+#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A
+#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B
+#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C
+#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D
+#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F
+#define GL_READ_ONLY_ARB                  0x88B8
+#define GL_WRITE_ONLY_ARB                 0x88B9
+#define GL_READ_WRITE_ARB                 0x88BA
+#define GL_BUFFER_ACCESS_ARB              0x88BB
+#define GL_BUFFER_MAPPED_ARB              0x88BC
+#define GL_BUFFER_MAP_POINTER_ARB         0x88BD
+#define GL_STREAM_DRAW_ARB                0x88E0
+#define GL_STREAM_READ_ARB                0x88E1
+#define GL_STREAM_COPY_ARB                0x88E2
+#define GL_STATIC_DRAW_ARB                0x88E4
+#define GL_STATIC_READ_ARB                0x88E5
+#define GL_STATIC_COPY_ARB                0x88E6
+#define GL_DYNAMIC_DRAW_ARB               0x88E8
+#define GL_DYNAMIC_READ_ARB               0x88E9
+#define GL_DYNAMIC_COPY_ARB               0x88EA
+#endif
+
+
+
+#ifndef GL_ARB_vertex_buffer_object
+/* GL types for handling large vertex buffer objects */
+typedef intptr_t GLintptrARB;
+typedef intptr_t GLsizeiptrARB;
+#endif
+
+
+#ifndef GL_ARB_vertex_buffer_object
+#define GL_ARB_vertex_buffer_object 1
+#ifdef GL_GLEXT_FUNCTION_POINTERS
+typedef void (* glBindBufferARBProcPtr) (GLenum target, GLuint buffer);
+typedef void (* glDeleteBufferARBProcPtr) (GLsizei n, const GLuint *buffers);
+typedef void (* glGenBuffersARBProcPtr) (GLsizei n, GLuint *buffers);
+typedef GLboolean (* glIsBufferARBProcPtr) (GLuint buffer);
+typedef void (* glBufferDataARBProcPtr) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage);
+typedef void (* glBufferSubDataARBProcPtr) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data);
+typedef void (* glGetBufferSubDataARBProcPtr) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data);
+typedef GLvoid* (* glMapBufferARBProcPtr) (GLenum target, GLenum access);	/* Flawfinder: ignore */
+typedef GLboolean (* glUnmapBufferARBProcPtr) (GLenum target);
+typedef void (* glGetBufferParameterivARBProcPtr) (GLenum target, GLenum pname, GLint *params);
+typedef void (* glGetBufferPointervARBProcPtr) (GLenum target, GLenum pname, GLvoid* *params);
+#else
+extern void glBindBufferARB (GLenum, GLuint);
+extern void glDeleteBuffersARB (GLsizei, const GLuint *);
+extern void glGenBuffersARB (GLsizei, GLuint *);
+extern GLboolean glIsBufferARB (GLuint);
+extern void glBufferDataARB (GLenum, GLsizeiptrARB, const GLvoid *, GLenum);
+extern void glBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, const GLvoid *);
+extern void glGetBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, GLvoid *);
+extern GLvoid* glMapBufferARB (GLenum, GLenum);
+extern GLboolean glUnmapBufferARB (GLenum);
+extern void glGetBufferParameterivARB (GLenum, GLenum, GLint *);
+extern void glGetBufferPointervARB (GLenum, GLenum, GLvoid* *);
+#endif /* GL_GLEXT_FUNCTION_POINTERS */
+#endif
+
+// May be needed for DARWIN...
+// #ifndef GL_ARB_compressed_tex_image
+// #define GL_ARB_compressed_tex_image 1
+// #ifdef GL_GLEXT_FUNCTION_POINTERS
+// typedef void (* glCompressedTexImage1D) (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid*);
+// typedef void (* glCompressedTexImage2D) (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*);
+// typedef void (* glCompressedTexImage3D) (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*);
+// typedef void (* glCompressedTexSubImage1D) (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid*);
+// typedef void (* glCompressedTexSubImage2D) (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*);
+// typedef void (* glCompressedTexSubImage3D) (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*);
+// typedef void (* glGetCompressedTexImage) (GLenum, GLint, GLvoid*);
+// #else
+// extern void glCompressedTexImage1D (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid*);
+// extern void glCompressedTexImage2D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*);
+// extern void glCompressedTexImage3D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*);
+// extern void glCompressedTexSubImage1D (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid*);
+// extern void glCompressedTexSubImage2D (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*);
+// extern void glCompressedTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*);
+// extern void glGetCompressedTexImage (GLenum, GLint, GLvoid*);
+// #endif /* GL_GLEXT_FUNCTION_POINTERS */
+// #endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#include <AGL/gl.h>
+
+#endif // LL_MESA / LL_WINDOWS / LL_DARWIN
+
+
+#endif // LL_LLGLHEADERS_H
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
new file mode 100644
index 00000000000..7b039449188
--- /dev/null
+++ b/indra/llrender/llglslshader.cpp
@@ -0,0 +1,823 @@
+/** 
+ * @file llglslshader.cpp
+ * @brief GLSL helper functions and state.
+ *
+ * $LicenseInfo:firstyear=2005&license=viewergpl$
+ * 
+ * Copyright (c) 2005-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llglslshader.h"
+
+#include "llshadermgr.h"
+#include "llfile.h"
+#include "llrender.h"
+
+#if LL_DARWIN
+#include "OpenGL/OpenGL.h"
+#endif
+
+#ifdef LL_RELEASE_FOR_DOWNLOAD
+#define UNIFORM_ERRS LL_WARNS_ONCE("Shader")
+#else
+#define UNIFORM_ERRS LL_ERRS("Shader")
+#endif
+
+// Lots of STL stuff in here, using namespace std to keep things more readable
+using std::vector;
+using std::pair;
+using std::make_pair;
+using std::string;
+
+BOOL shouldChange(const LLVector4& v1, const LLVector4& v2)
+{
+	return v1 != v2;
+}
+
+LLShaderFeatures::LLShaderFeatures()
+: calculatesLighting(false), isShiny(false), isFullbright(false), hasWaterFog(false),
+hasTransport(false), hasSkinning(false), hasAtmospherics(false), isSpecular(false),
+hasGamma(false), hasLighting(false), calculatesAtmospherics(false)
+{
+}
+
+//===============================
+// LLGLSL Shader implementation
+//===============================
+LLGLSLShader::LLGLSLShader()
+: mProgramObject(0), mShaderLevel(0), mShaderGroup(SG_DEFAULT)
+{
+}
+
+void LLGLSLShader::unload()
+{
+	stop_glerror();
+	mAttribute.clear();
+	mTexture.clear();
+	mUniform.clear();
+	mShaderFiles.clear();
+
+	if (mProgramObject)
+	{
+		GLhandleARB obj[1024];
+		GLsizei count;
+
+		glGetAttachedObjectsARB(mProgramObject, 1024, &count, obj);
+		for (GLsizei i = 0; i < count; i++)
+		{
+			glDeleteObjectARB(obj[i]);
+		}
+
+		glDeleteObjectARB(mProgramObject);
+
+		mProgramObject = 0;
+	}
+	
+	//hack to make apple not complain
+	glGetError();
+	
+	stop_glerror();
+}
+
+BOOL LLGLSLShader::createShader(vector<string> * attributes,
+								vector<string> * uniforms)
+{
+	llassert_always(!mShaderFiles.empty());
+	BOOL success = TRUE;
+
+	// Create program
+	mProgramObject = glCreateProgramObjectARB();
+	
+	// Attach existing objects
+	if (!LLShaderMgr::instance()->attachShaderFeatures(this))
+	{
+		return FALSE;
+	}
+
+	vector< pair<string,GLenum> >::iterator fileIter = mShaderFiles.begin();
+	for ( ; fileIter != mShaderFiles.end(); fileIter++ )
+	{
+		GLhandleARB shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second);
+		LL_DEBUGS("ShaderLoading") << "SHADER FILE: " << (*fileIter).first << " mShaderLevel=" << mShaderLevel << LL_ENDL;
+		if (mShaderLevel > 0)
+		{
+			attachObject(shaderhandle);
+		}
+		else
+		{
+			success = FALSE;
+		}
+	}
+
+	// Map attributes and uniforms
+	if (success)
+	{
+		success = mapAttributes(attributes);
+	}
+	if (success)
+	{
+		success = mapUniforms(uniforms);
+	}
+	if( !success )
+	{
+		LL_WARNS("ShaderLoading") << "Failed to link shader: " << mName << LL_ENDL;
+
+		// Try again using a lower shader level;
+		if (mShaderLevel > 0)
+		{
+			LL_WARNS("ShaderLoading") << "Failed to link using shader level " << mShaderLevel << " trying again using shader level " << (mShaderLevel - 1) << LL_ENDL;
+			mShaderLevel--;
+			return createShader(attributes,uniforms);
+		}
+	}
+	return success;
+}
+
+BOOL LLGLSLShader::attachObject(std::string object)
+{
+	if (LLShaderMgr::instance()->mShaderObjects.count(object) > 0)
+	{
+		stop_glerror();
+		glAttachObjectARB(mProgramObject, LLShaderMgr::instance()->mShaderObjects[object]);
+		stop_glerror();
+		return TRUE;
+	}
+	else
+	{
+		LL_WARNS("ShaderLoading") << "Attempting to attach shader object that hasn't been compiled: " << object << LL_ENDL;
+		return FALSE;
+	}
+}
+
+void LLGLSLShader::attachObject(GLhandleARB object)
+{
+	if (object != 0)
+	{
+		stop_glerror();
+		glAttachObjectARB(mProgramObject, object);
+		stop_glerror();
+	}
+	else
+	{
+		LL_WARNS("ShaderLoading") << "Attempting to attach non existing shader object. " << LL_ENDL;
+	}
+}
+
+void LLGLSLShader::attachObjects(GLhandleARB* objects, S32 count)
+{
+	for (S32 i = 0; i < count; i++)
+	{
+		attachObject(objects[i]);
+	}
+}
+
+BOOL LLGLSLShader::mapAttributes(const vector<string> * attributes)
+{
+	//link the program
+	BOOL res = link();
+
+	mAttribute.clear();
+	U32 numAttributes = (attributes == NULL) ? 0 : attributes->size();
+	mAttribute.resize(LLShaderMgr::instance()->mReservedAttribs.size() + numAttributes, -1);
+	
+	if (res)
+	{ //read back channel locations
+
+		//read back reserved channels first
+		for (U32 i = 0; i < (S32) LLShaderMgr::instance()->mReservedAttribs.size(); i++)
+		{
+			const char* name = LLShaderMgr::instance()->mReservedAttribs[i].c_str();
+			S32 index = glGetAttribLocationARB(mProgramObject, (const GLcharARB *)name);
+			if (index != -1)
+			{
+				mAttribute[i] = index;
+				LL_DEBUGS("ShaderLoading") << "Attribute " << name << " assigned to channel " << index << LL_ENDL;
+			}
+		}
+		if (attributes != NULL)
+		{
+			for (U32 i = 0; i < numAttributes; i++)
+			{
+				const char* name = (*attributes)[i].c_str();
+				S32 index = glGetAttribLocationARB(mProgramObject, name);
+				if (index != -1)
+				{
+					mAttribute[LLShaderMgr::instance()->mReservedAttribs.size() + i] = index;
+					LL_DEBUGS("ShaderLoading") << "Attribute " << name << " assigned to channel " << index << LL_ENDL;
+				}
+			}
+		}
+
+		return TRUE;
+	}
+	
+	return FALSE;
+}
+
+void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms)
+{
+	if (index == -1)
+	{
+		return;
+	}
+
+	GLenum type;
+	GLsizei length;
+	GLint size;
+	char name[1024];		/* Flawfinder: ignore */
+	name[0] = 0;
+
+	glGetActiveUniformARB(mProgramObject, index, 1024, &length, &size, &type, (GLcharARB *)name);
+	S32 location = glGetUniformLocationARB(mProgramObject, name);
+	if (location != -1)
+	{
+		mUniformMap[name] = location;
+		LL_DEBUGS("ShaderLoading") << "Uniform " << name << " is at location " << location << LL_ENDL;
+	
+		//find the index of this uniform
+		for (S32 i = 0; i < (S32) LLShaderMgr::instance()->mReservedUniforms.size(); i++)
+		{
+			if ( (mUniform[i] == -1)
+				&& (LLShaderMgr::instance()->mReservedUniforms[i].compare(0, length, name, LLShaderMgr::instance()->mReservedUniforms[i].length()) == 0))
+			{
+				//found it
+				mUniform[i] = location;
+				mTexture[i] = mapUniformTextureChannel(location, type);
+				return;
+			}
+		}
+
+		if (uniforms != NULL)
+		{
+			for (U32 i = 0; i < uniforms->size(); i++)
+			{
+				if ( (mUniform[i+LLShaderMgr::instance()->mReservedUniforms.size()] == -1)
+					&& ((*uniforms)[i].compare(0, length, name, (*uniforms)[i].length()) == 0))
+				{
+					//found it
+					mUniform[i+LLShaderMgr::instance()->mReservedUniforms.size()] = location;
+					mTexture[i+LLShaderMgr::instance()->mReservedUniforms.size()] = mapUniformTextureChannel(location, type);
+					return;
+				}
+			}
+		}
+	}
+ }
+
+GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type)
+{
+	if (type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB)
+	{	//this here is a texture
+		glUniform1iARB(location, mActiveTextureChannels);
+		LL_DEBUGS("ShaderLoading") << "Assigned to texture channel " << mActiveTextureChannels << LL_ENDL;
+		return mActiveTextureChannels++;
+	}
+	return -1;
+}
+
+BOOL LLGLSLShader::mapUniforms(const vector<string> * uniforms)
+{
+	BOOL res = TRUE;
+	
+	mActiveTextureChannels = 0;
+	mUniform.clear();
+	mUniformMap.clear();
+	mTexture.clear();
+	mValue.clear();
+	//initialize arrays
+	U32 numUniforms = (uniforms == NULL) ? 0 : uniforms->size();
+	mUniform.resize(numUniforms + LLShaderMgr::instance()->mReservedUniforms.size(), -1);
+	mTexture.resize(numUniforms + LLShaderMgr::instance()->mReservedUniforms.size(), -1);
+	
+	bind();
+
+	//get the number of active uniforms
+	GLint activeCount;
+	glGetObjectParameterivARB(mProgramObject, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &activeCount);
+
+	for (S32 i = 0; i < activeCount; i++)
+	{
+		mapUniform(i, uniforms);
+	}
+
+	unbind();
+
+	return res;
+}
+
+BOOL LLGLSLShader::link(BOOL suppress_errors)
+{
+	return LLShaderMgr::instance()->linkProgramObject(mProgramObject, suppress_errors);
+}
+
+void LLGLSLShader::bind()
+{
+	if (gGLManager.mHasShaderObjects)
+	{
+		glUseProgramObjectARB(mProgramObject);
+
+		if (mUniformsDirty)
+		{
+			LLShaderMgr::instance()->updateShaderUniforms(this);
+			mUniformsDirty = FALSE;
+		}
+	}
+}
+
+void LLGLSLShader::unbind()
+{
+	if (gGLManager.mHasShaderObjects)
+	{
+		for (U32 i = 0; i < mAttribute.size(); ++i)
+		{
+			vertexAttrib4f(i, 0,0,0,1);
+		}
+		glUseProgramObjectARB(0);
+	}
+}
+
+void LLGLSLShader::bindNoShader(void)
+{
+	glUseProgramObjectARB(0);
+}
+
+S32 LLGLSLShader::enableTexture(S32 uniform, S32 mode)
+{
+	if (uniform < 0 || uniform >= (S32)mTexture.size())
+	{
+		UNIFORM_ERRS << "Uniform out of range: " << uniform << LL_ENDL;
+		return -1;
+	}
+	S32 index = mTexture[uniform];
+	if (index != -1)
+	{
+		gGL.getTexUnit(index)->activate();
+		glEnable(mode);
+	}
+	return index;
+}
+
+S32 LLGLSLShader::disableTexture(S32 uniform, S32 mode)
+{
+	if (uniform < 0 || uniform >= (S32)mTexture.size())
+	{
+		UNIFORM_ERRS << "Uniform out of range: " << uniform << LL_ENDL;
+		return -1;
+	}
+	S32 index = mTexture[uniform];
+	if (index != -1)
+	{
+		gGL.getTexUnit(index)->activate();
+		glDisable(mode);
+	}
+	return index;
+}
+
+void LLGLSLShader::uniform1f(U32 index, GLfloat x)
+{
+	if (mProgramObject > 0)
+	{	
+		if (mUniform.size() <= index)
+		{
+			UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL;
+			return;
+		}
+
+		if (mUniform[index] >= 0)
+		{
+			std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]);
+			if (iter == mValue.end() || iter->second.mV[0] != x)
+			{
+				glUniform1fARB(mUniform[index], x);
+				mValue[mUniform[index]] = LLVector4(x,0.f,0.f,0.f);
+			}
+		}
+	}
+}
+
+void LLGLSLShader::uniform2f(U32 index, GLfloat x, GLfloat y)
+{
+	if (mProgramObject > 0)
+	{	
+		if (mUniform.size() <= index)
+		{
+			UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL;
+			return;
+		}
+
+		if (mUniform[index] >= 0)
+		{
+			std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]);
+			LLVector4 vec(x,y,0.f,0.f);
+			if (iter == mValue.end() || shouldChange(iter->second,vec))
+			{
+				glUniform2fARB(mUniform[index], x, y);
+				mValue[mUniform[index]] = vec;
+			}
+		}
+	}
+}
+
+void LLGLSLShader::uniform3f(U32 index, GLfloat x, GLfloat y, GLfloat z)
+{
+	if (mProgramObject > 0)
+	{	
+		if (mUniform.size() <= index)
+		{
+			UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL;
+			return;
+		}
+
+		if (mUniform[index] >= 0)
+		{
+			std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]);
+			LLVector4 vec(x,y,z,0.f);
+			if (iter == mValue.end() || shouldChange(iter->second,vec))
+			{
+				glUniform3fARB(mUniform[index], x, y, z);
+				mValue[mUniform[index]] = vec;
+			}
+		}
+	}
+}
+
+void LLGLSLShader::uniform4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+	if (mProgramObject > 0)
+	{	
+		if (mUniform.size() <= index)
+		{
+			UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL;
+			return;
+		}
+
+		if (mUniform[index] >= 0)
+		{
+			std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]);
+			LLVector4 vec(x,y,z,w);
+			if (iter == mValue.end() || shouldChange(iter->second,vec))
+			{
+				glUniform4fARB(mUniform[index], x, y, z, w);
+				mValue[mUniform[index]] = vec;
+			}
+		}
+	}
+}
+
+void LLGLSLShader::uniform1fv(U32 index, U32 count, const GLfloat* v)
+{
+	if (mProgramObject > 0)
+	{	
+		if (mUniform.size() <= index)
+		{
+			UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL;
+			return;
+		}
+
+		if (mUniform[index] >= 0)
+		{
+			std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]);
+			LLVector4 vec(v[0],0.f,0.f,0.f);
+			if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
+			{
+				glUniform1fvARB(mUniform[index], count, v);
+				mValue[mUniform[index]] = vec;
+			}
+		}
+	}
+}
+
+void LLGLSLShader::uniform2fv(U32 index, U32 count, const GLfloat* v)
+{
+	if (mProgramObject > 0)
+	{	
+		if (mUniform.size() <= index)
+		{
+			UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL;
+			return;
+		}
+
+		if (mUniform[index] >= 0)
+		{
+			std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]);
+			LLVector4 vec(v[0],v[1],0.f,0.f);
+			if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
+			{
+				glUniform2fvARB(mUniform[index], count, v);
+				mValue[mUniform[index]] = vec;
+			}
+		}
+	}
+}
+
+void LLGLSLShader::uniform3fv(U32 index, U32 count, const GLfloat* v)
+{
+	if (mProgramObject > 0)
+	{	
+		if (mUniform.size() <= index)
+		{
+			UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL;
+			return;
+		}
+
+		if (mUniform[index] >= 0)
+		{
+			std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]);
+			LLVector4 vec(v[0],v[1],v[2],0.f);
+			if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
+			{
+				glUniform3fvARB(mUniform[index], count, v);
+				mValue[mUniform[index]] = vec;
+			}
+		}
+	}
+}
+
+void LLGLSLShader::uniform4fv(U32 index, U32 count, const GLfloat* v)
+{
+	if (mProgramObject > 0)
+	{	
+		if (mUniform.size() <= index)
+		{
+			UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL;
+			return;
+		}
+
+		if (mUniform[index] >= 0)
+		{
+			std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]);
+			LLVector4 vec(v[0],v[1],v[2],v[3]);
+			if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
+			{
+				glUniform4fvARB(mUniform[index], count, v);
+				mValue[mUniform[index]] = vec;
+			}
+		}
+	}
+}
+
+void LLGLSLShader::uniformMatrix2fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v)
+{
+	if (mProgramObject > 0)
+	{	
+		if (mUniform.size() <= index)
+		{
+			UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL;
+			return;
+		}
+
+		if (mUniform[index] >= 0)
+		{
+			glUniformMatrix2fvARB(mUniform[index], count, transpose, v);
+		}
+	}
+}
+
+void LLGLSLShader::uniformMatrix3fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v)
+{
+	if (mProgramObject > 0)
+	{	
+		if (mUniform.size() <= index)
+		{
+			UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL;
+			return;
+		}
+
+		if (mUniform[index] >= 0)
+		{
+			glUniformMatrix3fvARB(mUniform[index], count, transpose, v);
+		}
+	}
+}
+
+void LLGLSLShader::uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v)
+{
+	if (mProgramObject > 0)
+	{	
+		if (mUniform.size() <= index)
+		{
+			UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL;
+			return;
+		}
+
+		if (mUniform[index] >= 0)
+		{
+			glUniformMatrix4fvARB(mUniform[index], count, transpose, v);
+		}
+	}
+}
+
+GLint LLGLSLShader::getUniformLocation(const string& uniform)
+{
+	if (mProgramObject > 0)
+	{
+		std::map<string, GLint>::iterator iter = mUniformMap.find(uniform);
+		if (iter != mUniformMap.end())
+		{
+			llassert(iter->second == glGetUniformLocationARB(mProgramObject, uniform.c_str()));
+			return iter->second;
+		}
+	}
+
+	return -1;
+}
+
+void LLGLSLShader::uniform1f(const string& uniform, GLfloat v)
+{
+	GLint location = getUniformLocation(uniform);
+				
+	if (location >= 0)
+	{
+		std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
+		LLVector4 vec(v,0.f,0.f,0.f);
+		if (iter == mValue.end() || shouldChange(iter->second,vec))
+		{
+			glUniform1fARB(location, v);
+			mValue[location] = vec;
+		}
+	}
+}
+
+void LLGLSLShader::uniform2f(const string& uniform, GLfloat x, GLfloat y)
+{
+	GLint location = getUniformLocation(uniform);
+				
+	if (location >= 0)
+	{
+		std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
+		LLVector4 vec(x,y,0.f,0.f);
+		if (iter == mValue.end() || shouldChange(iter->second,vec))
+		{
+			glUniform2fARB(location, x,y);
+			mValue[location] = vec;
+		}
+	}
+
+}
+
+void LLGLSLShader::uniform3f(const string& uniform, GLfloat x, GLfloat y, GLfloat z)
+{
+	GLint location = getUniformLocation(uniform);
+				
+	if (location >= 0)
+	{
+		std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
+		LLVector4 vec(x,y,z,0.f);
+		if (iter == mValue.end() || shouldChange(iter->second,vec))
+		{
+			glUniform3fARB(location, x,y,z);
+			mValue[location] = vec;
+		}
+	}
+}
+
+void LLGLSLShader::uniform4f(const string& uniform, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+	GLint location = getUniformLocation(uniform);
+
+	if (location >= 0)
+	{
+		std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
+		LLVector4 vec(x,y,z,w);
+		if (iter == mValue.end() || shouldChange(iter->second,vec))
+		{
+			glUniform4fARB(location, x,y,z,w);
+			mValue[location] = vec;
+		}
+	}
+}
+
+void LLGLSLShader::uniform1fv(const string& uniform, U32 count, const GLfloat* v)
+{
+	GLint location = getUniformLocation(uniform);
+
+	if (location >= 0)
+	{
+		std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
+		LLVector4 vec(v[0],0.f,0.f,0.f);
+		if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
+		{
+			glUniform1fvARB(location, count, v);
+			mValue[location] = vec;
+		}
+	}
+}
+
+void LLGLSLShader::uniform2fv(const string& uniform, U32 count, const GLfloat* v)
+{
+	GLint location = getUniformLocation(uniform);
+				
+	if (location >= 0)
+	{
+		std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
+		LLVector4 vec(v[0],v[1],0.f,0.f);
+		if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
+		{
+			glUniform2fvARB(location, count, v);
+			mValue[location] = vec;
+		}
+	}
+}
+
+void LLGLSLShader::uniform3fv(const string& uniform, U32 count, const GLfloat* v)
+{
+	GLint location = getUniformLocation(uniform);
+				
+	if (location >= 0)
+	{
+		std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
+		LLVector4 vec(v[0],v[1],v[2],0.f);
+		if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
+		{
+			glUniform3fvARB(location, count, v);
+			mValue[location] = vec;
+		}
+	}
+}
+
+void LLGLSLShader::uniform4fv(const string& uniform, U32 count, const GLfloat* v)
+{
+	GLint location = getUniformLocation(uniform);
+
+	if (location >= 0)
+	{
+		LLVector4 vec(v);
+		std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
+		if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
+		{
+			glUniform4fvARB(location, count, v);
+			mValue[location] = vec;
+		}
+	}
+}
+
+void LLGLSLShader::uniformMatrix2fv(const string& uniform, U32 count, GLboolean transpose, const GLfloat* v)
+{
+	GLint location = getUniformLocation(uniform);
+				
+	if (location >= 0)
+	{
+		glUniformMatrix2fvARB(location, count, transpose, v);
+	}
+}
+
+void LLGLSLShader::uniformMatrix3fv(const string& uniform, U32 count, GLboolean transpose, const GLfloat* v)
+{
+	GLint location = getUniformLocation(uniform);
+				
+	if (location >= 0)
+	{
+		glUniformMatrix3fvARB(location, count, transpose, v);
+	}
+}
+
+void LLGLSLShader::uniformMatrix4fv(const string& uniform, U32 count, GLboolean transpose, const GLfloat* v)
+{
+	GLint location = getUniformLocation(uniform);
+				
+	if (location >= 0)
+	{
+		glUniformMatrix4fvARB(location, count, transpose, v);
+	}
+}
+
+
+void LLGLSLShader::vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+	if (mAttribute[index] > 0)
+	{
+		glVertexAttrib4fARB(mAttribute[index], x, y, z, w);
+	}
+}
+
+void LLGLSLShader::vertexAttrib4fv(U32 index, GLfloat* v)
+{
+	if (mAttribute[index] > 0)
+	{
+		glVertexAttrib4fvARB(mAttribute[index], v);
+	}
+}
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
new file mode 100644
index 00000000000..c78188ba871
--- /dev/null
+++ b/indra/llrender/llglslshader.h
@@ -0,0 +1,139 @@
+/** 
+ * @file llglslshader.h
+ * @brief GLSL shader wrappers
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLGLSLSHADER_H
+#define LL_LLGLSLSHADER_H
+
+#include "llgl.h"
+
+class LLShaderFeatures
+{
+public:
+	bool calculatesLighting;
+	bool calculatesAtmospherics;
+	bool hasLighting; // implies no transport (it's possible to have neither though)
+	bool isShiny;
+	bool isFullbright; // implies no lighting
+	bool isSpecular;
+	bool hasWaterFog; // implies no gamma
+	bool hasTransport; // implies no lighting (it's possible to have neither though)
+	bool hasSkinning;	
+	bool hasAtmospherics;
+	bool hasGamma;
+
+	// char numLights;
+	
+	LLShaderFeatures();
+};
+
+class LLGLSLShader
+{
+public:
+
+	enum 
+	{
+		SG_DEFAULT = 0,
+		SG_SKY,
+		SG_WATER
+	};
+	
+	LLGLSLShader();
+
+	void unload();
+	BOOL createShader(std::vector<std::string> * attributes,
+						std::vector<std::string> * uniforms);
+	BOOL attachObject(std::string object);
+	void attachObject(GLhandleARB object);
+	void attachObjects(GLhandleARB* objects = NULL, S32 count = 0);
+	BOOL mapAttributes(const std::vector<std::string> * attributes);
+	BOOL mapUniforms(const std::vector<std::string> * uniforms);
+	void mapUniform(GLint index, const std::vector<std::string> * uniforms);
+	void uniform1f(U32 index, GLfloat v);
+	void uniform2f(U32 index, GLfloat x, GLfloat y);
+	void uniform3f(U32 index, GLfloat x, GLfloat y, GLfloat z);
+	void uniform4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+	void uniform1fv(U32 index, U32 count, const GLfloat* v);
+	void uniform2fv(U32 index, U32 count, const GLfloat* v);
+	void uniform3fv(U32 index, U32 count, const GLfloat* v);
+	void uniform4fv(U32 index, U32 count, const GLfloat* v);
+	void uniform1f(const std::string& uniform, GLfloat v);
+	void uniform2f(const std::string& uniform, GLfloat x, GLfloat y);
+	void uniform3f(const std::string& uniform, GLfloat x, GLfloat y, GLfloat z);
+	void uniform4f(const std::string& uniform, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+	void uniform1fv(const std::string& uniform, U32 count, const GLfloat* v);
+	void uniform2fv(const std::string& uniform, U32 count, const GLfloat* v);
+	void uniform3fv(const std::string& uniform, U32 count, const GLfloat* v);
+	void uniform4fv(const std::string& uniform, U32 count, const GLfloat* v);
+	void uniformMatrix2fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v);
+	void uniformMatrix3fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v);
+	void uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v);
+	void uniformMatrix2fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v);
+	void uniformMatrix3fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v);
+	void uniformMatrix4fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v);
+
+	void vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+	void vertexAttrib4fv(U32 index, GLfloat* v);
+	
+	GLint getUniformLocation(const std::string& uniform);
+	
+	GLint mapUniformTextureChannel(GLint location, GLenum type);
+	
+
+	//enable/disable texture channel for specified uniform
+	//if given texture uniform is active in the shader, 
+	//the corresponding channel will be active upon return
+	//returns channel texture is enabled in from [0-MAX)
+	S32 enableTexture(S32 uniform, S32 mode = GL_TEXTURE_2D);
+	S32 disableTexture(S32 uniform, S32 mode = GL_TEXTURE_2D); 
+	
+    BOOL link(BOOL suppress_errors = FALSE);
+	void bind();
+	void unbind();
+
+	// Unbinds any previously bound shader by explicitly binding no shader.
+	static void bindNoShader(void);
+
+	GLhandleARB mProgramObject;
+	std::vector<GLint> mAttribute; //lookup table of attribute enum to attribute channel
+	std::vector<GLint> mUniform;   //lookup table of uniform enum to uniform location
+	std::map<std::string, GLint> mUniformMap;  //lookup map of uniform name to uniform location
+	std::map<GLint, LLVector4> mValue; //lookup map of uniform location to last known value
+	std::vector<GLint> mTexture;
+	S32 mActiveTextureChannels;
+	S32 mShaderLevel;
+	S32 mShaderGroup;
+	BOOL mUniformsDirty;
+	LLShaderFeatures mFeatures;
+	std::vector< std::pair< std::string, GLenum > > mShaderFiles;
+	std::string mName;
+};
+
+#endif
diff --git a/indra/llrender/llglstates.h b/indra/llrender/llglstates.h
new file mode 100644
index 00000000000..907e4ee2e69
--- /dev/null
+++ b/indra/llrender/llglstates.h
@@ -0,0 +1,302 @@
+/** 
+ * @file llglstates.h
+ * @brief LLGL states definitions
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+//THIS HEADER SHOULD ONLY BE INCLUDED FROM llgl.h
+#ifndef LL_LLGLSTATES_H
+#define LL_LLGLSTATES_H
+
+#include "llimagegl.h"
+
+//----------------------------------------------------------------------------
+
+class LLGLDepthTest
+{
+	// Enabled by default
+public:
+	LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled = GL_TRUE, GLenum depth_func = GL_LEQUAL);
+	
+	~LLGLDepthTest();
+	
+	GLboolean mPrevDepthEnabled;
+	GLenum mPrevDepthFunc;
+	GLboolean mPrevWriteEnabled;
+private:
+	static GLboolean sDepthEnabled; // defaults to GL_FALSE
+	static GLenum sDepthFunc; // defaults to GL_LESS
+	static GLboolean sWriteEnabled; // defaults to GL_TRUE
+};
+
+//----------------------------------------------------------------------------
+
+class LLGLSDefault
+{
+protected:
+	LLGLEnable mColorMaterial;
+	LLGLDisable mAlphaTest, mBlend, mCullFace, mDither, mFog, 
+		mLineSmooth, mLineStipple, mNormalize, mPolygonSmooth,
+		mTextureGenQ, mTextureGenR, mTextureGenS, mTextureGenT,
+		mGLMultisample;
+public:
+	LLGLSDefault()
+		:
+		// Enable
+		mColorMaterial(GL_COLOR_MATERIAL),
+		// Disable
+		mAlphaTest(GL_ALPHA_TEST),
+		mBlend(GL_BLEND), 
+		mCullFace(GL_CULL_FACE),
+		mDither(GL_DITHER),
+		mFog(GL_FOG), 
+		mLineSmooth(GL_LINE_SMOOTH),
+		mLineStipple(GL_LINE_STIPPLE),
+		mNormalize(GL_NORMALIZE),
+		mPolygonSmooth(GL_POLYGON_SMOOTH),
+		mTextureGenQ(GL_TEXTURE_GEN_Q), 
+		mTextureGenR(GL_TEXTURE_GEN_R),
+		mTextureGenS(GL_TEXTURE_GEN_S), 
+		mTextureGenT(GL_TEXTURE_GEN_T),
+		mGLMultisample(GL_MULTISAMPLE_ARB)
+	{ }
+};
+
+class LLGLSNoTexture 
+{
+public:
+	LLGLSNoTexture()
+	{ LLImageGL::unbindTexture(0); }
+};
+
+class LLGLSObjectSelect
+{ 
+protected:
+	LLGLDisable mBlend, mFog, mAlphaTest;
+	LLGLEnable mCullFace;
+public:
+	LLGLSObjectSelect()
+		: mBlend(GL_BLEND), mFog(GL_FOG), 
+		  mAlphaTest(GL_ALPHA_TEST),
+		  mCullFace(GL_CULL_FACE)
+	{ LLImageGL::unbindTexture(0); }
+};
+
+class LLGLSObjectSelectAlpha
+{
+protected:
+	LLGLEnable mAlphaTest;
+public:
+	LLGLSObjectSelectAlpha()
+		: mAlphaTest(GL_ALPHA_TEST)
+	{}
+};
+
+//----------------------------------------------------------------------------
+
+class LLGLSUIDefault
+{ 
+protected:
+	LLGLEnable mBlend, mAlphaTest;
+	LLGLDisable mCullFace;
+	LLGLDepthTest mDepthTest;
+public:
+	LLGLSUIDefault() 
+		: mBlend(GL_BLEND), mAlphaTest(GL_ALPHA_TEST),
+		  mCullFace(GL_CULL_FACE),
+		  mDepthTest(GL_FALSE, GL_TRUE, GL_LEQUAL)
+	{}
+};
+
+class LLGLSNoAlphaTest // : public LLGLSUIDefault
+{
+protected:
+	LLGLDisable mAlphaTest;
+public:
+	LLGLSNoAlphaTest()
+		: mAlphaTest(GL_ALPHA_TEST)
+	{}
+};
+
+class LLGLSNoTextureNoAlphaTest // : public LLGLSUIDefault
+{
+protected:
+	LLGLDisable mAlphaTest;
+public:
+	LLGLSNoTextureNoAlphaTest()
+		: mAlphaTest(GL_ALPHA_TEST)
+		  
+	{ LLImageGL::unbindTexture(0); }
+};
+
+//----------------------------------------------------------------------------
+
+class LLGLSFog
+{
+protected:
+	LLGLEnable mFog;
+public:
+	LLGLSFog()
+		: mFog(GL_FOG)
+	{}
+};
+
+class LLGLSNoFog
+{
+protected:
+	LLGLDisable mFog;
+public:
+	LLGLSNoFog()
+		: mFog(GL_FOG)
+	{}
+};
+
+//----------------------------------------------------------------------------
+
+class LLGLSPipeline
+{ 
+protected:
+	LLGLEnable mCullFace;
+	LLGLDepthTest mDepthTest;
+public:
+	LLGLSPipeline()
+		: mCullFace(GL_CULL_FACE),
+		  mDepthTest(GL_TRUE, GL_TRUE, GL_LEQUAL)
+	{ }		
+};
+
+class LLGLSPipelineAlpha // : public LLGLSPipeline
+{ 
+protected:
+	LLGLEnable mBlend, mAlphaTest;
+public:
+	LLGLSPipelineAlpha()
+		: mBlend(GL_BLEND),
+		  mAlphaTest(GL_ALPHA_TEST)
+	{ }
+};
+
+class LLGLSPipelineEmbossBump
+{
+protected:
+	LLGLDisable mFog;
+public:
+	LLGLSPipelineEmbossBump()
+		: mFog(GL_FOG)
+	{ }
+};
+
+class LLGLSPipelineSelection
+{ 
+protected:
+	LLGLDisable mCullFace;
+public:
+	LLGLSPipelineSelection()
+		: mCullFace(GL_CULL_FACE)
+	{}
+};
+
+class LLGLSPipelineAvatar
+{
+protected:
+	LLGLEnable mNormalize;
+public:
+	LLGLSPipelineAvatar()
+		: mNormalize(GL_NORMALIZE)
+	{}
+};
+
+class LLGLSPipelineSkyBox
+{ 
+protected:
+	LLGLDisable mAlphaTest, mCullFace, mFog;
+public:
+	LLGLSPipelineSkyBox()
+		: mAlphaTest(GL_ALPHA_TEST), mCullFace(GL_CULL_FACE), mFog(GL_FOG)
+	{ }
+};
+
+class LLGLSTracker
+{
+protected:
+	LLGLEnable mCullFace, mBlend, mAlphaTest;
+public:
+	LLGLSTracker() :
+		mCullFace(GL_CULL_FACE),
+		mBlend(GL_BLEND),
+		mAlphaTest(GL_ALPHA_TEST)
+		
+	{ LLImageGL::unbindTexture(0); }
+};
+
+//----------------------------------------------------------------------------
+
+class LLGLSSpecular
+{
+public:
+	LLGLSSpecular(const LLColor4& color, F32 shininess)
+	{
+		if (shininess > 0.0f)
+		{
+			glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color.mV);
+			S32 shiny = (S32)(shininess*128.f);
+			shiny = llclamp(shiny,0,128);
+			glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, shiny);
+		}
+	}
+	~LLGLSSpecular()
+	{
+		glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, LLColor4(0.f,0.f,0.f,0.f).mV);
+		glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 0);
+	}
+};
+
+//----------------------------------------------------------------------------
+
+
+class LLGLSBlendFunc : public LLGLSPipeline {
+protected:
+	GLint mSavedSrc, mSavedDst;
+	LLGLEnable mBlend;
+
+public:
+	LLGLSBlendFunc(GLenum srcFunc, GLenum dstFunc) :
+		mBlend(GL_BLEND)
+	{
+		glGetIntegerv(GL_BLEND_SRC, &mSavedSrc);
+		glGetIntegerv(GL_BLEND_DST, &mSavedDst);
+		glBlendFunc(srcFunc, dstFunc);
+	}
+
+	~LLGLSBlendFunc(void) {
+		glBlendFunc(mSavedSrc, mSavedDst);
+	}
+};
+
+
+#endif
diff --git a/indra/llrender/llgltypes.h b/indra/llrender/llgltypes.h
new file mode 100644
index 00000000000..42050cf90f2
--- /dev/null
+++ b/indra/llrender/llgltypes.h
@@ -0,0 +1,44 @@
+/** 
+ * @file llgltypes.h
+ * @brief LLGL definition
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ * 
+ * Copyright (c) 2006-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LLGLTYPES_H
+#define LLGLTYPES_H
+
+#define MAX_GL_TEXTURE_UNITS 16
+
+typedef U32 LLGLenum;
+typedef U32 LLGLuint;
+typedef S32 LLGLint;
+typedef F32 LLGLfloat;
+typedef F64 LLGLdouble;
+typedef U8 LLGLboolean;
+
+#endif
diff --git a/indra/llrender/llpostprocess.cpp b/indra/llrender/llpostprocess.cpp
new file mode 100644
index 00000000000..7c14b57fff8
--- /dev/null
+++ b/indra/llrender/llpostprocess.cpp
@@ -0,0 +1,574 @@
+/** 
+ * @file llpostprocess.cpp
+ * @brief LLPostProcess class implementation
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llpostprocess.h"
+#include "llglslshader.h"
+#include "llsdserialize.h"
+#include "llrender.h"
+
+
+LLPostProcess * gPostProcess = NULL;
+
+
+static const unsigned int NOISE_SIZE = 512;
+
+/// CALCULATING LUMINANCE (Using NTSC lum weights)
+/// http://en.wikipedia.org/wiki/Luma_%28video%29
+static const float LUMINANCE_R = 0.299f;
+static const float LUMINANCE_G = 0.587f;
+static const float LUMINANCE_B = 0.114f;
+
+static const char * const XML_FILENAME = "postprocesseffects.xml";
+
+LLPostProcess::LLPostProcess(void) : 
+					sceneRenderTexture(0), noiseTexture(0),
+					tempBloomTexture(0),
+					initialized(false),  
+					mAllEffects(LLSD::emptyMap()),
+					screenW(1), screenH(1)
+{
+	/*  Do nothing.  Needs to be updated to use our current shader system, and to work with the move into llrender.
+	std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME));
+	LL_DEBUGS2("AppInit", "Shaders") << "Loading PostProcess Effects settings from " << pathName << LL_ENDL;
+
+	llifstream effectsXML(pathName);
+
+	if (effectsXML)
+	{
+		LLPointer<LLSDParser> parser = new LLSDXMLParser();
+
+		parser->parse(effectsXML, mAllEffects, LLSDSerialize::SIZE_UNLIMITED);
+	}
+
+	if (!mAllEffects.has("default"))
+	{
+		LLSD & defaultEffect = (mAllEffects["default"] = LLSD::emptyMap());
+
+		defaultEffect["enable_night_vision"] = LLSD::Boolean(false);
+		defaultEffect["enable_bloom"] = LLSD::Boolean(false);
+		defaultEffect["enable_color_filter"] = LLSD::Boolean(false);
+
+		/// NVG Defaults
+		defaultEffect["brightness_multiplier"] = 3.0;
+		defaultEffect["noise_size"] = 25.0;
+		defaultEffect["noise_strength"] = 0.4;
+
+		// TODO BTest potentially add this to tweaks?
+		noiseTextureScale = 1.0f;
+		
+		/// Bloom Defaults
+		defaultEffect["extract_low"] = 0.95;
+		defaultEffect["extract_high"] = 1.0;
+		defaultEffect["bloom_width"] = 2.25;
+		defaultEffect["bloom_strength"] = 1.5;
+
+		/// Color Filter Defaults
+		defaultEffect["brightness"] = 1.0;
+		defaultEffect["contrast"] = 1.0;
+		defaultEffect["saturation"] = 1.0;
+
+		LLSD& contrastBase = (defaultEffect["contrast_base"] = LLSD::emptyArray());
+		contrastBase.append(1.0);
+		contrastBase.append(1.0);
+		contrastBase.append(1.0);
+		contrastBase.append(0.5);
+	}
+
+	setSelectedEffect("default");
+	*/
+}
+
+LLPostProcess::~LLPostProcess(void)
+{
+	glDeleteTextures(1, &sceneRenderTexture);
+	glDeleteTextures(1, &noiseTexture);
+	glDeleteTextures(1, &tempBloomTexture);
+}
+
+// static
+void LLPostProcess::initClass(void)
+{
+	//this will cause system to crash at second time login
+	//if first time login fails due to network connection --- bao
+	//***llassert_always(gPostProcess == NULL);
+	//replaced by the following line:
+	if(gPostProcess)
+		return ;
+	
+	
+	gPostProcess = new LLPostProcess();
+}
+
+// static
+void LLPostProcess::cleanupClass()
+{
+	delete gPostProcess;
+	gPostProcess = NULL;
+}
+
+void LLPostProcess::setSelectedEffect(std::string const & effectName)
+{
+	mSelectedEffectName = effectName;
+	static_cast<LLSD &>(tweaks) = mAllEffects[effectName];
+}
+
+void LLPostProcess::saveEffect(std::string const & effectName)
+{
+	/*  Do nothing.  Needs to be updated to use our current shader system, and to work with the move into llrender.
+	mAllEffects[effectName] = tweaks;
+
+	std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME));
+	//llinfos << "Saving PostProcess Effects settings to " << pathName << llendl;
+
+	llofstream effectsXML(pathName);
+
+	LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
+
+	formatter->format(mAllEffects, effectsXML);
+	*/
+}
+
+void LLPostProcess::apply(unsigned int width, unsigned int height)
+{
+	if (!initialized || width != screenW || height != screenH){
+		initialize(width, height);
+	}
+	if (shadersEnabled()){
+		doEffects();
+	}
+}
+
+void LLPostProcess::initialize(unsigned int width, unsigned int height)
+{
+	screenW = width;
+	screenH = height;
+	createTexture(sceneRenderTexture, screenW, screenH);
+	initialized = true;
+
+	checkError();
+	createNightVisionShader();
+	createBloomShader();
+	createColorFilterShader();
+	checkError();
+}
+
+inline bool LLPostProcess::shadersEnabled(void)
+{
+	return (tweaks.useColorFilter().asBoolean() ||
+			tweaks.useNightVisionShader().asBoolean() ||
+			tweaks.useBloomShader().asBoolean() );
+
+}
+
+void LLPostProcess::applyShaders(void)
+{
+	if (tweaks.useColorFilter()){
+		applyColorFilterShader();
+		checkError();
+	}	
+	if (tweaks.useNightVisionShader()){
+		/// If any of the above shaders have been called update the frame buffer;
+		if (tweaks.useColorFilter()){
+			copyFrameBuffer(sceneRenderTexture, screenW, screenH);
+		}
+		applyNightVisionShader();
+		checkError();
+	}
+	if (tweaks.useBloomShader()){
+		/// If any of the above shaders have been called update the frame buffer;
+		if (tweaks.useColorFilter().asBoolean() || tweaks.useNightVisionShader().asBoolean()){
+			copyFrameBuffer(sceneRenderTexture, screenW, screenH);
+		}
+		applyBloomShader();
+		checkError();
+	}
+}
+
+void LLPostProcess::applyColorFilterShader(void)
+{	
+	/*  Do nothing.  Needs to be updated to use our current shader system, and to work with the move into llrender.
+	gPostColorFilterProgram.bind();
+
+	gGL.getTexUnit(0)->activate();
+	glEnable(GL_TEXTURE_RECTANGLE_ARB);	
+
+	glBindTexture(GL_TEXTURE_RECTANGLE_ARB, sceneRenderTexture);
+
+	getShaderUniforms(colorFilterUniforms, gPostColorFilterProgram.mProgramObject);
+	glUniform1iARB(colorFilterUniforms["RenderTexture"], 0);
+	glUniform1fARB(colorFilterUniforms["brightness"], tweaks.getBrightness());
+	glUniform1fARB(colorFilterUniforms["contrast"], tweaks.getContrast());
+	float baseI = (tweaks.getContrastBaseR() + tweaks.getContrastBaseG() + tweaks.getContrastBaseB()) / 3.0f;
+	baseI = tweaks.getContrastBaseIntensity() / ((baseI < 0.001f) ? 0.001f : baseI);
+	float baseR = tweaks.getContrastBaseR() * baseI;
+	float baseG = tweaks.getContrastBaseG() * baseI;
+	float baseB = tweaks.getContrastBaseB() * baseI;
+	glUniform3fARB(colorFilterUniforms["contrastBase"], baseR, baseG, baseB);
+	glUniform1fARB(colorFilterUniforms["saturation"], tweaks.getSaturation());
+	glUniform3fARB(colorFilterUniforms["lumWeights"], LUMINANCE_R, LUMINANCE_G, LUMINANCE_B);
+	
+	LLGLEnable blend(GL_BLEND);
+	gGL.setSceneBlendType(LLRender::BT_REPLACE);
+	LLGLDepthTest depth(GL_FALSE);
+		
+	/// Draw a screen space quad
+	drawOrthoQuad(screenW, screenH, QUAD_NORMAL);
+	gPostColorFilterProgram.unbind();
+	*/
+}
+
+void LLPostProcess::createColorFilterShader(void)
+{
+	/// Define uniform names
+	colorFilterUniforms["RenderTexture"] = 0;
+	colorFilterUniforms["brightness"] = 0;
+	colorFilterUniforms["contrast"] = 0;
+	colorFilterUniforms["contrastBase"] = 0;
+	colorFilterUniforms["saturation"] = 0;
+	colorFilterUniforms["lumWeights"] = 0;
+}
+
+void LLPostProcess::applyNightVisionShader(void)
+{	
+	/*  Do nothing.  Needs to be updated to use our current shader system, and to work with the move into llrender.
+	gPostNightVisionProgram.bind();
+
+	gGL.getTexUnit(0)->activate();
+	glEnable(GL_TEXTURE_RECTANGLE_ARB);	
+
+	getShaderUniforms(nightVisionUniforms, gPostNightVisionProgram.mProgramObject);
+	glBindTexture(GL_TEXTURE_RECTANGLE_ARB, sceneRenderTexture);
+	glUniform1iARB(nightVisionUniforms["RenderTexture"], 0);
+
+	gGL.getTexUnit(1)->activate();
+	glEnable(GL_TEXTURE_2D);	
+
+	glBindTexture(GL_TEXTURE_2D, noiseTexture);
+	glUniform1iARB(nightVisionUniforms["NoiseTexture"], 1);
+
+	
+	glUniform1fARB(nightVisionUniforms["brightMult"], tweaks.getBrightMult());
+	glUniform1fARB(nightVisionUniforms["noiseStrength"], tweaks.getNoiseStrength());
+	noiseTextureScale = 0.01f + ((101.f - tweaks.getNoiseSize()) / 100.f);
+	noiseTextureScale *= (screenH / NOISE_SIZE);
+
+
+	glUniform3fARB(nightVisionUniforms["lumWeights"], LUMINANCE_R, LUMINANCE_G, LUMINANCE_B);
+	
+	LLGLEnable blend(GL_BLEND);
+	gGL.setSceneBlendType(LLRender::BT_REPLACE);
+	LLGLDepthTest depth(GL_FALSE);
+		
+	/// Draw a screen space quad
+	drawOrthoQuad(screenW, screenH, QUAD_NOISE);
+	gPostNightVisionProgram.unbind();
+	gGL.getTexUnit(0)->activate();
+	*/
+}
+
+void LLPostProcess::createNightVisionShader(void)
+{
+	/// Define uniform names
+	nightVisionUniforms["RenderTexture"] = 0;
+	nightVisionUniforms["NoiseTexture"] = 0;
+	nightVisionUniforms["brightMult"] = 0;	
+	nightVisionUniforms["noiseStrength"] = 0;
+	nightVisionUniforms["lumWeights"] = 0;	
+
+	createNoiseTexture(noiseTexture);
+}
+
+void LLPostProcess::applyBloomShader(void)
+{
+
+}
+
+void LLPostProcess::createBloomShader(void)
+{
+	createTexture(tempBloomTexture, unsigned(screenW * 0.5), unsigned(screenH * 0.5));
+
+	/// Create Bloom Extract Shader
+	bloomExtractUniforms["RenderTexture"] = 0;
+	bloomExtractUniforms["extractLow"] = 0;
+	bloomExtractUniforms["extractHigh"] = 0;	
+	bloomExtractUniforms["lumWeights"] = 0;	
+	
+	/// Create Bloom Blur Shader
+	bloomBlurUniforms["RenderTexture"] = 0;
+	bloomBlurUniforms["bloomStrength"] = 0;	
+	bloomBlurUniforms["texelSize"] = 0;
+	bloomBlurUniforms["blurDirection"] = 0;
+	bloomBlurUniforms["blurWidth"] = 0;
+}
+
+void LLPostProcess::getShaderUniforms(glslUniforms & uniforms, GLhandleARB & prog)
+{
+	/// Find uniform locations and insert into map	
+	std::map<const char *, GLuint>::iterator i;
+	for (i  = uniforms.begin(); i != uniforms.end(); ++i){
+		i->second = glGetUniformLocationARB(prog, i->first);
+	}
+}
+
+void LLPostProcess::doEffects(void)
+{
+	/// Save GL State
+	glPushAttrib(GL_ALL_ATTRIB_BITS);
+	glPushClientAttrib(GL_ALL_ATTRIB_BITS);
+
+	/// Copy the screen buffer to the render texture
+	copyFrameBuffer(sceneRenderTexture, screenW, screenH);
+
+	/// Clear the frame buffer.
+	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+	glClear(GL_COLOR_BUFFER_BIT);
+	
+	/// Change to an orthogonal view
+	viewOrthogonal(screenW, screenH);
+	
+	checkError();
+	applyShaders();
+	
+	LLGLSLShader::bindNoShader();
+	checkError();
+
+	/// Change to a perspective view
+	viewPerspective();	
+
+	/// Reset GL State
+	glPopClientAttrib();
+	glPopAttrib();
+	checkError();
+}
+
+void LLPostProcess::copyFrameBuffer(GLuint & texture, unsigned int width, unsigned int height)
+{
+	glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture);
+	glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 0, 0, width, height, 0);
+}
+
+void LLPostProcess::drawOrthoQuad(unsigned int width, unsigned int height, QuadType type)
+{
+#if 0
+	float noiseX = 0.f;
+	float noiseY = 0.f;
+	float screenRatio = 1.0f;
+
+	if (type == QUAD_NOISE){
+		noiseX = ((float) rand() / (float) RAND_MAX);
+		noiseY = ((float) rand() / (float) RAND_MAX);
+		screenRatio = (float) width / (float) height;
+	}
+	
+
+	glBegin(GL_QUADS);
+		if (type != QUAD_BLOOM_EXTRACT){
+			glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.f, (GLfloat) height);
+		} else {
+			glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.f, (GLfloat) height * 2.0f);
+		}
+		if (type == QUAD_NOISE){
+			glMultiTexCoord2fARB(GL_TEXTURE1_ARB,
+									noiseX,
+									noiseTextureScale + noiseY);
+		} else if (type == QUAD_BLOOM_COMBINE){
+			glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.f, (GLfloat) height * 0.5f);
+		}
+		glVertex2f(0.f, (GLfloat) screenH - height);
+
+		if (type != QUAD_BLOOM_EXTRACT){
+			glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.f, 0.f);
+		} else {
+			glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.f, 0.f);
+		}
+		if (type == QUAD_NOISE){
+			glMultiTexCoord2fARB(GL_TEXTURE1_ARB,
+									noiseX,
+									noiseY);
+		} else if (type == QUAD_BLOOM_COMBINE){
+			glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.f, 0.f);
+		}
+		glVertex2f(0.f, (GLfloat) height + (screenH - height));
+
+		
+		if (type != QUAD_BLOOM_EXTRACT){
+			glMultiTexCoord2fARB(GL_TEXTURE0_ARB, (GLfloat) width, 0.f);
+		} else {
+			glMultiTexCoord2fARB(GL_TEXTURE0_ARB, (GLfloat) width * 2.0f, 0.f);
+		}
+		if (type == QUAD_NOISE){
+			glMultiTexCoord2fARB(GL_TEXTURE1_ARB,
+									screenRatio * noiseTextureScale + noiseX,
+									noiseY);
+		} else if (type == QUAD_BLOOM_COMBINE){
+			glMultiTexCoord2fARB(GL_TEXTURE1_ARB, (GLfloat) width * 0.5f, 0.f);
+		}
+		glVertex2f((GLfloat) width, (GLfloat) height + (screenH - height));
+
+		
+		if (type != QUAD_BLOOM_EXTRACT){
+			glMultiTexCoord2fARB(GL_TEXTURE0_ARB, (GLfloat) width, (GLfloat) height);
+		} else {
+			glMultiTexCoord2fARB(GL_TEXTURE0_ARB, (GLfloat) width * 2.0f, (GLfloat) height * 2.0f);
+		}
+		if (type == QUAD_NOISE){
+			glMultiTexCoord2fARB(GL_TEXTURE1_ARB,
+									screenRatio * noiseTextureScale + noiseX,
+									noiseTextureScale + noiseY);
+		} else if (type == QUAD_BLOOM_COMBINE){
+			glMultiTexCoord2fARB(GL_TEXTURE1_ARB, (GLfloat) width * 0.5f, (GLfloat) height * 0.5f);
+		}
+		glVertex2f((GLfloat) width, (GLfloat) screenH - height);
+	glEnd();
+#endif
+}
+
+void LLPostProcess::viewOrthogonal(unsigned int width, unsigned int height)
+{
+	glMatrixMode(GL_PROJECTION);
+	glPushMatrix();
+	glLoadIdentity();
+	glOrtho( 0.f, (GLdouble) width , (GLdouble) height , 0.f, -1.f, 1.f );
+	glMatrixMode(GL_MODELVIEW);
+	glPushMatrix();
+	glLoadIdentity();
+}
+
+void LLPostProcess::viewPerspective(void)
+{
+	glMatrixMode( GL_PROJECTION );
+	glPopMatrix();
+	glMatrixMode( GL_MODELVIEW );
+	glPopMatrix();
+}
+
+void LLPostProcess::changeOrthogonal(unsigned int width, unsigned int height)
+{
+	viewPerspective();
+	viewOrthogonal(width, height);
+}
+
+void LLPostProcess::createTexture(GLuint & texture, unsigned int width, unsigned int height)
+{
+	if (texture != 0){
+		glDeleteTextures(1, &texture);
+	}
+
+	std::vector<GLubyte> data(width * height * 4, 0);
+
+	glGenTextures(1, &texture);
+	glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture);
+	glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, width, height, 0,
+		GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
+	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+}
+
+void LLPostProcess::createNoiseTexture(GLuint & texture)
+{
+	if (texture != 0){
+		glDeleteTextures(1, &texture);
+	}
+	glGenTextures(1, &texture);
+
+	std::vector<GLubyte> buffer(NOISE_SIZE * NOISE_SIZE);
+	for (unsigned int i = 0; i < NOISE_SIZE; i++){
+		for (unsigned int k = 0; k < NOISE_SIZE; k++){
+			buffer[(i * NOISE_SIZE) + k] = (GLubyte)((double) rand() / ((double) RAND_MAX + 1.f) * 255.f);
+		}
+	}
+	glBindTexture(GL_TEXTURE_2D, texture);
+	glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, NOISE_SIZE, NOISE_SIZE, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &buffer[0]);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+}
+
+bool LLPostProcess::checkError(void)
+{
+	GLenum glErr;
+    bool    retCode = false;
+
+    glErr = glGetError();
+    while (glErr != GL_NO_ERROR)
+    {
+		// shaderErrorLog << (const char *) gluErrorString(glErr) << std::endl;
+		char const * err_str_raw = (const char *) gluErrorString(glErr);
+
+		if(err_str_raw == NULL)
+		{
+			std::ostringstream err_builder;
+			err_builder << "unknown error number " << glErr;
+			mShaderErrorString = err_builder.str();
+		}
+		else
+		{
+			mShaderErrorString = err_str_raw;
+		}
+
+        retCode = true;
+        glErr = glGetError();
+    }
+    return retCode;
+}
+
+void LLPostProcess::checkShaderError(GLhandleARB shader)
+{
+    GLint infologLength = 0;
+    GLint charsWritten  = 0;
+    GLchar *infoLog;
+
+    checkError();  // Check for OpenGL errors
+
+    glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &infologLength);
+
+    checkError();  // Check for OpenGL errors
+
+    if (infologLength > 0)
+    {
+        infoLog = (GLchar *)malloc(infologLength);
+        if (infoLog == NULL)
+        {
+            /// Could not allocate infolog buffer
+            return;
+        }
+        glGetInfoLogARB(shader, infologLength, &charsWritten, infoLog);
+		// shaderErrorLog << (char *) infoLog << std::endl;
+		mShaderErrorString = (char *) infoLog;
+        free(infoLog);
+    }
+    checkError();  // Check for OpenGL errors
+}
diff --git a/indra/llrender/llpostprocess.h b/indra/llrender/llpostprocess.h
new file mode 100644
index 00000000000..b31333a28b7
--- /dev/null
+++ b/indra/llrender/llpostprocess.h
@@ -0,0 +1,268 @@
+/** 
+ * @file llpostprocess.h
+ * @brief LLPostProcess class definition
+ *
+ * $LicenseInfo:firstyear=2007&license=viewergpl$
+ * 
+ * Copyright (c) 2007-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_POSTPROCESS_H
+#define LL_POSTPROCESS_H
+
+#include <map>
+#include <fstream>
+#include "llgl.h"
+#include "llglheaders.h"
+
+class LLPostProcess 
+{
+public:
+
+	typedef enum _QuadType {
+		QUAD_NORMAL,
+		QUAD_NOISE,
+		QUAD_BLOOM_EXTRACT,
+		QUAD_BLOOM_COMBINE
+	} QuadType;
+
+	/// GLSL Shader Encapsulation Struct
+	typedef std::map<const char *, GLuint> glslUniforms;
+
+	struct PostProcessTweaks : public LLSD {
+		inline PostProcessTweaks() : LLSD(LLSD::emptyMap())
+		{
+		}
+
+		inline LLSD & brightMult() {
+			return (*this)["brightness_multiplier"];
+		}
+
+		inline LLSD & noiseStrength() {
+			return (*this)["noise_strength"];
+		}
+
+		inline LLSD & noiseSize() {
+			return (*this)["noise_size"];
+		}
+
+		inline LLSD & extractLow() {
+			return (*this)["extract_low"];
+		}
+
+		inline LLSD & extractHigh() {
+			return (*this)["extract_high"];
+		}
+
+		inline LLSD & bloomWidth() {
+			return (*this)["bloom_width"];
+		}
+
+		inline LLSD & bloomStrength() {
+			return (*this)["bloom_strength"];
+		}
+
+		inline LLSD & brightness() {
+			return (*this)["brightness"];
+		}
+
+		inline LLSD & contrast() {
+			return (*this)["contrast"];
+		}
+
+		inline LLSD & contrastBaseR() {
+			return (*this)["contrast_base"][0];
+		}
+
+		inline LLSD & contrastBaseG() {
+			return (*this)["contrast_base"][1];
+		}
+
+		inline LLSD & contrastBaseB() {
+			return (*this)["contrast_base"][2];
+		}
+
+		inline LLSD & contrastBaseIntensity() {
+			return (*this)["contrast_base"][3];
+		}
+
+		inline LLSD & saturation() {
+			return (*this)["saturation"];
+		}
+
+		inline LLSD & useNightVisionShader() {
+			return (*this)["enable_night_vision"];
+		}
+
+		inline LLSD & useBloomShader() {
+			return (*this)["enable_bloom"];
+		}
+
+		inline LLSD & useColorFilter() {
+			return (*this)["enable_color_filter"];
+		}
+
+
+		inline F32 getBrightMult() const {
+			return F32((*this)["brightness_multiplier"].asReal());
+		}
+
+		inline F32 getNoiseStrength() const {
+			return F32((*this)["noise_strength"].asReal());
+		}
+
+		inline F32 getNoiseSize() const {
+			return F32((*this)["noise_size"].asReal());
+		}
+
+		inline F32 getExtractLow() const {
+			return F32((*this)["extract_low"].asReal());
+		}
+
+		inline F32 getExtractHigh() const {
+			return F32((*this)["extract_high"].asReal());
+		}
+
+		inline F32 getBloomWidth() const {
+			return F32((*this)["bloom_width"].asReal());
+		}
+
+		inline F32 getBloomStrength() const {
+			return F32((*this)["bloom_strength"].asReal());
+		}
+
+		inline F32 getBrightness() const {
+			return F32((*this)["brightness"].asReal());
+		}
+
+		inline F32 getContrast() const {
+			return F32((*this)["contrast"].asReal());
+		}
+
+		inline F32 getContrastBaseR() const {
+			return F32((*this)["contrast_base"][0].asReal());
+		}
+
+		inline F32 getContrastBaseG() const {
+			return F32((*this)["contrast_base"][1].asReal());
+		}
+
+		inline F32 getContrastBaseB() const {
+			return F32((*this)["contrast_base"][2].asReal());
+		}
+
+		inline F32 getContrastBaseIntensity() const {
+			return F32((*this)["contrast_base"][3].asReal());
+		}
+
+		inline F32 getSaturation() const {
+			return F32((*this)["saturation"].asReal());
+		}
+
+	};
+	
+	GLuint sceneRenderTexture;
+	GLuint noiseTexture;
+	GLuint tempBloomTexture;
+	bool initialized;
+	PostProcessTweaks tweaks;
+
+	// the map of all availible effects
+	LLSD mAllEffects;
+
+public:
+	LLPostProcess(void);
+
+	~LLPostProcess(void);
+
+	void apply(unsigned int width, unsigned int height);
+
+	/// Perform global initialization for this class.
+	static void initClass(void);
+
+	// Cleanup of global data that's only inited once per class.
+	static void cleanupClass();
+
+	void setSelectedEffect(std::string const & effectName);
+
+	inline std::string const & getSelectedEffect(void) const {
+		return mSelectedEffectName;
+	}
+
+	void saveEffect(std::string const & effectName);
+
+private:
+		/// read in from file
+	std::string mShaderErrorString;
+	unsigned int screenW;
+	unsigned int screenH;
+
+	float noiseTextureScale;
+	
+	/// Shader Uniforms
+	glslUniforms nightVisionUniforms;
+	glslUniforms bloomExtractUniforms;
+	glslUniforms bloomBlurUniforms;
+	glslUniforms colorFilterUniforms;
+
+	// the name of currently selected effect in mAllEffects
+	// invariant: tweaks == mAllEffects[mSelectedEffectName]
+	std::string mSelectedEffectName;
+
+	/// General functions
+	void initialize(unsigned int width, unsigned int height);
+	void doEffects(void);
+	void applyShaders(void);
+	bool shadersEnabled(void);
+
+	/// Night Vision Functions
+	void createNightVisionShader(void);
+	void applyNightVisionShader(void);
+
+	/// Bloom Functions
+	void createBloomShader(void);
+	void applyBloomShader(void);
+
+	/// Color Filter Functions
+	void createColorFilterShader(void);
+	void applyColorFilterShader(void);
+
+	/// OpenGL Helper Functions
+	void getShaderUniforms(glslUniforms & uniforms, GLhandleARB & prog);
+	void createTexture(GLuint & texture, unsigned int width, unsigned int height);
+	void copyFrameBuffer(GLuint & texture, unsigned int width, unsigned int height);
+	void createNoiseTexture(GLuint & texture);
+	bool checkError(void);
+	void checkShaderError(GLhandleARB shader);
+	void drawOrthoQuad(unsigned int width, unsigned int height, QuadType type);
+	void viewOrthogonal(unsigned int width, unsigned int height);
+	void changeOrthogonal(unsigned int width, unsigned int height);
+	void viewPerspective(void);
+};
+
+extern LLPostProcess * gPostProcess;
+
+
+#endif // LL_POSTPROCESS_H
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 1168155f8b7..fc911de46bd 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -36,6 +36,12 @@
 
 LLRender gGL;
 
+// Handy copies of last good GL matrices
+F64	gGLModelView[16];
+F64	gGLLastModelView[16];
+F64 gGLProjection[16];
+S32	gGLViewport[4];
+
 static const U32 LL_NUM_TEXTURE_LAYERS = 8; 
 
 static GLenum sGLCompareFunc[] =
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index 2fa3237ef92..a0a492bc730 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -232,7 +232,10 @@ class LLRender
 	std::vector<LLTexUnit*> mTexUnits;
 };
 
-
+extern F64 gGLModelView[16];
+extern F64 gGLLastModelView[16];
+extern F64 gGLProjection[16];
+extern S32 gGLViewport[4];
 
 extern LLRender gGL;
 
diff --git a/indra/llrender/llrendersphere.cpp b/indra/llrender/llrendersphere.cpp
new file mode 100644
index 00000000000..296fa771842
--- /dev/null
+++ b/indra/llrender/llrendersphere.cpp
@@ -0,0 +1,159 @@
+/** 
+ * @file llrendersphere.cpp
+ * @brief implementation of the LLRenderSphere class.
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+//	Sphere creates a set of display lists that can then be called to create 
+//	a lit sphere at different LOD levels.  You only need one instance of sphere 
+//	per viewer - then call the appropriate list.  
+
+#include "linden_common.h"
+
+#include "llrendersphere.h"
+#include "llerror.h"
+
+#include "llglheaders.h"
+
+GLUquadricObj *gQuadObj2 = NULL;
+LLRenderSphere gSphere;
+
+void drawSolidSphere(GLdouble radius, GLint slices, GLint stacks);
+
+void drawSolidSphere(GLdouble radius, GLint slices, GLint stacks)
+{
+	if (!gQuadObj2)
+	{
+		gQuadObj2 = gluNewQuadric();
+		if (!gQuadObj2)
+		{
+			llwarns << "drawSolidSphere couldn't allocate quadric" << llendl;
+			return;
+		}
+	}
+
+	gluQuadricDrawStyle(gQuadObj2, GLU_FILL);
+	gluQuadricNormals(gQuadObj2, GLU_SMOOTH);
+	// If we ever changed/used the texture or orientation state
+	// of quadObj, we'd need to change it to the defaults here
+	// with gluQuadricTexture and/or gluQuadricOrientation.
+	gluQuadricTexture(gQuadObj2, GL_TRUE);
+	gluSphere(gQuadObj2, radius, slices, stacks);
+}
+
+
+// lat = 0 is Z-axis
+// lon = 0, lat = 90 at X-axis
+void lat2xyz(LLVector3 * result, F32 lat, F32 lon)
+{
+	// Convert a latitude and longitude to x,y,z on a normal sphere and return it in result
+	F32 r;
+	result->mV[VX] = (F32) (cos(lon * DEG_TO_RAD) * sin(lat * DEG_TO_RAD));
+	result->mV[VY] = (F32) (sin(lon * DEG_TO_RAD) * sin(lat * DEG_TO_RAD));
+	r = (F32) pow(result->mV[VX] * result->mV[VX] + result->mV[VY] * result->mV[VY], 0.5f);
+	if (r == 1.0f) 
+	{
+		result->mV[VZ] = 0.0f;
+	}
+	else
+	{
+		result->mV[VZ] = (F32) pow(1 - r*r, 0.5f);
+		if (lat > 90.01)
+		{
+			result->mV[VZ] *= -1.0;
+		}
+	}
+}
+
+void lat2xyz_rad(LLVector3 * result, F32 lat, F32 lon)
+{
+	// Convert a latitude and longitude to x,y,z on a normal sphere and return it in result
+	F32 r;
+	result->mV[VX] = (F32) (cos(lon) * sin(lat));
+	result->mV[VY] = (F32) (sin(lon) * sin(lat));
+	r = (F32) pow(result->mV[VX] * result->mV[VX] + result->mV[VY] * result->mV[VY], 0.5f);
+	if (r == 1.0f) 
+		result->mV[VZ] = 0.0f;
+	else
+	{
+		result->mV[VZ] = (F32) pow(1 - r*r, 0.5f);
+		if (lat > F_PI_BY_TWO) result->mV[VZ] *= -1.0;
+	}
+}
+
+// A couple thoughts on sphere drawing:
+// 1) You need more slices than stacks, but little less than 2:1
+// 2) At low LOD, setting stacks to an odd number avoids a "band" around the equator, making things look smoother
+void LLRenderSphere::prerender()
+{
+	//  Create a series of display lists for different LODs
+	mDList[0] = glGenLists(1);
+	glNewList(mDList[0], GL_COMPILE);
+	drawSolidSphere(1.0, 30, 20);
+	glEndList();
+
+	mDList[1] = glGenLists(1);
+	glNewList(mDList[1], GL_COMPILE);
+	drawSolidSphere(1.0, 20, 15);
+	glEndList();
+
+	mDList[2] = glGenLists(1);
+	glNewList(mDList[2], GL_COMPILE);
+	drawSolidSphere(1.0, 12, 8);
+	glEndList();
+
+	mDList[3] = glGenLists(1);
+	glNewList(mDList[3], GL_COMPILE);
+	drawSolidSphere(1.0, 8, 5);
+	glEndList();
+}
+
+void LLRenderSphere::cleanupGL()
+{
+	for (S32 detail = 0; detail < 4; detail++)
+	{
+		glDeleteLists(mDList[detail], 1);
+		mDList[detail] = 0;
+	}
+	
+	if (gQuadObj2)
+	{
+		gluDeleteQuadric(gQuadObj2);
+		gQuadObj2 = NULL;
+	}
+}
+
+// Constants here are empirically derived from my eyeballs, JNC
+//
+// The toughest adjustment is the cutoff for the lowest LOD
+// Maybe we should have more LODs at the low end?
+void LLRenderSphere::render(F32 pixel_area)
+{
+	S32 level_of_detail;
+
+	if (pixel_area > 10000.f)
+	{
+		level_of_detail = 0;
+	}
+	else if (pixel_area > 800.f)
+	{
+		level_of_detail = 1;
+	}
+	else if (pixel_area > 100.f)
+	{
+		level_of_detail = 2;
+	}
+	else
+	{
+		level_of_detail = 3;
+	}
+	glCallList(mDList[level_of_detail]);
+}
+
+
+void LLRenderSphere::render()
+{
+	glCallList(mDList[0]);
+}
diff --git a/indra/llrender/llrendersphere.h b/indra/llrender/llrendersphere.h
new file mode 100644
index 00000000000..3e58f6fb31c
--- /dev/null
+++ b/indra/llrender/llrendersphere.h
@@ -0,0 +1,34 @@
+/** 
+ * @file llrendersphere.h
+ * @brief interface for the LLRenderSphere class.
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLRENDERSPHERE_H
+#define LL_LLRENDERSPHERE_H
+
+#include "llmath.h"
+#include "v3math.h"
+#include "v4math.h"
+#include "m3math.h"
+#include "m4math.h"
+#include "v4color.h"
+#include "llgl.h"
+
+void lat2xyz(LLVector3 * result, F32 lat, F32 lon);			// utility routine
+
+class LLRenderSphere  
+{
+public:
+	LLGLuint	mDList[5];
+
+	void prerender();
+	void cleanupGL();
+	void render(F32 pixel_area);		// of a box of size 1.0 at that position
+	void render();						// render at highest LOD
+};
+
+extern LLRenderSphere gSphere;
+#endif
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
new file mode 100644
index 00000000000..3bdc36c6773
--- /dev/null
+++ b/indra/llrender/llshadermgr.cpp
@@ -0,0 +1,513 @@
+/** 
+ * @file llshadermgr.cpp
+ * @brief Shader manager implementation.
+ *
+ * $LicenseInfo:firstyear=2005&license=viewergpl$
+ * 
+ * Copyright (c) 2005-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llshadermgr.h"
+
+#include "llfile.h"
+#include "llrender.h"
+
+#if LL_DARWIN
+#include "OpenGL/OpenGL.h"
+#endif
+
+#ifdef LL_RELEASE_FOR_DOWNLOAD
+#define UNIFORM_ERRS LL_WARNS_ONCE("Shader")
+#else
+#define UNIFORM_ERRS LL_ERRS("Shader")
+#endif
+
+// Lots of STL stuff in here, using namespace std to keep things more readable
+using std::vector;
+using std::pair;
+using std::make_pair;
+using std::string;
+
+LLShaderMgr * LLShaderMgr::sInstance = NULL;
+
+LLShaderMgr::LLShaderMgr()
+{
+}
+
+
+LLShaderMgr::~LLShaderMgr()
+{
+}
+
+// static
+LLShaderMgr * LLShaderMgr::instance()
+{
+	if(NULL == sInstance)
+	{
+		LL_ERRS("Shaders") << "LLShaderMgr should already have been instantiated by the application!" << LL_ENDL;
+	}
+
+	return sInstance;
+}
+
+BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
+{
+	llassert_always(shader != NULL);
+	LLShaderFeatures *features = & shader->mFeatures;
+	
+	//////////////////////////////////////
+	// Attach Vertex Shader Features First
+	//////////////////////////////////////
+	
+	// NOTE order of shader object attaching is VERY IMPORTANT!!!
+	if (features->calculatesAtmospherics)
+	{
+		if (!shader->attachObject("windlight/atmosphericsVarsV.glsl"))
+		{
+			return FALSE;
+		}
+	}
+
+	if (features->calculatesLighting)
+	{
+		if (!shader->attachObject("windlight/atmosphericsHelpersV.glsl"))
+		{
+			return FALSE;
+		}
+		
+		if (features->isSpecular)
+		{
+			if (!shader->attachObject("lighting/lightFuncSpecularV.glsl"))
+			{
+				return FALSE;
+			}
+			
+			if (!shader->attachObject("lighting/sumLightsSpecularV.glsl"))
+			{
+				return FALSE;
+			}
+			
+			if (!shader->attachObject("lighting/lightSpecularV.glsl"))
+			{
+				return FALSE;
+			}
+		}
+		else 
+		{
+			if (!shader->attachObject("lighting/lightFuncV.glsl"))
+			{
+				return FALSE;
+			}
+			
+			if (!shader->attachObject("lighting/sumLightsV.glsl"))
+			{
+				return FALSE;
+			}
+			
+			if (!shader->attachObject("lighting/lightV.glsl"))
+			{
+				return FALSE;
+			}
+		}
+	}
+	
+	// NOTE order of shader object attaching is VERY IMPORTANT!!!
+	if (features->calculatesAtmospherics)
+	{
+		if (!shader->attachObject("windlight/atmosphericsV.glsl"))
+		{
+			return FALSE;
+		}
+	}
+
+	if (features->hasSkinning)
+	{
+		if (!shader->attachObject("avatar/avatarSkinV.glsl"))
+		{
+			return FALSE;
+		}
+	}
+	
+	///////////////////////////////////////
+	// Attach Fragment Shader Features Next
+	///////////////////////////////////////
+
+	if(features->calculatesAtmospherics)
+	{
+		if (!shader->attachObject("windlight/atmosphericsVarsF.glsl"))
+		{
+			return FALSE;
+		}
+	}
+
+	// NOTE order of shader object attaching is VERY IMPORTANT!!!
+	if (features->hasGamma)
+	{
+		if (!shader->attachObject("windlight/gammaF.glsl"))
+		{
+			return FALSE;
+		}
+	}
+	
+	if (features->hasAtmospherics)
+	{
+		if (!shader->attachObject("windlight/atmosphericsF.glsl"))
+		{
+			return FALSE;
+		}
+	}
+	
+	if (features->hasTransport)
+	{
+		if (!shader->attachObject("windlight/transportF.glsl"))
+		{
+			return FALSE;
+		}
+
+		// Test hasFullbright and hasShiny and attach fullbright and 
+		// fullbright shiny atmos transport if we split them out.
+	}
+
+	// NOTE order of shader object attaching is VERY IMPORTANT!!!
+	if (features->hasWaterFog)
+	{
+		if (!shader->attachObject("environment/waterFogF.glsl"))
+		{
+			return FALSE;
+		}
+	}
+	
+	if (features->hasLighting)
+	{
+	
+		if (features->hasWaterFog)
+		{
+			if (!shader->attachObject("lighting/lightWaterF.glsl"))
+			{
+				return FALSE;
+			}
+		}
+		
+		else
+		{
+			if (!shader->attachObject("lighting/lightF.glsl"))
+			{
+				return FALSE;
+			}
+		}		
+	}
+	
+	// NOTE order of shader object attaching is VERY IMPORTANT!!!
+	else if (features->isFullbright)
+	{
+	
+		if (features->hasWaterFog)
+		{
+			if (!shader->attachObject("lighting/lightFullbrightWaterF.glsl"))
+			{
+				return FALSE;
+			}
+		}
+		
+		else if (features->isShiny)
+		{
+			if (!shader->attachObject("lighting/lightFullbrightShinyF.glsl"))
+			{
+				return FALSE;
+			}
+		}
+		
+		else
+		{
+			if (!shader->attachObject("lighting/lightFullbrightF.glsl"))
+			{
+				return FALSE;
+			}
+		}
+	}
+
+	// NOTE order of shader object attaching is VERY IMPORTANT!!!
+	else if (features->isShiny)
+	{
+	
+		if (features->hasWaterFog)
+		{
+			if (!shader->attachObject("lighting/lightShinyWaterF.glsl"))
+			{
+				return FALSE;
+			}
+		}
+		
+		else 
+		{
+			if (!shader->attachObject("lighting/lightShinyF.glsl"))
+			{
+				return FALSE;
+			}
+		}
+	}
+	return TRUE;
+}
+
+//============================================================================
+// Load Shader
+
+static std::string get_object_log(GLhandleARB ret)
+{
+	std::string res;
+	
+	//get log length 
+	GLint length;
+	glGetObjectParameterivARB(ret, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
+	if (length > 0)
+	{
+		//the log could be any size, so allocate appropriately
+		GLcharARB* log = new GLcharARB[length];
+		glGetInfoLogARB(ret, length, &length, log);
+		res = std::string((char *)log);
+		delete[] log;
+	}
+	return res;
+}
+
+void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns) 
+{
+	std::string log = get_object_log(ret);
+	if ( log.length() > 0 )
+	{
+		if (warns)
+		{
+			LL_WARNS("ShaderLoading") << log << LL_ENDL;
+		}
+		else
+		{
+			LL_DEBUGS("ShaderLoading") << log << LL_ENDL;
+		}
+}
+}
+
+GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type)
+{
+	GLenum error;
+	error = glGetError();
+	if (error != GL_NO_ERROR)
+	{
+		LL_WARNS("ShaderLoading") << "GL ERROR entering loadShaderFile(): " << error << LL_ENDL;
+	}
+	
+	LL_DEBUGS("ShaderLoading") << "Loading shader file: " << filename << " class " << shader_level << LL_ENDL;
+
+	if (filename.empty()) 
+	{
+		return 0;
+	}
+
+
+	//read in from file
+	LLFILE* file = NULL;
+
+	S32 try_gpu_class = shader_level;
+	S32 gpu_class;
+
+	//find the most relevant file
+	for (gpu_class = try_gpu_class; gpu_class > 0; gpu_class--)
+	{	//search from the current gpu class down to class 1 to find the most relevant shader
+		std::stringstream fname;
+		fname << getShaderDirPrefix();
+		fname << gpu_class << "/" << filename;
+		
+ 		LL_DEBUGS("ShaderLoading") << "Looking in " << fname.str() << LL_ENDL;
+		file = LLFile::fopen(fname.str(), "r");		/* Flawfinder: ignore */
+		if (file)
+		{
+			LL_INFOS("ShaderLoading") << "Loading file: shaders/class" << gpu_class << "/" << filename << " (Want class " << gpu_class << ")" << LL_ENDL;
+			break; // done
+		}
+	}
+	
+	if (file == NULL)
+	{
+		LL_WARNS("ShaderLoading") << "GLSL Shader file not found: " << filename << LL_ENDL;
+		return 0;
+	}
+
+	//we can't have any lines longer than 1024 characters 
+	//or any shaders longer than 1024 lines... deal - DaveP
+	GLcharARB buff[1024];
+	GLcharARB* text[1024];
+	GLuint count = 0;
+
+
+	//copy file into memory
+	while(fgets((char *)buff, 1024, file) != NULL && count < (sizeof(buff)/sizeof(buff[0]))) 
+	{
+		text[count++] = (GLcharARB *)strdup((char *)buff); 
+	}
+	fclose(file);
+
+	//create shader object
+	GLhandleARB ret = glCreateShaderObjectARB(type);
+	error = glGetError();
+	if (error != GL_NO_ERROR)
+	{
+		LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShaderObjectARB: " << error << LL_ENDL;
+	}
+	else
+	{
+		//load source
+		glShaderSourceARB(ret, count, (const GLcharARB**) text, NULL);
+		error = glGetError();
+		if (error != GL_NO_ERROR)
+		{
+			LL_WARNS("ShaderLoading") << "GL ERROR in glShaderSourceARB: " << error << LL_ENDL;
+		}
+		else
+		{
+			//compile source
+			glCompileShaderARB(ret);
+			error = glGetError();
+			if (error != GL_NO_ERROR)
+			{
+				LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << LL_ENDL;
+			}
+		}
+	}
+	//free memory
+	for (GLuint i = 0; i < count; i++)
+	{
+		free(text[i]);
+	}
+	if (error == GL_NO_ERROR)
+	{
+		//check for errors
+		GLint success = GL_TRUE;
+		glGetObjectParameterivARB(ret, GL_OBJECT_COMPILE_STATUS_ARB, &success);
+		error = glGetError();
+		if (error != GL_NO_ERROR || success == GL_FALSE) 
+		{
+			//an error occured, print log
+			LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL;
+			dumpObjectLog(ret);
+			ret = 0;
+		}
+	}
+	else
+	{
+		ret = 0;
+	}
+	stop_glerror();
+
+	//successfully loaded, save results
+	if (ret)
+	{
+		// Add shader file to map
+		mShaderObjects[filename] = ret;
+		shader_level = try_gpu_class;
+	}
+	else
+	{
+		if (shader_level > 1)
+		{
+			shader_level--;
+			return loadShaderFile(filename,shader_level,type);
+		}
+		LL_WARNS("ShaderLoading") << "Failed to load " << filename << LL_ENDL;	
+	}
+	return ret;
+}
+
+BOOL LLShaderMgr::linkProgramObject(GLhandleARB obj, BOOL suppress_errors) 
+{
+	//check for errors
+	glLinkProgramARB(obj);
+	GLint success = GL_TRUE;
+	glGetObjectParameterivARB(obj, GL_OBJECT_LINK_STATUS_ARB, &success);
+	if (!suppress_errors && success == GL_FALSE) 
+	{
+		//an error occured, print log
+		LL_WARNS("ShaderLoading") << "GLSL Linker Error:" << LL_ENDL;
+	}
+
+// NOTE: Removing LL_DARWIN block as it doesn't seem to actually give the correct answer, 
+// but want it for reference once I move it.
+#if 0
+	// Force an evaluation of the gl state so the driver can tell if the shader will run in hardware or software
+	// per Apple's suggestion   
+	glBegin(gGL.mMode);
+	glEnd();
+
+	// Query whether the shader can or cannot run in hardware
+	// http://developer.apple.com/qa/qa2007/qa1502.html
+	long vertexGPUProcessing;
+	CGLContextObj ctx = CGLGetCurrentContext();
+	CGLGetParameter (ctx, kCGLCPGPUVertexProcessing, &vertexGPUProcessing);	
+	long fragmentGPUProcessing;
+	CGLGetParameter (ctx, kCGLCPGPUFragmentProcessing, &fragmentGPUProcessing);
+	if (!fragmentGPUProcessing || !vertexGPUProcessing)
+	{
+		LL_WARNS("ShaderLoading") << "GLSL Linker: Running in Software:" << LL_ENDL;
+		success = GL_FALSE;
+		suppress_errors = FALSE;		
+	}
+	
+#else
+	std::string log = get_object_log(obj);
+	LLStringUtil::toLower(log);
+	if (log.find("software") != std::string::npos)
+	{
+		LL_WARNS("ShaderLoading") << "GLSL Linker: Running in Software:" << LL_ENDL;
+		success = GL_FALSE;
+		suppress_errors = FALSE;
+	}
+#endif
+	if (!suppress_errors)
+	{
+        dumpObjectLog(obj, !success);
+	}
+
+	return success;
+}
+
+BOOL LLShaderMgr::validateProgramObject(GLhandleARB obj)
+{
+	//check program validity against current GL
+	glValidateProgramARB(obj);
+	GLint success = GL_TRUE;
+	glGetObjectParameterivARB(obj, GL_OBJECT_VALIDATE_STATUS_ARB, &success);
+	if (success == GL_FALSE)
+	{
+		LL_WARNS("ShaderLoading") << "GLSL program not valid: " << LL_ENDL;
+		dumpObjectLog(obj);
+	}
+	else
+	{
+		dumpObjectLog(obj, FALSE);
+	}
+
+	return success;
+}
+
diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h
new file mode 100644
index 00000000000..09b9ca812e7
--- /dev/null
+++ b/indra/llrender/llshadermgr.h
@@ -0,0 +1,75 @@
+/** 
+ * @file llshadermgr.h
+ * @brief Shader Manager
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2008, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_SHADERMGR_H
+#define LL_SHADERMGR_H
+
+#include "llgl.h"
+#include "llglslshader.h"
+
+class LLShaderMgr
+{
+public:
+	LLShaderMgr();
+	virtual ~LLShaderMgr();
+
+	// singleton pattern implementation
+	static LLShaderMgr * instance();
+
+	BOOL attachShaderFeatures(LLGLSLShader * shader);
+	void dumpObjectLog(GLhandleARB ret, BOOL warns = TRUE);
+	BOOL	linkProgramObject(GLhandleARB obj, BOOL suppress_errors = FALSE);
+	BOOL	validateProgramObject(GLhandleARB obj);
+	GLhandleARB loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type);
+
+	// Implemented in the application to actually point to the shader directory.
+	virtual std::string getShaderDirPrefix(void) = 0; // Pure Virtual
+
+	// Implemented in the application to actually update out of date uniforms for a particular shader
+	virtual void updateShaderUniforms(LLGLSLShader * shader) = 0; // Pure Virtual
+
+public:
+	// Map of shader names to compiled
+	std::map<std::string, GLhandleARB> mShaderObjects;
+
+	//global (reserved slot) shader parameters
+	std::vector<std::string> mReservedAttribs;
+
+	std::vector<std::string> mReservedUniforms;
+
+protected:
+
+	// our parameter manager singleton instance
+	static LLShaderMgr * sInstance;
+
+}; //LLShaderMgr
+
+#endif
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index 2b5f4e200b1..45f501fe1e7 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -41,6 +41,7 @@
 #include "llmemory.h"
 #include <set>
 #include <vector>
+#include <list>
 
 //============================================================================
 // NOTES
diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt
index acfeb6484f6..95e315f38e1 100644
--- a/indra/llwindow/CMakeLists.txt
+++ b/indra/llwindow/CMakeLists.txt
@@ -45,16 +45,11 @@ set(llwindows_HEADER_FILES
     )
 
 set(viewer_SOURCE_FILES
-    llgl.cpp
     llwindow.cpp
     )
 
 set(viewer_HEADER_FILES
-    llgl.h
     llwindow.h
-    llglheaders.h
-    llglstates.h
-    llgltypes.h
     llpreeditor.h
     llmousehandler.h
     )
@@ -123,21 +118,10 @@ if (SERVER AND NOT WINDOWS AND NOT DARWIN)
   set(server_HEADER_FILES
        llwindowmesaheadless.h
        )
-  set(copied_SOURCES
-      llgl
+  copy_server_sources(
       llwindow
       )
 
-  foreach (PREFIX ${copied_SOURCES})
-    add_custom_command(
-        OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${PREFIX}_server.cpp
-        COMMAND ${CMAKE_COMMAND}
-        ARGS -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${PREFIX}.cpp
-             ${CMAKE_CURRENT_BINARY_DIR}/${PREFIX}_server.cpp
-        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${PREFIX}.cpp
-        )
-    list(APPEND server_SOURCE_FILES ${PREFIX}_server.cpp)
-  endforeach (PREFIX ${copied_SOURCES})
 
   set_source_files_properties(
     ${server_SOURCE_FILES}
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index a1515abf9d1..46fb6a62465 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -85,7 +85,6 @@ set(viewer_SOURCE_FILES
     llconfirmationmanager.cpp
     llconsole.cpp
     llcontainerview.cpp
-    llcubemap.cpp
     llcurrencyuimanager.cpp
     llcylinder.cpp
     lldebugmessagebox.cpp
@@ -196,7 +195,6 @@ set(viewer_SOURCE_FILES
     llgesturemgr.cpp
     llgivemoney.cpp
     llglsandbox.cpp
-    llglslshader.cpp
     llgroupmgr.cpp
     llgroupnotify.cpp
     llhoverview.cpp
@@ -285,7 +283,6 @@ set(viewer_SOURCE_FILES
     llpatchvertexarray.cpp
     llpolymesh.cpp
     llpolymorph.cpp
-    llpostprocess.cpp
     llprefschat.cpp
     llprefsim.cpp
     llprefsvoice.cpp
@@ -299,7 +296,6 @@ set(viewer_SOURCE_FILES
     llpreviewtexture.cpp
     llprogressview.cpp
     llregionposition.cpp
-    llrendersphere.cpp
     llremoteparcelrequest.cpp
     llsavedsettingsglue.cpp
     llselectmgr.cpp
@@ -385,6 +381,7 @@ set(viewer_SOURCE_FILES
     llviewerpartsim.cpp
     llviewerpartsource.cpp
     llviewerregion.cpp
+    llviewershadermgr.cpp
     llviewerstats.cpp
     llviewertexteditor.cpp
     llviewertextureanim.cpp
@@ -475,7 +472,6 @@ set(viewer_HEADER_FILES
     llconfirmationmanager.h
     llconsole.h
     llcontainerview.h
-    llcubemap.h
     llcurrencyuimanager.h
     llcylinder.h
     lldebugmessagebox.h
@@ -586,7 +582,6 @@ set(viewer_HEADER_FILES
     llgenepool.h
     llgesturemgr.h
     llgivemoney.h
-    llglslshader.h
     llgroupmgr.h
     llgroupnotify.h
     llhoverview.h
@@ -674,7 +669,6 @@ set(viewer_HEADER_FILES
     llpanelweb.h
     llparcelselection.h
     llpatchvertexarray.h
-    llpostprocess.h
     llpolymesh.h
     llpolymorph.h
     llprefschat.h
@@ -691,7 +685,6 @@ set(viewer_HEADER_FILES
     llprogressview.h
     llregionposition.h
     llremoteparcelrequest.h
-    llrendersphere.h
     llresourcedata.h
     llsavedsettingsglue.h
     llselectmgr.h
@@ -778,6 +771,7 @@ set(viewer_HEADER_FILES
     llviewerpartsource.h
     llviewerprecompiledheaders.h
     llviewerregion.h
+    llviewershadermgr.h
     llviewerstats.h
     llviewertexteditor.h
     llviewertextureanim.h
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index c040dae469b..30634a3f2c0 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -408,7 +408,7 @@ bool handleCrashSubmitBehaviorChanged(const LLSD& newvalue)
 	else if(gSavedSettings.getBOOL("WatchdogEnabled") == TRUE)
 	{
 		// Don't re-enable the watchdog when we change the setting; this may get called before it's started
-// 		LLWatchdog::getInstance()->init();		
+// 		LLWatchdog::getInstance()->init();
 	}
 	return true;
 }
@@ -459,6 +459,8 @@ static void settings_to_globals()
 	gMiniMapScale = gSavedSettings.getF32("MiniMapScale");
 	gHandleKeysAsync = gSavedSettings.getBOOL("AsyncKeyboard");
 	LLHoverView::sShowHoverTips = gSavedSettings.getBOOL("ShowHoverTips");
+
+	LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap");
 }
 
 static void settings_modify()
@@ -2225,7 +2227,7 @@ void LLAppViewer::writeSystemInfo()
 	gDebugInfo["RAMInfo"]["Physical"] = (LLSD::Integer)(gSysMemory.getPhysicalMemoryKB());
 	gDebugInfo["RAMInfo"]["Allocated"] = (LLSD::Integer)(gMemoryAllocated>>10); // MB -> KB
 	gDebugInfo["OSInfo"] = getOSInfo().getOSStringSimple();
-
+		
 	// The user is not logged on yet, but record the current grid choice login url
 	// which may have been the intended grid. This can b
 	gDebugInfo["GridName"] = LLViewerLogin::getInstance()->getGridLabel();
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index fe2c2041ae4..e7c89035619 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -49,7 +49,7 @@
 #include "llviewerobjectlist.h" // For debugging
 #include "llviewerwindow.h"
 #include "pipeline.h"
-#include "llglslshader.h"
+#include "llviewershadermgr.h"
 #include "llviewerregion.h"
 #include "lldrawpoolwater.h"
 #include "llspatialpartition.h"
@@ -72,7 +72,7 @@ LLDrawPoolAlpha::~LLDrawPoolAlpha()
 
 void LLDrawPoolAlpha::prerender()
 {
-	mVertexShaderLevel = LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_OBJECT);
+	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
 }
 
 void LLDrawPoolAlpha::beginRenderPass(S32 pass)
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 04a7cfd8a0f..422c0dc9a87 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -45,7 +45,7 @@
 #include "llviewerregion.h"
 #include "noise.h"
 #include "pipeline.h"
-#include "llglslshader.h"
+#include "llviewershadermgr.h"
 #include "llappviewer.h"
 
 static U32 sDataMask = LLDrawPoolAvatar::VERTEX_DATA_MASK;
@@ -107,12 +107,12 @@ BOOL gRenderAvatar = TRUE;
 S32 LLDrawPoolAvatar::getVertexShaderLevel() const
 {
 	return sShaderLevel;
-	//return (S32) LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_AVATAR);
+	//return (S32) LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR);
 }
 
 void LLDrawPoolAvatar::prerender()
 {
-	mVertexShaderLevel = LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_AVATAR);
+	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR);
 	sShaderLevel = mVertexShaderLevel;
 	
 	if (sShaderLevel > 0)
@@ -289,16 +289,16 @@ void LLDrawPoolAvatar::beginSkinned()
 		sVertexProgram->bind();
 		if (sShaderLevel >= SHADER_LEVEL_CLOTH)
 		{
-			enable_cloth_weights(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_CLOTHING]);
+			enable_cloth_weights(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_CLOTHING]);
 		}
-		enable_vertex_weighting(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_WEIGHT]);
+		enable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
 
 		if (sShaderLevel >= SHADER_LEVEL_BUMP)
 		{
-			enable_binormals(sVertexProgram->mAttribute[LLShaderMgr::BINORMAL]);
+			enable_binormals(sVertexProgram->mAttribute[LLViewerShaderMgr::BINORMAL]);
 		}
 		
-		sVertexProgram->enableTexture(LLShaderMgr::BUMP_MAP);
+		sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
 		gGL.getTexUnit(0)->activate();
 	}
 	else
@@ -318,16 +318,16 @@ void LLDrawPoolAvatar::endSkinned()
 	if (sShaderLevel > 0)
 	{
 		sRenderingSkinned = FALSE;
-		sVertexProgram->disableTexture(LLShaderMgr::BUMP_MAP);
+		sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP);
 		gGL.getTexUnit(0)->activate();
-		disable_vertex_weighting(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_WEIGHT]);
+		disable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
 		if (sShaderLevel >= SHADER_LEVEL_BUMP)
 		{
-			disable_binormals(sVertexProgram->mAttribute[LLShaderMgr::BINORMAL]);
+			disable_binormals(sVertexProgram->mAttribute[LLViewerShaderMgr::BINORMAL]);
 		}
 		if ((sShaderLevel >= SHADER_LEVEL_CLOTH))
 		{
-			disable_cloth_weights(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_CLOTHING]);
+			disable_cloth_weights(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_CLOTHING]);
 		}
 
 		sVertexProgram->unbind();
@@ -466,7 +466,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 	
 	if (sShaderLevel > 0)
 	{
-		gAvatarMatrixParam = sVertexProgram->mUniform[LLShaderMgr::AVATAR_MATRIX];
+		gAvatarMatrixParam = sVertexProgram->mUniform[LLViewerShaderMgr::AVATAR_MATRIX];
 	}
     
 	if ((sShaderLevel >= SHADER_LEVEL_CLOTH))
@@ -482,16 +482,16 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 		wind = wind * rot_mat;
 		wind.mV[VW] = avatarp->mWindVec.mV[VW];
 
-		sVertexProgram->vertexAttrib4fv(LLShaderMgr::AVATAR_WIND, wind.mV);
+		sVertexProgram->vertexAttrib4fv(LLViewerShaderMgr::AVATAR_WIND, wind.mV);
 		F32 phase = -1.f * (avatarp->mRipplePhase);
 
 		F32 freq = 7.f + (noise1(avatarp->mRipplePhase) * 2.f);
 		LLVector4 sin_params(freq, freq, freq, phase);
-		sVertexProgram->vertexAttrib4fv(LLShaderMgr::AVATAR_SINWAVE, sin_params.mV);
+		sVertexProgram->vertexAttrib4fv(LLViewerShaderMgr::AVATAR_SINWAVE, sin_params.mV);
 
 		LLVector4 gravity(0.f, 0.f, -CLOTHING_GRAVITY_EFFECT, 0.f);
 		gravity = gravity * rot_mat;
-		sVertexProgram->vertexAttrib4fv(LLShaderMgr::AVATAR_GRAVITY, gravity.mV);
+		sVertexProgram->vertexAttrib4fv(LLViewerShaderMgr::AVATAR_GRAVITY, gravity.mV);
 	}
 
 	if( !single_avatar || (avatarp == single_avatar) )
@@ -611,7 +611,7 @@ void LLDrawPoolAvatar::renderForSelect()
 	sVertexProgram = &gAvatarPickProgram;
 	if (sShaderLevel > 0)
 	{
-		gAvatarMatrixParam = sVertexProgram->mUniform[LLShaderMgr::AVATAR_MATRIX];
+		gAvatarMatrixParam = sVertexProgram->mUniform[LLViewerShaderMgr::AVATAR_MATRIX];
 	}
 	gGL.setAlphaRejectSettings(LLRender::CF_GREATER_EQUAL, 0.2f);
 	gGL.setSceneBlendType(LLRender::BT_REPLACE);
@@ -622,7 +622,7 @@ void LLDrawPoolAvatar::renderForSelect()
 	{
 		sRenderingSkinned = TRUE;
 		sVertexProgram->bind();
-		enable_vertex_weighting(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_WEIGHT]);
+		enable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
 	}
 	
 	avatarp->renderSkinned(AVATAR_RENDER_PASS_SINGLE);
@@ -632,7 +632,7 @@ void LLDrawPoolAvatar::renderForSelect()
 	{
 		sRenderingSkinned = FALSE;
 		sVertexProgram->unbind();
-		disable_vertex_weighting(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_WEIGHT]);
+		disable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
 	}
 
 	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
@@ -670,7 +670,7 @@ LLColor3 LLDrawPoolAvatar::getDebugColor() const
 
 LLVertexBufferAvatar::LLVertexBufferAvatar()
 : LLVertexBuffer(sDataMask, 
-	LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_AVATAR) > 0 ?	
+	LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) > 0 ?	
 	GL_STATIC_DRAW_ARB : 
 	GL_STREAM_DRAW_ARB)
 {
@@ -692,16 +692,16 @@ void LLVertexBufferAvatar::setupVertexBuffer(U32 data_mask) const
 		glClientActiveTextureARB(GL_TEXTURE0_ARB);
 		glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD]));
 		
-		set_vertex_weights(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_WEIGHT], mStride, (F32*)(base + mOffsets[TYPE_WEIGHT]));
+		set_vertex_weights(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT], mStride, (F32*)(base + mOffsets[TYPE_WEIGHT]));
 
 		if (sShaderLevel >= LLDrawPoolAvatar::SHADER_LEVEL_BUMP)
 		{
-			set_binormals(sVertexProgram->mAttribute[LLShaderMgr::BINORMAL], mStride, (LLVector3*)(base + mOffsets[TYPE_BINORMAL]));
+			set_binormals(sVertexProgram->mAttribute[LLViewerShaderMgr::BINORMAL], mStride, (LLVector3*)(base + mOffsets[TYPE_BINORMAL]));
 		}
 	
 		if (sShaderLevel >= LLDrawPoolAvatar::SHADER_LEVEL_CLOTH)
 		{
-			set_vertex_clothing_weights(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_CLOTHING], mStride, (LLVector4*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
+			set_vertex_clothing_weights(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_CLOTHING], mStride, (LLVector4*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
 		}
 	}
 	else
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 56dc61c1a36..11391ee6fbd 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -53,7 +53,7 @@
 #include "llviewerimagelist.h"
 #include "pipeline.h"
 #include "llspatialpartition.h"
-#include "llglslshader.h"
+#include "llviewershadermgr.h"
 
 //#include "llimagebmp.h"
 //#include "../tools/imdebug/imdebug.h"
@@ -177,7 +177,7 @@ LLDrawPoolBump::LLDrawPoolBump()
 
 void LLDrawPoolBump::prerender()
 {
-	mVertexShaderLevel = LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_OBJECT);
+	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
 }
 
 // static
@@ -333,7 +333,7 @@ void LLDrawPoolBump::beginShiny(bool invisible)
 	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 	if( cube_map )
 	{
-		if (!invisible && LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_OBJECT) > 0 )
+		if (!invisible && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0 )
 		{
 			LLMatrix4 mat;
 			mat.initRows(LLVector4(gGLModelView+0),
@@ -343,23 +343,23 @@ void LLDrawPoolBump::beginShiny(bool invisible)
 			shader->bind();
 			LLVector3 vec = LLVector3(gShinyOrigin) * mat;
 			LLVector4 vec4(vec, gShinyOrigin.mV[3]);
-			shader->uniform4fv(LLShaderMgr::SHINY_ORIGIN, 1, vec4.mV);			
+			shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV);			
 			if (mVertexShaderLevel > 1)
 			{
 				cube_map->setMatrix(1);
 				// Make sure that texture coord generation happens for tex unit 1, as that's the one we use for 
 				// the cube map in the one pass shiny shaders
-				cube_channel = shader->enableTexture(LLShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB);
+				cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB);
 				cube_map->enableTexture(cube_channel);
 				cube_map->enableTextureCoords(1);
-				diffuse_channel = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
+				diffuse_channel = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 			}
 			else
 			{
 				cube_channel = 0;
 				diffuse_channel = -1;
 				cube_map->setMatrix(0);
-				cube_map->enable(shader->enableTexture(LLShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB));
+				cube_map->enable(shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB));
 			}			
 			cube_map->bind();
 		}
@@ -423,13 +423,13 @@ void LLDrawPoolBump::endShiny(bool invisible)
 
 		if (!invisible && mVertexShaderLevel > 1)
 		{
-			shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB);
+			shader->disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB);
 					
-			if (LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_OBJECT) > 0)
+			if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0)
 			{
 				if (diffuse_channel != 0)
 				{
-					shader->disableTexture(LLShaderMgr::DIFFUSE_MAP);
+					shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 				}
 			}
 
@@ -483,15 +483,15 @@ void LLDrawPoolBump::beginFullbrightShiny()
 		shader->bind();
 		LLVector3 vec = LLVector3(gShinyOrigin) * mat;
 		LLVector4 vec4(vec, gShinyOrigin.mV[3]);
-		shader->uniform4fv(LLShaderMgr::SHINY_ORIGIN, 1, vec4.mV);			
+		shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV);			
 
 		cube_map->setMatrix(1);
 		// Make sure that texture coord generation happens for tex unit 1, as that's the one we use for 
 		// the cube map in the one pass shiny shaders
-		cube_channel = shader->enableTexture(LLShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB);
+		cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB);
 		cube_map->enableTexture(cube_channel);
 		cube_map->enableTextureCoords(1);
-		diffuse_channel = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
+		diffuse_channel = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 
 		cube_map->bind();
 	}
@@ -531,7 +531,7 @@ void LLDrawPoolBump::endFullbrightShiny()
 
 		if (diffuse_channel != 0)
 		{
-			shader->disableTexture(LLShaderMgr::DIFFUSE_MAP);
+			shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 		}
 		gGL.getTexUnit(0)->activate();
 		glEnable(GL_TEXTURE_2D);
@@ -556,7 +556,7 @@ void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL
 	for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) 
 	{
 		LLDrawInfo& params = **k;
-			
+		
 		applyModelMatrix(params);
 
 		params.mVertexBuffer->setBuffer(mask);
diff --git a/indra/newview/lldrawpoolground.cpp b/indra/newview/lldrawpoolground.cpp
index 3500d9471f9..c7e8aa32b7f 100644
--- a/indra/newview/lldrawpoolground.cpp
+++ b/indra/newview/lldrawpoolground.cpp
@@ -44,7 +44,7 @@
 #include "pipeline.h"
 #include "llagent.h"
 #include "llviewerregion.h"
-#include "llglslshader.h"
+#include "llviewershadermgr.h"
 
 LLDrawPoolGround::LLDrawPoolGround() :
 	LLFacePool(POOL_GROUND)
@@ -58,7 +58,7 @@ LLDrawPool *LLDrawPoolGround::instancePool()
 
 void LLDrawPoolGround::prerender()
 {
-	mVertexShaderLevel = LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_ENVIRONMENT);
+	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT);
 }
 
 void LLDrawPoolGround::render(S32 pass)
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index b5348860479..2015535b304 100644
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -40,7 +40,7 @@
 #include "llsky.h"
 #include "pipeline.h"
 #include "llspatialpartition.h"
-#include "llglslshader.h"
+#include "llviewershadermgr.h"
 #include "llrender.h"
 
 
@@ -54,7 +54,7 @@ void LLDrawPoolGlow::render(S32 pass)
 	LLGLDisable test(GL_ALPHA_TEST);
 	gGL.setSceneBlendType(LLRender::BT_ADD);
 	
-	U32 shader_level = LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_OBJECT);
+	U32 shader_level = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
 
 	if (shader_level > 0 && fullbright_shader)
 	{
@@ -92,7 +92,7 @@ LLDrawPoolSimple::LLDrawPoolSimple() :
 
 void LLDrawPoolSimple::prerender()
 {
-	mVertexShaderLevel = LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_OBJECT);
+	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
 }
 
 void LLDrawPoolSimple::beginRenderPass(S32 pass)
@@ -113,7 +113,7 @@ void LLDrawPoolSimple::beginRenderPass(S32 pass)
 	if (mVertexShaderLevel > 0)
 	{
 		simple_shader->bind();
-		simple_shader->uniform1f(LLShaderMgr::FULLBRIGHT, 0.f);
+		simple_shader->uniform1f(LLViewerShaderMgr::FULLBRIGHT, 0.f);
 	}
 	else 
 	{
@@ -161,7 +161,7 @@ void LLDrawPoolSimple::render(S32 pass)
 		if (mVertexShaderLevel > 0)
 		{
 			fullbright_shader->bind();
-			fullbright_shader->uniform1f(LLShaderMgr::FULLBRIGHT, 1.f);
+			fullbright_shader->uniform1f(LLViewerShaderMgr::FULLBRIGHT, 1.f);
 		}
 		else
 		{
diff --git a/indra/newview/lldrawpoolsky.cpp b/indra/newview/lldrawpoolsky.cpp
index 585af6c47fd..2687e6d2c0b 100644
--- a/indra/newview/lldrawpoolsky.cpp
+++ b/indra/newview/lldrawpoolsky.cpp
@@ -46,7 +46,7 @@
 #include "llvosky.h"
 #include "llworld.h" // To get water height
 #include "pipeline.h"
-#include "llglslshader.h"
+#include "llviewershadermgr.h"
 
 LLDrawPoolSky::LLDrawPoolSky() :
 	LLFacePool(POOL_SKY), mShader(NULL)
@@ -60,7 +60,7 @@ LLDrawPool *LLDrawPoolSky::instancePool()
 
 void LLDrawPoolSky::prerender()
 {
-	mVertexShaderLevel = LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_ENVIRONMENT);
+	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT);
 	gSky.mVOSkyp->updateGeometry(gSky.mVOSkyp->mDrawable);
 }
 
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index 854067a32d8..e5850a00572 100644
--- a/indra/newview/lldrawpoolterrain.cpp
+++ b/indra/newview/lldrawpoolterrain.cpp
@@ -51,7 +51,7 @@
 #include "llviewerimagelist.h" // To get alpha gradients
 #include "llworld.h"
 #include "pipeline.h"
-#include "llglslshader.h"
+#include "llviewershadermgr.h"
 #include "llrender.h"
 
 const F32 DETAIL_SCALE = 1.f/16.f;
@@ -101,7 +101,7 @@ LLDrawPool *LLDrawPoolTerrain::instancePool()
 
 void LLDrawPoolTerrain::prerender()
 {
-	mVertexShaderLevel = LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_ENVIRONMENT);
+	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT);
 	if (mVertexShaderLevel > 0)
 	{
 		sDetailMode = 1;
@@ -239,7 +239,7 @@ void LLDrawPoolTerrain::renderFullShader()
 	//
 	// detail texture 0
 	//
-	S32 detail0 = sShader->enableTexture(LLShaderMgr::TERRAIN_DETAIL0);
+	S32 detail0 = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0);
 	LLViewerImage::bindTexture(detail_texture0p,detail0);
 	gGL.getTexUnit(0)->activate();
 
@@ -257,7 +257,7 @@ void LLDrawPoolTerrain::renderFullShader()
 	//
 	// detail texture 1
 	//
-	S32 detail1 = sShader->enableTexture(LLShaderMgr::TERRAIN_DETAIL1); 
+	S32 detail1 = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_DETAIL1); 
 	LLViewerImage::bindTexture(detail_texture1p,detail1);
 	
 	/// ALPHA TEXTURE COORDS 0:
@@ -268,7 +268,7 @@ void LLDrawPoolTerrain::renderFullShader()
 	
 	// detail texture 2
 	//
-	S32 detail2 = sShader->enableTexture(LLShaderMgr::TERRAIN_DETAIL2);
+	S32 detail2 = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_DETAIL2);
 	LLViewerImage::bindTexture(detail_texture2p,detail2);
 	glEnable(GL_TEXTURE_2D);
 	
@@ -282,7 +282,7 @@ void LLDrawPoolTerrain::renderFullShader()
 	//
 	// detail texture 3
 	//
-	S32 detail3 = sShader->enableTexture(LLShaderMgr::TERRAIN_DETAIL3);
+	S32 detail3 = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_DETAIL3);
 	LLViewerImage::bindTexture(detail_texture3p,detail3);
 	
 	/// ALPHA TEXTURE COORDS 2:
@@ -295,18 +295,18 @@ void LLDrawPoolTerrain::renderFullShader()
 	//
 	// Alpha Ramp 
 	//
-	S32 alpha_ramp = sShader->enableTexture(LLShaderMgr::TERRAIN_ALPHARAMP);
+	S32 alpha_ramp = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP);
 	LLViewerImage::bindTexture(m2DAlphaRampImagep,alpha_ramp);
 		
 	// GL_BLEND disabled by default
 	drawLoop();
 
 	// Disable multitexture
-	sShader->disableTexture(LLShaderMgr::TERRAIN_ALPHARAMP);
-	sShader->disableTexture(LLShaderMgr::TERRAIN_DETAIL0);
-	sShader->disableTexture(LLShaderMgr::TERRAIN_DETAIL1);
-	sShader->disableTexture(LLShaderMgr::TERRAIN_DETAIL2);
-	sShader->disableTexture(LLShaderMgr::TERRAIN_DETAIL3);
+	sShader->disableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP);
+	sShader->disableTexture(LLViewerShaderMgr::TERRAIN_DETAIL0);
+	sShader->disableTexture(LLViewerShaderMgr::TERRAIN_DETAIL1);
+	sShader->disableTexture(LLViewerShaderMgr::TERRAIN_DETAIL2);
+	sShader->disableTexture(LLViewerShaderMgr::TERRAIN_DETAIL3);
 
 	LLImageGL::unbindTexture(alpha_ramp, GL_TEXTURE_2D);
 	gGL.getTexUnit(4)->activate();
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index 1ebd0772a82..33f23ab6fa3 100644
--- a/indra/newview/lldrawpooltree.cpp
+++ b/indra/newview/lldrawpooltree.cpp
@@ -40,7 +40,7 @@
 #include "llvotree.h"
 #include "pipeline.h"
 #include "llviewercamera.h"
-#include "llglslshader.h"
+#include "llviewershadermgr.h"
 #include "llrender.h"
 
 S32 LLDrawPoolTree::sDiffTex = 0;
@@ -61,7 +61,7 @@ LLDrawPool *LLDrawPoolTree::instancePool()
 
 void LLDrawPoolTree::prerender()
 {
-	mVertexShaderLevel = LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_OBJECT);
+	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
 }
 
 void LLDrawPoolTree::beginRenderPass(S32 pass)
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index e76423c8eb3..f7770f001c6 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -51,7 +51,7 @@
 #include "llvowater.h"
 #include "llworld.h"
 #include "pipeline.h"
-#include "llglslshader.h"
+#include "llviewershadermgr.h"
 #include "llwaterparammanager.h"
 
 const LLUUID WATER_TEST("2bfd3884-7e27-69b9-ba3a-3e673f680004");
@@ -100,8 +100,8 @@ LLDrawPool *LLDrawPoolWater::instancePool()
 
 void LLDrawPoolWater::prerender()
 {
-	mVertexShaderLevel = (gGLManager.mHasCubeMap && LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap")) ?
-		LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_WATER) : 0;
+	mVertexShaderLevel = (gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps) ?
+		LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WATER) : 0;
 
 	// got rid of modulation by light color since it got a little too
 	// green at sunset and sl-57047 (underwater turns black at 8:00)
@@ -385,7 +385,7 @@ void LLDrawPoolWater::shade()
 
 	sTime = (F32)LLFrameTimer::getElapsedSeconds()*0.5f;
 	
-	S32 reftex = shader->enableTexture(LLShaderMgr::WATER_REFTEX);
+	S32 reftex = shader->enableTexture(LLViewerShaderMgr::WATER_REFTEX);
 		
 	if (reftex > -1)
 	{
@@ -395,7 +395,7 @@ void LLDrawPoolWater::shade()
 	}	
 
 	//bind normal map
-	S32 bumpTex = shader->enableTexture(LLShaderMgr::BUMP_MAP);
+	S32 bumpTex = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP);
 
 	LLWaterParamManager * param_mgr = LLWaterParamManager::instance();
 
@@ -410,15 +410,15 @@ void LLDrawPoolWater::shade()
 	mWaterNormp->setMipFilterNearest (mWaterNormp->getMipFilterNearest(),
 									  !gSavedSettings.getBOOL("RenderWaterMipNormal"));
 	
-	S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX);	
+	S32 screentex = shader->enableTexture(LLViewerShaderMgr::WATER_SCREENTEX);	
 	stop_glerror();
 	
 	shader->bind();
 
 	if (screentex > -1)
 	{
-		shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, sWaterFogColor.mV);
-		shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, 
+		shader->uniform4fv(LLViewerShaderMgr::WATER_FOGCOLOR, 1, sWaterFogColor.mV);
+		shader->uniform1f(LLViewerShaderMgr::WATER_FOGDENSITY, 
 			param_mgr->getFogDensity());
 	}
 	
@@ -427,7 +427,7 @@ void LLDrawPoolWater::shade()
 	if (mVertexShaderLevel == 1)
 	{
 		sWaterFogColor.mV[3] = param_mgr->mDensitySliderValue;
-		shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, sWaterFogColor.mV);
+		shader->uniform4fv(LLViewerShaderMgr::WATER_FOGCOLOR, 1, sWaterFogColor.mV);
 	}
 
 	F32 screenRes[] = 
@@ -438,7 +438,7 @@ void LLDrawPoolWater::shade()
 	shader->uniform2fv("screenRes", 1, screenRes);
 	stop_glerror();
 	
-	S32 diffTex = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
+	S32 diffTex = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 	stop_glerror();
 	
 	light_dir.normVec();
@@ -447,14 +447,14 @@ void LLDrawPoolWater::shade()
 	light_diffuse *= 6.f;
 
 	//shader->uniformMatrix4fv("inverse_ref", 1, GL_FALSE, (GLfloat*) gGLObliqueProjectionInverse.mMatrix);
-	shader->uniform1f(LLShaderMgr::WATER_WATERHEIGHT, eyedepth);
-	shader->uniform1f(LLShaderMgr::WATER_TIME, sTime);
-	shader->uniform3fv(LLShaderMgr::WATER_EYEVEC, 1, LLViewerCamera::getInstance()->getOrigin().mV);
-	shader->uniform3fv(LLShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV);
-	shader->uniform1f(LLShaderMgr::WATER_SPECULAR_EXP, light_exp);
-	shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, param_mgr->getWave1Dir().mV);
-	shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, param_mgr->getWave2Dir().mV);
-	shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV);
+	shader->uniform1f(LLViewerShaderMgr::WATER_WATERHEIGHT, eyedepth);
+	shader->uniform1f(LLViewerShaderMgr::WATER_TIME, sTime);
+	shader->uniform3fv(LLViewerShaderMgr::WATER_EYEVEC, 1, LLViewerCamera::getInstance()->getOrigin().mV);
+	shader->uniform3fv(LLViewerShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV);
+	shader->uniform1f(LLViewerShaderMgr::WATER_SPECULAR_EXP, light_exp);
+	shader->uniform2fv(LLViewerShaderMgr::WATER_WAVE_DIR1, 1, param_mgr->getWave1Dir().mV);
+	shader->uniform2fv(LLViewerShaderMgr::WATER_WAVE_DIR2, 1, param_mgr->getWave2Dir().mV);
+	shader->uniform3fv(LLViewerShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV);
 
 	shader->uniform3fv("normScale", 1, param_mgr->getNormalScale().mV);
 	shader->uniform1f("fresnelScale", param_mgr->getFresnelScale());
@@ -474,12 +474,12 @@ void LLDrawPoolWater::shade()
 	if (LLViewerCamera::getInstance()->cameraUnderWater())
 	{
 		water_color.setVec(1.f, 1.f, 1.f, 0.4f);
-		shader->uniform1f(LLShaderMgr::WATER_REFSCALE, param_mgr->getScaleBelow());
+		shader->uniform1f(LLViewerShaderMgr::WATER_REFSCALE, param_mgr->getScaleBelow());
 	}
 	else
 	{
 		water_color.setVec(1.f, 1.f, 1.f, 0.5f*(1.f + up_dot));
-		shader->uniform1f(LLShaderMgr::WATER_REFSCALE, param_mgr->getScaleAbove());
+		shader->uniform1f(LLViewerShaderMgr::WATER_REFSCALE, param_mgr->getScaleAbove());
 	}
 
 	if (water_color.mV[3] > 0.9f)
@@ -527,12 +527,12 @@ void LLDrawPoolWater::shade()
 		}
 	}
 	
-	shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB);
-	shader->disableTexture(LLShaderMgr::WATER_SCREENTEX);	
-	shader->disableTexture(LLShaderMgr::BUMP_MAP);
-	shader->disableTexture(LLShaderMgr::DIFFUSE_MAP);
-	shader->disableTexture(LLShaderMgr::WATER_REFTEX);
-	shader->disableTexture(LLShaderMgr::WATER_SCREENDEPTH);
+	shader->disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB);
+	shader->disableTexture(LLViewerShaderMgr::WATER_SCREENTEX);	
+	shader->disableTexture(LLViewerShaderMgr::BUMP_MAP);
+	shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	shader->disableTexture(LLViewerShaderMgr::WATER_REFTEX);
+	shader->disableTexture(LLViewerShaderMgr::WATER_SCREENDEPTH);
 	shader->unbind();
 
 	gGL.getTexUnit(0)->activate();
diff --git a/indra/newview/llhudrender.cpp b/indra/newview/llhudrender.cpp
index 0f83da82407..0668655ac33 100644
--- a/indra/newview/llhudrender.cpp
+++ b/indra/newview/llhudrender.cpp
@@ -33,6 +33,7 @@
 
 #include "llhudrender.h"
 
+#include "llrender.h"
 #include "llgl.h"
 #include "llviewercamera.h"
 #include "v3math.h"
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index a1a2c342225..5f6fcb70e3c 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -50,9 +50,6 @@
 #include "lltoolmgr.h"
 #include "llviewerjoystick.h"
 
-GLfloat gGLZFar;
-GLfloat gGLZNear;
-
 //glu pick matrix implementation borrowed from Mesa3D
 glh::matrix4f gl_pick_matrix(GLfloat x, GLfloat y, GLfloat width, GLfloat height, GLint* viewport)
 {
@@ -146,12 +143,6 @@ void LLViewerCamera::updateCameraLocation(const LLVector3 &center,
 	mScreenPixelArea =(S32)((F32)mViewHeightInPixels * ((F32)mViewHeightInPixels * mAspect));
 }
 
-// Handy copies of last good GL matrices
-F64	gGLModelView[16];
-F64	gGLLastModelView[16];
-F64 gGLProjection[16];
-S32	gGLViewport[4];
-
 const LLMatrix4 &LLViewerCamera::getProjection() const
 {
 	calcProjection(getFar());
@@ -343,9 +334,6 @@ void LLViewerCamera::setPerspective(BOOL for_selection,
 		gGLProjection[i] = proj_mat.m[i];
 	}
 
-	gGLZNear = z_near;
-	gGLZFar = z_far;
-
 	glMatrixMode( GL_MODELVIEW );
 
 	glh::matrix4f modelview((GLfloat*) OGL_TO_CFR_ROTATION);
diff --git a/indra/newview/llviewercamera.h b/indra/newview/llviewercamera.h
index a16f25ff813..cc37851d050 100644
--- a/indra/newview/llviewercamera.h
+++ b/indra/newview/llviewercamera.h
@@ -111,11 +111,4 @@ class LLViewerCamera : public LLCamera, public LLSingleton<LLViewerCamera>
 public:
 };
 
-extern F64 gGLModelView[16];
-extern F64 gGLLastModelView[16];
-extern F64 gGLProjection[16];
-extern S32 gGLViewport[4];
-extern F32 gGLZNear;
-extern F32 gGLZFar;
-
 #endif // LL_LLVIEWERCAMERA_H
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 422546c811f..f3acad35da4 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -43,7 +43,7 @@
 #include "lldrawpoolterrain.h"
 #include "llflexibleobject.h"
 #include "llfeaturemanager.h"
-#include "llglslshader.h"
+#include "llviewershadermgr.h"
 #include "llnetmap.h"
 #include "llpanelgeneral.h"
 #include "llpanelinput.h"
@@ -114,7 +114,7 @@ static bool handleTerrainDetailChanged(const LLSD& newvalue)
 
 static bool handleSetShaderChanged(const LLSD& newvalue)
 {
-	LLShaderMgr::setShaders();
+	LLViewerShaderMgr::instance()->setShaders();
 	return true;
 }
 
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index d4249ce1354..b2cf873a219 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -68,6 +68,7 @@
 #include "llspatialpartition.h"
 #include "llappviewer.h"
 #include "llstartup.h"
+#include "llviewershadermgr.h"
 #include "llfasttimer.h"
 #include "llfloatertools.h"
 #include "llviewerimagelist.h"
@@ -531,7 +532,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		
 		gFrameStats.start(LLFrameStats::UPDATE_CULL);
 		S32 water_clip = 0;
-		if ((LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_ENVIRONMENT) > 1) &&
+		if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT) > 1) &&
 			 gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER))
 		{
 			if (LLViewerCamera::getInstance()->cameraUnderWater())
diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp
index 95166278d5d..f975e56b95f 100644
--- a/indra/newview/llviewerjointmesh.cpp
+++ b/indra/newview/llviewerjointmesh.cpp
@@ -56,7 +56,7 @@
 #include "llvoavatar.h"
 #include "llsky.h"
 #include "pipeline.h"
-#include "llglslshader.h"
+#include "llviewershadermgr.h"
 #include "llmath.h"
 #include "v4math.h"
 #include "m3math.h"
@@ -880,7 +880,7 @@ void LLViewerJointMesh::updateJointGeometry()
 		  && mFace
 		  && mMesh->hasWeights()
 		  && mFace->mVertexBuffer.notNull()
-		  && LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_AVATAR) == 0))
+		  && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) == 0))
 	{
 		return;
 	}
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
new file mode 100644
index 00000000000..fe0f3f12a60
--- /dev/null
+++ b/indra/newview/llviewershadermgr.cpp
@@ -0,0 +1,1094 @@
+/** 
+ * @file llviewershadermgr.cpp
+ * @brief Viewer shader manager implementation.
+ *
+ * $LicenseInfo:firstyear=2005&license=viewergpl$
+ * 
+ * Copyright (c) 2005-2007, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llfeaturemanager.h"
+#include "llviewershadermgr.h"
+
+#include "llfile.h"
+#include "llviewerwindow.h"
+#include "llviewercontrol.h"
+#include "pipeline.h"
+#include "llworld.h"
+#include "llwlparammanager.h"
+#include "llwaterparammanager.h"
+#include "llsky.h"
+#include "llvosky.h"
+#include "llrender.h"
+
+#if LL_DARWIN
+#include "OpenGL/OpenGL.h"
+#endif
+
+#ifdef LL_RELEASE_FOR_DOWNLOAD
+#define UNIFORM_ERRS LL_WARNS_ONCE("Shader")
+#else
+#define UNIFORM_ERRS LL_ERRS("Shader")
+#endif
+
+// Lots of STL stuff in here, using namespace std to keep things more readable
+using std::vector;
+using std::pair;
+using std::make_pair;
+using std::string;
+
+LLVector4			gShinyOrigin;
+
+//object shaders
+LLGLSLShader		gObjectSimpleProgram;
+LLGLSLShader		gObjectSimpleWaterProgram;
+LLGLSLShader		gObjectFullbrightProgram;
+LLGLSLShader		gObjectFullbrightWaterProgram;
+
+LLGLSLShader		gObjectFullbrightShinyProgram;
+LLGLSLShader		gObjectShinyProgram;
+LLGLSLShader		gObjectShinyWaterProgram;
+
+//environment shaders
+LLGLSLShader		gTerrainProgram;
+LLGLSLShader		gTerrainWaterProgram;
+LLGLSLShader		gWaterProgram;
+LLGLSLShader		gUnderWaterProgram;
+
+//interface shaders
+LLGLSLShader		gHighlightProgram;
+
+//avatar shader handles
+LLGLSLShader		gAvatarProgram;
+LLGLSLShader		gAvatarWaterProgram;
+LLGLSLShader		gAvatarEyeballProgram;
+LLGLSLShader		gAvatarPickProgram;
+
+// WindLight shader handles
+LLGLSLShader			gWLSkyProgram;
+LLGLSLShader			gWLCloudProgram;
+
+// Effects Shaders
+LLGLSLShader			gGlowProgram;
+LLGLSLShader			gGlowExtractProgram;
+LLGLSLShader			gPostColorFilterProgram;
+LLGLSLShader			gPostNightVisionProgram;
+
+// Deferred rendering shaders
+LLGLSLShader			gDeferredDiffuseProgram;
+
+//current avatar shader parameter pointer
+GLint				gAvatarMatrixParam;
+
+LLViewerShaderMgr::LLViewerShaderMgr() :
+	mVertexShaderLevel(SHADER_COUNT, 0)
+{	
+/// Make sure WL Sky is the first program
+	mShaderList.push_back(&gWLSkyProgram);
+	mShaderList.push_back(&gWLCloudProgram);
+	mShaderList.push_back(&gAvatarProgram);
+	mShaderList.push_back(&gObjectShinyProgram);
+	mShaderList.push_back(&gWaterProgram);
+	mShaderList.push_back(&gAvatarEyeballProgram); 
+	mShaderList.push_back(&gObjectSimpleProgram);
+	mShaderList.push_back(&gObjectFullbrightProgram);
+	mShaderList.push_back(&gObjectFullbrightShinyProgram);
+	mShaderList.push_back(&gTerrainProgram);
+	mShaderList.push_back(&gTerrainWaterProgram);
+	mShaderList.push_back(&gObjectSimpleWaterProgram);
+	mShaderList.push_back(&gObjectFullbrightWaterProgram);
+	mShaderList.push_back(&gAvatarWaterProgram);
+	mShaderList.push_back(&gObjectShinyWaterProgram);
+	mShaderList.push_back(&gUnderWaterProgram);
+}
+
+LLViewerShaderMgr::~LLViewerShaderMgr()
+{
+	mVertexShaderLevel.clear();
+	mShaderList.clear();
+}
+
+// static
+LLViewerShaderMgr * LLViewerShaderMgr::instance()
+{
+	if(NULL == sInstance)
+	{
+		sInstance = new LLViewerShaderMgr();
+	}	
+	
+	return static_cast<LLViewerShaderMgr*>(sInstance);
+	}
+
+void LLViewerShaderMgr::initAttribsAndUniforms(void)
+	{
+	if (mReservedAttribs.empty())
+		{
+		mReservedAttribs.push_back("materialColor");
+		mReservedAttribs.push_back("specularColor");
+		mReservedAttribs.push_back("binormal");
+		
+		mAvatarAttribs.reserve(5);
+		mAvatarAttribs.push_back("weight");
+		mAvatarAttribs.push_back("clothing");
+		mAvatarAttribs.push_back("gWindDir");
+		mAvatarAttribs.push_back("gSinWaveParams");
+		mAvatarAttribs.push_back("gGravity");
+			
+		mAvatarUniforms.push_back("matrixPalette");
+			
+		mReservedUniforms.reserve(24);
+		mReservedUniforms.push_back("diffuseMap");
+		mReservedUniforms.push_back("specularMap");
+		mReservedUniforms.push_back("bumpMap");
+		mReservedUniforms.push_back("environmentMap");
+		mReservedUniforms.push_back("cloude_noise_texture");
+		mReservedUniforms.push_back("fullbright");
+		mReservedUniforms.push_back("lightnorm");
+		mReservedUniforms.push_back("sunlight_color");
+		mReservedUniforms.push_back("ambient");
+		mReservedUniforms.push_back("blue_horizon");
+		mReservedUniforms.push_back("blue_density");
+		mReservedUniforms.push_back("haze_horizon");
+		mReservedUniforms.push_back("haze_density");
+		mReservedUniforms.push_back("cloud_shadow");
+		mReservedUniforms.push_back("density_multiplier");
+		mReservedUniforms.push_back("distance_multiplier");
+		mReservedUniforms.push_back("max_y");
+		mReservedUniforms.push_back("glow");
+		mReservedUniforms.push_back("cloud_color");
+		mReservedUniforms.push_back("cloud_pos_density1");
+		mReservedUniforms.push_back("cloud_pos_density2");
+		mReservedUniforms.push_back("cloud_scale");
+		mReservedUniforms.push_back("gamma");
+		mReservedUniforms.push_back("scene_light_strength");
+			
+		mWLUniforms.push_back("camPosLocal");
+			
+		mTerrainUniforms.reserve(5);
+		mTerrainUniforms.push_back("detail_0");
+		mTerrainUniforms.push_back("detail_1");
+		mTerrainUniforms.push_back("detail_2");
+		mTerrainUniforms.push_back("detail_3");
+		mTerrainUniforms.push_back("alpha_ramp");
+	
+		mGlowUniforms.push_back("glowDelta");
+		mGlowUniforms.push_back("glowStrength");
+
+		mGlowExtractUniforms.push_back("minLuminance");
+		mGlowExtractUniforms.push_back("maxExtractAlpha");
+		mGlowExtractUniforms.push_back("lumWeights");
+		mGlowExtractUniforms.push_back("warmthWeights");
+		mGlowExtractUniforms.push_back("warmthAmount");
+	
+		mShinyUniforms.push_back("origin");
+
+		mWaterUniforms.reserve(12);
+		mWaterUniforms.push_back("screenTex");
+		mWaterUniforms.push_back("screenDepth");
+		mWaterUniforms.push_back("refTex");
+		mWaterUniforms.push_back("eyeVec");
+		mWaterUniforms.push_back("time");
+		mWaterUniforms.push_back("d1");
+		mWaterUniforms.push_back("d2");
+		mWaterUniforms.push_back("lightDir");
+		mWaterUniforms.push_back("specular");
+		mWaterUniforms.push_back("lightExp");
+		mWaterUniforms.push_back("fogCol");
+		mWaterUniforms.push_back("kd");
+		mWaterUniforms.push_back("refScale");
+		mWaterUniforms.push_back("waterHeight");
+		}
+	}
+
+
+//============================================================================
+// Set Levels
+
+S32 LLViewerShaderMgr::getVertexShaderLevel(S32 type)
+{
+	return LLPipeline::sDisableShaders ? 0 : mVertexShaderLevel[type];
+}
+
+//============================================================================
+// Shader Management
+
+void LLViewerShaderMgr::setShaders()
+{
+	if (!gPipeline.mInitialized)
+	{
+		return;
+	}
+	// Make sure the compiled shader map is cleared before we recompile shaders.
+	mShaderObjects.clear();
+	
+	initAttribsAndUniforms();
+	gPipeline.releaseGLBuffers();
+
+	if (gSavedSettings.getBOOL("VertexShaderEnable"))
+	{
+		LLPipeline::sWaterReflections = gGLManager.mHasCubeMap;
+		LLPipeline::sRenderGlow = gSavedSettings.getBOOL("RenderGlow"); 
+	}
+	else
+	{
+			LLPipeline::sRenderGlow = 
+			LLPipeline::sWaterReflections = FALSE;
+	}
+	
+	//hack to reset buffers that change behavior with shaders
+	gPipeline.resetVertexBuffers();
+
+	if (gViewerWindow)
+	{
+		gViewerWindow->setCursor(UI_CURSOR_WAIT);
+	}
+
+	// Lighting
+	gPipeline.setLightingDetail(-1);
+
+	// Shaders
+	LL_INFOS("ShaderLoading") << "\n~~~~~~~~~~~~~~~~~~\n Loading Shaders:\n~~~~~~~~~~~~~~~~~~" << LL_ENDL;
+	for (S32 i = 0; i < SHADER_COUNT; i++)
+	{
+		mVertexShaderLevel[i] = 0;
+	}
+	mMaxAvatarShaderLevel = 0;
+
+	if (LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable") 
+		&& gSavedSettings.getBOOL("VertexShaderEnable"))
+	{
+		S32 light_class = 2;
+		S32 env_class = 2;
+		S32 obj_class = 2;
+		S32 effect_class = 2;
+		S32 wl_class = 2;
+		S32 water_class = 2;
+		S32 deferred_class = 0;
+		if (!gSavedSettings.getBOOL("WindLightUseAtmosShaders"))
+		{
+			// user has disabled WindLight in their settings, downgrade
+			// windlight shaders to stub versions.
+			wl_class = 1;
+
+			// if class one or less, turn off more shaders
+			// since higher end cards won't see any real gain
+			// from turning off most of the shaders,
+			// but class one would
+			// TODO: Make water on class one cards color things
+			// beneath it properly
+			if(LLFeatureManager::getInstance()->getGPUClass() < GPU_CLASS_2)
+			{
+				// use lesser water and other stuff
+				light_class = 2;
+				env_class = 0;
+				obj_class = 0;
+				effect_class = 1;
+				water_class = 1;
+			}
+		}
+
+		if (gSavedSettings.getBOOL("RenderDeferred"))
+		{
+			light_class = 1;
+			env_class = 0;
+			obj_class = 0;
+			water_class = 1;
+			effect_class = 1;
+			deferred_class = 1;
+		}
+
+		if(!gSavedSettings.getBOOL("EnableRippleWater"))
+		{
+			water_class = 0;
+		}
+
+		// Trigger a full rebuild of the fallback skybox / cubemap if we've toggled windlight shaders
+		if (mVertexShaderLevel[SHADER_WINDLIGHT] != wl_class && gSky.mVOSkyp.notNull())
+		{
+			gSky.mVOSkyp->forceSkyUpdate();
+		}
+
+		// Load lighting shaders
+		mVertexShaderLevel[SHADER_LIGHTING] = light_class;
+		mVertexShaderLevel[SHADER_INTERFACE] = light_class;
+		mVertexShaderLevel[SHADER_ENVIRONMENT] = env_class;
+		mVertexShaderLevel[SHADER_WATER] = water_class;
+		mVertexShaderLevel[SHADER_OBJECT] = obj_class;
+		mVertexShaderLevel[SHADER_EFFECT] = effect_class;
+		mVertexShaderLevel[SHADER_WINDLIGHT] = wl_class;
+		mVertexShaderLevel[SHADER_DEFERRED] = deferred_class;
+
+		BOOL loaded = loadBasicShaders();
+
+		if (loaded)
+		{
+			gPipeline.mVertexShadersEnabled = TRUE;
+			gPipeline.mVertexShadersLoaded = 1;
+
+			// Load all shaders to set max levels
+			loadShadersEnvironment();
+			loadShadersWater();
+			loadShadersObject();
+			loadShadersWindLight();
+			loadShadersEffects();
+			loadShadersInterface();
+			loadShadersDeferred();
+
+			// Load max avatar shaders to set the max level
+			mVertexShaderLevel[SHADER_AVATAR] = 3;
+			mMaxAvatarShaderLevel = 3;
+			loadShadersAvatar();
+			
+#if 0 && LL_DARWIN // force avatar shaders off for mac
+			mVertexShaderLevel[SHADER_AVATAR] = 0;
+			sMaxAvatarShaderLevel = 0;
+#else
+			if (gSavedSettings.getBOOL("RenderAvatarVP"))
+			{
+				BOOL avatar_cloth = gSavedSettings.getBOOL("RenderAvatarCloth");
+				S32 avatar_class = 1;
+				
+				// cloth is a class3 shader
+				if(avatar_cloth)
+				{
+					avatar_class = 3;
+				}
+
+				// Set the actual level
+				mVertexShaderLevel[SHADER_AVATAR] = avatar_class;
+				loadShadersAvatar();
+				if (mVertexShaderLevel[SHADER_AVATAR] != avatar_class)
+				{
+					if (mVertexShaderLevel[SHADER_AVATAR] == 0)
+					{
+						gSavedSettings.setBOOL("RenderAvatarVP", FALSE);
+					}
+					if(llmax(mVertexShaderLevel[SHADER_AVATAR]-1,0) >= 3)
+					{
+						avatar_cloth = true;
+					}
+					else
+					{
+						avatar_cloth = false;
+					}
+					gSavedSettings.setBOOL("RenderAvatarCloth", avatar_cloth);
+				}
+			}
+			else
+			{
+				mVertexShaderLevel[SHADER_AVATAR] = 0;
+				gSavedSettings.setBOOL("RenderAvatarCloth", FALSE);
+				loadShadersAvatar(); // unloads
+			}
+#endif
+		}
+		else
+		{
+			gPipeline.mVertexShadersEnabled = FALSE;
+			gPipeline.mVertexShadersLoaded = 0;
+			mVertexShaderLevel[SHADER_LIGHTING] = 0;
+			mVertexShaderLevel[SHADER_INTERFACE] = 0;
+			mVertexShaderLevel[SHADER_ENVIRONMENT] = 0;
+			mVertexShaderLevel[SHADER_WATER] = 0;
+			mVertexShaderLevel[SHADER_OBJECT] = 0;
+			mVertexShaderLevel[SHADER_EFFECT] = 0;
+			mVertexShaderLevel[SHADER_WINDLIGHT] = 0;
+		}
+	}
+	else
+	{
+		gPipeline.mVertexShadersEnabled = FALSE;
+		gPipeline.mVertexShadersLoaded = 0;
+		mVertexShaderLevel[SHADER_LIGHTING] = 0;
+		mVertexShaderLevel[SHADER_INTERFACE] = 0;
+		mVertexShaderLevel[SHADER_ENVIRONMENT] = 0;
+		mVertexShaderLevel[SHADER_WATER] = 0;
+		mVertexShaderLevel[SHADER_OBJECT] = 0;
+		mVertexShaderLevel[SHADER_EFFECT] = 0;
+		mVertexShaderLevel[SHADER_WINDLIGHT] = 0;
+	}
+	
+	if (gViewerWindow)
+	{
+		gViewerWindow->setCursor(UI_CURSOR_ARROW);
+	}
+	gPipeline.createGLBuffers();
+}
+
+void LLViewerShaderMgr::unloadShaders()
+{
+	gObjectSimpleProgram.unload();
+	gObjectSimpleWaterProgram.unload();
+	gObjectFullbrightProgram.unload();
+	gObjectFullbrightWaterProgram.unload();
+
+	gObjectShinyProgram.unload();
+	gObjectFullbrightShinyProgram.unload();
+	gObjectShinyWaterProgram.unload();
+	gWaterProgram.unload();
+	gUnderWaterProgram.unload();
+	gTerrainProgram.unload();
+	gTerrainWaterProgram.unload();
+	gGlowProgram.unload();
+	gGlowExtractProgram.unload();
+	gAvatarProgram.unload();
+	gAvatarWaterProgram.unload();
+	gAvatarEyeballProgram.unload();
+	gAvatarPickProgram.unload();
+	gHighlightProgram.unload();
+
+	gWLSkyProgram.unload();
+	gWLCloudProgram.unload();
+
+	gPostColorFilterProgram.unload();
+	gPostNightVisionProgram.unload();
+
+	gDeferredDiffuseProgram.unload();
+
+	mVertexShaderLevel[SHADER_LIGHTING] = 0;
+	mVertexShaderLevel[SHADER_OBJECT] = 0;
+	mVertexShaderLevel[SHADER_AVATAR] = 0;
+	mVertexShaderLevel[SHADER_ENVIRONMENT] = 0;
+	mVertexShaderLevel[SHADER_WATER] = 0;
+	mVertexShaderLevel[SHADER_INTERFACE] = 0;
+
+	gPipeline.mVertexShadersLoaded = 0;
+}
+
+BOOL LLViewerShaderMgr::loadBasicShaders()
+{
+	// Load basic dependency shaders first
+	// All of these have to load for any shaders to function
+	
+#if LL_DARWIN // Mac can't currently handle all 8 lights, 
+	S32 sum_lights_class = 2;
+#else 
+	S32 sum_lights_class = 3;
+
+	// class one cards will get the lower sum lights
+	// class zero we're not going to think about
+	// since a class zero card COULD be a ridiculous new card
+	// and old cards should have the features masked
+	if(LLFeatureManager::getInstance()->getGPUClass() == GPU_CLASS_1)
+	{
+		sum_lights_class = 2;
+	}
+#endif
+
+	// If we have sun and moon only checked, then only sum those lights.
+	if (gPipeline.getLightingDetail() == 0)
+	{
+		sum_lights_class = 1;
+	}
+
+	// Load the Basic Vertex Shaders at the appropriate level. 
+	// (in order of shader function call depth for reference purposes, deepest level first)
+
+	vector< pair<string, S32> > shaders;
+	shaders.reserve(10);
+	shaders.push_back( make_pair( "windlight/atmosphericsVarsV.glsl",		mVertexShaderLevel[SHADER_WINDLIGHT] ) );
+	shaders.push_back( make_pair( "windlight/atmosphericsHelpersV.glsl",	mVertexShaderLevel[SHADER_WINDLIGHT] ) );
+	shaders.push_back( make_pair( "lighting/lightFuncV.glsl",				mVertexShaderLevel[SHADER_LIGHTING] ) );
+	shaders.push_back( make_pair( "lighting/sumLightsV.glsl",				sum_lights_class ) );
+	shaders.push_back( make_pair( "lighting/lightV.glsl",					mVertexShaderLevel[SHADER_LIGHTING] ) );
+	shaders.push_back( make_pair( "lighting/lightFuncSpecularV.glsl",		mVertexShaderLevel[SHADER_LIGHTING] ) );
+	shaders.push_back( make_pair( "lighting/sumLightsSpecularV.glsl",		sum_lights_class ) );
+	shaders.push_back( make_pair( "lighting/lightSpecularV.glsl",			mVertexShaderLevel[SHADER_LIGHTING] ) );
+	shaders.push_back( make_pair( "windlight/atmosphericsV.glsl",			mVertexShaderLevel[SHADER_WINDLIGHT] ) );
+	shaders.push_back( make_pair( "avatar/avatarSkinV.glsl",				1 ) );
+
+	// We no longer have to bind the shaders to global glhandles, they are automatically added to a map now.
+	for (U32 i = 0; i < shaders.size(); i++)
+	{
+		// Note usage of GL_VERTEX_SHADER_ARB
+		if (loadShaderFile(shaders[i].first, shaders[i].second, GL_VERTEX_SHADER_ARB) == 0)
+		{
+			return FALSE;
+		}
+	}
+
+	// Load the Basic Fragment Shaders at the appropriate level. 
+	// (in order of shader function call depth for reference purposes, deepest level first)
+
+	shaders.clear();
+	shaders.reserve(12);
+	shaders.push_back( make_pair( "windlight/atmosphericsVarsF.glsl",		mVertexShaderLevel[SHADER_WINDLIGHT] ) );
+	shaders.push_back( make_pair( "windlight/gammaF.glsl",					mVertexShaderLevel[SHADER_WINDLIGHT]) );
+	shaders.push_back( make_pair( "windlight/atmosphericsF.glsl",			mVertexShaderLevel[SHADER_WINDLIGHT] ) );
+	shaders.push_back( make_pair( "windlight/transportF.glsl",				mVertexShaderLevel[SHADER_WINDLIGHT] ) );	
+	shaders.push_back( make_pair( "environment/waterFogF.glsl",				mVertexShaderLevel[SHADER_WATER] ) );
+	shaders.push_back( make_pair( "lighting/lightF.glsl",					mVertexShaderLevel[SHADER_LIGHTING] ) );
+	shaders.push_back( make_pair( "lighting/lightFullbrightF.glsl",			mVertexShaderLevel[SHADER_LIGHTING] ) );
+	shaders.push_back( make_pair( "lighting/lightWaterF.glsl",				mVertexShaderLevel[SHADER_LIGHTING] ) );
+	shaders.push_back( make_pair( "lighting/lightFullbrightWaterF.glsl",	mVertexShaderLevel[SHADER_LIGHTING] ) );
+	shaders.push_back( make_pair( "lighting/lightShinyF.glsl",				mVertexShaderLevel[SHADER_LIGHTING] ) );
+	shaders.push_back( make_pair( "lighting/lightFullbrightShinyF.glsl",	mVertexShaderLevel[SHADER_LIGHTING] ) );
+	shaders.push_back( make_pair( "lighting/lightShinyWaterF.glsl",			mVertexShaderLevel[SHADER_LIGHTING] ) );
+	
+	for (U32 i = 0; i < shaders.size(); i++)
+	{
+		// Note usage of GL_FRAGMENT_SHADER_ARB
+		if (loadShaderFile(shaders[i].first, shaders[i].second, GL_FRAGMENT_SHADER_ARB) == 0)
+		{
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+BOOL LLViewerShaderMgr::loadShadersEnvironment()
+{
+	BOOL success = TRUE;
+
+	if (mVertexShaderLevel[SHADER_ENVIRONMENT] == 0)
+	{
+		gTerrainProgram.unload();
+		return FALSE;
+	}
+
+	if (success)
+	{
+		gTerrainProgram.mName = "Terrain Shader";
+		gTerrainProgram.mFeatures.calculatesLighting = true;
+		gTerrainProgram.mFeatures.calculatesAtmospherics = true;
+		gTerrainProgram.mFeatures.hasAtmospherics = true;
+		gTerrainProgram.mFeatures.hasGamma = true;
+		gTerrainProgram.mShaderFiles.clear();
+		gTerrainProgram.mShaderFiles.push_back(make_pair("environment/terrainV.glsl", GL_VERTEX_SHADER_ARB));
+		gTerrainProgram.mShaderFiles.push_back(make_pair("environment/terrainF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gTerrainProgram.mShaderLevel = mVertexShaderLevel[SHADER_ENVIRONMENT];
+		success = gTerrainProgram.createShader(NULL, &mTerrainUniforms);
+	}
+
+	if (!success)
+	{
+		mVertexShaderLevel[SHADER_ENVIRONMENT] = 0;
+		return FALSE;
+	}
+	
+	LLWorld::getInstance()->updateWaterObjects();
+	
+	return TRUE;
+}
+
+BOOL LLViewerShaderMgr::loadShadersWater()
+{
+	BOOL success = TRUE;
+	BOOL terrainWaterSuccess = TRUE;
+
+	if (mVertexShaderLevel[SHADER_WATER] == 0)
+	{
+		gWaterProgram.unload();
+		gUnderWaterProgram.unload();
+		gTerrainWaterProgram.unload();
+		return FALSE;
+	}
+
+	if (success)
+	{
+		// load water shader
+		gWaterProgram.mName = "Water Shader";
+		gWaterProgram.mFeatures.calculatesAtmospherics = true;
+		gWaterProgram.mFeatures.hasGamma = true;
+		gWaterProgram.mFeatures.hasTransport = true;
+		gWaterProgram.mShaderFiles.clear();
+		gWaterProgram.mShaderFiles.push_back(make_pair("environment/waterV.glsl", GL_VERTEX_SHADER_ARB));
+		gWaterProgram.mShaderFiles.push_back(make_pair("environment/waterF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_WATER];
+		success = gWaterProgram.createShader(NULL, &mWaterUniforms);
+	}
+
+	if (success)
+	{
+		//load under water vertex shader
+		gUnderWaterProgram.mName = "Underwater Shader";
+		gUnderWaterProgram.mFeatures.calculatesAtmospherics = true;
+		gUnderWaterProgram.mShaderFiles.clear();
+		gUnderWaterProgram.mShaderFiles.push_back(make_pair("environment/waterV.glsl", GL_VERTEX_SHADER_ARB));
+		gUnderWaterProgram.mShaderFiles.push_back(make_pair("environment/underWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gUnderWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_WATER];
+		gUnderWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+		
+		success = gUnderWaterProgram.createShader(NULL, &mWaterUniforms);
+	}
+
+	if (success)
+	{
+		//load terrain water shader
+		gTerrainWaterProgram.mName = "Terrain Water Shader";
+		gTerrainWaterProgram.mFeatures.calculatesLighting = true;
+		gTerrainWaterProgram.mFeatures.calculatesAtmospherics = true;
+		gTerrainWaterProgram.mFeatures.hasAtmospherics = true;
+		gTerrainWaterProgram.mFeatures.hasWaterFog = true;
+		gTerrainWaterProgram.mShaderFiles.clear();
+		gTerrainWaterProgram.mShaderFiles.push_back(make_pair("environment/terrainV.glsl", GL_VERTEX_SHADER_ARB));
+		gTerrainWaterProgram.mShaderFiles.push_back(make_pair("environment/terrainWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gTerrainWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_ENVIRONMENT];
+		gTerrainWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+		terrainWaterSuccess = gTerrainWaterProgram.createShader(NULL, &mTerrainUniforms);
+	}	
+
+	/// Keep track of water shader levels
+	if (gWaterProgram.mShaderLevel != mVertexShaderLevel[SHADER_WATER]
+		|| gUnderWaterProgram.mShaderLevel != mVertexShaderLevel[SHADER_WATER])
+	{
+		mVertexShaderLevel[SHADER_WATER] = llmin(gWaterProgram.mShaderLevel, gUnderWaterProgram.mShaderLevel);
+	}
+
+	if (!success)
+	{
+		mVertexShaderLevel[SHADER_WATER] = 0;
+		return FALSE;
+	}
+
+	// if we failed to load the terrain water shaders and we need them (using class2 water),
+	// then drop down to class1 water.
+	if (mVertexShaderLevel[SHADER_WATER] > 1 && !terrainWaterSuccess)
+	{
+		mVertexShaderLevel[SHADER_WATER]--;
+		return loadShadersWater();
+	}
+	
+	LLWorld::getInstance()->updateWaterObjects();
+
+	return TRUE;
+}
+
+BOOL LLViewerShaderMgr::loadShadersEffects()
+{
+	BOOL success = TRUE;
+
+	if (mVertexShaderLevel[SHADER_EFFECT] == 0)
+	{
+		gGlowProgram.unload();
+		gGlowExtractProgram.unload();
+		gPostColorFilterProgram.unload();	
+		gPostNightVisionProgram.unload();
+		return FALSE;
+	}
+
+	if (success)
+	{
+		gGlowProgram.mName = "Glow Shader (Post)";
+		gGlowProgram.mShaderFiles.clear();
+		gGlowProgram.mShaderFiles.push_back(make_pair("effects/glowV.glsl", GL_VERTEX_SHADER_ARB));
+		gGlowProgram.mShaderFiles.push_back(make_pair("effects/glowF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gGlowProgram.mShaderLevel = mVertexShaderLevel[SHADER_EFFECT];
+		success = gGlowProgram.createShader(NULL, &mGlowUniforms);
+		if (!success)
+		{
+			LLPipeline::sRenderGlow = FALSE;
+		}
+	}
+	
+	if (success)
+	{
+		gGlowExtractProgram.mName = "Glow Extract Shader (Post)";
+		gGlowExtractProgram.mShaderFiles.clear();
+		gGlowExtractProgram.mShaderFiles.push_back(make_pair("effects/glowExtractV.glsl", GL_VERTEX_SHADER_ARB));
+		gGlowExtractProgram.mShaderFiles.push_back(make_pair("effects/glowExtractF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gGlowExtractProgram.mShaderLevel = mVertexShaderLevel[SHADER_EFFECT];
+		success = gGlowExtractProgram.createShader(NULL, &mGlowExtractUniforms);
+		if (!success)
+		{
+			LLPipeline::sRenderGlow = FALSE;
+		}
+	}
+	
+#if 0
+	// disabling loading of postprocess shaders until we fix
+	// ATI sampler2DRect compatibility.
+	
+	//load Color Filter Shader
+	if (success)
+	{
+		vector<string> shaderUniforms;
+		shaderUniforms.reserve(7);
+		shaderUniforms.push_back("RenderTexture");
+		shaderUniforms.push_back("gamma");
+		shaderUniforms.push_back("brightness");
+		shaderUniforms.push_back("contrast");
+		shaderUniforms.push_back("contrastBase");
+		shaderUniforms.push_back("saturation");
+		shaderUniforms.push_back("lumWeights");
+
+		gPostColorFilterProgram.mName = "Color Filter Shader (Post)";
+		gPostColorFilterProgram.mShaderFiles.clear();
+		gPostColorFilterProgram.mShaderFiles.push_back(make_pair("effects/colorFilterF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gPostColorFilterProgram.mShaderFiles.push_back(make_pair("effects/drawQuadV.glsl", GL_VERTEX_SHADER_ARB));
+		gPostColorFilterProgram.mShaderLevel = mVertexShaderLevel[SHADER_EFFECT];
+		success = gPostColorFilterProgram.createShader(NULL, &shaderUniforms);
+	}
+
+	//load Night Vision Shader
+	if (success)
+	{
+		vector<string> shaderUniforms;
+		shaderUniforms.reserve(5);
+		shaderUniforms.push_back("RenderTexture");
+		shaderUniforms.push_back("NoiseTexture");
+		shaderUniforms.push_back("brightMult");
+		shaderUniforms.push_back("noiseStrength");
+		shaderUniforms.push_back("lumWeights");
+
+		gPostNightVisionProgram.mName = "Night Vision Shader (Post)";
+		gPostNightVisionProgram.mShaderFiles.clear();
+		gPostNightVisionProgram.mShaderFiles.push_back(make_pair("effects/nightVisionF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gPostNightVisionProgram.mShaderFiles.push_back(make_pair("effects/drawQuadV.glsl", GL_VERTEX_SHADER_ARB));
+		gPostNightVisionProgram.mShaderLevel = mVertexShaderLevel[SHADER_EFFECT];
+		success = gPostNightVisionProgram.createShader(NULL, &shaderUniforms);
+	}
+	#endif
+
+	return success;
+
+}
+
+BOOL LLViewerShaderMgr::loadShadersDeferred()
+{
+	if (mVertexShaderLevel[SHADER_DEFERRED] == 0)
+	{
+		gDeferredDiffuseProgram.unload();
+		return FALSE;
+	}
+
+	BOOL success = TRUE;
+
+	if (success)
+	{
+		gDeferredDiffuseProgram.mName = "Deffered Diffuse Shader";
+		gDeferredDiffuseProgram.mShaderFiles.clear();
+		gDeferredDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredDiffuseProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredDiffuseProgram.createShader(NULL, NULL);
+	}
+
+	return success;
+}
+
+BOOL LLViewerShaderMgr::loadShadersObject()
+{
+	BOOL success = TRUE;
+
+	if (mVertexShaderLevel[SHADER_OBJECT] == 0)
+	{
+		gObjectShinyProgram.unload();
+		gObjectFullbrightShinyProgram.unload();
+		gObjectShinyWaterProgram.unload();
+		gObjectSimpleProgram.unload();
+		gObjectSimpleWaterProgram.unload();
+		gObjectFullbrightProgram.unload();
+		gObjectFullbrightWaterProgram.unload();
+		return FALSE;
+	}
+
+	if (success)
+	{
+		gObjectSimpleProgram.mName = "Simple Shader";
+		gObjectSimpleProgram.mFeatures.calculatesLighting = true;
+		gObjectSimpleProgram.mFeatures.calculatesAtmospherics = true;
+		gObjectSimpleProgram.mFeatures.hasGamma = true;
+		gObjectSimpleProgram.mFeatures.hasAtmospherics = true;
+		gObjectSimpleProgram.mFeatures.hasLighting = true;
+		gObjectSimpleProgram.mShaderFiles.clear();
+		gObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB));
+		gObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gObjectSimpleProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		success = gObjectSimpleProgram.createShader(NULL, NULL);
+	}
+	
+	if (success)
+	{
+		gObjectSimpleWaterProgram.mName = "Simple Water Shader";
+		gObjectSimpleWaterProgram.mFeatures.calculatesLighting = true;
+		gObjectSimpleWaterProgram.mFeatures.calculatesAtmospherics = true;
+		gObjectSimpleWaterProgram.mFeatures.hasWaterFog = true;
+		gObjectSimpleWaterProgram.mFeatures.hasAtmospherics = true;
+		gObjectSimpleWaterProgram.mFeatures.hasLighting = true;
+		gObjectSimpleWaterProgram.mShaderFiles.clear();
+		gObjectSimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB));
+		gObjectSimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gObjectSimpleWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		gObjectSimpleWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+		success = gObjectSimpleWaterProgram.createShader(NULL, NULL);
+	}
+	
+	if (success)
+	{
+		gObjectFullbrightProgram.mName = "Fullbright Shader";
+		gObjectFullbrightProgram.mFeatures.calculatesAtmospherics = true;
+		gObjectFullbrightProgram.mFeatures.hasGamma = true;
+		gObjectFullbrightProgram.mFeatures.hasTransport = true;
+		gObjectFullbrightProgram.mFeatures.isFullbright = true;
+		gObjectFullbrightProgram.mShaderFiles.clear();
+		gObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
+		gObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gObjectFullbrightProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		success = gObjectFullbrightProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gObjectFullbrightWaterProgram.mName = "Fullbright Water Shader";
+		gObjectFullbrightWaterProgram.mFeatures.calculatesAtmospherics = true;
+		gObjectFullbrightWaterProgram.mFeatures.isFullbright = true;
+		gObjectFullbrightWaterProgram.mFeatures.hasWaterFog = true;		
+		gObjectFullbrightWaterProgram.mFeatures.hasTransport = true;
+		gObjectFullbrightWaterProgram.mShaderFiles.clear();
+		gObjectFullbrightWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
+		gObjectFullbrightWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gObjectFullbrightWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		gObjectFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+		success = gObjectFullbrightWaterProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gObjectShinyProgram.mName = "Shiny Shader";
+		gObjectShinyProgram.mFeatures.calculatesAtmospherics = true;
+		gObjectShinyProgram.mFeatures.calculatesLighting = true;
+		gObjectShinyProgram.mFeatures.hasGamma = true;
+		gObjectShinyProgram.mFeatures.hasAtmospherics = true;
+		gObjectShinyProgram.mFeatures.isShiny = true;
+		gObjectShinyProgram.mShaderFiles.clear();
+		gObjectShinyProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB));
+		gObjectShinyProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB));		
+		gObjectShinyProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		success = gObjectShinyProgram.createShader(NULL, &mShinyUniforms);
+	}
+
+	if (success)
+	{
+		gObjectShinyWaterProgram.mName = "Shiny Water Shader";
+		gObjectShinyWaterProgram.mFeatures.calculatesAtmospherics = true;
+		gObjectShinyWaterProgram.mFeatures.calculatesLighting = true;
+		gObjectShinyWaterProgram.mFeatures.isShiny = true;
+		gObjectShinyWaterProgram.mFeatures.hasWaterFog = true;
+		gObjectShinyWaterProgram.mFeatures.hasAtmospherics = true;
+		gObjectShinyWaterProgram.mShaderFiles.clear();
+		gObjectShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gObjectShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB));
+		gObjectShinyWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		gObjectShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+		success = gObjectShinyWaterProgram.createShader(NULL, &mShinyUniforms);
+	}
+	
+	if (success)
+	{
+		gObjectFullbrightShinyProgram.mName = "Fullbright Shiny Shader";
+		gObjectFullbrightShinyProgram.mFeatures.calculatesAtmospherics = true;
+		gObjectFullbrightShinyProgram.mFeatures.isFullbright = true;
+		gObjectFullbrightShinyProgram.mFeatures.isShiny = true;
+		gObjectFullbrightShinyProgram.mFeatures.hasGamma = true;
+		gObjectFullbrightShinyProgram.mFeatures.hasTransport = true;
+		gObjectFullbrightShinyProgram.mShaderFiles.clear();
+		gObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB));
+		gObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gObjectFullbrightShinyProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		success = gObjectFullbrightShinyProgram.createShader(NULL, &mShinyUniforms);
+	}
+
+
+	if( !success )
+	{
+		mVertexShaderLevel[SHADER_OBJECT] = 0;
+		return FALSE;
+	}
+	
+	return TRUE;
+}
+
+BOOL LLViewerShaderMgr::loadShadersAvatar()
+{
+	BOOL success = TRUE;
+
+	if (mVertexShaderLevel[SHADER_AVATAR] == 0)
+	{
+		gAvatarProgram.unload();
+		gAvatarWaterProgram.unload();
+		gAvatarEyeballProgram.unload();
+		gAvatarPickProgram.unload();
+		return FALSE;
+	}
+
+	if (success)
+	{
+		gAvatarProgram.mName = "Avatar Shader";
+		gAvatarProgram.mFeatures.hasSkinning = true;
+		gAvatarProgram.mFeatures.calculatesAtmospherics = true;
+		gAvatarProgram.mFeatures.calculatesLighting = true;
+		gAvatarProgram.mFeatures.hasGamma = true;
+		gAvatarProgram.mFeatures.hasAtmospherics = true;
+		gAvatarProgram.mFeatures.hasLighting = true;
+		gAvatarProgram.mShaderFiles.clear();
+		gAvatarProgram.mShaderFiles.push_back(make_pair("avatar/avatarV.glsl", GL_VERTEX_SHADER_ARB));
+		gAvatarProgram.mShaderFiles.push_back(make_pair("avatar/avatarF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gAvatarProgram.mShaderLevel = mVertexShaderLevel[SHADER_AVATAR];
+		success = gAvatarProgram.createShader(&mAvatarAttribs, &mAvatarUniforms);
+			
+		if (success)
+		{
+			gAvatarWaterProgram.mName = "Avatar Water Shader";
+			gAvatarWaterProgram.mFeatures.hasSkinning = true;
+			gAvatarWaterProgram.mFeatures.calculatesAtmospherics = true;
+			gAvatarWaterProgram.mFeatures.calculatesLighting = true;
+			gAvatarWaterProgram.mFeatures.hasWaterFog = true;
+			gAvatarWaterProgram.mFeatures.hasAtmospherics = true;
+			gAvatarWaterProgram.mFeatures.hasLighting = true;
+			gAvatarWaterProgram.mShaderFiles.clear();
+			gAvatarWaterProgram.mShaderFiles.push_back(make_pair("avatar/avatarV.glsl", GL_VERTEX_SHADER_ARB));
+			gAvatarWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
+			// Note: no cloth under water:
+			gAvatarWaterProgram.mShaderLevel = llmin(mVertexShaderLevel[SHADER_AVATAR], 1);	
+			gAvatarWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;				
+			success = gAvatarWaterProgram.createShader(&mAvatarAttribs, &mAvatarUniforms);
+		}
+
+		/// Keep track of avatar levels
+		if (gAvatarProgram.mShaderLevel != mVertexShaderLevel[SHADER_AVATAR])
+		{
+			mMaxAvatarShaderLevel = mVertexShaderLevel[SHADER_AVATAR] = gAvatarProgram.mShaderLevel;
+		}
+	}
+
+	if (success)
+	{
+		gAvatarPickProgram.mName = "Avatar Pick Shader";
+		gAvatarPickProgram.mFeatures.hasSkinning = true;
+		gAvatarPickProgram.mShaderFiles.clear();
+		gAvatarPickProgram.mShaderFiles.push_back(make_pair("avatar/pickAvatarV.glsl", GL_VERTEX_SHADER_ARB));
+		gAvatarPickProgram.mShaderFiles.push_back(make_pair("avatar/pickAvatarF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gAvatarPickProgram.mShaderLevel = mVertexShaderLevel[SHADER_AVATAR];
+		success = gAvatarPickProgram.createShader(&mAvatarAttribs, &mAvatarUniforms);
+	}
+
+	if (success)
+	{
+		gAvatarEyeballProgram.mName = "Avatar Eyeball Program";
+		gAvatarEyeballProgram.mFeatures.calculatesLighting = true;
+		gAvatarEyeballProgram.mFeatures.isSpecular = true;
+		gAvatarEyeballProgram.mFeatures.calculatesAtmospherics = true;
+		gAvatarEyeballProgram.mFeatures.hasGamma = true;
+		gAvatarEyeballProgram.mFeatures.hasAtmospherics = true;
+		gAvatarEyeballProgram.mFeatures.hasLighting = true;
+		gAvatarEyeballProgram.mShaderFiles.clear();
+		gAvatarEyeballProgram.mShaderFiles.push_back(make_pair("avatar/eyeballV.glsl", GL_VERTEX_SHADER_ARB));
+		gAvatarEyeballProgram.mShaderFiles.push_back(make_pair("avatar/eyeballF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gAvatarEyeballProgram.mShaderLevel = mVertexShaderLevel[SHADER_AVATAR];
+		success = gAvatarEyeballProgram.createShader(NULL, NULL);
+	}
+
+	if( !success )
+	{
+		mVertexShaderLevel[SHADER_AVATAR] = 0;
+		mMaxAvatarShaderLevel = 0;
+		return FALSE;
+	}
+	
+	return TRUE;
+}
+
+BOOL LLViewerShaderMgr::loadShadersInterface()
+{
+	BOOL success = TRUE;
+
+	if (mVertexShaderLevel[SHADER_INTERFACE] == 0)
+	{
+		gHighlightProgram.unload();
+		return FALSE;
+	}
+	
+	if (success)
+	{
+		gHighlightProgram.mName = "Highlight Shader";
+		gHighlightProgram.mShaderFiles.clear();
+		gHighlightProgram.mShaderFiles.push_back(make_pair("interface/highlightV.glsl", GL_VERTEX_SHADER_ARB));
+		gHighlightProgram.mShaderFiles.push_back(make_pair("interface/highlightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gHighlightProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE];		
+		success = gHighlightProgram.createShader(NULL, NULL);
+	}
+
+	if( !success )
+	{
+		mVertexShaderLevel[SHADER_INTERFACE] = 0;
+		return FALSE;
+	}
+	
+	return TRUE;
+}
+
+BOOL LLViewerShaderMgr::loadShadersWindLight()
+{	
+	BOOL success = TRUE;
+
+	if (mVertexShaderLevel[SHADER_WINDLIGHT] < 2)
+	{
+		gWLSkyProgram.unload();
+		gWLCloudProgram.unload();
+		return FALSE;
+	}
+
+	if (success)
+	{
+		gWLSkyProgram.mName = "Windlight Sky Shader";
+		//gWLSkyProgram.mFeatures.hasGamma = true;
+		gWLSkyProgram.mShaderFiles.clear();
+		gWLSkyProgram.mShaderFiles.push_back(make_pair("windlight/skyV.glsl", GL_VERTEX_SHADER_ARB));
+		gWLSkyProgram.mShaderFiles.push_back(make_pair("windlight/skyF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gWLSkyProgram.mShaderLevel = mVertexShaderLevel[SHADER_WINDLIGHT];
+		gWLSkyProgram.mShaderGroup = LLGLSLShader::SG_SKY;
+		success = gWLSkyProgram.createShader(NULL, &mWLUniforms);
+	}
+
+	if (success)
+	{
+		gWLCloudProgram.mName = "Windlight Cloud Program";
+		//gWLCloudProgram.mFeatures.hasGamma = true;
+		gWLCloudProgram.mShaderFiles.clear();
+		gWLCloudProgram.mShaderFiles.push_back(make_pair("windlight/cloudsV.glsl", GL_VERTEX_SHADER_ARB));
+		gWLCloudProgram.mShaderFiles.push_back(make_pair("windlight/cloudsF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gWLCloudProgram.mShaderLevel = mVertexShaderLevel[SHADER_WINDLIGHT];
+		gWLCloudProgram.mShaderGroup = LLGLSLShader::SG_SKY;
+		success = gWLCloudProgram.createShader(NULL, &mWLUniforms);
+	}
+
+	return success;
+}
+
+std::string LLViewerShaderMgr::getShaderDirPrefix(void)
+	{
+	return gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "shaders/class");
+	}
+
+void LLViewerShaderMgr::updateShaderUniforms(LLGLSLShader * shader)
+			{
+	LLWLParamManager::instance()->updateShaderUniforms(shader);
+	LLWaterParamManager::instance()->updateShaderUniforms(shader);
+}
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
new file mode 100644
index 00000000000..6b8189b4a63
--- /dev/null
+++ b/indra/newview/llviewershadermgr.h
@@ -0,0 +1,313 @@
+/** 
+ * @file llviewershadermgr.h
+ * @brief Viewer Shader Manager
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2008, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_VIEWER_SHADER_MGR_H
+#define LL_VIEWER_SHADER_MGR_H
+
+#include "llshadermgr.h"
+
+class LLViewerShaderMgr: public LLShaderMgr
+{
+public:
+	LLViewerShaderMgr();
+	/* virtual */ ~LLViewerShaderMgr();
+
+	// singleton pattern implementation
+	static LLViewerShaderMgr * instance();
+
+	void initAttribsAndUniforms(void);
+	void setShaders();
+	void unloadShaders();
+	S32 getVertexShaderLevel(S32 type);
+	BOOL loadBasicShaders();
+	BOOL loadShadersEffects();
+	BOOL loadShadersDeferred();
+	BOOL loadShadersObject();
+	BOOL loadShadersAvatar();
+	BOOL loadShadersEnvironment();
+	BOOL loadShadersWater();
+	BOOL loadShadersInterface();
+	BOOL loadShadersWindLight();
+
+	std::vector<S32> mVertexShaderLevel;
+	S32	mMaxAvatarShaderLevel;
+
+	enum EShaderClass
+	{
+		SHADER_LIGHTING,
+		SHADER_OBJECT,
+		SHADER_AVATAR,
+		SHADER_ENVIRONMENT,
+		SHADER_INTERFACE,
+		SHADER_EFFECT,
+		SHADER_WINDLIGHT,
+		SHADER_WATER,
+		SHADER_DEFERRED,
+		SHADER_COUNT
+	};
+
+	typedef enum 
+	{
+		MATERIAL_COLOR = 0,
+		SPECULAR_COLOR,
+		BINORMAL,
+		END_RESERVED_ATTRIBS
+	} eGLSLReservedAttribs;
+	
+	typedef enum
+	{
+		DIFFUSE_MAP = 0,
+		SPECULAR_MAP,
+		BUMP_MAP,
+		ENVIRONMENT_MAP,
+		CLOUD_NOISE_MAP,
+		FULLBRIGHT,
+		LIGHTNORM,
+		SUNLIGHT_COLOR,
+		AMBIENT,
+		BLUE_HORIZON,
+		BLUE_DENSITY,
+		HAZE_HORIZON,
+		HAZE_DENSITY,
+		CLOUD_SHADOW,
+		DENSITY_MULTIPLIER,
+		DISTANCE_MULTIPLIER,
+		MAX_Y,
+		GLOW,
+		CLOUD_COLOR,
+		CLOUD_POS_DENSITY1,
+		CLOUD_POS_DENSITY2,
+		CLOUD_SCALE,
+		GAMMA,
+		SCENE_LIGHT_STRENGTH,
+		END_RESERVED_UNIFORMS
+	} eGLSLReservedUniforms;
+
+	typedef enum
+	{
+		SHINY_ORIGIN = END_RESERVED_UNIFORMS
+	} eShinyUniforms;
+
+	typedef enum
+	{
+		WATER_SCREENTEX = END_RESERVED_UNIFORMS,
+		WATER_SCREENDEPTH,
+		WATER_REFTEX,
+		WATER_EYEVEC,
+		WATER_TIME,
+		WATER_WAVE_DIR1,
+		WATER_WAVE_DIR2,
+		WATER_LIGHT_DIR,
+		WATER_SPECULAR,
+		WATER_SPECULAR_EXP,
+		WATER_FOGCOLOR,
+		WATER_FOGDENSITY,
+		WATER_REFSCALE,
+		WATER_WATERHEIGHT,
+	} eWaterUniforms;
+
+	typedef enum
+	{
+		WL_CAMPOSLOCAL = END_RESERVED_UNIFORMS,
+		WL_WATERHEIGHT
+	} eWLUniforms;
+
+	typedef enum
+	{
+		TERRAIN_DETAIL0 = END_RESERVED_UNIFORMS,
+		TERRAIN_DETAIL1,
+		TERRAIN_DETAIL2,
+		TERRAIN_DETAIL3,
+		TERRAIN_ALPHARAMP
+	} eTerrainUniforms;
+
+	typedef enum
+	{
+		GLOW_DELTA = END_RESERVED_UNIFORMS
+	} eGlowUniforms;
+
+	typedef enum
+	{
+		AVATAR_WEIGHT = END_RESERVED_ATTRIBS,
+		AVATAR_CLOTHING,
+		AVATAR_WIND,
+		AVATAR_SINWAVE,
+		AVATAR_GRAVITY
+	} eAvatarAttribs;
+
+	typedef enum
+	{
+		AVATAR_MATRIX = END_RESERVED_UNIFORMS
+	} eAvatarUniforms;
+
+	// simple model of forward iterator
+	// http://www.sgi.com/tech/stl/ForwardIterator.html
+	class shader_iter
+	{
+	private:
+		friend bool operator == (shader_iter const & a, shader_iter const & b);
+		friend bool operator != (shader_iter const & a, shader_iter const & b);
+
+		typedef std::vector<LLGLSLShader *>::const_iterator base_iter_t;
+	public:
+		shader_iter()
+		{
+		}
+
+		shader_iter(base_iter_t iter) : mIter(iter)
+		{
+		}
+
+		LLGLSLShader & operator * () const
+		{
+			return **mIter;
+		}
+
+		LLGLSLShader * operator -> () const
+		{
+			return *mIter;
+		}
+
+		shader_iter & operator++ ()
+		{
+			++mIter;
+			return *this;
+		}
+
+		shader_iter operator++ (int)
+		{
+			return mIter++;
+		}
+
+	private:
+		base_iter_t mIter;
+	};
+
+	shader_iter beginShaders() const
+	{
+		return mShaderList.begin();
+	}
+
+	shader_iter endShaders() const
+	{
+		return mShaderList.end();
+	}
+
+
+	/* virtual */ std::string getShaderDirPrefix(void); // Virtual
+
+	/* virtual */ void updateShaderUniforms(LLGLSLShader * shader); // Virtual
+
+private:
+	
+	std::vector<std::string> mShinyUniforms;
+
+	//water parameters
+	std::vector<std::string> mWaterUniforms;
+
+	std::vector<std::string> mWLUniforms;
+
+	//terrain parameters
+	std::vector<std::string> mTerrainUniforms;
+
+	//glow parameters
+	std::vector<std::string> mGlowUniforms;
+
+	std::vector<std::string> mGlowExtractUniforms;
+
+	//avatar shader parameter tables
+	std::vector<std::string> mAvatarAttribs;
+
+	std::vector<std::string> mAvatarUniforms;
+
+	// the list of shaders we need to propagate parameters to.
+	std::vector<LLGLSLShader *> mShaderList;
+
+}; //LLViewerShaderMgr
+
+inline bool operator == (LLViewerShaderMgr::shader_iter const & a, LLViewerShaderMgr::shader_iter const & b)
+{
+	return a.mIter == b.mIter;
+}
+
+inline bool operator != (LLViewerShaderMgr::shader_iter const & a, LLViewerShaderMgr::shader_iter const & b)
+{
+	return a.mIter != b.mIter;
+}
+
+extern LLVector4			gShinyOrigin;
+
+//object shaders
+extern LLGLSLShader			gObjectSimpleProgram;
+extern LLGLSLShader			gObjectSimpleWaterProgram;
+extern LLGLSLShader			gObjectFullbrightProgram;
+extern LLGLSLShader			gObjectFullbrightWaterProgram;
+
+extern LLGLSLShader			gObjectSimpleLODProgram;
+extern LLGLSLShader			gObjectFullbrightLODProgram;
+
+extern LLGLSLShader			gObjectFullbrightShinyProgram;
+extern LLGLSLShader			gObjectShinyProgram;
+extern LLGLSLShader			gObjectShinyWaterProgram;
+
+//environment shaders
+extern LLGLSLShader			gTerrainProgram;
+extern LLGLSLShader			gTerrainWaterProgram;
+extern LLGLSLShader			gWaterProgram;
+extern LLGLSLShader			gUnderWaterProgram;
+extern LLGLSLShader			gGlowProgram;
+extern LLGLSLShader			gGlowExtractProgram;
+
+//interface shaders
+extern LLGLSLShader			gHighlightProgram;
+
+// avatar shader handles
+extern LLGLSLShader			gAvatarProgram;
+extern LLGLSLShader			gAvatarWaterProgram;
+extern LLGLSLShader			gAvatarEyeballProgram;
+extern LLGLSLShader			gAvatarPickProgram;
+
+// WindLight shader handles
+extern LLGLSLShader			gWLSkyProgram;
+extern LLGLSLShader			gWLCloudProgram;
+
+// Post Process Shaders
+extern LLGLSLShader			gPostColorFilterProgram;
+extern LLGLSLShader			gPostNightVisionProgram;
+
+// Deferred rendering shaders
+extern LLGLSLShader			gDeferredDiffuseProgram;
+
+//current avatar shader parameter pointer
+extern GLint				gAvatarMatrixParam;
+
+
+#endif
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index cf2c094deda..287f0637572 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -114,7 +114,7 @@
 #include "llworld.h"
 #include "pipeline.h"
 #include "llspatialpartition.h"
-#include "llglslshader.h"
+#include "llviewershadermgr.h"
 #include "llappviewer.h"
 #include "llsky.h"
 #include "llanimstatelabels.h"
@@ -2824,7 +2824,7 @@ void LLVOAvatar::idleUpdateLoadingEffect()
 void LLVOAvatar::idleUpdateWindEffect()
 {
 	// update wind effect
-	if ((LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_AVATAR) >= LLDrawPoolAvatar::SHADER_LEVEL_CLOTH))
+	if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) >= LLDrawPoolAvatar::SHADER_LEVEL_CLOTH))
 	{
 		F32 hover_strength = 0.f;
 		F32 time_delta = mRippleTimer.getElapsedTimeF32() - mRippleTimeLast;
@@ -3388,7 +3388,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
 			return FALSE;
 		}
 	}
-	
+
 	// change animation time quanta based on avatar render load
 	if (!mIsSelf && !mIsDummy)
 	{
@@ -4000,7 +4000,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
 		mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY);
 	}
 
-	if (LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_AVATAR) <= 0)
+	if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) <= 0)
 	{
 		if (mNeedsSkin)
 		{
@@ -9714,7 +9714,7 @@ BOOL LLVOAvatar::updateLOD()
 	}
 	
 	updateVisibility();
-	
+
 	return res;
 }
 
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index 1ef721e9183..330d5c370d4 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -441,7 +441,7 @@ void LLVOSky::initCubeMap()
 	{
 		mCubeMap->init(images);
 	}
-	else if (gSavedSettings.getBOOL("RenderWater") && gGLManager.mHasCubeMap && LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap"))
+	else if (gSavedSettings.getBOOL("RenderWater") && gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps)
 	{
 		mCubeMap = new LLCubeMap();
 		mCubeMap->init(images);
@@ -479,7 +479,7 @@ void LLVOSky::restoreGL()
 	calcAtmospherics();	
 
 	if (gSavedSettings.getBOOL("RenderWater") && gGLManager.mHasCubeMap
-	    && LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap"))
+	    && LLCubeMap::sUseCubeMaps)
 	{
 		LLCubeMap* cube_map = getCubeMap();
 
diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp
index 4f2dd663edd..29f086b7f96 100644
--- a/indra/newview/llwaterparammanager.cpp
+++ b/indra/newview/llwaterparammanager.cpp
@@ -33,6 +33,8 @@
 
 #include "llwaterparammanager.h"
 
+#include "llrender.h"
+
 #include "pipeline.h"
 #include "llsky.h"
 
@@ -205,9 +207,9 @@ void LLWaterParamManager::propagateParameters(void)
 	// bind the variables only if we're using shaders
 	if(gPipeline.canUseVertexShaders())
 	{
-		LLShaderMgr::shader_iter shaders_iter, end_shaders;
-		end_shaders = LLShaderMgr::endShaders();
-		for(shaders_iter = LLShaderMgr::beginShaders(); shaders_iter != end_shaders; ++shaders_iter)
+		LLViewerShaderMgr::shader_iter shaders_iter, end_shaders;
+		end_shaders = LLViewerShaderMgr::instance()->endShaders();
+		for(shaders_iter = LLViewerShaderMgr::instance()->beginShaders(); shaders_iter != end_shaders; ++shaders_iter)
 		{
 			if (shaders_iter->mProgramObject != 0
 				&& shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER)
@@ -229,7 +231,7 @@ void LLWaterParamManager::updateShaderUniforms(LLGLSLShader * shader)
 {
 	if (shader->mShaderGroup == LLGLSLShader::SG_WATER)
 	{
-		shader->uniform4fv(LLShaderMgr::LIGHTNORM, 1, LLWLParamManager::instance()->getRotatedLightDir().mV);
+		shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, LLWLParamManager::instance()->getRotatedLightDir().mV);
 		shader->uniform3fv("camPosLocal", 1, LLViewerCamera::getInstance()->getOrigin().mV);
 		shader->uniform4fv("waterFogColor", 1, LLDrawPoolWater::sWaterFogColor.mV);
 		shader->uniform4fv("waterPlane", 1, mWaterPlane.mV);
@@ -289,9 +291,9 @@ void LLWaterParamManager::update(LLViewerCamera * cam)
 		sunMoonDir.normVec();
 		mWaterFogKS = 1.f/llmax(sunMoonDir.mV[2], WATER_FOG_LIGHT_CLAMP);
 
-		LLShaderMgr::shader_iter shaders_iter, end_shaders;
-		end_shaders = LLShaderMgr::endShaders();
-		for(shaders_iter = LLShaderMgr::beginShaders(); shaders_iter != end_shaders; ++shaders_iter)
+		LLViewerShaderMgr::shader_iter shaders_iter, end_shaders;
+		end_shaders = LLViewerShaderMgr::instance()->endShaders();
+		for(shaders_iter = LLViewerShaderMgr::instance()->beginShaders(); shaders_iter != end_shaders; ++shaders_iter)
 		{
 			if (shaders_iter->mProgramObject != 0
 				&& shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER)
diff --git a/indra/newview/llwaterparamset.h b/indra/newview/llwaterparamset.h
index b733160dff8..c16901a4cd5 100644
--- a/indra/newview/llwaterparamset.h
+++ b/indra/newview/llwaterparamset.h
@@ -37,7 +37,7 @@
 
 #include "v4math.h"
 #include "v4color.h"
-#include "llglslshader.h"
+#include "llviewershadermgr.h"
 
 class LLFloaterWater;
 class LLWaterParamSet;
diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp
index 24ddb6fc08b..b55c3e5b6d5 100644
--- a/indra/newview/llwlparammanager.cpp
+++ b/indra/newview/llwlparammanager.cpp
@@ -281,13 +281,13 @@ void LLWLParamManager::updateShaderUniforms(LLGLSLShader * shader)
 
 	if (shader->mShaderGroup == LLGLSLShader::SG_DEFAULT)
 	{
-		shader->uniform4fv(LLShaderMgr::LIGHTNORM, 1, mRotatedLightDir.mV);
+		shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, mRotatedLightDir.mV);
 		shader->uniform3fv("camPosLocal", 1, LLViewerCamera::getInstance()->getOrigin().mV);
 	} 
 
 	else if (shader->mShaderGroup == LLGLSLShader::SG_SKY)
 	{
-		shader->uniform4fv(LLShaderMgr::LIGHTNORM, 1, mClampedLightDir.mV);
+		shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, mClampedLightDir.mV);
 	}
 
 	shader->uniform1f("scene_light_strength", mSceneLightStrength);
@@ -345,9 +345,9 @@ void LLWLParamManager::propagateParameters(void)
 	mCurParams.set("lightnorm", mLightDir);
 
 	// bind the variables for all shaders only if we're using WindLight
-	LLShaderMgr::shader_iter shaders_iter, end_shaders;
-	end_shaders = LLShaderMgr::endShaders();
-	for(shaders_iter = LLShaderMgr::beginShaders(); shaders_iter != end_shaders; ++shaders_iter) 
+	LLViewerShaderMgr::shader_iter shaders_iter, end_shaders;
+	end_shaders = LLViewerShaderMgr::instance()->endShaders();
+	for(shaders_iter = LLViewerShaderMgr::instance()->beginShaders(); shaders_iter != end_shaders; ++shaders_iter) 
 	{
 		if (shaders_iter->mProgramObject != 0
 			&& (gPipeline.canUseWindLightShaders()
@@ -408,9 +408,9 @@ void LLWLParamManager::update(LLViewerCamera * cam)
 		lightNorm3 *= LLQuaternion(-(camYaw + camYawDelta), LLVector3(0.f, 1.f, 0.f));
 		mRotatedLightDir = LLVector4(lightNorm3, 0.f);
 
-		LLShaderMgr::shader_iter shaders_iter, end_shaders;
-		end_shaders = LLShaderMgr::endShaders();
-		for(shaders_iter = LLShaderMgr::beginShaders(); shaders_iter != end_shaders; ++shaders_iter)
+		LLViewerShaderMgr::shader_iter shaders_iter, end_shaders;
+		end_shaders = LLViewerShaderMgr::instance()->endShaders();
+		for(shaders_iter = LLViewerShaderMgr::instance()->beginShaders(); shaders_iter != end_shaders; ++shaders_iter)
 		{
 			if (shaders_iter->mProgramObject != 0
 				&& (gPipeline.canUseWindLightShaders()
diff --git a/indra/newview/llwlparamset.h b/indra/newview/llwlparamset.h
index 15afeaf3649..76a7b8a189c 100644
--- a/indra/newview/llwlparamset.h
+++ b/indra/newview/llwlparamset.h
@@ -37,7 +37,7 @@
 
 #include "v4math.h"
 #include "v4color.h"
-#include "llglslshader.h"
+#include "llviewershadermgr.h"
 
 class LLFloaterWindLight;
 class LLWLParamSet;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 3679b57da83..f9a18bf1925 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -93,7 +93,7 @@
 #include "llworld.h"
 #include "llcubemap.h"
 #include "lldebugmessagebox.h"
-#include "llglslshader.h"
+#include "llviewershadermgr.h"
 #include "llviewerjoystick.h"
 #include "llviewerdisplay.h"
 #include "llwlparammanager.h"
@@ -300,7 +300,7 @@ void LLPipeline::init()
 	
 	// Enable features
 		
-	LLShaderMgr::setShaders();
+	LLViewerShaderMgr::instance()->setShaders();
 
 	stop_glerror();
 }
@@ -565,7 +565,7 @@ void LLPipeline::restoreGL()
 
 	if (mVertexShadersEnabled)
 	{
-		LLShaderMgr::setShaders();
+		LLViewerShaderMgr::instance()->setShaders();
 	}
 
 	for (LLWorld::region_list_t::iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
@@ -603,18 +603,18 @@ BOOL LLPipeline::canUseWindLightShaders() const
 {
 	return (!LLPipeline::sDisableShaders &&
 			gWLSkyProgram.mProgramObject != 0 &&
-			LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_WINDLIGHT) > 1);
+			LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1);
 }
 
 BOOL LLPipeline::canUseWindLightShadersOnObjects() const
 {
 	return (canUseWindLightShaders() 
-		&& LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_OBJECT) > 0);
+		&& LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0);
 }
 
 void LLPipeline::unloadShaders()
 {
-	LLShaderMgr::unloadShaders();
+	LLViewerShaderMgr::instance()->unloadShaders();
 
 	mVertexShadersLoaded = 0;
 }
@@ -660,7 +660,7 @@ S32 LLPipeline::setLightingDetail(S32 level)
 
 		if (mVertexShadersLoaded == 1)
 		{
-			LLShaderMgr::setShaders();
+			LLViewerShaderMgr::instance()->setShaders();
 		}
 	}
 	return mLightingDetail;
@@ -1795,7 +1795,7 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
 			else if (drawablep->isAvatar())
 			{
 				drawablep->updateDistance(camera); // calls vobj->updateLOD() which calls LLVOAvatar::updateVisibility()
-			}
+		}
 		}
 	}
 
@@ -2192,10 +2192,10 @@ void LLPipeline::renderHighlights()
 	LLGLEnable color_mat(GL_COLOR_MATERIAL);
 	disableLights();
 
-	if ((LLShaderMgr::sVertexShaderLevel[LLShaderMgr::SHADER_INTERFACE] > 0))
+	if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0))
 	{
 		gHighlightProgram.bind();
-		gHighlightProgram.vertexAttrib4f(LLShaderMgr::MATERIAL_COLOR,1,1,1,0.5f);
+		gHighlightProgram.vertexAttrib4f(LLViewerShaderMgr::MATERIAL_COLOR,1,1,1,0.5f);
 	}
 	
 	if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED))
@@ -2225,9 +2225,9 @@ void LLPipeline::renderHighlights()
 	{
 		// Paint 'em red!
 		color.setVec(1.f, 0.f, 0.f, 0.5f);
-		if ((LLShaderMgr::sVertexShaderLevel[LLShaderMgr::SHADER_INTERFACE] > 0))
+		if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0))
 		{
-			gHighlightProgram.vertexAttrib4f(LLShaderMgr::MATERIAL_COLOR,1,0,0,0.5f);
+			gHighlightProgram.vertexAttrib4f(LLViewerShaderMgr::MATERIAL_COLOR,1,0,0,0.5f);
 		}
 		int count = mHighlightFaces.size();
 		for (S32 i = 0; i < count; i++)
@@ -2241,7 +2241,7 @@ void LLPipeline::renderHighlights()
 	// have touch-handlers.
 	mHighlightFaces.clear();
 
-	if (LLShaderMgr::sVertexShaderLevel[LLShaderMgr::SHADER_INTERFACE] > 0)
+	if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)
 	{
 		gHighlightProgram.unbind();
 	}
-- 
GitLab