From ad332810078a0bbb8fa08fcbfdf3d756de6914f6 Mon Sep 17 00:00:00 2001
From: Steven Bennetts <steve@lindenlab.com>
Date: Fri, 6 Jun 2008 22:43:38 +0000
Subject: QAR-650 - Viewer RC 9 merge -> release (post cmake) merge
 release@88802 Branch_1-20-Viewer-2-merge-1@89178 -> release

---
 indra/llrender/CMakeLists.txt     |   6 +-
 indra/llrender/llfontgl.cpp       |   5 +-
 indra/llrender/llimagegl.cpp      | 114 ++++--
 indra/llrender/llimagegl.h        |  19 +-
 indra/llrender/llrender.cpp       | 704 ++++++++++++++++++++++++++++++++++++++
 indra/llrender/llrender.h         | 239 +++++++++++++
 indra/llrender/llrendertarget.cpp |   3 +-
 indra/llrender/llvertexbuffer.cpp |  33 +-
 8 files changed, 1083 insertions(+), 40 deletions(-)
 create mode 100644 indra/llrender/llrender.cpp
 create mode 100644 indra/llrender/llrender.h

(limited to 'indra/llrender')

diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt
index 9938a0198b..2dba8ef60d 100644
--- a/indra/llrender/CMakeLists.txt
+++ b/indra/llrender/CMakeLists.txt
@@ -23,11 +23,10 @@ set(llrender_SOURCE_FILES
     llfont.cpp
     llfontgl.cpp
     llgldbg.cpp
-    llglimmediate.cpp
     llimagegl.cpp
+    llrender.cpp
     llrendertarget.cpp
     llvertexbuffer.cpp
-    llvertexprogramgl.cpp
     )
     
 set(llrender_HEADER_FILES
@@ -36,11 +35,10 @@ set(llrender_HEADER_FILES
     llfontgl.h
     llfont.h
     llgldbg.h
-    llglimmediate.h
     llimagegl.h
+    llrender.h
     llrendertarget.h
     llvertexbuffer.h
-    llvertexprogramgl.h
     )
 
 set_source_files_properties(${llrender_HEADER_FILES}
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 3a408b5550..1e0d9767ca 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -36,7 +36,7 @@
 #include "llfont.h"
 #include "llfontgl.h"
 #include "llgl.h"
-#include "llglimmediate.h"
+#include "llrender.h"
 #include "v4color.h"
 #include "llstl.h"
 
@@ -665,7 +665,8 @@ S32 LLFontGL::render(const LLWString &wstr,
 	
 	mImageGLp->bind(0);
 	
- 	gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Not guaranteed to be set correctly
+ 	// Not guaranteed to be set correctly
+	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 	
 	cur_x = ((F32)x * sScaleX);
 	cur_y = ((F32)y * sScaleY);
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 55fa48f437..dd9f22361f 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -41,7 +41,7 @@
 
 #include "llmath.h"
 #include "llgl.h"
-#include "llglimmediate.h"
+#include "llrender.h"
 
 
 //----------------------------------------------------------------------------
@@ -61,6 +61,8 @@ S32 LLImageGL::sCount					= 0;
 BOOL LLImageGL::sGlobalUseAnisotropic	= FALSE;
 F32 LLImageGL::sLastFrameTime			= 0.f;
 
+BOOL LLImageGL::sRefCheck = TRUE ;
+
 std::set<LLImageGL*> LLImageGL::sImageList;
 
 //----------------------------------------------------------------------------
@@ -130,13 +132,13 @@ void LLImageGL::bindExternalTexture(LLGLuint gl_name, S32 stage, LLGLenum bind_t
 	gGL.flush();
 	if (stage > 0)
 	{
-		glActiveTextureARB(GL_TEXTURE0_ARB + stage);
+		gGL.getTexUnit(stage)->activate();
 	}
 	glBindTexture(bind_target, gl_name);
 	sCurrentBoundTextures[stage] = gl_name;
 	if (stage > 0)
 	{
-		glActiveTextureARB(GL_TEXTURE0_ARB);
+		gGL.getTexUnit(0)->activate();
 	}
 }
 
@@ -149,9 +151,9 @@ void LLImageGL::unbindTexture(S32 stage, LLGLenum bind_target)
 		gGL.flush();
 		if (stage > 0)
 		{
-			glActiveTextureARB(GL_TEXTURE0_ARB + stage);
+			gGL.getTexUnit(stage)->activate();
 			glBindTexture(GL_TEXTURE_2D, 0);
-			glActiveTextureARB(GL_TEXTURE0_ARB);
+			gGL.getTexUnit(0)->activate();
 		}
 		else
 		{
@@ -276,7 +278,10 @@ LLImageGL::LLImageGL(const LLImageRaw* imageraw, BOOL usemipmaps)
 	setSize(0, 0, 0);
 	sImageList.insert(this);
 	sCount++;
+
+	sRefCheck = FALSE ;
 	createGLTexture(0, imageraw); 
+	sRefCheck = TRUE ;
 }
 
 LLImageGL::~LLImageGL()
@@ -304,7 +309,9 @@ void LLImageGL::init(BOOL usemipmaps)
 	mIsResident       = 0;
 	mClampS			  = FALSE;
 	mClampT			  = FALSE;
-	mMipFilterNearest  = FALSE;
+	mClampR			  = FALSE;
+	mMagFilterNearest  = FALSE;
+	mMinFilterNearest  = FALSE;
 	mWidth				= 0;
 	mHeight				= 0;
 	mComponents			= 0;
@@ -331,17 +338,19 @@ void LLImageGL::cleanup()
 
 //----------------------------------------------------------------------------
 
+//this function is used to check the size of a texture image.
+//so dim should be a positive number
 static bool check_power_of_two(S32 dim)
 {
-	while(dim > 1)
+	if(dim < 0)
 	{
-		if (dim & 1)
-		{
-			return false;
-		}
-		dim >>= 1;
+		return false ;
+	}
+	if(!dim)//0 is a power-of-two number
+	{
+		return true ;
 	}
-	return true;
+	return !(dim & (dim - 1)) ;
 }
 
 //static
@@ -418,6 +427,8 @@ void LLImageGL::dump()
 
 BOOL LLImageGL::bindTextureInternal(const S32 stage) const
 {
+	llassert_always(!sRefCheck || (getNumRefs() > 0 && getNumRefs() < 100000)) ;	
+	
 	if (gGLManager.mIsDisabled)
 	{
 		llwarns << "Trying to bind a texture while GL is disabled!" << llendl;
@@ -439,7 +450,7 @@ BOOL LLImageGL::bindTextureInternal(const S32 stage) const
 		gGL.flush();
 		if (stage > 0)
 		{
-			glActiveTextureARB(GL_TEXTURE0_ARB + stage);
+			gGL.getTexUnit(stage)->activate();
 		}
 	
 		glBindTexture(mBindTarget, mTexName);
@@ -448,7 +459,7 @@ BOOL LLImageGL::bindTextureInternal(const S32 stage) const
 
 		if (stage > 0)
 		{
-			glActiveTextureARB(GL_TEXTURE0_ARB);
+			gGL.getTexUnit(0)->activate();
 		}
 		
 		if (mLastBindTime != sLastFrameTime)
@@ -466,12 +477,12 @@ BOOL LLImageGL::bindTextureInternal(const S32 stage) const
 		gGL.flush();
 		if (stage > 0)
 		{
-			glActiveTextureARB(GL_TEXTURE0_ARB+stage);
+			gGL.getTexUnit(stage)->activate();
 		}
 		glBindTexture(mBindTarget, 0);
 		if (stage > 0)
 		{
-			glActiveTextureARB(GL_TEXTURE0_ARB+stage);
+			gGL.getTexUnit(0)->activate();
 		}
 		sCurrentBoundTextures[stage] = 0;
 		return FALSE;
@@ -941,7 +952,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
 	setImage(data_in, data_hasmips);
 
 	setClamp(mClampS, mClampT);
-	setMipFilterNearest(mMipFilterNearest);
+	setMipFilterNearest(mMagFilterNearest);
 	
 	// things will break if we don't unbind after creation
 	unbindTexture(0, mBindTarget);
@@ -1044,8 +1055,23 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre
 
 	S32 gl_discard = discard_level - mCurrentDiscardLevel;
 
+	//explicitly unbind texture 
+	LLImageGL::unbindTexture(0, mTarget);
 	llverify(bindTextureInternal(0));	
 
+	if (gDebugGL)
+	{
+		if (mTarget == GL_TEXTURE_2D)
+		{
+			GLint texname;
+			glGetIntegerv(GL_TEXTURE_BINDING_2D, &texname);
+			if (texname != mTexName)
+			{
+				llerrs << "Invalid texture bound!" << llendl;
+			}
+		}
+	}
+
 	LLGLint glwidth = 0;
 	glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_WIDTH, (GLint*)&glwidth);
 	if (glwidth == 0)
@@ -1153,25 +1179,55 @@ void LLImageGL::destroyGLTexture()
 
 //----------------------------------------------------------------------------
 
-void LLImageGL::setClamp(BOOL clamps, BOOL clampt)
+void LLImageGL::glClampCubemap (BOOL clamps, BOOL clampt, BOOL clampr)
+{
+	glTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, clamps ? GL_CLAMP_TO_EDGE : GL_REPEAT);
+	glTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, clamps ? GL_CLAMP_TO_EDGE : GL_REPEAT);
+	glTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, clamps ? GL_CLAMP_TO_EDGE : GL_REPEAT);
+}
+
+void LLImageGL::glClamp (BOOL clamps, BOOL clampt)
 {
-	mClampS = clamps;
-	mClampT = clampt;
 	if (mTexName != 0)
 	{
-		glTexParameteri(mBindTarget, GL_TEXTURE_WRAP_S, clamps ? GL_CLAMP_TO_EDGE : GL_REPEAT);
-		glTexParameteri(mBindTarget, GL_TEXTURE_WRAP_T, clampt ? GL_CLAMP_TO_EDGE : GL_REPEAT);
+		glTexParameteri (mBindTarget, GL_TEXTURE_WRAP_S, clamps ? GL_CLAMP_TO_EDGE : GL_REPEAT);
+		glTexParameteri (mBindTarget, GL_TEXTURE_WRAP_T, clampt ? GL_CLAMP_TO_EDGE : GL_REPEAT);
 	}
-	stop_glerror();
 }
 
-void LLImageGL::setMipFilterNearest(BOOL nearest, BOOL min_nearest)
+void LLImageGL::setClampCubemap (BOOL clamps, BOOL clampt, BOOL clampr)
+{
+	mClampS = clamps;
+	mClampT = clampt;
+	mClampR = clampr;
+	glClampCubemap (clamps, clampt, clampr);
+}
+
+void LLImageGL::setClamp(BOOL clamps, BOOL clampt)
+{
+	mClampS = clamps;
+	mClampT = clampt;
+	glClamp (clamps, clampt);
+}
+
+void LLImageGL::overrideClamp (BOOL clamps, BOOL clampt)
+{
+	glClamp (clamps, clampt);
+}
+
+void LLImageGL::restoreClamp (void)
+{
+	glClamp (mClampS, mClampT);
+}
+
+void LLImageGL::setMipFilterNearest(BOOL mag_nearest, BOOL min_nearest)
 {
-	mMipFilterNearest = nearest;
+	mMagFilterNearest = mag_nearest;
+	mMinFilterNearest = min_nearest;
 
 	if (mTexName != 0)
 	{
-		if (min_nearest)
+		if (mMinFilterNearest)
 		{
 			glTexParameteri(mBindTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 		}
@@ -1183,7 +1239,7 @@ void LLImageGL::setMipFilterNearest(BOOL nearest, BOOL min_nearest)
 		{
 			glTexParameteri(mBindTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 		}
-		if (mMipFilterNearest)
+		if (mMagFilterNearest)
 		{
 			glTexParameteri(mBindTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 		}
@@ -1193,7 +1249,7 @@ void LLImageGL::setMipFilterNearest(BOOL nearest, BOOL min_nearest)
 		}
 		if (gGLManager.mHasAnisotropic)
 		{
-			if (sGlobalUseAnisotropic && !mMipFilterNearest)
+			if (sGlobalUseAnisotropic && !mMagFilterNearest)
 			{
 				F32 largest_anisotropy;
 				glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_anisotropy);
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 82ea147d6e..c5fe9b7299 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -81,6 +81,10 @@ protected:
 	virtual ~LLImageGL();
 	BOOL bindTextureInternal(const S32 stage = 0) const;
 
+private:
+	void glClamp (BOOL clamps, BOOL clampt);
+	void glClampCubemap (BOOL clamps, BOOL clampt, BOOL clampr = FALSE);
+
 public:
 	virtual void dump();	// debugging info to llinfos
 	virtual BOOL bind(const S32 stage = 0) const;
@@ -99,8 +103,11 @@ public:
 	BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok); 
 	void destroyGLTexture();
 	
+	void setClampCubemap (BOOL clamps, BOOL clampt, BOOL clampr = FALSE);
 	void setClamp(BOOL clamps, BOOL clampt);
-	void setMipFilterNearest(BOOL nearest, BOOL min_nearest = FALSE);
+	void overrideClamp (BOOL clamps, BOOL clampt);
+	void restoreClamp (void);
+	void setMipFilterNearest(BOOL mag_nearest, BOOL min_nearest = FALSE);
 	void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE);
 	void dontDiscard() { mDontDiscard = 1; }
 
@@ -117,7 +124,8 @@ public:
 	
 	BOOL getClampS() const { return mClampS; }
 	BOOL getClampT() const { return mClampT; }
-	BOOL getMipFilterNearest() const { return mMipFilterNearest; }
+	BOOL getClampR() const { return mClampR; }
+	BOOL getMipFilterNearest() const { return mMagFilterNearest; }
 	
 	BOOL getHasGLTexture() const { return mTexName != 0; }
 	LLGLuint getTexName() const { return mTexName; }
@@ -167,7 +175,9 @@ protected:
 
 	S8 mClampS;					// Need to save clamp state
 	S8 mClampT;
-	S8 mMipFilterNearest;		// if TRUE, set magfilter to GL_NEAREST
+	S8 mClampR;
+	S8 mMagFilterNearest;		// if TRUE, set magfilter to GL_NEAREST
+	S8 mMinFilterNearest;		// if TRUE, set minfilter to GL_NEAREST
 	
 	LLGLint  mFormatInternal; // = GL internalformat
 	LLGLenum mFormatPrimary;  // = GL format (pixel data format)
@@ -197,6 +207,9 @@ public:
 #else
 	BOOL getMissed() const { return FALSE; };
 #endif
+
+private://paranoia error check
+	static BOOL sRefCheck ;
 };
 
 #endif // LL_LLIMAGEGL_H
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
new file mode 100644
index 0000000000..1168155f8b
--- /dev/null
+++ b/indra/llrender/llrender.cpp
@@ -0,0 +1,704 @@
+/** 
+ * @file llrender.cpp
+ * @brief LLRender 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$
+ */
+
+#include "linden_common.h"
+
+#include "llrender.h"
+#include "llvertexbuffer.h"
+
+LLRender gGL;
+
+static const U32 LL_NUM_TEXTURE_LAYERS = 8; 
+
+static GLenum sGLCompareFunc[] =
+{
+	GL_NEVER,
+	GL_ALWAYS,
+	GL_LESS,
+	GL_LEQUAL,
+	GL_EQUAL,
+	GL_NOTEQUAL,
+	GL_GEQUAL,
+	GL_GREATER
+};
+
+const U32 immediate_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXCOORD;
+
+static GLenum sGLBlendFactor[] =
+{
+	GL_ONE,
+	GL_ZERO,
+	GL_DST_COLOR,
+	GL_SRC_COLOR,
+	GL_ONE_MINUS_DST_COLOR,
+	GL_ONE_MINUS_SRC_COLOR,
+	GL_DST_ALPHA,
+	GL_SRC_ALPHA,
+	GL_ONE_MINUS_DST_ALPHA,
+	GL_ONE_MINUS_SRC_ALPHA
+};
+
+LLTexUnit::LLTexUnit(U32 index)
+: mIsEnabled(false), mCurrBlendType(TB_MULT), 
+mCurrColorOp(TBO_MULT), mCurrAlphaOp(TBO_MULT),
+mCurrColorSrc1(TBS_TEX_COLOR), mCurrColorSrc2(TBS_PREV_COLOR),
+mCurrAlphaSrc1(TBS_TEX_ALPHA), mCurrAlphaSrc2(TBS_PREV_ALPHA),
+mCurrColorScale(1), mCurrAlphaScale(1)
+{
+	llassert_always(index < LL_NUM_TEXTURE_LAYERS);
+	mIndex = index;
+}
+
+U32 LLTexUnit::getIndex(void)
+{
+	return mIndex;
+}
+
+void LLTexUnit::enable(void)
+{
+	if (!mIsEnabled)
+	{
+		activate();
+		glEnable(GL_TEXTURE_2D);
+		mIsEnabled = true;
+	}
+}
+
+void LLTexUnit::disable(void)
+{
+	if (mIsEnabled)
+	{
+		activate();
+		glDisable(GL_TEXTURE_2D);
+		mIsEnabled = false;
+	}
+}
+
+void LLTexUnit::activate(void)
+{
+	//if (gGL.mCurrTextureUnitIndex != mIndex)
+	{
+		glActiveTextureARB(GL_TEXTURE0_ARB + mIndex);
+		gGL.mCurrTextureUnitIndex = mIndex;
+	}
+}
+
+// Useful for debugging that you've manually assigned a texture operation to the correct 
+// texture unit based on the currently set active texture in opengl.
+void LLTexUnit::debugTextureUnit(void)
+{
+	GLint activeTexture;
+	glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &activeTexture);
+	if ((GL_TEXTURE0_ARB + mIndex) != activeTexture)
+	{
+		llerrs << "Incorrect Texture Unit!  Expected: " << (activeTexture - GL_TEXTURE0_ARB) << " Actual: " << mIndex << llendl;
+	}
+}
+
+void LLTexUnit::bindTexture(const LLImageGL* texture)
+{
+	if (texture != NULL)
+	{
+		activate();
+		texture->bind(mIndex);
+	}
+}
+
+void LLTexUnit::unbindTexture(void)
+{
+	activate();
+	glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+void LLTexUnit::setTextureBlendType(eTextureBlendType type)
+{
+	// Do nothing if it's already correctly set.
+	if (mCurrBlendType == type)
+	{
+		return;
+	}
+
+	activate();
+	mCurrBlendType = type;
+	S32 scale_amount = 1;
+	switch (type) 
+	{
+		case TB_REPLACE:
+			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+			break;
+		case TB_ADD:
+			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
+			break;
+		case TB_MULT:
+			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+			break;
+		case TB_MULT_X2:
+			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+			scale_amount = 2;
+			break;
+		case TB_ALPHA_BLEND:
+			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+			break;
+		case TB_COMBINE:
+			glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+			break;
+		default:
+			llerrs << "Unknown Texture Blend Type: " << type << llendl;
+			break;
+	}
+	setColorScale(scale_amount);
+	setAlphaScale(1);
+}
+
+GLint LLTexUnit::getTextureSource(eTextureBlendSrc src)
+{
+	switch(src)
+	{
+		// All four cases should return the same value.
+		case TBS_PREV_COLOR:
+		case TBS_PREV_ALPHA:
+		case TBS_ONE_MINUS_PREV_COLOR:
+		case TBS_ONE_MINUS_PREV_ALPHA:
+			return GL_PREVIOUS_ARB;
+
+		// All four cases should return the same value.
+		case TBS_TEX_COLOR:
+		case TBS_TEX_ALPHA:
+		case TBS_ONE_MINUS_TEX_COLOR:
+		case TBS_ONE_MINUS_TEX_ALPHA:
+			return GL_TEXTURE;
+
+		// All four cases should return the same value.
+		case TBS_VERT_COLOR:
+		case TBS_VERT_ALPHA:
+		case TBS_ONE_MINUS_VERT_COLOR:
+		case TBS_ONE_MINUS_VERT_ALPHA:
+			return GL_PRIMARY_COLOR_ARB;
+
+		// All four cases should return the same value.
+		case TBS_CONST_COLOR:
+		case TBS_CONST_ALPHA:
+		case TBS_ONE_MINUS_CONST_COLOR:
+		case TBS_ONE_MINUS_CONST_ALPHA:
+			return GL_CONSTANT_ARB;
+
+		default:
+			llwarns << "Unknown eTextureBlendSrc: " << src << ".  Using Vertex Color instead." << llendl;
+			return GL_PRIMARY_COLOR_ARB;
+	}
+}
+
+GLint LLTexUnit::getTextureSourceType(eTextureBlendSrc src, bool isAlpha)
+{
+	switch(src)
+	{
+		// All four cases should return the same value.
+		case TBS_PREV_COLOR:
+		case TBS_TEX_COLOR:
+		case TBS_VERT_COLOR:
+		case TBS_CONST_COLOR:
+			return (isAlpha) ? GL_SRC_ALPHA: GL_SRC_COLOR;
+
+		// All four cases should return the same value.
+		case TBS_PREV_ALPHA:
+		case TBS_TEX_ALPHA:
+		case TBS_VERT_ALPHA:
+		case TBS_CONST_ALPHA:
+			return GL_SRC_ALPHA;
+
+		// All four cases should return the same value.
+		case TBS_ONE_MINUS_PREV_COLOR:
+		case TBS_ONE_MINUS_TEX_COLOR:
+		case TBS_ONE_MINUS_VERT_COLOR:
+		case TBS_ONE_MINUS_CONST_COLOR:
+			return (isAlpha) ? GL_ONE_MINUS_SRC_ALPHA : GL_ONE_MINUS_SRC_COLOR;
+
+		// All four cases should return the same value.
+		case TBS_ONE_MINUS_PREV_ALPHA:
+		case TBS_ONE_MINUS_TEX_ALPHA:
+		case TBS_ONE_MINUS_VERT_ALPHA:
+		case TBS_ONE_MINUS_CONST_ALPHA:
+			return GL_ONE_MINUS_SRC_ALPHA;
+
+		default:
+			llwarns << "Unknown eTextureBlendSrc: " << src << ".  Using Source Color or Alpha instead." << llendl;
+			return (isAlpha) ? GL_SRC_ALPHA: GL_SRC_COLOR;
+	}
+}
+
+void LLTexUnit::setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2, bool isAlpha)
+{
+	activate();
+	if (mCurrBlendType != TB_COMBINE)
+	{
+		mCurrBlendType = TB_COMBINE;
+		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+	}
+
+	// We want an early out, because this function does a LOT of stuff.
+	if ( (isAlpha && (mCurrAlphaOp == op) && (mCurrAlphaSrc1 == src1) && (mCurrAlphaSrc2 == src2) )
+		|| (!isAlpha && (mCurrColorOp == op) && (mCurrColorSrc1 == src1) && (mCurrColorSrc2 == src2) ))
+	{
+		return;
+	}
+
+	// Get the gl source enums according to the eTextureBlendSrc sources passed in
+	GLint source1 = getTextureSource(src1);
+	GLint source2 = getTextureSource(src2);
+	// Get the gl operand enums according to the eTextureBlendSrc sources passed in
+	GLint operand1 = getTextureSourceType(src1, isAlpha);
+	GLint operand2 = getTextureSourceType(src2, isAlpha);
+	// Default the scale amount to 1
+	S32 scale_amount = 1;
+	GLenum comb_enum, src0_enum, src1_enum, src2_enum, operand0_enum, operand1_enum, operand2_enum;
+	
+	if (isAlpha)
+	{
+		// Set enums to ALPHA ones
+		comb_enum = GL_COMBINE_ALPHA_ARB;
+		src0_enum = GL_SOURCE0_ALPHA_ARB;
+		src1_enum = GL_SOURCE1_ALPHA_ARB;
+		src2_enum = GL_SOURCE2_ALPHA_ARB;
+		operand0_enum = GL_OPERAND0_ALPHA_ARB;
+		operand1_enum = GL_OPERAND1_ALPHA_ARB;
+		operand2_enum = GL_OPERAND2_ALPHA_ARB;
+
+		// cache current combiner
+		mCurrAlphaOp = op;
+		mCurrAlphaSrc1 = src1;
+		mCurrAlphaSrc2 = src2;
+	}
+	else 
+	{
+		// Set enums to ALPHA ones
+		comb_enum = GL_COMBINE_RGB_ARB;
+		src0_enum = GL_SOURCE0_RGB_ARB;
+		src1_enum = GL_SOURCE1_RGB_ARB;
+		src2_enum = GL_SOURCE2_RGB_ARB;
+		operand0_enum = GL_OPERAND0_RGB_ARB;
+		operand1_enum = GL_OPERAND1_RGB_ARB;
+		operand2_enum = GL_OPERAND2_RGB_ARB;
+
+		// cache current combiner
+		mCurrColorOp = op;
+		mCurrColorSrc1 = src1;
+		mCurrColorSrc2 = src2;
+	}
+
+	switch(op)
+	{
+		case TBO_REPLACE:
+			// Slightly special syntax (no second sources), just set all and return.
+			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_REPLACE);
+			glTexEnvi(GL_TEXTURE_ENV, src0_enum, source1);
+			glTexEnvi(GL_TEXTURE_ENV, operand0_enum, operand1);
+			(isAlpha) ? setAlphaScale(1) : setColorScale(1);
+			return;
+
+		case TBO_MULT:
+			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_MODULATE);
+			break;
+
+		case TBO_MULT_X2:
+			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_MODULATE);
+			scale_amount = 2;
+			break;
+
+		case TBO_MULT_X4:
+			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_MODULATE);
+			scale_amount = 4;
+			break;
+
+		case TBO_ADD:
+			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_ADD);
+			break;
+
+		case TBO_ADD_SIGNED:
+			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_ADD_SIGNED_ARB);
+			break;
+
+		case TBO_SUBTRACT:
+			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_SUBTRACT_ARB);
+			break;
+
+		case TBO_LERP_VERT_ALPHA:
+			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_INTERPOLATE);
+			glTexEnvi(GL_TEXTURE_ENV, src2_enum, GL_PRIMARY_COLOR_ARB);
+			glTexEnvi(GL_TEXTURE_ENV, operand2_enum, GL_SRC_ALPHA);
+			break;
+
+		case TBO_LERP_TEX_ALPHA:
+			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_INTERPOLATE);
+			glTexEnvi(GL_TEXTURE_ENV, src2_enum, GL_TEXTURE);
+			glTexEnvi(GL_TEXTURE_ENV, operand2_enum, GL_SRC_ALPHA);
+			break;
+
+		case TBO_LERP_PREV_ALPHA:
+			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_INTERPOLATE);
+			glTexEnvi(GL_TEXTURE_ENV, src2_enum, GL_PREVIOUS_ARB);
+			glTexEnvi(GL_TEXTURE_ENV, operand2_enum, GL_SRC_ALPHA);
+			break;
+
+		case TBO_LERP_CONST_ALPHA:
+			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_INTERPOLATE);
+			glTexEnvi(GL_TEXTURE_ENV, src2_enum, GL_CONSTANT_ARB);
+			glTexEnvi(GL_TEXTURE_ENV, operand2_enum, GL_SRC_ALPHA);
+			break;
+
+		case TBO_LERP_VERT_COLOR:
+			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_INTERPOLATE);
+			glTexEnvi(GL_TEXTURE_ENV, src2_enum, GL_PRIMARY_COLOR_ARB);
+			glTexEnvi(GL_TEXTURE_ENV, operand2_enum, (isAlpha) ? GL_SRC_ALPHA : GL_SRC_COLOR);
+			break;
+
+		default:
+			llwarns << "Unknown eTextureBlendOp: " << op << ".  Setting op to replace." << llendl;
+			// Slightly special syntax (no second sources), just set all and return.
+			glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_REPLACE);
+			glTexEnvi(GL_TEXTURE_ENV, src0_enum, source1);
+			glTexEnvi(GL_TEXTURE_ENV, operand0_enum, operand1);
+			(isAlpha) ? setAlphaScale(1) : setColorScale(1);
+			return;
+	}
+
+	// Set sources, operands, and scale accordingly
+	glTexEnvi(GL_TEXTURE_ENV, src0_enum, source1);
+	glTexEnvi(GL_TEXTURE_ENV, operand0_enum, operand1);
+	glTexEnvi(GL_TEXTURE_ENV, src1_enum, source2);
+	glTexEnvi(GL_TEXTURE_ENV, operand1_enum, operand2);
+	(isAlpha) ? setAlphaScale(scale_amount) : setColorScale(scale_amount);
+}
+
+void LLTexUnit::setColorScale(S32 scale)
+{
+	if (mCurrColorScale != scale)
+	{
+		mCurrColorScale = scale;
+		glTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE, scale );
+	}
+}
+
+void LLTexUnit::setAlphaScale(S32 scale)
+{
+	if (mCurrAlphaScale != scale)
+	{
+		mCurrAlphaScale = scale;
+		glTexEnvi( GL_TEXTURE_ENV, GL_ALPHA_SCALE, scale );
+	}
+}
+
+LLRender::LLRender()
+{
+	mCount = 0;
+	mMode = LLVertexBuffer::TRIANGLES;
+	mBuffer = new LLVertexBuffer(immediate_mask, 0);
+	mBuffer->allocateBuffer(4096, 0, TRUE);
+	mBuffer->getVertexStrider(mVerticesp);
+	mBuffer->getTexCoordStrider(mTexcoordsp);
+	mBuffer->getColorStrider(mColorsp);
+
+	for (unsigned int i = 0; i < LL_NUM_TEXTURE_LAYERS; i++)
+	{
+		mTexUnits.push_back(new LLTexUnit(i));
+	}
+}
+
+LLRender::~LLRender()
+{
+	for (U32 i = 0; i < mTexUnits.size(); i++)
+	{
+		delete mTexUnits[i];
+	}
+}
+
+void LLRender::translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z)
+{
+	flush();
+	glTranslatef(x,y,z);
+}
+
+void LLRender::pushMatrix()
+{
+	flush();
+	glPushMatrix();
+}
+
+void LLRender::popMatrix()
+{
+	flush();
+	glPopMatrix();
+}
+
+void LLRender::setColorMask(bool writeColor, bool writeAlpha)
+{
+	setColorMask(writeColor, writeColor, writeColor, writeAlpha);
+}
+
+void LLRender::setColorMask(bool writeColorR, bool writeColorG, bool writeColorB, bool writeAlpha)
+{
+	flush();
+	glColorMask(writeColorR, writeColorG, writeColorB, writeAlpha);
+}
+
+void LLRender::setSceneBlendType(eBlendType type)
+{
+	flush();
+	switch (type) 
+	{
+		case BT_ALPHA:
+			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+			break;
+		case BT_ADD:
+			glBlendFunc(GL_ONE, GL_ONE);
+			break;
+		case BT_ADD_WITH_ALPHA:
+			glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+			break;
+		case BT_MULT:
+			glBlendFunc(GL_DST_COLOR, GL_ZERO);
+			break;
+		case BT_MULT_X2:
+			glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
+			break;
+		case BT_REPLACE:
+			glBlendFunc(GL_ONE, GL_ZERO);
+			break;
+		default:
+			llerrs << "Unknown Scene Blend Type: " << type << llendl;
+			break;
+	}
+}
+
+void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value)
+{
+	flush();
+	if (func == CF_DEFAULT)
+	{
+		glAlphaFunc(GL_GREATER, 0.01f);
+	} 
+	else
+	{
+		glAlphaFunc(sGLCompareFunc[func], value);
+	}
+}
+
+void LLRender::blendFunc(eBlendFactor sfactor, eBlendFactor dfactor)
+{
+	flush();
+	glBlendFunc(sGLBlendFactor[sfactor], sGLBlendFactor[dfactor]);
+}
+
+LLTexUnit* LLRender::getTexUnit(U32 index)
+{
+	if (index < mTexUnits.size())
+	{
+		return mTexUnits[index];
+	}
+	llerrs << "Non-existing texture unit layer requested: " << index << llendl;
+	return NULL;
+}
+
+void LLRender::begin(const GLuint& mode)
+{
+	if (mode != mMode)
+	{
+		if (mMode == LLVertexBuffer::QUADS ||
+			mMode == LLVertexBuffer::LINES ||
+			mMode == LLVertexBuffer::TRIANGLES ||
+			mMode == LLVertexBuffer::POINTS)
+		{
+			flush();
+		}
+		else if (mCount != 0)
+		{
+			llerrs << "gGL.begin() called redundantly." << llendl;
+		}
+		
+		mMode = mode;
+	}
+}
+
+void LLRender::end()
+{ 
+	if (mCount == 0)
+	{
+		return;
+		//IMM_ERRS << "GL begin and end called with no vertices specified." << llendl;
+	}
+
+	if ((mMode != LLVertexBuffer::QUADS && 
+		mMode != LLVertexBuffer::LINES &&
+		mMode != LLVertexBuffer::TRIANGLES &&
+		mMode != LLVertexBuffer::POINTS) ||
+		mCount > 2048)
+	{
+		flush();
+	}
+}
+void LLRender::flush()
+{
+	if (mCount > 0)
+	{
+#if 0
+		if (!glIsEnabled(GL_VERTEX_ARRAY))
+		{
+			llerrs << "foo 1" << llendl;
+		}
+
+		if (!glIsEnabled(GL_COLOR_ARRAY))
+		{
+			llerrs << "foo 2" << llendl;
+		}
+
+		if (!glIsEnabled(GL_TEXTURE_COORD_ARRAY))
+		{
+			llerrs << "foo 3" << llendl;
+		}
+
+		if (glIsEnabled(GL_NORMAL_ARRAY))
+		{
+			llerrs << "foo 7" << llendl;
+		}
+
+		GLvoid* pointer;
+
+		glGetPointerv(GL_VERTEX_ARRAY_POINTER, &pointer);
+		if (pointer != &(mBuffer[0].v))
+		{
+			llerrs << "foo 4" << llendl;
+		}
+
+		glGetPointerv(GL_COLOR_ARRAY_POINTER, &pointer);
+		if (pointer != &(mBuffer[0].c))
+		{
+			llerrs << "foo 5" << llendl;
+		}
+
+		glGetPointerv(GL_TEXTURE_COORD_ARRAY_POINTER, &pointer);
+		if (pointer != &(mBuffer[0].uv))
+		{
+			llerrs << "foo 6" << llendl;
+		}
+#endif
+				
+		mBuffer->setBuffer(immediate_mask);
+		mBuffer->drawArrays(mMode, 0, mCount);
+
+		mVerticesp[0] = mVerticesp[mCount];
+		mTexcoordsp[0] = mTexcoordsp[mCount];
+		mColorsp[0] = mColorsp[mCount];
+		mCount = 0;
+	}
+}
+void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z)
+{ 
+	if (mCount >= 4096)
+	{
+	//	llwarns << "GL immediate mode overflow.  Some geometry not drawn." << llendl;
+		return;
+	}
+
+	mVerticesp[mCount] = LLVector3(x,y,z);
+	mCount++;
+	if (mCount < 4096)
+	{
+		mVerticesp[mCount] = mVerticesp[mCount-1];
+		mColorsp[mCount] = mColorsp[mCount-1];
+		mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+	}
+}
+void LLRender::vertex2i(const GLint& x, const GLint& y)
+{
+	vertex3f((GLfloat) x, (GLfloat) y, 0);	
+}
+
+void LLRender::vertex2f(const GLfloat& x, const GLfloat& y)
+{ 
+	vertex3f(x,y,0);
+}
+
+void LLRender::vertex2fv(const GLfloat* v)
+{ 
+	vertex3f(v[0], v[1], 0);
+}
+
+void LLRender::vertex3fv(const GLfloat* v)
+{
+	vertex3f(v[0], v[1], v[2]);
+}
+
+void LLRender::texCoord2f(const GLfloat& x, const GLfloat& y)
+{ 
+	mTexcoordsp[mCount] = LLVector2(x,y);
+}
+
+void LLRender::texCoord2i(const GLint& x, const GLint& y)
+{ 
+	texCoord2f((GLfloat) x, (GLfloat) y);
+}
+
+void LLRender::texCoord2fv(const GLfloat* tc)
+{ 
+	texCoord2f(tc[0], tc[1]);
+}
+
+void LLRender::color4ub(const GLubyte& r, const GLubyte& g, const GLubyte& b, const GLubyte& a)
+{
+	mColorsp[mCount] = LLColor4U(r,g,b,a);
+}
+void LLRender::color4ubv(const GLubyte* c)
+{
+	color4ub(c[0], c[1], c[2], c[3]);
+}
+
+void LLRender::color4f(const GLfloat& r, const GLfloat& g, const GLfloat& b, const GLfloat& a)
+{
+	color4ub((GLubyte) (llclamp(r, 0.f, 1.f)*255),
+		(GLubyte) (llclamp(g, 0.f, 1.f)*255),
+		(GLubyte) (llclamp(b, 0.f, 1.f)*255),
+		(GLubyte) (llclamp(a, 0.f, 1.f)*255));
+}
+
+void LLRender::color4fv(const GLfloat* c)
+{ 
+	color4f(c[0],c[1],c[2],c[3]);
+}
+
+void LLRender::color3f(const GLfloat& r, const GLfloat& g, const GLfloat& b)
+{ 
+	color4f(r,g,b,1);
+}
+
+void LLRender::color3fv(const GLfloat* c)
+{ 
+	color4f(c[0],c[1],c[2],1);
+}
+
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
new file mode 100644
index 0000000000..2fa3237ef9
--- /dev/null
+++ b/indra/llrender/llrender.h
@@ -0,0 +1,239 @@
+/** 
+ * @file llrender.h
+ * @brief LLRender definition
+ *
+ *	This class acts as a wrapper for OpenGL calls.
+ *	The goal of this class is to minimize the number of api calls due to legacy rendering
+ *	code, to define an interface for a multiple rendering API abstraction of the UI
+ *	rendering, and to abstract out direct rendering calls in a way that is cleaner and easier to maintain.
+ *
+ * $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_LLGLRENDER_H
+#define LL_LLGLRENDER_H
+
+#include "stdtypes.h"
+#include "llgltypes.h"
+#include "llglheaders.h"
+#include "llvertexbuffer.h"
+
+class LLTexUnit
+{
+public:
+	typedef enum 
+	{
+		TB_REPLACE = 0,
+		TB_ADD,
+		TB_MULT,
+		TB_MULT_X2,
+		TB_ALPHA_BLEND,
+		TB_COMBINE			// Doesn't need to be set directly, setTexture___Blend() set TB_COMBINE automatically
+	} eTextureBlendType;
+
+	typedef enum 
+	{
+		TBO_REPLACE = 0,			// Use Source 1
+		TBO_MULT,					// Multiply: ( Source1 * Source2 )
+		TBO_MULT_X2,				// Multiply then scale by 2:  ( 2.0 * ( Source1 * Source2 ) )
+		TBO_MULT_X4,				// Multiply then scale by 4:  ( 4.0 * ( Source1 * Source2 ) )
+		TBO_ADD,					// Add: ( Source1 + Source2 )
+		TBO_ADD_SIGNED,				// Add then subtract 0.5: ( ( Source1 + Source2 ) - 0.5 )
+		TBO_SUBTRACT,				// Subtract Source2 from Source1: ( Source1 - Source2 )
+		TBO_LERP_VERT_ALPHA,		// Interpolate based on Vertex Alpha (VA): ( Source1 * VA + Source2 * (1-VA) )
+		TBO_LERP_TEX_ALPHA,			// Interpolate based on Texture Alpha (TA): ( Source1 * TA + Source2 * (1-TA) )
+		TBO_LERP_PREV_ALPHA,		// Interpolate based on Previous Alpha (PA): ( Source1 * PA + Source2 * (1-PA) )
+		TBO_LERP_CONST_ALPHA,		// Interpolate based on Const Alpha (CA): ( Source1 * CA + Source2 * (1-CA) )
+		TBO_LERP_VERT_COLOR			// Interpolate based on Vertex Col (VC): ( Source1 * VC + Source2 * (1-VC) )
+										// *Note* TBO_LERP_VERTEX_COLOR only works with setTextureColorBlend(),
+										// and falls back to TBO_LERP_VERTEX_ALPHA for setTextureAlphaBlend().
+	} eTextureBlendOp;
+
+	typedef enum 
+	{
+		TBS_PREV_COLOR = 0,			// Color from the previous texture stage
+		TBS_PREV_ALPHA,
+		TBS_ONE_MINUS_PREV_COLOR,
+		TBS_ONE_MINUS_PREV_ALPHA,
+		TBS_TEX_COLOR,				// Color from the texture bound to this stage
+		TBS_TEX_ALPHA,
+		TBS_ONE_MINUS_TEX_COLOR,
+		TBS_ONE_MINUS_TEX_ALPHA,
+		TBS_VERT_COLOR,				// The vertex color currently set
+		TBS_VERT_ALPHA,
+		TBS_ONE_MINUS_VERT_COLOR,
+		TBS_ONE_MINUS_VERT_ALPHA,
+		TBS_CONST_COLOR,			// The constant color value currently set
+		TBS_CONST_ALPHA,
+		TBS_ONE_MINUS_CONST_COLOR,
+		TBS_ONE_MINUS_CONST_ALPHA
+	} eTextureBlendSrc;
+
+	LLTexUnit(U32 index);
+	U32 getIndex(void);
+
+	void enable(void);
+	void disable(void);
+	void activate(void);
+
+	void bindTexture(const LLImageGL* texture);
+	void unbindTexture(void);
+
+	void setTextureBlendType(eTextureBlendType type);
+
+	inline void setTextureColorBlend(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2 = TBS_PREV_COLOR)
+	{ setTextureCombiner(op, src1, src2, false); }
+
+	// NOTE: If *_COLOR enums are passed to src1 or src2, the corresponding *_ALPHA enum will be used instead.
+	inline void setTextureAlphaBlend(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2 = TBS_PREV_ALPHA)
+	{ setTextureCombiner(op, src1, src2, true); }	
+
+private:
+	U32					mIndex;
+	bool				mIsEnabled;
+	eTextureBlendType	mCurrBlendType;
+	eTextureBlendOp		mCurrColorOp;
+	eTextureBlendSrc	mCurrColorSrc1;
+	eTextureBlendSrc	mCurrColorSrc2;
+	eTextureBlendOp		mCurrAlphaOp;
+	eTextureBlendSrc	mCurrAlphaSrc1;
+	eTextureBlendSrc	mCurrAlphaSrc2;
+	S32					mCurrColorScale;
+	S32					mCurrAlphaScale;
+	
+	void debugTextureUnit(void);
+	void setColorScale(S32 scale);
+	void setAlphaScale(S32 scale);
+	GLint getTextureSource(eTextureBlendSrc src);
+	GLint getTextureSourceType(eTextureBlendSrc src, bool isAlpha = false);
+	void setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2, bool isAlpha = false);
+};
+
+class LLRender
+{
+	friend class LLTexUnit;
+public:
+	typedef enum 
+	{
+		CF_NEVER = 0,
+		CF_ALWAYS,
+		CF_LESS,
+		CF_LESS_EQUAL,
+		CF_EQUAL,
+		CF_NOT_EQUAL,
+		CF_GREATER_EQUAL,
+		CF_GREATER,
+		CF_DEFAULT
+	}  eCompareFunc;
+
+	typedef enum 
+	{
+		BT_ALPHA = 0,
+		BT_ADD,
+		BT_ADD_WITH_ALPHA,	// Additive blend modulated by the fragment's alpha.
+		BT_MULT,
+		BT_MULT_X2,
+		BT_REPLACE
+	} eBlendType;
+
+	typedef enum 
+	{
+		BF_ONE = 0,
+		BF_ZERO,
+		BF_DEST_COLOR,
+		BF_SOURCE_COLOR,
+		BF_ONE_MINUS_DEST_COLOR,
+		BF_ONE_MINUS_SOURCE_COLOR,
+		BF_DEST_ALPHA,
+		BF_SOURCE_ALPHA,
+		BF_ONE_MINUS_DEST_ALPHA,
+		BF_ONE_MINUS_SOURCE_ALPHA
+	} eBlendFactor;
+
+	LLRender();
+	~LLRender();
+
+	void translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z);
+	void pushMatrix();
+	void popMatrix();
+
+	void flush();
+
+	void begin(const GLuint& mode);
+	void end();
+	void vertex2i(const GLint& x, const GLint& y);
+	void vertex2f(const GLfloat& x, const GLfloat& y);
+	void vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z);
+	void vertex2fv(const GLfloat* v);
+	void vertex3fv(const GLfloat* v);
+	
+	void texCoord2i(const GLint& x, const GLint& y);
+	void texCoord2f(const GLfloat& x, const GLfloat& y);
+	void texCoord2fv(const GLfloat* tc);
+
+	void color4ub(const GLubyte& r, const GLubyte& g, const GLubyte& b, const GLubyte& a);
+	void color4f(const GLfloat& r, const GLfloat& g, const GLfloat& b, const GLfloat& a);
+	void color4fv(const GLfloat* c);
+	void color3f(const GLfloat& r, const GLfloat& g, const GLfloat& b);
+	void color3fv(const GLfloat* c);
+	void color4ubv(const GLubyte* c);
+
+	void setColorMask(bool writeColor, bool writeAlpha);
+	void setColorMask(bool writeColorR, bool writeColorG, bool writeColorB, bool writeAlpha);
+	void setSceneBlendType(eBlendType type);
+
+	void setAlphaRejectSettings(eCompareFunc func, F32 value = 0.01f);
+
+	void blendFunc(eBlendFactor sfactor, eBlendFactor dfactor);
+
+	LLTexUnit* getTexUnit(U32 index);
+
+	typedef struct Vertex
+	{
+		GLfloat v[3];
+		GLubyte c[4];
+		GLfloat uv[2];
+	};
+
+public:
+
+private:
+	U32 mCount;
+	U32 mMode;
+	U32 mCurrTextureUnitIndex;
+	LLPointer<LLVertexBuffer> mBuffer;
+	LLStrider<LLVector3> mVerticesp;
+	LLStrider<LLVector2> mTexcoordsp;
+	LLStrider<LLColor4U> mColorsp;
+	std::vector<LLTexUnit*> mTexUnits;
+};
+
+
+
+extern LLRender gGL;
+
+#endif
diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
index 5111c7ae2d..885ccde2d1 100644
--- a/indra/llrender/llrendertarget.cpp
+++ b/indra/llrender/llrendertarget.cpp
@@ -32,7 +32,7 @@
 #include "linden_common.h"
 
 #include "llrendertarget.h"
-#include "llglimmediate.h"
+#include "llrender.h"
 #include "llgl.h"
 
 
@@ -181,6 +181,7 @@ void LLRenderTarget::clear()
 	{
 		LLGLEnable scissor(GL_SCISSOR_TEST);
 		glScissor(0, 0, mResX, mResY);
+		stop_glerror();
 		glClear(mask);
 	}
 }
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 2f053a6493..d79a0d6034 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -38,7 +38,7 @@
 #include "llglheaders.h"
 #include "llmemory.h"
 #include "llmemtype.h"
-#include "llglimmediate.h"
+#include "llrender.h"
 
 //============================================================================
 
@@ -768,11 +768,26 @@ U8* LLVertexBuffer::mapBuffer(S32 access)
 		sMapped = TRUE;*/
 		if (!mMappedData)
 		{
+			GLint buff;
+			glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff);
+			if (buff != mGLBuffer)
+			{
+				llerrs << "Invalid GL vertex buffer bound: " << buff << llendl;
+			}
+
+			
 			llerrs << "glMapBuffer returned NULL (no vertex data)" << llendl;
 		}
 
 		if (!mMappedIndexData)
 		{
+			GLint buff;
+			glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff);
+			if (buff != mGLIndices)
+			{
+				llerrs << "Invalid GL index buffer bound: " << buff << llendl;
+			}
+
 			llerrs << "glMapBuffer returned NULL (no index data)" << llendl;
 		}
 
@@ -952,6 +967,22 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
 			sIBOActive = TRUE;
 		}
 		
+		if (gDebugGL)
+		{
+			GLint buff;
+			glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff);
+			if (buff != mGLBuffer)
+			{
+				llerrs << "Invalid GL vertex buffer bound: " << buff << llendl;
+			}
+
+			glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff);
+			if (buff != mGLIndices)
+			{
+				llerrs << "Invalid GL index buffer bound: " << buff << llendl;
+			}
+		}
+
 		if (mResized)
 		{
 			if (gDebugGL)
-- 
cgit v1.2.3