summaryrefslogtreecommitdiff
path: root/indra/llrender
diff options
context:
space:
mode:
authorDave Parks <davep@lindenlab.com>2011-09-13 16:11:22 -0500
committerDave Parks <davep@lindenlab.com>2011-09-13 16:11:22 -0500
commitc0ca2c62fd6b9a90542907ce46bf1fe0ab379e13 (patch)
tree69bed5c3a72357e183384917b5495c2990e1ac13 /indra/llrender
parent19371a9abed3198f9f6083c3b2483e65778e944a (diff)
parent38c19f4e55c0f6a104de87dfb57313a6c529b4d6 (diff)
merge
Diffstat (limited to 'indra/llrender')
-rw-r--r--indra/llrender/llgl.cpp81
-rw-r--r--indra/llrender/llgl.h12
-rw-r--r--indra/llrender/llglslshader.cpp8
-rw-r--r--indra/llrender/llrender.cpp75
-rw-r--r--indra/llrender/llrender.h6
-rw-r--r--indra/llrender/llrendersphere.cpp97
-rw-r--r--indra/llrender/llrendersphere.h5
-rw-r--r--indra/llrender/llshadermgr.cpp18
-rw-r--r--indra/llrender/llvertexbuffer.cpp464
-rw-r--r--indra/llrender/llvertexbuffer.h13
10 files changed, 512 insertions, 267 deletions
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 4e3cfb9c8a..1a2fe0ea0e 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -582,6 +582,8 @@ bool LLGLManager::initGL()
glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords);
}
+ //HACK always disable texture multisample, use FXAA instead
+ mHasTextureMultisample = FALSE;
#if LL_WINDOWS
if (mIsATI)
{ //using multisample textures on ATI results in black screen for some reason
@@ -1329,8 +1331,6 @@ void LLGLState::initClass()
sStateMap[GL_MULTISAMPLE_ARB] = GL_FALSE;
glDisable(GL_MULTISAMPLE_ARB);
-
- glEnableClientState(GL_VERTEX_ARRAY);
}
//static
@@ -1604,7 +1604,7 @@ void LLGLState::checkTextureChannels(const std::string& msg)
void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
{
- if (!gDebugGL)
+ if (!gDebugGL || LLGLSLShader::sNoFixedFunction)
{
return;
}
@@ -1661,7 +1661,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
};
- for (S32 j = 0; j < 4; j++)
+ for (S32 j = 1; j < 4; j++)
{
if (glIsEnabled(value[j]))
{
@@ -1875,79 +1875,6 @@ void LLGLManager::initGLStates()
////////////////////////////////////////////////////////////////////////////////
-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 parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific )
{
// GL_VERSION returns a null-terminated string with the format:
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index d736133f3f..495e523c31 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -252,7 +252,7 @@ public:
static void dumpStates();
static void checkStates(const std::string& msg = "");
static void checkTextureChannels(const std::string& msg = "");
- static void checkClientArrays(const std::string& msg = "", U32 data_mask = 0x0001);
+ static void checkClientArrays(const std::string& msg = "", U32 data_mask = 0);
protected:
static boost::unordered_map<LLGLenum, LLGLboolean> sStateMap;
@@ -419,15 +419,7 @@ 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 parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific );
extern BOOL gClothRipple;
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index f51d83abe4..61648e527d 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -31,6 +31,7 @@
#include "llshadermgr.h"
#include "llfile.h"
#include "llrender.h"
+#include "llvertexbuffer.h"
#if LL_DARWIN
#include "OpenGL/OpenGL.h"
@@ -116,10 +117,12 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
// Create program
mProgramObject = glCreateProgramObjectARB();
+#if !LL_DARWIN
if (gGLManager.mGLVersion < 3.1f)
{ //force indexed texture channels to 1 if GL version is old (performance improvement for drivers with poor branching shader model support)
mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1);
}
+#endif // !LL_DARWIN
//compile new source
vector< pair<string,GLenum> >::iterator fileIter = mShaderFiles.begin();
@@ -386,6 +389,7 @@ void LLGLSLShader::bind()
gGL.flush();
if (gGLManager.mHasShaderObjects)
{
+ LLVertexBuffer::unbind();
glUseProgramObjectARB(mProgramObject);
sCurBoundShader = mProgramObject;
sCurBoundShaderPtr = this;
@@ -411,6 +415,7 @@ void LLGLSLShader::unbind()
stop_glerror();
}
}
+ LLVertexBuffer::unbind();
glUseProgramObjectARB(0);
sCurBoundShader = 0;
sCurBoundShaderPtr = NULL;
@@ -420,6 +425,7 @@ void LLGLSLShader::unbind()
void LLGLSLShader::bindNoShader(void)
{
+ LLVertexBuffer::unbind();
glUseProgramObjectARB(0);
sCurBoundShader = 0;
sCurBoundShaderPtr = NULL;
@@ -930,7 +936,9 @@ void LLGLSLShader::uniform4fv(const string& uniform, U32 count, const GLfloat* v
std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1)
{
+ stop_glerror();
glUniform4fvARB(location, count, v);
+ stop_glerror();
mValue[location] = vec;
}
}
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index edcc47aa14..426419f912 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -1586,6 +1586,81 @@ 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("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("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("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("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("color", c[0]/255.f, c[1]/255.f, c[2]/255.f, c[3]/255.f);
+ }
+ else
+ {
+ glColor4ubv(c);
+ }
+}
+
void LLRender::debugTexUnits(void)
{
LL_INFOS("TextureUnit") << "Active TexUnit: " << mCurrTextureUnitIndex << LL_ENDL;
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index 8f7ee30d87..c202aa4b73 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -351,6 +351,12 @@ public:
void color3fv(const GLfloat* c);
void color4ubv(const GLubyte* c);
+ void diffuseColor3f(F32 r, F32 g, F32 b);
+ void diffuseColor3fv(const F32* c);
+ void diffuseColor4f(F32 r, F32 g, F32 b, F32 a);
+ void diffuseColor4fv(const F32* c);
+ void diffuseColor4ubv(const U8* c);
+
void vertexBatchPreTransformed(LLVector3* verts, S32 vert_count);
void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count);
void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLColor4U*, S32 vert_count);
diff --git a/indra/llrender/llrendersphere.cpp b/indra/llrender/llrendersphere.cpp
index a5cd70445f..e7e07a1ab2 100644
--- a/indra/llrender/llrendersphere.cpp
+++ b/indra/llrender/llrendersphere.cpp
@@ -35,106 +35,11 @@
#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);
-}
-
-
-// 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]);
+ renderGGL();
}
inline LLVector3 polar_to_cart(F32 latitude, F32 longitude)
diff --git a/indra/llrender/llrendersphere.h b/indra/llrender/llrendersphere.h
index 96a6bec80c..f8e9e86e7f 100644
--- a/indra/llrender/llrendersphere.h
+++ b/indra/llrender/llrendersphere.h
@@ -40,11 +40,6 @@ 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
void renderGGL(); // render using LLRender
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index 986c1f2774..db3d7becd9 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -531,9 +531,9 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
}
//we can't have any lines longer than 1024 characters
- //or any shaders longer than 1024 lines... deal - DaveP
+ //or any shaders longer than 4096 lines... deal - DaveP
GLcharARB buff[1024];
- GLcharARB* text[1024];
+ GLcharARB* text[4096];
GLuint count = 0;
if (gGLManager.mGLVersion < 2.1f)
@@ -544,10 +544,13 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
{
//set version to 1.20
text[count++] = strdup("#version 120\n");
+ text[count++] = strdup("#define FXAA_GLSL_120 1\n");
+ text[count++] = strdup("#define FXAA_FAST_PIXEL_OFFSET 0\n");
}
else
{ //set version to 1.30
text[count++] = strdup("#version 130\n");
+ text[count++] = strdup("#define FXAA_GLSL_130 1\n");
}
//copy preprocessor definitions into buffer
@@ -649,7 +652,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
}
//copy file into memory
- while( fgets((char *)buff, 1024, file) != NULL && count < LL_ARRAY_SIZE(buff) )
+ while( fgets((char *)buff, 1024, file) != NULL && count < LL_ARRAY_SIZE(text) )
{
text[count++] = (GLcharARB *)strdup((char *)buff);
}
@@ -704,14 +707,23 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL;
dumpObjectLog(ret);
+#if LL_WINDOWS
std::stringstream ostr;
//dump shader source for debugging
for (GLuint i = 0; i < count; i++)
{
ostr << i << ": " << text[i];
+
+ if (i % 128 == 0)
+ { //dump every 128 lines
+ LL_WARNS("ShaderLoading") << "\n" << ostr.str() << llendl;
+ ostr = std::stringstream();
+ }
+
}
LL_WARNS("ShaderLoading") << "\n" << ostr.str() << llendl;
+#endif // LL_WINDOWS
ret = 0;
}
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 8fd1193780..bb8f067e8d 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -63,7 +63,6 @@ U32 LLVertexBuffer::sAllocatedBytes = 0;
BOOL LLVertexBuffer::sMapped = FALSE;
BOOL LLVertexBuffer::sUseStreamDraw = TRUE;
BOOL LLVertexBuffer::sPreferStreamDraw = FALSE;
-S32 LLVertexBuffer::sWeight4Loc = -1;
std::vector<U32> LLVertexBuffer::sDeleteList;
@@ -131,6 +130,7 @@ S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
sizeof(LLVector2), // TYPE_TEXCOORD2,
sizeof(LLVector2), // TYPE_TEXCOORD3,
sizeof(LLColor4U), // TYPE_COLOR,
+ sizeof(U8), // TYPE_EMISSIVE
sizeof(LLVector4), // TYPE_BINORMAL,
sizeof(F32), // TYPE_WEIGHT,
sizeof(LLVector4), // TYPE_WEIGHT4,
@@ -157,36 +157,79 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
llerrs << "Cannot use LLGLImmediate and LLVertexBuffer simultaneously!" << llendl;
}*/
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+
if (sLastMask != data_mask)
{
+ llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+ static LLGLSLShader* last_shader = LLGLSLShader::sCurBoundShaderPtr;
+ llassert(sLastMask == 0 || last_shader == shader);
+ last_shader = shader;
+
U32 mask[] =
{
MAP_VERTEX,
MAP_NORMAL,
MAP_TEXCOORD0,
MAP_COLOR,
+ MAP_EMISSIVE,
+ MAP_WEIGHT,
+ MAP_WEIGHT4,
+ MAP_BINORMAL,
+ MAP_CLOTHWEIGHT,
};
+ U32 type[] =
+ {
+ TYPE_VERTEX,
+ TYPE_NORMAL,
+ TYPE_TEXCOORD0,
+ TYPE_COLOR,
+ TYPE_EMISSIVE,
+ TYPE_WEIGHT,
+ TYPE_WEIGHT4,
+ TYPE_BINORMAL,
+ TYPE_CLOTHWEIGHT,
+ };
+
GLenum array[] =
{
GL_VERTEX_ARRAY,
GL_NORMAL_ARRAY,
GL_TEXTURE_COORD_ARRAY,
GL_COLOR_ARRAY,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
};
BOOL error = FALSE;
- for (U32 i = 0; i < 4; ++i)
+ for (U32 i = 0; i < 9; ++i)
{
+ S32 loc = -1;
+ if (shader)
+ {
+ loc = shader->getAttribLocation(type[i]);
+ }
+
if (sLastMask & mask[i])
{ //was enabled
- if (!(data_mask & mask[i]) && i > 0)
+ if (!(data_mask & mask[i]))
{ //needs to be disabled
- glDisableClientState(array[i]);
+ if (loc >= 0)
+ {
+ glDisableVertexAttribArrayARB(loc);
+ }
+ else if (!shader)
+ {
+ glDisableClientState(array[i]);
+ }
}
- else if (gDebugGL)
- { //needs to be enabled, make sure it was (DEBUG TEMPORARY)
- if (i > 0 && !glIsEnabled(array[i]))
+ else if (gDebugGL && !shader && array[i])
+ { //needs to be enabled, make sure it was (DEBUG)
+ if (loc < 0 && !glIsEnabled(array[i]))
{
if (gDebugSession)
{
@@ -202,11 +245,18 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
}
else
{ //was disabled
- if (data_mask & mask[i] && i > 0)
+ if (data_mask & mask[i])
{ //needs to be enabled
- glEnableClientState(array[i]);
+ if (loc >= 0)
+ {
+ glEnableVertexAttribArrayARB(loc);
+ }
+ else if (!shader)
+ {
+ glEnableClientState(array[i]);
+ }
}
- else if (gDebugGL && i > 0 && glIsEnabled(array[i]))
+ else if (!shader && array[i] && gDebugGL && glIsEnabled(array[i]))
{ //needs to be disabled, make sure it was (DEBUG TEMPORARY)
if (gDebugSession)
{
@@ -233,62 +283,71 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
MAP_TEXCOORD3
};
+ U32 type_tc[] =
+ {
+ TYPE_TEXCOORD1,
+ TYPE_TEXCOORD2,
+ TYPE_TEXCOORD3
+ };
+
for (U32 i = 0; i < 3; i++)
{
+ S32 loc = -1;
+ if (shader)
+ {
+ loc = shader->getAttribLocation(type_tc[i]);
+ }
+
if (sLastMask & map_tc[i])
{
if (!(data_mask & map_tc[i]))
- {
- glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ { //disable
+ if (loc >= 0)
+ {
+ glDisableVertexAttribArrayARB(loc);
+ }
+ else if (!shader)
+ {
+ glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
}
}
else if (data_mask & map_tc[i])
{
- glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ if (loc >= 0)
+ {
+ glEnableVertexAttribArrayARB(loc);
+ }
+ else if (!shader)
+ {
+ glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
}
}
- if (sLastMask & MAP_BINORMAL)
+ if (!shader)
{
- if (!(data_mask & MAP_BINORMAL))
+ if (sLastMask & MAP_BINORMAL)
{
- glClientActiveTextureARB(GL_TEXTURE2_ARB);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ if (!(data_mask & MAP_BINORMAL))
+ {
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
}
- }
- else if (data_mask & MAP_BINORMAL)
- {
- glClientActiveTextureARB(GL_TEXTURE2_ARB);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glClientActiveTextureARB(GL_TEXTURE0_ARB);
- }
-
- if (sLastMask & MAP_WEIGHT4)
- {
- if (sWeight4Loc < 0)
+ else if (data_mask & MAP_BINORMAL)
{
- llerrs << "Weighting disabled but vertex buffer still bound!" << llendl;
- }
-
- if (!(data_mask & MAP_WEIGHT4))
- { //disable 4-component skin weight
- glDisableVertexAttribArrayARB(sWeight4Loc);
- }
- }
- else if (data_mask & MAP_WEIGHT4)
- {
- if (sWeight4Loc >= 0)
- { //enable 4-component skin weight
- glEnableVertexAttribArrayARB(sWeight4Loc);
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
}
}
-
-
+
sLastMask = data_mask;
}
}
@@ -296,6 +355,8 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
//static
void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm)
{
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+
U32 count = pos.size();
llassert_always(norm.size() >= pos.size());
llassert_always(count > 0) ;
@@ -304,12 +365,73 @@ void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, con
setupClientArrays(MAP_VERTEX | MAP_NORMAL);
- glVertexPointer(3, GL_FLOAT, 0, pos[0].mV);
- glNormalPointer(GL_FLOAT, 0, norm[0].mV);
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+
+ if (shader)
+ {
+ S32 loc = shader->getAttribLocation(LLVertexBuffer::TYPE_VERTEX);
+ if (loc > -1)
+ {
+ glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, pos[0].mV);
+ }
+ loc = shader->getAttribLocation(LLVertexBuffer::TYPE_NORMAL);
+ if (loc > -1)
+ {
+ glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, norm[0].mV);
+ }
+ }
+ else
+ {
+ glVertexPointer(3, GL_FLOAT, 0, pos[0].mV);
+ glNormalPointer(GL_FLOAT, 0, norm[0].mV);
+ }
glDrawArrays(sGLMode[mode], 0, count);
}
+//static
+void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp)
+{
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+
+ U32 mask = LLVertexBuffer::MAP_VERTEX;
+ if (tc)
+ {
+ mask = mask | LLVertexBuffer::MAP_TEXCOORD0;
+ }
+
+ unbind();
+
+ setupClientArrays(mask);
+
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+
+ if (shader)
+ {
+ S32 loc = shader->getAttribLocation(LLVertexBuffer::TYPE_VERTEX);
+ if (loc > -1)
+ {
+ glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 16, pos);
+
+ if (tc)
+ {
+ loc = shader->getAttribLocation(LLVertexBuffer::TYPE_TEXCOORD0);
+ if (loc > -1)
+ {
+ glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, 0, tc);
+ }
+ }
+ }
+ }
+ else
+ {
+ glTexCoordPointer(2, GL_FLOAT, 0, tc);
+ glVertexPointer(3, GL_FLOAT, 16, pos);
+ }
+
+ glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp);
+}
+
void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
{
if (start >= (U32) mRequestedNumVerts ||
@@ -344,6 +466,7 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
validateRange(start, end, count, indices_offset);
llassert(mRequestedNumVerts >= 0);
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
if (mGLIndices != sGLRenderIndices)
{
@@ -372,6 +495,8 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
{
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+
llassert(mRequestedNumIndices >= 0);
if (indices_offset >= (U32) mRequestedNumIndices ||
indices_offset + count > (U32) mRequestedNumIndices)
@@ -404,6 +529,8 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
{
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+
llassert(mRequestedNumVerts >= 0);
if (first >= (U32) mRequestedNumVerts ||
first + count > (U32) mRequestedNumVerts)
@@ -1601,6 +1728,10 @@ bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, S32 index, S
{
return VertexBufferStrider<LLColor4U,TYPE_COLOR>::get(*this, strider, index, count, map_range);
}
+bool LLVertexBuffer::getEmissiveStrider(LLStrider<U8>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<U8,TYPE_EMISSIVE>::get(*this, strider, index, count, map_range);
+}
bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, S32 index, S32 count, bool map_range)
{
return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index, count, map_range);
@@ -1625,6 +1756,34 @@ void LLVertexBuffer::setBuffer(U32 data_mask, S32 type)
//set up pointers if the data mask is different ...
BOOL setup = (sLastMask != data_mask);
+ if (gDebugGL && data_mask != 0)
+ {
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ if (shader)
+ {
+ U32 required_mask = 0;
+ for (U32 i = 0; i < LLVertexBuffer::TYPE_MAX; ++i)
+ {
+ if (shader->getAttribLocation(i) > -1)
+ {
+ U32 required = 1 << i;
+ if ((data_mask & required) == 0)
+ {
+ llwarns << "Missing attribute: " << i << llendl;
+ }
+
+ required_mask |= required;
+
+ }
+ }
+
+ if ((data_mask & required_mask) != required_mask)
+ {
+ llerrs << "Shader consumption mismatches data provision." << llendl;
+ }
+ }
+ }
+
if (useVBOs())
{
if (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))
@@ -1819,66 +1978,223 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl;
}
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+
+ //assert that fixed function is allowed OR a shader is currently bound
+ llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
+
if (data_mask & MAP_NORMAL)
{
- glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
+ S32 loc = -1;
+ if (shader)
+ {
+ loc = shader->getAttribLocation(TYPE_NORMAL);
+ }
+
+ if (loc >= 0)
+ {
+ glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
+ }
+ else if (!shader)
+ {
+ glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
+ }
}
if (data_mask & MAP_TEXCOORD3)
{
- glClientActiveTextureARB(GL_TEXTURE3_ARB);
- glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3]));
- glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ S32 loc = -1;
+ if (shader)
+ {
+ loc = shader->getAttribLocation(TYPE_TEXCOORD3);
+ }
+
+ if (loc >= 0)
+ {
+ glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3]));
+ }
+ else if (!shader)
+ {
+ glClientActiveTextureARB(GL_TEXTURE3_ARB);
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
}
if (data_mask & MAP_TEXCOORD2)
{
- glClientActiveTextureARB(GL_TEXTURE2_ARB);
- glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2]));
- glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ S32 loc = -1;
+ if (shader)
+ {
+ loc = shader->getAttribLocation(TYPE_TEXCOORD2);
+ }
+
+ if (loc >= 0)
+ {
+ glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2]));
+ }
+ else if (!shader)
+ {
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
}
if (data_mask & MAP_TEXCOORD1)
{
- glClientActiveTextureARB(GL_TEXTURE1_ARB);
- glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
- glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ S32 loc = -1;
+ if (shader)
+ {
+ loc = shader->getAttribLocation(TYPE_TEXCOORD1);
+ }
+
+ if (loc >= 0)
+ {
+ glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
+ }
+ else if (!shader)
+ {
+ glClientActiveTextureARB(GL_TEXTURE1_ARB);
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
}
if (data_mask & MAP_BINORMAL)
{
- glClientActiveTextureARB(GL_TEXTURE2_ARB);
- glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
- glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ S32 loc = -1;
+ if (shader)
+ {
+ loc = shader->getAttribLocation(TYPE_BINORMAL);
+ }
+
+ if (loc >= 0)
+ {
+ glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
+ }
+ else if (!shader)
+ {
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
+ glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
}
if (data_mask & MAP_TEXCOORD0)
{
- glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
+ S32 loc = -1;
+ if (shader)
+ {
+ loc = shader->getAttribLocation(TYPE_TEXCOORD0);
+ }
+
+ if (loc >= 0)
+ {
+ glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
+ }
+ else if (!shader)
+ {
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
+ }
}
if (data_mask & MAP_COLOR)
{
- glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
+ S32 loc = -1;
+ if (shader)
+ {
+ loc = shader->getAttribLocation(TYPE_COLOR);
+ }
+
+ if (loc >= 0)
+ {
+ glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
+ }
+ else if (!shader)
+ {
+ glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
+ }
+ }
+ if (data_mask & MAP_EMISSIVE)
+ {
+ S32 loc = -1;
+ if (shader)
+ {
+ loc = shader->getAttribLocation(TYPE_EMISSIVE);
+ }
+
+ if (loc >= 0)
+ {
+ glVertexAttribPointerARB(loc, 1, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], (void*)(base + mOffsets[TYPE_EMISSIVE]));
+ }
}
-
if (data_mask & MAP_WEIGHT)
{
- glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], (void*)(base + mOffsets[TYPE_WEIGHT]));
+ S32 loc = -1;
+ if (shader)
+ {
+ loc = shader->getAttribLocation(TYPE_WEIGHT);
+ }
+
+ if (loc < 0)
+ { //legacy behavior, some shaders have weight hardcoded to location 1
+ loc = 1;
+ }
+
+ glVertexAttribPointerARB(loc, 1, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], (void*)(base + mOffsets[TYPE_WEIGHT]));
+
}
- if (data_mask & MAP_WEIGHT4 && sWeight4Loc != -1)
+ if (data_mask & MAP_WEIGHT4)
{
- glVertexAttribPointerARB(sWeight4Loc, 4, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], (void*)(base+mOffsets[TYPE_WEIGHT4]));
+ if (shader)
+ {
+ S32 loc = shader->getAttribLocation(TYPE_WEIGHT4);
+ if (loc > -1)
+ {
+ glVertexAttribPointerARB(loc, 4, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], (void*)(base+mOffsets[TYPE_WEIGHT4]));
+ }
+ }
}
if (data_mask & MAP_CLOTHWEIGHT)
{
- glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
+ S32 loc = -1;
+ if (shader)
+ {
+ loc = shader->getAttribLocation(TYPE_CLOTHWEIGHT);
+ }
+
+ if (loc < 0)
+ { //legacy behavior, some shaders have weight hardcoded to location 4
+ loc = 4;
+ }
+ glVertexAttribPointerARB(loc, 4, GL_FLOAT, TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
}
if (data_mask & MAP_VERTEX)
{
- if (data_mask & MAP_TEXTURE_INDEX)
+ S32 loc = -1;
+ if (shader)
{
- glVertexPointer(4,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
+ loc = shader->getAttribLocation(TYPE_VERTEX);
}
- else
+
+ if (loc >= 0)
{
- glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
+ if (data_mask & MAP_TEXTURE_INDEX)
+ {
+ glVertexAttribPointerARB(loc, 4,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
+ }
+ else
+ {
+ glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
+ }
+ }
+ else if (!shader)
+ {
+ if (data_mask & MAP_TEXTURE_INDEX)
+ {
+ glVertexPointer(4,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
+ }
+ else
+ {
+ glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
+ }
}
}
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index 578cec3885..7aa5928524 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -111,8 +111,6 @@ public:
static LLVBOPool sStreamIBOPool;
static LLVBOPool sDynamicIBOPool;
- static S32 sWeight4Loc;
-
static BOOL sUseStreamDraw;
static BOOL sPreferStreamDraw;
@@ -120,6 +118,7 @@ public:
static void cleanupClass();
static void setupClientArrays(U32 data_mask);
static void drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm);
+ static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp);
static void clientCopy(F64 max_time = 0.005); //copy data from client to GL
static void unbind(); //unbind any bound vertex buffer
@@ -133,6 +132,12 @@ public:
static S32 calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices);
+ //WARNING -- when updating these enums you MUST
+ // 1 - update LLVertexBuffer::sTypeSize
+ // 2 - add a strider accessor
+ // 3 - modify LLVertexBuffer::setupVertexBuffer
+ // 4 - modify LLVertexBuffer::setupClientArray
+ // 5 - modify LLViewerShaderMgr::mReservedAttribs
enum {
TYPE_VERTEX,
TYPE_NORMAL,
@@ -141,6 +146,7 @@ public:
TYPE_TEXCOORD2,
TYPE_TEXCOORD3,
TYPE_COLOR,
+ TYPE_EMISSIVE,
// These use VertexAttribPointer and should possibly be made generic
TYPE_BINORMAL,
TYPE_WEIGHT,
@@ -160,6 +166,7 @@ public:
MAP_TEXCOORD2 = (1<<TYPE_TEXCOORD2),
MAP_TEXCOORD3 = (1<<TYPE_TEXCOORD3),
MAP_COLOR = (1<<TYPE_COLOR),
+ MAP_EMISSIVE = (1<<TYPE_EMISSIVE),
// These use VertexAttribPointer and should possibly be made generic
MAP_BINORMAL = (1<<TYPE_BINORMAL),
MAP_WEIGHT = (1<<TYPE_WEIGHT),
@@ -218,10 +225,12 @@ public:
bool getNormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getBinormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
+ bool getEmissiveStrider(LLStrider<U8>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getWeightStrider(LLStrider<F32>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
+
BOOL isEmpty() const { return mEmpty; }
BOOL isLocked() const { return mVertexLocked || mIndexLocked; }
S32 getNumVerts() const { return mNumVerts; }