summaryrefslogtreecommitdiff
path: root/indra/llrender/llrender.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llrender/llrender.cpp')
-rwxr-xr-x[-rw-r--r--]indra/llrender/llrender.cpp1399
1 files changed, 1233 insertions, 166 deletions
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index c3540a717c..1ca6e99ecf 100644..100755
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -1,32 +1,26 @@
-/**
+ /**
* @file llrender.cpp
* @brief LLRender implementation
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* 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://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
*
- * 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://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * 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.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -36,39 +30,45 @@
#include "llvertexbuffer.h"
#include "llcubemap.h"
+#include "llglslshader.h"
#include "llimagegl.h"
#include "llrendertarget.h"
#include "lltexture.h"
+#include "llshadermgr.h"
LLRender gGL;
// Handy copies of last good GL matrices
-F64 gGLModelView[16];
-F64 gGLLastModelView[16];
-F64 gGLLastProjection[16];
-F64 gGLProjection[16];
+F32 gGLModelView[16];
+F32 gGLLastModelView[16];
+F32 gGLLastProjection[16];
+F32 gGLProjection[16];
S32 gGLViewport[4];
U32 LLRender::sUICalls = 0;
U32 LLRender::sUIVerts = 0;
+U32 LLTexUnit::sWhiteTexture = 0;
+bool LLRender::sGLCoreProfile = false;
-static const U32 LL_NUM_TEXTURE_LAYERS = 16;
+static const U32 LL_NUM_TEXTURE_LAYERS = 32;
+static const U32 LL_NUM_LIGHT_UNITS = 8;
-static GLenum sGLTextureType[] =
+static const GLenum sGLTextureType[] =
{
GL_TEXTURE_2D,
GL_TEXTURE_RECTANGLE_ARB,
- GL_TEXTURE_CUBE_MAP_ARB
+ GL_TEXTURE_CUBE_MAP_ARB,
+ GL_TEXTURE_2D_MULTISAMPLE
};
-static GLint sGLAddressMode[] =
+static const GLint sGLAddressMode[] =
{
GL_REPEAT,
GL_MIRRORED_REPEAT,
GL_CLAMP_TO_EDGE
};
-static GLenum sGLCompareFunc[] =
+static const GLenum sGLCompareFunc[] =
{
GL_NEVER,
GL_ALWAYS,
@@ -82,7 +82,7 @@ static GLenum sGLCompareFunc[] =
const U32 immediate_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXCOORD0;
-static GLenum sGLBlendFactor[] =
+static const GLenum sGLBlendFactor[] =
{
GL_ONE,
GL_ZERO,
@@ -99,12 +99,12 @@ static GLenum sGLBlendFactor[] =
};
LLTexUnit::LLTexUnit(S32 index)
-: mCurrTexType(TT_NONE), 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), mCurrTexture(0),
-mHasMipMaps(false)
+ : mCurrTexType(TT_NONE), 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), mCurrTexture(0),
+ mHasMipMaps(false)
{
llassert_always(index < (S32)LL_NUM_TEXTURE_LAYERS);
mIndex = index;
@@ -124,14 +124,30 @@ void LLTexUnit::refreshState(void)
gGL.flush();
glActiveTextureARB(GL_TEXTURE0_ARB + mIndex);
+
+ //
+ // Per apple spec, don't call glEnable/glDisable when index exceeds max texture units
+ // http://www.mailinglistarchive.com/html/mac-opengl@lists.apple.com/2008-07/msg00653.html
+ //
+ bool enableDisable = !LLGLSLShader::sNoFixedFunction &&
+ (mIndex < gGLManager.mNumTextureUnits) && mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE;
+
if (mCurrTexType != TT_NONE)
{
- glEnable(sGLTextureType[mCurrTexType]);
+ if (enableDisable)
+ {
+ glEnable(sGLTextureType[mCurrTexType]);
+ }
+
glBindTexture(sGLTextureType[mCurrTexType], mCurrTexture);
}
else
{
- glDisable(GL_TEXTURE_2D);
+ if (enableDisable)
+ {
+ glDisable(GL_TEXTURE_2D);
+ }
+
glBindTexture(GL_TEXTURE_2D, 0);
}
@@ -164,15 +180,25 @@ void LLTexUnit::enable(eTextureType type)
if ( (mCurrTexType != type || gGL.mDirty) && (type != TT_NONE) )
{
+ stop_glerror();
activate();
+ stop_glerror();
if (mCurrTexType != TT_NONE && !gGL.mDirty)
{
disable(); // Force a disable of a previous texture type if it's enabled.
+ stop_glerror();
}
mCurrTexType = type;
gGL.flush();
- glEnable(sGLTextureType[type]);
+ if (!LLGLSLShader::sNoFixedFunction &&
+ type != LLTexUnit::TT_MULTISAMPLE_TEXTURE &&
+ mIndex < gGLManager.mNumTextureUnits)
+ {
+ stop_glerror();
+ glEnable(sGLTextureType[type]);
+ stop_glerror();
+ }
}
}
@@ -185,7 +211,13 @@ void LLTexUnit::disable(void)
activate();
unbind(mCurrTexType);
gGL.flush();
- glDisable(sGLTextureType[mCurrTexType]);
+ if (!LLGLSLShader::sNoFixedFunction &&
+ mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE &&
+ mIndex < gGLManager.mNumTextureUnits)
+ {
+ glDisable(sGLTextureType[mCurrTexType]);
+ }
+
mCurrTexType = TT_NONE;
}
}
@@ -193,35 +225,16 @@ void LLTexUnit::disable(void)
bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
{
stop_glerror();
- if (mIndex < 0) return false;
-
+ if (mIndex >= 0)
+ {
gGL.flush();
LLImageGL* gl_tex = NULL ;
- if (texture == NULL || !(gl_tex = texture->getGLTexture()))
+ if (texture != NULL && (gl_tex = texture->getGLTexture()))
{
- llwarns << "NULL LLTexUnit::bind texture" << llendl;
- return false;
- }
-
- if (!gl_tex->getTexName()) //if texture does not exist
+ if (gl_tex->getTexName()) //if texture exists
{
- //if deleted, will re-generate it immediately
- texture->forceImmediateUpdate() ;
-
- gl_tex->forceUpdateBindStats() ;
- return texture->bindDefaultImage(mIndex);
- }
-
//in audit, replace the selected texture by the default one.
- if(gAuditTexture && for_rendering && LLImageGL::sCurTexPickSize > 0)
- {
- if(texture->getWidth() * texture->getHeight() == LLImageGL::sCurTexPickSize)
- {
- gl_tex->updateBindStats(gl_tex->mTextureMemory);
- return bind(LLImageGL::sHighlightTexturep.get());
- }
- }
if ((mCurrTexture != gl_tex->getTexName()) || forceBind)
{
activate();
@@ -241,6 +254,27 @@ bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
setTextureFilteringOption(gl_tex->mFilterOption);
}
}
+ }
+ else
+ {
+ //if deleted, will re-generate it immediately
+ texture->forceImmediateUpdate() ;
+
+ gl_tex->forceUpdateBindStats() ;
+ return texture->bindDefaultImage(mIndex);
+ }
+ }
+ else
+ {
+ LL_WARNS() << "NULL LLTexUnit::bind texture" << LL_ENDL;
+ return false;
+ }
+ }
+ else
+ { // mIndex < 0
+ return false;
+ }
+
return true;
}
@@ -251,7 +285,7 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind)
if(!texture)
{
- llwarns << "NULL LLTexUnit::bind texture" << llendl;
+ LL_WARNS() << "NULL LLTexUnit::bind texture" << LL_ENDL;
return false;
}
@@ -261,26 +295,35 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind)
{
return bind(LLImageGL::sDefaultGLTexture) ;
}
+ stop_glerror();
return false ;
}
if ((mCurrTexture != texture->getTexName()) || forceBind)
{
gGL.flush();
+ stop_glerror();
activate();
+ stop_glerror();
enable(texture->getTarget());
+ stop_glerror();
mCurrTexture = texture->getTexName();
glBindTexture(sGLTextureType[texture->getTarget()], mCurrTexture);
+ stop_glerror();
texture->updateBindStats(texture->mTextureMemory);
mHasMipMaps = texture->mHasMipMaps;
if (texture->mTexOptionsDirty)
{
+ stop_glerror();
texture->mTexOptionsDirty = false;
setTextureAddressMode(texture->mAddressMode);
setTextureFilteringOption(texture->mFilterOption);
+ stop_glerror();
}
}
+ stop_glerror();
+
return true;
}
@@ -292,7 +335,7 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap)
if (cubeMap == NULL)
{
- llwarns << "NULL LLTexUnit::bind cubemap" << llendl;
+ LL_WARNS() << "NULL LLTexUnit::bind cubemap" << LL_ENDL;
return false;
}
@@ -316,7 +359,7 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap)
}
else
{
- llwarns << "Using cube map without extension!" << llendl;
+ LL_WARNS() << "Using cube map without extension!" << LL_ENDL;
return false;
}
}
@@ -324,7 +367,6 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap)
}
// LLRenderTarget is unavailible on the mapserver since it uses FBOs.
-#if !LL_MESA_HEADLESS
bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth)
{
if (mIndex < 0) return false;
@@ -335,7 +377,7 @@ bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth)
{
if (renderTarget->hasStencil())
{
- llerrs << "Cannot bind a render buffer for sampling. Allocate render target without a stencil buffer if sampling of depth buffer is required." << llendl;
+ LL_ERRS() << "Cannot bind a render buffer for sampling. Allocate render target without a stencil buffer if sampling of depth buffer is required." << LL_ENDL;
}
bindManual(renderTarget->getUsage(), renderTarget->getDepth());
@@ -347,7 +389,6 @@ bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth)
return true;
}
-#endif // LL_MESA_HEADLESS
bool LLTexUnit::bindManual(eTextureType type, U32 texture, bool hasMips)
{
@@ -375,14 +416,24 @@ void LLTexUnit::unbind(eTextureType type)
if (mIndex < 0) return;
+ //always flush and activate for consistency
+ // some code paths assume unbind always flushes and sets the active texture
+ gGL.flush();
+ activate();
+
// Disabled caching of binding state.
if (mCurrTexType == type)
{
- gGL.flush();
-
- activate();
mCurrTexture = 0;
- glBindTexture(sGLTextureType[type], 0);
+ if (LLGLSLShader::sNoFixedFunction && type == LLTexUnit::TT_TEXTURE)
+ {
+ glBindTexture(sGLTextureType[type], sWhiteTexture);
+ }
+ else
+ {
+ glBindTexture(sGLTextureType[type], 0);
+ }
+ stop_glerror();
}
}
@@ -404,7 +455,7 @@ void LLTexUnit::setTextureAddressMode(eTextureAddressMode mode)
void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions option)
{
- if (mIndex < 0 || mCurrTexture == 0) return;
+ if (mIndex < 0 || mCurrTexture == 0 || mCurrTexType == LLTexUnit::TT_MULTISAMPLE_TEXTURE) return;
gGL.flush();
@@ -423,11 +474,25 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio
}
else if (option >= TFO_BILINEAR)
{
- glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ if (mHasMipMaps)
+ {
+ glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ }
+ else
+ {
+ glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ }
}
else
{
- glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ if (mHasMipMaps)
+ {
+ glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+ }
+ else
+ {
+ glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
}
if (gGLManager.mHasAnisotropic)
@@ -437,6 +502,9 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio
if (gGL.mMaxAnisotropy < 1.f)
{
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gGL.mMaxAnisotropy);
+
+ LL_INFOS() << "gGL.mMaxAnisotropy: " << gGL.mMaxAnisotropy << LL_ENDL ;
+ gGL.mMaxAnisotropy = llmax(1.f, gGL.mMaxAnisotropy) ;
}
glTexParameterf(sGLTextureType[mCurrTexType], GL_TEXTURE_MAX_ANISOTROPY_EXT, gGL.mMaxAnisotropy);
}
@@ -449,6 +517,11 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio
void LLTexUnit::setTextureBlendType(eTextureBlendType type)
{
+ if (LLGLSLShader::sNoFixedFunction)
+ { //texture blend type means nothing when using shaders
+ return;
+ }
+
if (mIndex < 0) return;
// Do nothing if it's already correctly set.
@@ -484,7 +557,7 @@ void LLTexUnit::setTextureBlendType(eTextureBlendType type)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
break;
default:
- llerrs << "Unknown Texture Blend Type: " << type << llendl;
+ LL_ERRS() << "Unknown Texture Blend Type: " << type << LL_ENDL;
break;
}
setColorScale(scale_amount);
@@ -524,7 +597,7 @@ GLint LLTexUnit::getTextureSource(eTextureBlendSrc src)
return GL_CONSTANT_ARB;
default:
- llwarns << "Unknown eTextureBlendSrc: " << src << ". Using Vertex Color instead." << llendl;
+ LL_WARNS() << "Unknown eTextureBlendSrc: " << src << ". Using Vertex Color instead." << LL_ENDL;
return GL_PRIMARY_COLOR_ARB;
}
}
@@ -562,13 +635,18 @@ GLint LLTexUnit::getTextureSourceType(eTextureBlendSrc src, bool isAlpha)
return GL_ONE_MINUS_SRC_ALPHA;
default:
- llwarns << "Unknown eTextureBlendSrc: " << src << ". Using Source Color or Alpha instead." << llendl;
+ LL_WARNS() << "Unknown eTextureBlendSrc: " << src << ". Using Source Color or Alpha instead." << LL_ENDL;
return (isAlpha) ? GL_SRC_ALPHA: GL_SRC_COLOR;
}
}
void LLTexUnit::setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2, bool isAlpha)
{
+ if (LLGLSLShader::sNoFixedFunction)
+ { //register combiners do nothing when not using fixed function
+ return;
+ }
+
if (mIndex < 0) return;
activate();
@@ -578,7 +656,7 @@ void LLTexUnit::setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eT
gGL.flush();
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)) ) && !gGL.mDirty)
@@ -698,7 +776,7 @@ void LLTexUnit::setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eT
break;
default:
- llwarns << "Unknown eTextureBlendOp: " << op << ". Setting op to replace." << llendl;
+ LL_WARNS() << "Unknown eTextureBlendOp: " << op << ". Setting op to replace." << LL_ENDL;
// 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);
@@ -746,24 +824,207 @@ void LLTexUnit::debugTextureUnit(void)
if ((GL_TEXTURE0_ARB + mIndex) != activeTexture)
{
U32 set_unit = (activeTexture - GL_TEXTURE0_ARB);
- llwarns << "Incorrect Texture Unit! Expected: " << set_unit << " Actual: " << mIndex << llendl;
+ LL_WARNS() << "Incorrect Texture Unit! Expected: " << set_unit << " Actual: " << mIndex << LL_ENDL;
+ }
+}
+
+LLLightState::LLLightState(S32 index)
+: mIndex(index),
+ mEnabled(false),
+ mConstantAtten(1.f),
+ mLinearAtten(0.f),
+ mQuadraticAtten(0.f),
+ mSpotExponent(0.f),
+ mSpotCutoff(180.f)
+{
+ if (mIndex == 0)
+ {
+ mDiffuse.set(1,1,1,1);
+ mSpecular.set(1,1,1,1);
+ }
+
+ mAmbient.set(0,0,0,1);
+ mPosition.set(0,0,1,0);
+ mSpotDirection.set(0,0,-1);
+}
+
+void LLLightState::enable()
+{
+ if (!mEnabled)
+ {
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glEnable(GL_LIGHT0+mIndex);
+ }
+ mEnabled = true;
+ }
+}
+
+void LLLightState::disable()
+{
+ if (mEnabled)
+ {
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glDisable(GL_LIGHT0+mIndex);
+ }
+ mEnabled = false;
+ }
+}
+
+void LLLightState::setDiffuse(const LLColor4& diffuse)
+{
+ if (mDiffuse != diffuse)
+ {
+ ++gGL.mLightHash;
+ mDiffuse = diffuse;
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightfv(GL_LIGHT0+mIndex, GL_DIFFUSE, mDiffuse.mV);
+ }
+ }
+}
+
+void LLLightState::setAmbient(const LLColor4& ambient)
+{
+ if (mAmbient != ambient)
+ {
+ ++gGL.mLightHash;
+ mAmbient = ambient;
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightfv(GL_LIGHT0+mIndex, GL_AMBIENT, mAmbient.mV);
+ }
+ }
+}
+
+void LLLightState::setSpecular(const LLColor4& specular)
+{
+ if (mSpecular != specular)
+ {
+ ++gGL.mLightHash;
+ mSpecular = specular;
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightfv(GL_LIGHT0+mIndex, GL_SPECULAR, mSpecular.mV);
+ }
+ }
+}
+
+void LLLightState::setPosition(const LLVector4& position)
+{
+ //always set position because modelview matrix may have changed
+ ++gGL.mLightHash;
+ mPosition = position;
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightfv(GL_LIGHT0+mIndex, GL_POSITION, mPosition.mV);
+ }
+ else
+ { //transform position by current modelview matrix
+ glh::vec4f pos(position.mV);
+
+ const glh::matrix4f& mat = gGL.getModelviewMatrix();
+ mat.mult_matrix_vec(pos);
+
+ mPosition.set(pos.v);
+ }
+
+}
+
+void LLLightState::setConstantAttenuation(const F32& atten)
+{
+ if (mConstantAtten != atten)
+ {
+ mConstantAtten = atten;
+ ++gGL.mLightHash;
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightf(GL_LIGHT0+mIndex, GL_CONSTANT_ATTENUATION, atten);
+ }
+ }
+}
+
+void LLLightState::setLinearAttenuation(const F32& atten)
+{
+ if (mLinearAtten != atten)
+ {
+ ++gGL.mLightHash;
+ mLinearAtten = atten;
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightf(GL_LIGHT0+mIndex, GL_LINEAR_ATTENUATION, atten);
+ }
+ }
+}
+
+void LLLightState::setQuadraticAttenuation(const F32& atten)
+{
+ if (mQuadraticAtten != atten)
+ {
+ ++gGL.mLightHash;
+ mQuadraticAtten = atten;
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightf(GL_LIGHT0+mIndex, GL_QUADRATIC_ATTENUATION, atten);
+ }
}
}
+void LLLightState::setSpotExponent(const F32& exponent)
+{
+ if (mSpotExponent != exponent)
+ {
+ ++gGL.mLightHash;
+ mSpotExponent = exponent;
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightf(GL_LIGHT0+mIndex, GL_SPOT_EXPONENT, exponent);
+ }
+ }
+}
+
+void LLLightState::setSpotCutoff(const F32& cutoff)
+{
+ if (mSpotCutoff != cutoff)
+ {
+ ++gGL.mLightHash;
+ mSpotCutoff = cutoff;
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightf(GL_LIGHT0+mIndex, GL_SPOT_CUTOFF, cutoff);
+ }
+ }
+}
+
+void LLLightState::setSpotDirection(const LLVector3& direction)
+{
+ //always set direction because modelview matrix may have changed
+ ++gGL.mLightHash;
+ mSpotDirection = direction;
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightfv(GL_LIGHT0+mIndex, GL_SPOT_DIRECTION, direction.mV);
+ }
+ else
+ { //transform direction by current modelview matrix
+ glh::vec3f dir(direction.mV);
+
+ const glh::matrix4f& mat = gGL.getModelviewMatrix();
+ mat.mult_matrix_dir(dir);
+
+ mSpotDirection.set(dir.v);
+ }
+}
LLRender::LLRender()
: mDirty(false),
mCount(0),
+ mQuadCycle(0),
mMode(LLRender::TRIANGLES),
mCurrTextureUnitIndex(0),
mMaxAnisotropy(0.f)
-{
- mBuffer = new LLVertexBuffer(immediate_mask, 0);
- mBuffer->allocateBuffer(4096, 0, TRUE);
- mBuffer->getVertexStrider(mVerticesp);
- mBuffer->getTexCoord0Strider(mTexcoordsp);
- mBuffer->getColorStrider(mColorsp);
-
+{
mTexUnits.reserve(LL_NUM_TEXTURE_LAYERS);
for (U32 i = 0; i < LL_NUM_TEXTURE_LAYERS; i++)
{
@@ -771,6 +1032,11 @@ LLRender::LLRender()
}
mDummyTexUnit = new LLTexUnit(-1);
+ for (U32 i = 0; i < LL_NUM_LIGHT_UNITS; ++i)
+ {
+ mLightState.push_back(new LLLightState(i));
+ }
+
for (U32 i = 0; i < 4; i++)
{
mCurrColorMask[i] = true;
@@ -778,8 +1044,21 @@ LLRender::LLRender()
mCurrAlphaFunc = CF_DEFAULT;
mCurrAlphaFuncVal = 0.01f;
- mCurrBlendSFactor = BF_UNDEF;
- mCurrBlendDFactor = BF_UNDEF;
+ mCurrBlendColorSFactor = BF_UNDEF;
+ mCurrBlendAlphaSFactor = BF_UNDEF;
+ mCurrBlendColorDFactor = BF_UNDEF;
+ mCurrBlendAlphaDFactor = BF_UNDEF;
+
+ mMatrixMode = LLRender::MM_MODELVIEW;
+
+ for (U32 i = 0; i < NUM_MATRIX_MODES; ++i)
+ {
+ mMatIdx[i] = 0;
+ mMatHash[i] = 0;
+ mCurMatHash[i] = 0xFFFFFFFF;
+ }
+
+ mLightHash = 0;
}
LLRender::~LLRender()
@@ -787,6 +1066,28 @@ LLRender::~LLRender()
shutdown();
}
+void LLRender::init()
+{
+ if (sGLCoreProfile && !LLVertexBuffer::sUseVAO)
+ { //bind a dummy vertex array object so we're core profile compliant
+#ifdef GL_ARB_vertex_array_object
+ U32 ret;
+ glGenVertexArrays(1, &ret);
+ glBindVertexArray(ret);
+#endif
+ }
+
+
+ llassert_always(mBuffer.isNull()) ;
+ stop_glerror();
+ mBuffer = new LLVertexBuffer(immediate_mask, 0);
+ mBuffer->allocateBuffer(4096, 0, TRUE);
+ mBuffer->getVertexStrider(mVerticesp);
+ mBuffer->getTexCoord0Strider(mTexcoordsp);
+ mBuffer->getColorStrider(mColorsp);
+ stop_glerror();
+}
+
void LLRender::shutdown()
{
for (U32 i = 0; i < mTexUnits.size(); i++)
@@ -796,6 +1097,13 @@ void LLRender::shutdown()
mTexUnits.clear();
delete mDummyTexUnit;
mDummyTexUnit = NULL;
+
+ for (U32 i = 0; i < mLightState.size(); ++i)
+ {
+ delete mLightState[i];
+ }
+ mLightState.clear();
+ mBuffer = NULL ;
}
void LLRender::refreshState(void)
@@ -818,70 +1126,408 @@ void LLRender::refreshState(void)
mDirty = false;
}
+void LLRender::syncLightState()
+{
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+
+ if (!shader)
+ {
+ return;
+ }
+
+ if (shader->mLightHash != mLightHash)
+ {
+ shader->mLightHash = mLightHash;
+
+ LLVector4 position[8];
+ LLVector3 direction[8];
+ LLVector3 attenuation[8];
+ LLVector3 diffuse[8];
+
+ for (U32 i = 0; i < 8; i++)
+ {
+ LLLightState* light = mLightState[i];
+
+ position[i] = light->mPosition;
+ direction[i] = light->mSpotDirection;
+ attenuation[i].set(light->mLinearAtten, light->mQuadraticAtten, light->mSpecular.mV[3]);
+ diffuse[i].set(light->mDiffuse.mV);
+ }
+
+ shader->uniform4fv(LLShaderMgr::LIGHT_POSITION, 8, position[0].mV);
+ shader->uniform3fv(LLShaderMgr::LIGHT_DIRECTION, 8, direction[0].mV);
+ shader->uniform3fv(LLShaderMgr::LIGHT_ATTENUATION, 8, attenuation[0].mV);
+ shader->uniform3fv(LLShaderMgr::LIGHT_DIFFUSE, 8, diffuse[0].mV);
+ shader->uniform4fv(LLShaderMgr::LIGHT_AMBIENT, 1, mAmbientLightColor.mV);
+ //HACK -- duplicate sunlight color for compatibility with drivers that can't deal with multiple shader objects referencing the same uniform
+ shader->uniform4fv(LLShaderMgr::SUNLIGHT_COLOR, 1, diffuse[0].mV);
+ }
+}
+
+void LLRender::syncMatrices()
+{
+ stop_glerror();
+
+ static const U32 name[] =
+ {
+ LLShaderMgr::MODELVIEW_MATRIX,
+ LLShaderMgr::PROJECTION_MATRIX,
+ LLShaderMgr::TEXTURE_MATRIX0,
+ LLShaderMgr::TEXTURE_MATRIX1,
+ LLShaderMgr::TEXTURE_MATRIX2,
+ LLShaderMgr::TEXTURE_MATRIX3,
+ };
+
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+
+ static glh::matrix4f cached_mvp;
+ static U32 cached_mvp_mdv_hash = 0xFFFFFFFF;
+ static U32 cached_mvp_proj_hash = 0xFFFFFFFF;
+
+ static glh::matrix4f cached_normal;
+ static U32 cached_normal_hash = 0xFFFFFFFF;
+
+ if (shader)
+ {
+ //llassert(shader);
+
+ bool mvp_done = false;
+
+ U32 i = MM_MODELVIEW;
+ if (mMatHash[i] != shader->mMatHash[i])
+ { //update modelview, normal, and MVP
+ glh::matrix4f& mat = mMatrix[i][mMatIdx[i]];
+
+ shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mat.m);
+ shader->mMatHash[i] = mMatHash[i];
+
+ //update normal matrix
+ S32 loc = shader->getUniformLocation(LLShaderMgr::NORMAL_MATRIX);
+ if (loc > -1)
+ {
+ if (cached_normal_hash != mMatHash[i])
+ {
+ cached_normal = mat.inverse().transpose();
+ cached_normal_hash = mMatHash[i];
+ }
+
+ glh::matrix4f& norm = cached_normal;
+
+ F32 norm_mat[] =
+ {
+ norm.m[0], norm.m[1], norm.m[2],
+ norm.m[4], norm.m[5], norm.m[6],
+ norm.m[8], norm.m[9], norm.m[10]
+ };
+
+ shader->uniformMatrix3fv(LLShaderMgr::NORMAL_MATRIX, 1, GL_FALSE, norm_mat);
+ }
+
+ //update MVP matrix
+ mvp_done = true;
+ loc = shader->getUniformLocation(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX);
+ if (loc > -1)
+ {
+ U32 proj = MM_PROJECTION;
+
+ if (cached_mvp_mdv_hash != mMatHash[i] || cached_mvp_proj_hash != mMatHash[MM_PROJECTION])
+ {
+ cached_mvp = mat;
+ cached_mvp.mult_left(mMatrix[proj][mMatIdx[proj]]);
+ cached_mvp_mdv_hash = mMatHash[i];
+ cached_mvp_proj_hash = mMatHash[MM_PROJECTION];
+ }
+
+ shader->uniformMatrix4fv(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX, 1, GL_FALSE, cached_mvp.m);
+ }
+ }
+
+
+ i = MM_PROJECTION;
+ if (mMatHash[i] != shader->mMatHash[i])
+ { //update projection matrix, normal, and MVP
+ glh::matrix4f& mat = mMatrix[i][mMatIdx[i]];
+
+ shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mat.m);
+ shader->mMatHash[i] = mMatHash[i];
+
+ if (!mvp_done)
+ {
+ //update MVP matrix
+ S32 loc = shader->getUniformLocation(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX);
+ if (loc > -1)
+ {
+ if (cached_mvp_mdv_hash != mMatHash[i] || cached_mvp_proj_hash != mMatHash[MM_PROJECTION])
+ {
+ U32 mdv = MM_MODELVIEW;
+ cached_mvp = mat;
+ cached_mvp.mult_right(mMatrix[mdv][mMatIdx[mdv]]);
+ cached_mvp_mdv_hash = mMatHash[MM_MODELVIEW];
+ cached_mvp_proj_hash = mMatHash[MM_PROJECTION];
+ }
+
+ shader->uniformMatrix4fv(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX, 1, GL_FALSE, cached_mvp.m);
+ }
+ }
+ }
+
+ for (i = MM_TEXTURE0; i < NUM_MATRIX_MODES; ++i)
+ {
+ if (mMatHash[i] != shader->mMatHash[i])
+ {
+ shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mMatrix[i][mMatIdx[i]].m);
+ shader->mMatHash[i] = mMatHash[i];
+ }
+ }
+
+
+ if (shader->mFeatures.hasLighting || shader->mFeatures.calculatesLighting)
+ { //also sync light state
+ syncLightState();
+ }
+ }
+ else if (!LLGLSLShader::sNoFixedFunction)
+ {
+ static const GLenum mode[] =
+ {
+ GL_MODELVIEW,
+ GL_PROJECTION,
+ GL_TEXTURE,
+ GL_TEXTURE,
+ GL_TEXTURE,
+ GL_TEXTURE,
+ };
+
+ for (U32 i = 0; i < 2; ++i)
+ {
+ if (mMatHash[i] != mCurMatHash[i])
+ {
+ glMatrixMode(mode[i]);
+ glLoadMatrixf(mMatrix[i][mMatIdx[i]].m);
+ mCurMatHash[i] = mMatHash[i];
+ }
+ }
+
+ for (U32 i = 2; i < NUM_MATRIX_MODES; ++i)
+ {
+ if (mMatHash[i] != mCurMatHash[i])
+ {
+ gGL.getTexUnit(i-2)->activate();
+ glMatrixMode(mode[i]);
+ glLoadMatrixf(mMatrix[i][mMatIdx[i]].m);
+ mCurMatHash[i] = mMatHash[i];
+ }
+ }
+ }
+
+ stop_glerror();
+}
+
void LLRender::translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z)
{
flush();
- glTranslatef(x,y,z);
+
+ {
+ glh::matrix4f trans_mat(1,0,0,x,
+ 0,1,0,y,
+ 0,0,1,z,
+ 0,0,0,1);
+
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(trans_mat);
+ mMatHash[mMatrixMode]++;
+ }
}
void LLRender::scalef(const GLfloat& x, const GLfloat& y, const GLfloat& z)
{
flush();
- glScalef(x,y,z);
+
+ {
+ glh::matrix4f scale_mat(x,0,0,0,
+ 0,y,0,0,
+ 0,0,z,0,
+ 0,0,0,1);
+
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(scale_mat);
+ mMatHash[mMatrixMode]++;
+ }
+}
+
+void LLRender::ortho(F32 left, F32 right, F32 bottom, F32 top, F32 zNear, F32 zFar)
+{
+ flush();
+
+ {
+
+ glh::matrix4f ortho_mat(2.f/(right-left),0,0, -(right+left)/(right-left),
+ 0,2.f/(top-bottom),0, -(top+bottom)/(top-bottom),
+ 0,0,-2.f/(zFar-zNear), -(zFar+zNear)/(zFar-zNear),
+ 0,0,0,1);
+
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(ortho_mat);
+ mMatHash[mMatrixMode]++;
+ }
+}
+
+void LLRender::rotatef(const GLfloat& a, const GLfloat& x, const GLfloat& y, const GLfloat& z)
+{
+ flush();
+
+ {
+ F32 r = a * DEG_TO_RAD;
+
+ F32 c = cosf(r);
+ F32 s = sinf(r);
+
+ F32 ic = 1.f-c;
+
+ glh::matrix4f rot_mat(x*x*ic+c, x*y*ic-z*s, x*z*ic+y*s, 0,
+ x*y*ic+z*s, y*y*ic+c, y*z*ic-x*s, 0,
+ x*z*ic-y*s, y*z*ic+x*s, z*z*ic+c, 0,
+ 0,0,0,1);
+
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(rot_mat);
+ mMatHash[mMatrixMode]++;
+ }
}
void LLRender::pushMatrix()
{
flush();
- glPushMatrix();
+
+ {
+ if (mMatIdx[mMatrixMode] < LL_MATRIX_STACK_DEPTH-1)
+ {
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]+1] = mMatrix[mMatrixMode][mMatIdx[mMatrixMode]];
+ ++mMatIdx[mMatrixMode];
+ }
+ else
+ {
+ LL_WARNS() << "Matrix stack overflow." << LL_ENDL;
+ }
+ }
}
void LLRender::popMatrix()
{
flush();
- glPopMatrix();
+ {
+ if (mMatIdx[mMatrixMode] > 0)
+ {
+ --mMatIdx[mMatrixMode];
+ mMatHash[mMatrixMode]++;
+ }
+ else
+ {
+ LL_WARNS() << "Matrix stack underflow." << LL_ENDL;
+ }
+ }
+}
+
+void LLRender::loadMatrix(const GLfloat* m)
+{
+ flush();
+ {
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].set_value((GLfloat*) m);
+ mMatHash[mMatrixMode]++;
+ }
+}
+
+void LLRender::multMatrix(const GLfloat* m)
+{
+ flush();
+ {
+ glh::matrix4f mat((GLfloat*) m);
+
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(mat);
+ mMatHash[mMatrixMode]++;
+ }
+}
+
+void LLRender::matrixMode(U32 mode)
+{
+ if (mode == MM_TEXTURE)
+ {
+ mode = MM_TEXTURE0 + gGL.getCurrentTexUnitIndex();
+ }
+
+ llassert(mode < NUM_MATRIX_MODES);
+ mMatrixMode = mode;
+}
+
+U32 LLRender::getMatrixMode()
+{
+ if (mMatrixMode >= MM_TEXTURE0 && mMatrixMode <= MM_TEXTURE3)
+ { //always return MM_TEXTURE if current matrix mode points at any texture matrix
+ return MM_TEXTURE;
+ }
+
+ return mMatrixMode;
+}
+
+
+void LLRender::loadIdentity()
+{
+ flush();
+
+ {
+ llassert_always(mMatrixMode < NUM_MATRIX_MODES) ;
+
+ mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].make_identity();
+ mMatHash[mMatrixMode]++;
+ }
+}
+
+const glh::matrix4f& LLRender::getModelviewMatrix()
+{
+ return mMatrix[MM_MODELVIEW][mMatIdx[MM_MODELVIEW]];
+}
+
+const glh::matrix4f& LLRender::getProjectionMatrix()
+{
+ return mMatrix[MM_PROJECTION][mMatIdx[MM_PROJECTION]];
}
void LLRender::translateUI(F32 x, F32 y, F32 z)
{
if (mUIOffset.empty())
{
- llerrs << "Need to push a UI translation frame before offsetting" << llendl;
+ LL_ERRS() << "Need to push a UI translation frame before offsetting" << LL_ENDL;
}
- mUIOffset.front().mV[0] += x;
- mUIOffset.front().mV[1] += y;
- mUIOffset.front().mV[2] += z;
+ mUIOffset.back().mV[0] += x;
+ mUIOffset.back().mV[1] += y;
+ mUIOffset.back().mV[2] += z;
}
void LLRender::scaleUI(F32 x, F32 y, F32 z)
{
if (mUIScale.empty())
{
- llerrs << "Need to push a UI transformation frame before scaling." << llendl;
+ LL_ERRS() << "Need to push a UI transformation frame before scaling." << LL_ENDL;
}
- mUIScale.front().scaleVec(LLVector3(x,y,z));
+ mUIScale.back().scaleVec(LLVector3(x,y,z));
}
void LLRender::pushUIMatrix()
{
if (mUIOffset.empty())
{
- mUIOffset.push_front(LLVector3(0,0,0));
+ mUIOffset.push_back(LLVector3(0,0,0));
}
else
{
- mUIOffset.push_front(mUIOffset.front());
+ mUIOffset.push_back(mUIOffset.back());
}
if (mUIScale.empty())
{
- mUIScale.push_front(LLVector3(1,1,1));
+ mUIScale.push_back(LLVector3(1,1,1));
}
else
{
- mUIScale.push_front(mUIScale.front());
+ mUIScale.push_back(mUIScale.back());
}
}
@@ -889,28 +1535,28 @@ void LLRender::popUIMatrix()
{
if (mUIOffset.empty())
{
- llerrs << "UI offset stack blown." << llendl;
+ LL_ERRS() << "UI offset stack blown." << LL_ENDL;
}
- mUIOffset.pop_front();
- mUIScale.pop_front();
+ mUIOffset.pop_back();
+ mUIScale.pop_back();
}
LLVector3 LLRender::getUITranslation()
{
if (mUIOffset.empty())
{
- llerrs << "UI offset stack empty." << llendl;
+ return LLVector3(0,0,0);
}
- return mUIOffset.front();
+ return mUIOffset.back();
}
LLVector3 LLRender::getUIScale()
{
if (mUIScale.empty())
{
- llerrs << "UI scale stack empty." << llendl;
+ return LLVector3(1,1,1);
}
- return mUIScale.front();
+ return mUIScale.back();
}
@@ -918,10 +1564,10 @@ void LLRender::loadUIIdentity()
{
if (mUIOffset.empty())
{
- llerrs << "Need to push UI translation frame before clearing offset." << llendl;
+ LL_ERRS() << "Need to push UI translation frame before clearing offset." << LL_ENDL;
}
- mUIOffset.front().setVec(0,0,0);
- mUIScale.front().setVec(1,1,1);
+ mUIOffset.back().setVec(0,0,0);
+ mUIScale.back().setVec(1,1,1);
}
void LLRender::setColorMask(bool writeColor, bool writeAlpha)
@@ -933,15 +1579,21 @@ void LLRender::setColorMask(bool writeColorR, bool writeColorG, bool writeColorB
{
flush();
- mCurrColorMask[0] = writeColorR;
- mCurrColorMask[1] = writeColorG;
- mCurrColorMask[2] = writeColorB;
- mCurrColorMask[3] = writeAlpha;
+ if (mCurrColorMask[0] != writeColorR ||
+ mCurrColorMask[1] != writeColorG ||
+ mCurrColorMask[2] != writeColorB ||
+ mCurrColorMask[3] != writeAlpha)
+ {
+ mCurrColorMask[0] = writeColorR;
+ mCurrColorMask[1] = writeColorG;
+ mCurrColorMask[2] = writeColorB;
+ mCurrColorMask[3] = writeAlpha;
- glColorMask(writeColorR ? GL_TRUE : GL_FALSE,
- writeColorG ? GL_TRUE : GL_FALSE,
- writeColorB ? GL_TRUE : GL_FALSE,
- writeAlpha ? GL_TRUE : GL_FALSE);
+ glColorMask(writeColorR ? GL_TRUE : GL_FALSE,
+ writeColorG ? GL_TRUE : GL_FALSE,
+ writeColorB ? GL_TRUE : GL_FALSE,
+ writeAlpha ? GL_TRUE : GL_FALSE);
+ }
}
void LLRender::setSceneBlendType(eBlendType type)
@@ -970,7 +1622,7 @@ void LLRender::setSceneBlendType(eBlendType type)
blendFunc(BF_ONE, BF_ZERO);
break;
default:
- llerrs << "Unknown Scene Blend Type: " << type << llendl;
+ LL_ERRS() << "Unknown Scene Blend Type: " << type << LL_ENDL;
break;
}
}
@@ -979,15 +1631,48 @@ void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value)
{
flush();
- mCurrAlphaFunc = func;
- mCurrAlphaFuncVal = value;
- if (func == CF_DEFAULT)
- {
- glAlphaFunc(GL_GREATER, 0.01f);
- }
- else
+ if (LLGLSLShader::sNoFixedFunction)
+ { //glAlphaFunc is deprecated in OpenGL 3.3
+ return;
+ }
+
+ if (mCurrAlphaFunc != func ||
+ mCurrAlphaFuncVal != value)
{
- glAlphaFunc(sGLCompareFunc[func], value);
+ mCurrAlphaFunc = func;
+ mCurrAlphaFuncVal = value;
+ if (func == CF_DEFAULT)
+ {
+ glAlphaFunc(GL_GREATER, 0.01f);
+ }
+ else
+ {
+ glAlphaFunc(sGLCompareFunc[func], value);
+ }
+ }
+
+ if (gDebugGL)
+ { //make sure cached state is correct
+ GLint cur_func = 0;
+ glGetIntegerv(GL_ALPHA_TEST_FUNC, &cur_func);
+
+ if (func == CF_DEFAULT)
+ {
+ func = CF_GREATER;
+ }
+
+ if (cur_func != sGLCompareFunc[func])
+ {
+ LL_ERRS() << "Alpha test function corrupted!" << LL_ENDL;
+ }
+
+ F32 ref = 0.f;
+ glGetFloatv(GL_ALPHA_TEST_REF, &ref);
+
+ if (ref != value)
+ {
+ LL_ERRS() << "Alpha test value corrupted!" << LL_ENDL;
+ }
}
}
@@ -995,15 +1680,44 @@ void LLRender::blendFunc(eBlendFactor sfactor, eBlendFactor dfactor)
{
llassert(sfactor < BF_UNDEF);
llassert(dfactor < BF_UNDEF);
- if (mCurrBlendSFactor != sfactor || mCurrBlendDFactor != dfactor)
+ if (mCurrBlendColorSFactor != sfactor || mCurrBlendColorDFactor != dfactor ||
+ mCurrBlendAlphaSFactor != sfactor || mCurrBlendAlphaDFactor != dfactor)
{
- mCurrBlendSFactor = sfactor;
- mCurrBlendDFactor = dfactor;
+ mCurrBlendColorSFactor = sfactor;
+ mCurrBlendAlphaSFactor = sfactor;
+ mCurrBlendColorDFactor = dfactor;
+ mCurrBlendAlphaDFactor = dfactor;
flush();
glBlendFunc(sGLBlendFactor[sfactor], sGLBlendFactor[dfactor]);
}
}
+void LLRender::blendFunc(eBlendFactor color_sfactor, eBlendFactor color_dfactor,
+ eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor)
+{
+ llassert(color_sfactor < BF_UNDEF);
+ llassert(color_dfactor < BF_UNDEF);
+ llassert(alpha_sfactor < BF_UNDEF);
+ llassert(alpha_dfactor < BF_UNDEF);
+ if (!gGLManager.mHasBlendFuncSeparate)
+ {
+ LL_WARNS_ONCE("render") << "no glBlendFuncSeparateEXT(), using color-only blend func" << LL_ENDL;
+ blendFunc(color_sfactor, color_dfactor);
+ return;
+ }
+ if (mCurrBlendColorSFactor != color_sfactor || mCurrBlendColorDFactor != color_dfactor ||
+ mCurrBlendAlphaSFactor != alpha_sfactor || mCurrBlendAlphaDFactor != alpha_dfactor)
+ {
+ mCurrBlendColorSFactor = color_sfactor;
+ mCurrBlendAlphaSFactor = alpha_sfactor;
+ mCurrBlendColorDFactor = color_dfactor;
+ mCurrBlendAlphaDFactor = alpha_dfactor;
+ flush();
+ glBlendFuncSeparateEXT(sGLBlendFactor[color_sfactor], sGLBlendFactor[color_dfactor],
+ sGLBlendFactor[alpha_sfactor], sGLBlendFactor[alpha_dfactor]);
+ }
+}
+
LLTexUnit* LLRender::getTexUnit(U32 index)
{
if (index < mTexUnits.size())
@@ -1012,11 +1726,34 @@ LLTexUnit* LLRender::getTexUnit(U32 index)
}
else
{
- lldebugs << "Non-existing texture unit layer requested: " << index << llendl;
+ LL_DEBUGS() << "Non-existing texture unit layer requested: " << index << LL_ENDL;
return mDummyTexUnit;
}
}
+LLLightState* LLRender::getLight(U32 index)
+{
+ if (index < mLightState.size())
+ {
+ return mLightState[index];
+ }
+
+ return NULL;
+}
+
+void LLRender::setAmbientLightColor(const LLColor4& color)
+{
+ if (color != mAmbientLightColor)
+ {
+ ++mLightHash;
+ mAmbientLightColor = color;
+ if (!LLGLSLShader::sNoFixedFunction)
+ {
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, color.mV);
+ }
+ }
+}
+
bool LLRender::verifyTexUnitActive(U32 unitToVerify)
{
if (mCurrTextureUnitIndex == unitToVerify)
@@ -1025,7 +1762,7 @@ bool LLRender::verifyTexUnitActive(U32 unitToVerify)
}
else
{
- llwarns << "TexUnit currently active: " << mCurrTextureUnitIndex << " (expecting " << unitToVerify << ")" << llendl;
+ LL_WARNS() << "TexUnit currently active: " << mCurrTextureUnitIndex << " (expecting " << unitToVerify << ")" << LL_ENDL;
return false;
}
}
@@ -1042,6 +1779,11 @@ void LLRender::begin(const GLuint& mode)
{
if (mode != mMode)
{
+ if (mode == LLRender::QUADS)
+ {
+ mQuadCycle = 1;
+ }
+
if (mMode == LLRender::QUADS ||
mMode == LLRender::LINES ||
mMode == LLRender::TRIANGLES ||
@@ -1051,7 +1793,7 @@ void LLRender::begin(const GLuint& mode)
}
else if (mCount != 0)
{
- llerrs << "gGL.begin() called redundantly." << llendl;
+ LL_ERRS() << "gGL.begin() called redundantly." << LL_ENDL;
}
mMode = mode;
@@ -1063,7 +1805,7 @@ void LLRender::end()
if (mCount == 0)
{
return;
- //IMM_ERRS << "GL begin and end called with no vertices specified." << llendl;
+ //IMM_ERRS << "GL begin and end called with no vertices specified." << LL_ENDL;
}
if ((mMode != LLRender::QUADS &&
@@ -1082,22 +1824,22 @@ void LLRender::flush()
#if 0
if (!glIsEnabled(GL_VERTEX_ARRAY))
{
- llerrs << "foo 1" << llendl;
+ LL_ERRS() << "foo 1" << LL_ENDL;
}
if (!glIsEnabled(GL_COLOR_ARRAY))
{
- llerrs << "foo 2" << llendl;
+ LL_ERRS() << "foo 2" << LL_ENDL;
}
if (!glIsEnabled(GL_TEXTURE_COORD_ARRAY))
{
- llerrs << "foo 3" << llendl;
+ LL_ERRS() << "foo 3" << LL_ENDL;
}
if (glIsEnabled(GL_NORMAL_ARRAY))
{
- llerrs << "foo 7" << llendl;
+ LL_ERRS() << "foo 7" << LL_ENDL;
}
GLvoid* pointer;
@@ -1105,19 +1847,19 @@ void LLRender::flush()
glGetPointerv(GL_VERTEX_ARRAY_POINTER, &pointer);
if (pointer != &(mBuffer[0].v))
{
- llerrs << "foo 4" << llendl;
+ LL_ERRS() << "foo 4" << LL_ENDL;
}
glGetPointerv(GL_COLOR_ARRAY_POINTER, &pointer);
if (pointer != &(mBuffer[0].c))
{
- llerrs << "foo 5" << llendl;
+ LL_ERRS() << "foo 5" << LL_ENDL;
}
glGetPointerv(GL_TEXTURE_COORD_ARRAY_POINTER, &pointer);
if (pointer != &(mBuffer[0].uv))
{
- llerrs << "foo 6" << llendl;
+ LL_ERRS() << "foo 6" << LL_ENDL;
}
#endif
@@ -1127,13 +1869,15 @@ void LLRender::flush()
sUIVerts += mCount;
}
- if (gDebugGL)
- {
- if (mMode == LLRender::QUADS)
+ //store mCount in a local variable to avoid re-entrance (drawArrays may call flush)
+ U32 count = mCount;
+
+ if (mMode == LLRender::QUADS && !sGLCoreProfile)
{
if (mCount%4 != 0)
{
- llerrs << "Incomplete quad rendered." << llendl;
+ count -= (mCount % 4);
+ LL_WARNS() << "Incomplete quad requested." << LL_ENDL;
}
}
@@ -1141,7 +1885,8 @@ void LLRender::flush()
{
if (mCount%3 != 0)
{
- llerrs << "Incomplete triangle rendered." << llendl;
+ count -= (mCount % 3);
+ LL_WARNS() << "Incomplete triangle requested." << LL_ENDL;
}
}
@@ -1149,17 +1894,37 @@ void LLRender::flush()
{
if (mCount%2 != 0)
{
- llerrs << "Incomplete line rendered." << llendl;
- }
+ count -= (mCount % 2);
+ LL_WARNS() << "Incomplete line requested." << LL_ENDL;
}
}
+ mCount = 0;
+
+ if (mBuffer->useVBOs() && !mBuffer->isLocked())
+ { //hack to only flush the part of the buffer that was updated (relies on stream draw using buffersubdata)
+ mBuffer->getVertexStrider(mVerticesp, 0, count);
+ mBuffer->getTexCoord0Strider(mTexcoordsp, 0, count);
+ mBuffer->getColorStrider(mColorsp, 0, count);
+ }
+
+ mBuffer->flush();
mBuffer->setBuffer(immediate_mask);
- mBuffer->drawArrays(mMode, 0, mCount);
+
+ if (mMode == LLRender::QUADS && sGLCoreProfile)
+ {
+ mBuffer->drawArrays(LLRender::TRIANGLES, 0, count);
+ mQuadCycle = 1;
+ }
+ else
+ {
+ mBuffer->drawArrays(mMode, 0, count);
+ }
+
+ mVerticesp[0] = mVerticesp[count];
+ mTexcoordsp[0] = mTexcoordsp[count];
+ mColorsp[0] = mColorsp[count];
- mVerticesp[0] = mVerticesp[mCount];
- mTexcoordsp[0] = mTexcoordsp[mCount];
- mColorsp[0] = mColorsp[mCount];
mCount = 0;
}
}
@@ -1167,9 +1932,20 @@ void LLRender::flush()
void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z)
{
//the range of mVerticesp, mColorsp and mTexcoordsp is [0, 4095]
+ if (mCount > 2048)
+ { //break when buffer gets reasonably full to keep GL command buffers happy and avoid overflow below
+ switch (mMode)
+ {
+ case LLRender::POINTS: flush(); break;
+ case LLRender::TRIANGLES: if (mCount%3==0) flush(); break;
+ case LLRender::QUADS: if(mCount%4 == 0) flush(); break;
+ case LLRender::LINES: if (mCount%2 == 0) flush(); break;
+ }
+ }
+
if (mCount > 4094)
{
- // llwarns << "GL immediate mode overflow. Some geometry not drawn." << llendl;
+ // LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL;
return;
}
@@ -1179,18 +1955,210 @@ void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z)
}
else
{
- LLVector3 vert = (LLVector3(x,y,z)+mUIOffset.front()).scaledVec(mUIScale.front());
+ LLVector3 vert = (LLVector3(x,y,z)+mUIOffset.back()).scaledVec(mUIScale.back());
mVerticesp[mCount] = vert;
}
+ if (mMode == LLRender::QUADS && LLRender::sGLCoreProfile)
+ {
+ mQuadCycle++;
+ if (mQuadCycle == 4)
+ { //copy two vertices so fourth quad element will add a triangle
+ mQuadCycle = 0;
+
+ mCount++;
+ mVerticesp[mCount] = mVerticesp[mCount-3];
+ mColorsp[mCount] = mColorsp[mCount-3];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-3];
+
+ mCount++;
+ mVerticesp[mCount] = mVerticesp[mCount-2];
+ mColorsp[mCount] = mColorsp[mCount-2];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-2];
+ }
+ }
+
mCount++;
- if (mCount < 4096)
+ mVerticesp[mCount] = mVerticesp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+}
+
+void LLRender::vertexBatchPreTransformed(LLVector3* verts, S32 vert_count)
+{
+ if (mCount + vert_count > 4094)
{
- mVerticesp[mCount] = mVerticesp[mCount-1];
- mColorsp[mCount] = mColorsp[mCount-1];
- mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ // LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL;
+ return;
}
+
+ if (sGLCoreProfile && mMode == LLRender::QUADS)
+ { //quads are deprecated, convert to triangle list
+ S32 i = 0;
+
+ while (i < vert_count)
+ {
+ //read first three
+ mVerticesp[mCount++] = verts[i++];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ mVerticesp[mCount++] = verts[i++];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ mVerticesp[mCount++] = verts[i++];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ //copy two
+ mVerticesp[mCount++] = verts[i-3];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ mVerticesp[mCount++] = verts[i-1];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ //copy last one
+ mVerticesp[mCount++] = verts[i++];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+ }
+ }
+ else
+ {
+ for (S32 i = 0; i < vert_count; i++)
+ {
+ mVerticesp[mCount] = verts[i];
+
+ mCount++;
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+ }
+ }
+
+ mVerticesp[mCount] = mVerticesp[mCount-1];
+}
+
+void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count)
+{
+ if (mCount + vert_count > 4094)
+ {
+ // LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL;
+ return;
+ }
+
+ if (sGLCoreProfile && mMode == LLRender::QUADS)
+ { //quads are deprecated, convert to triangle list
+ S32 i = 0;
+
+ while (i < vert_count)
+ {
+ //read first three
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount++] = uvs[i++];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount++] = uvs[i++];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount++] = uvs[i++];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ //copy last two
+ mVerticesp[mCount] = verts[i-3];
+ mTexcoordsp[mCount++] = uvs[i-3];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ mVerticesp[mCount] = verts[i-1];
+ mTexcoordsp[mCount++] = uvs[i-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+
+ //copy last one
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount++] = uvs[i++];
+ mColorsp[mCount] = mColorsp[mCount-1];
+ }
+ }
+ else
+ {
+ for (S32 i = 0; i < vert_count; i++)
+ {
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount] = uvs[i];
+
+ mCount++;
+ mColorsp[mCount] = mColorsp[mCount-1];
+ }
+ }
+
+ mVerticesp[mCount] = mVerticesp[mCount-1];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
}
+
+void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLColor4U* colors, S32 vert_count)
+{
+ if (mCount + vert_count > 4094)
+ {
+ // LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL;
+ return;
+ }
+
+
+ if (sGLCoreProfile && mMode == LLRender::QUADS)
+ { //quads are deprecated, convert to triangle list
+ S32 i = 0;
+
+ while (i < vert_count)
+ {
+ //read first three
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount] = uvs[i];
+ mColorsp[mCount++] = colors[i++];
+
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount] = uvs[i];
+ mColorsp[mCount++] = colors[i++];
+
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount] = uvs[i];
+ mColorsp[mCount++] = colors[i++];
+
+ //copy last two
+ mVerticesp[mCount] = verts[i-3];
+ mTexcoordsp[mCount] = uvs[i-3];
+ mColorsp[mCount++] = colors[i-3];
+
+ mVerticesp[mCount] = verts[i-1];
+ mTexcoordsp[mCount] = uvs[i-1];
+ mColorsp[mCount++] = colors[i-1];
+
+ //copy last one
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount] = uvs[i];
+ mColorsp[mCount++] = colors[i++];
+ }
+ }
+ else
+ {
+ for (S32 i = 0; i < vert_count; i++)
+ {
+ mVerticesp[mCount] = verts[i];
+ mTexcoordsp[mCount] = uvs[i];
+ mColorsp[mCount] = colors[i];
+
+ mCount++;
+ }
+ }
+
+ mVerticesp[mCount] = mVerticesp[mCount-1];
+ mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+ mColorsp[mCount] = mColorsp[mCount-1];
+}
+
void LLRender::vertex2i(const GLint& x, const GLint& y)
{
vertex3f((GLfloat) x, (GLfloat) y, 0);
@@ -1228,7 +2196,15 @@ void LLRender::texCoord2fv(const GLfloat* tc)
void LLRender::color4ub(const GLubyte& r, const GLubyte& g, const GLubyte& b, const GLubyte& a)
{
- mColorsp[mCount] = LLColor4U(r,g,b,a);
+ if (!LLGLSLShader::sCurBoundShaderPtr ||
+ LLGLSLShader::sCurBoundShaderPtr->mAttributeMask & LLVertexBuffer::MAP_COLOR)
+ {
+ mColorsp[mCount] = LLColor4U(r,g,b,a);
+ }
+ else
+ { //not using shaders or shader reads color from a uniform
+ diffuseColor4ub(r,g,b,a);
+ }
}
void LLRender::color4ubv(const GLubyte* c)
{
@@ -1258,6 +2234,97 @@ void LLRender::color3fv(const GLfloat* c)
color4f(c[0],c[1],c[2],1);
}
+void LLRender::diffuseColor3f(F32 r, F32 g, F32 b)
+{
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+
+ if (shader)
+ {
+ shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,1.f);
+ }
+ else
+ {
+ glColor3f(r,g,b);
+ }
+}
+
+void LLRender::diffuseColor3fv(const F32* c)
+{
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+
+ if (shader)
+ {
+ shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0], c[1], c[2], 1.f);
+ }
+ else
+ {
+ glColor3fv(c);
+ }
+}
+
+void LLRender::diffuseColor4f(F32 r, F32 g, F32 b, F32 a)
+{
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+
+ if (shader)
+ {
+ shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,a);
+ }
+ else
+ {
+ glColor4f(r,g,b,a);
+ }
+}
+
+void LLRender::diffuseColor4fv(const F32* c)
+{
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+
+ if (shader)
+ {
+ shader->uniform4fv(LLShaderMgr::DIFFUSE_COLOR, 1, c);
+ }
+ else
+ {
+ glColor4fv(c);
+ }
+}
+
+void LLRender::diffuseColor4ubv(const U8* c)
+{
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+
+ if (shader)
+ {
+ shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0]/255.f, c[1]/255.f, c[2]/255.f, c[3]/255.f);
+ }
+ else
+ {
+ glColor4ubv(c);
+ }
+}
+
+void LLRender::diffuseColor4ub(U8 r, U8 g, U8 b, U8 a)
+{
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+
+ if (shader)
+ {
+ shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r/255.f, g/255.f, b/255.f, a/255.f);
+ }
+ else
+ {
+ glColor4ub(r,g,b,a);
+ }
+}
+
+
void LLRender::debugTexUnits(void)
{
LL_INFOS("TextureUnit") << "Active TexUnit: " << mCurrTextureUnitIndex << LL_ENDL;