diff options
Diffstat (limited to 'indra/newview/llface.cpp')
-rwxr-xr-x[-rw-r--r--] | indra/newview/llface.cpp | 2295 |
1 files changed, 1564 insertions, 731 deletions
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index fe201a6773..de349a03d4 100644..100755 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -33,8 +33,10 @@ #include "llviewercontrol.h" #include "llvolume.h" #include "m3math.h" +#include "llmatrix4a.h" #include "v3color.h" +#include "lldrawpoolavatar.h" #include "lldrawpoolbump.h" #include "llgl.h" #include "llrender.h" @@ -42,19 +44,32 @@ #include "llsky.h" #include "llviewercamera.h" #include "llviewertexturelist.h" +#include "llvopartgroup.h" #include "llvosky.h" #include "llvovolume.h" #include "pipeline.h" #include "llviewerregion.h" #include "llviewerwindow.h" +#include "llviewershadermgr.h" +#include "llviewertexture.h" +#include "llvoavatar.h" +#if LL_LINUX +// Work-around spurious used before init warning on Vector4a +// +#pragma GCC diagnostic ignored "-Wuninitialized" +#endif + +extern BOOL gGLDebugLoggingEnabled; #define LL_MAX_INDICES_COUNT 1000000 +static LLStaticHashedString sTextureIndexIn("texture_index_in"); +static LLStaticHashedString sColorIn("color_in"); + BOOL LLFace::sSafeRenderSelect = TRUE; // FALSE #define DOTVEC(a,b) (a.mV[0]*b.mV[0] + a.mV[1]*b.mV[1] + a.mV[2]*b.mV[2]) - /* For each vertex, given: B - binormal @@ -67,66 +82,39 @@ The resulting texture coordinate <u,v> is: u = 2(B dot P) v = 2(T dot P) */ -void planarProjection(LLVector2 &tc, const LLVector3& normal, - const LLVector3 &mCenter, const LLVector3& vec) -{ //DONE! - LLVector3 binormal; - float d = normal * LLVector3(1,0,0); +void planarProjection(LLVector2 &tc, const LLVector4a& normal, + const LLVector4a ¢er, const LLVector4a& vec) +{ + LLVector4a binormal; + F32 d = normal[0]; + if (d >= 0.5f || d <= -0.5f) { - binormal = LLVector3(0,1,0); - if (normal.mV[0] < 0) + if (d < 0) { - binormal = -binormal; + binormal.set(0,-1,0); + } + else + { + binormal.set(0, 1, 0); } } else { - binormal = LLVector3(1,0,0); - if (normal.mV[1] > 0) + if (normal[1] > 0) { - binormal = -binormal; + binormal.set(-1,0,0); + } + else + { + binormal.set(1,0,0); } } - LLVector3 tangent = binormal % normal; - - tc.mV[1] = -((tangent*vec)*2 - 0.5f); - tc.mV[0] = 1.0f+((binormal*vec)*2 - 0.5f); -} - -void sphericalProjection(LLVector2 &tc, const LLVector3& normal, - const LLVector3 &mCenter, const LLVector3& vec) -{ //BROKEN - /*tc.mV[0] = acosf(vd.mNormal * LLVector3(1,0,0))/3.14159f; - - tc.mV[1] = acosf(vd.mNormal * LLVector3(0,0,1))/6.284f; - if (vd.mNormal.mV[1] > 0) - { - tc.mV[1] = 1.0f-tc.mV[1]; - }*/ -} - -void cylindricalProjection(LLVector2 &tc, const LLVector3& normal, const LLVector3 &mCenter, const LLVector3& vec) -{ //BROKEN - /*LLVector3 binormal; - float d = vd.mNormal * LLVector3(1,0,0); - if (d >= 0.5f || d <= -0.5f) - { - binormal = LLVector3(0,1,0); - } - else{ - binormal = LLVector3(1,0,0); - } - LLVector3 tangent = binormal % vd.mNormal; - - tc.mV[1] = -((tangent*vec)*2 - 0.5f); - - tc.mV[0] = acosf(vd.mNormal * LLVector3(1,0,0))/6.284f; + LLVector4a tangent; + tangent.setCross3(binormal,normal); - if (vd.mNormal.mV[1] < 0) - { - tc.mV[0] = 1.0f-tc.mV[0]; - }*/ + tc.mV[1] = -((tangent.dot3(vec).getF32())*2 - 0.5f); + tc.mV[0] = 1.0f+((binormal.dot3(vec).getF32())*2 - 0.5f); } //////////////////// @@ -138,6 +126,7 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) { mLastUpdateTime = gFrameTimeSeconds; mLastMoveTime = 0.f; + mLastSkinTime = gFrameTimeSeconds; mVSize = 0.f; mPixelArea = 16.f; mState = GLOBAL; @@ -150,10 +139,18 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) mGeomCount = 0; mGeomIndex = 0; mIndicesCount = 0; - mIndicesIndex = 0; - mIndexInTex = 0; - mTexture = NULL; + + //special value to indicate uninitialized position + mIndicesIndex = 0xFFFFFFFF; + + for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i) + { + mIndexInTex[i] = 0; + mTexture[i] = NULL; + } + mTEOffset = -1; + mTextureIndex = 255; setDrawable(drawablep); mVObjp = objp; @@ -165,31 +162,44 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) mFaceColor = LLColor4(1,0,0,1); - mLastVertexBuffer = mVertexBuffer; - mLastGeomCount = mGeomCount; - mLastGeomIndex = mGeomIndex; - mLastIndicesCount = mIndicesCount; - mLastIndicesIndex = mIndicesIndex; - mImportanceToCamera = 0.f ; mBoundingSphereRadius = 0.0f ; - mAtlasInfop = NULL ; - mUsingAtlas = FALSE ; mHasMedia = FALSE ; } - void LLFace::destroy() { - if(mTexture.notNull()) + if (gDebugGL) + { + gPipeline.checkReferences(this); + } + + for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i) { - mTexture->removeFace(this) ; + if(mTexture[i].notNull()) + { + mTexture[i]->removeFace(i, this) ; + } } + if (isState(LLFace::PARTICLE)) + { + LLVOPartGroup::freeVBSlot(getGeomIndex()/4); + clearState(LLFace::PARTICLE); + } + if (mDrawPoolp) { - mDrawPoolp->removeFace(this); + if (this->isState(LLFace::RIGGED) && mDrawPoolp->getType() == LLDrawPool::POOL_AVATAR) + { + ((LLDrawPoolAvatar*) mDrawPoolp)->removeRiggedFace(this); + } + else + { + mDrawPoolp->removeFace(this); + } + mDrawPoolp = NULL; } @@ -210,8 +220,7 @@ void LLFace::destroy() } setDrawInfo(NULL); - - removeAtlas(); + mDrawablep = NULL; mVObjp = NULL; } @@ -224,16 +233,19 @@ void LLFace::initClass() void LLFace::setWorldMatrix(const LLMatrix4 &mat) { - llerrs << "Faces on this drawable are not independently modifiable\n" << llendl; + LL_ERRS() << "Faces on this drawable are not independently modifiable\n" << LL_ENDL; +} + +void LLFace::setPool(LLFacePool* pool) +{ + mDrawPoolp = pool; } void LLFace::setPool(LLFacePool* new_pool, LLViewerTexture *texturep) { - LLMemType mt1(LLMemType::MTYPE_DRAWABLE); - if (!new_pool) { - llerrs << "Setting pool to null!" << llendl; + LL_ERRS() << "Setting pool to null!" << LL_ENDL; } if (new_pool != mDrawPoolp) @@ -261,48 +273,130 @@ void LLFace::setPool(LLFacePool* new_pool, LLViewerTexture *texturep) setTexture(texturep) ; } -void LLFace::setTexture(LLViewerTexture* tex) +void LLFace::setTexture(U32 ch, LLViewerTexture* tex) { - if(mTexture == tex) + llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); + + if(mTexture[ch] == tex) { return ; } - if(mTexture.notNull()) + if(mTexture[ch].notNull()) { - mTexture->removeFace(this) ; - removeAtlas() ; + mTexture[ch]->removeFace(ch, this) ; } if(tex) { - tex->addFace(this) ; + tex->addFace(ch, this) ; } - mTexture = tex ; + mTexture[ch] = tex ; +} + +void LLFace::setTexture(LLViewerTexture* tex) +{ + setDiffuseMap(tex); +} + +void LLFace::setDiffuseMap(LLViewerTexture* tex) +{ + setTexture(LLRender::DIFFUSE_MAP, tex); +} + +void LLFace::setNormalMap(LLViewerTexture* tex) +{ + setTexture(LLRender::NORMAL_MAP, tex); +} + +void LLFace::setSpecularMap(LLViewerTexture* tex) +{ + setTexture(LLRender::SPECULAR_MAP, tex); } void LLFace::dirtyTexture() { - gPipeline.markTextured(getDrawable()); + LLDrawable* drawablep = getDrawable(); + + if (mVObjp.notNull() && mVObjp->getVolume()) + { + for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch) + { + if (mTexture[ch].notNull() && mTexture[ch]->getComponents() == 4) + { //dirty texture on an alpha object should be treated as an LoD update + LLVOVolume* vobj = drawablep->getVOVolume(); + if (vobj) + { + vobj->mLODChanged = TRUE; + + LLVOAvatar* avatar = vobj->getAvatar(); + if (avatar) + { //avatar render cost may have changed + avatar->updateVisualComplexity(); + } + } + gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_VOLUME, FALSE); + } + } + } + + gPipeline.markTextured(drawablep); } -void LLFace::switchTexture(LLViewerTexture* new_texture) +void LLFace::notifyAboutCreatingTexture(LLViewerTexture *texture) { - if(mTexture == new_texture) + LLDrawable* drawablep = getDrawable(); + if(mVObjp.notNull() && mVObjp->getVolume()) + { + LLVOVolume *vobj = drawablep->getVOVolume(); + if(vobj && vobj->notifyAboutCreatingTexture(texture)) + { + gPipeline.markTextured(drawablep); + gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_VOLUME); + } + } +} + +void LLFace::notifyAboutMissingAsset(LLViewerTexture *texture) +{ + LLDrawable* drawablep = getDrawable(); + if(mVObjp.notNull() && mVObjp->getVolume()) + { + LLVOVolume *vobj = drawablep->getVOVolume(); + if(vobj && vobj->notifyAboutMissingAsset(texture)) + { + gPipeline.markTextured(drawablep); + gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_VOLUME); + } + } +} + +void LLFace::switchTexture(U32 ch, LLViewerTexture* new_texture) +{ + llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); + + if(mTexture[ch] == new_texture) { return ; } if(!new_texture) { - llerrs << "Can not switch to a null texture." << llendl; + LL_ERRS() << "Can not switch to a null texture." << LL_ENDL; return; } - new_texture->addTextureStats(mTexture->getMaxVirtualSize()) ; + llassert(mTexture[ch].notNull()); + + new_texture->addTextureStats(mTexture[ch]->getMaxVirtualSize()) ; + + if (ch == LLRender::DIFFUSE_MAP) + { getViewerObject()->changeTEImage(mTEOffset, new_texture) ; - setTexture(new_texture) ; + } + + setTexture(ch, new_texture) ; dirtyTexture(); } @@ -329,18 +423,63 @@ void LLFace::setDrawable(LLDrawable *drawable) mXform = &drawable->mXform; } -void LLFace::setSize(const S32 num_vertices, const S32 num_indices) +void LLFace::setSize(S32 num_vertices, S32 num_indices, bool align) { + if (align) + { + //allocate vertices in blocks of 4 for alignment + num_vertices = (num_vertices + 0x3) & ~0x3; + } + if (mGeomCount != num_vertices || mIndicesCount != num_indices) { mGeomCount = num_vertices; mIndicesCount = num_indices; mVertexBuffer = NULL; - mLastVertexBuffer = NULL; + } + + llassert(verify()); +} + +void LLFace::setGeomIndex(U16 idx) +{ + if (mGeomIndex != idx) + { + mGeomIndex = idx; + mVertexBuffer = NULL; + } +} + +void LLFace::setTextureIndex(U8 index) +{ + if (index != mTextureIndex) + { + mTextureIndex = index; + + if (mTextureIndex != 255) + { + mDrawablep->setState(LLDrawable::REBUILD_POSITION); + } + else + { + if (mDrawInfo && !mDrawInfo->mTextureList.empty()) + { + LL_ERRS() << "Face with no texture index references indexed texture draw info." << LL_ENDL; + } + } } } +void LLFace::setIndicesIndex(S32 idx) +{ + if (mIndicesIndex != idx) + { + mIndicesIndex = idx; + mVertexBuffer = NULL; + } +} + //============================================================================ U16 LLFace::getGeometryAvatar( @@ -350,15 +489,13 @@ U16 LLFace::getGeometryAvatar( LLStrider<F32> &vertex_weights, LLStrider<LLVector4> &clothing_weights) { - LLMemType mt1(LLMemType::MTYPE_DRAWABLE); - if (mVertexBuffer.notNull()) { - mVertexBuffer->getVertexStrider (vertices, mGeomIndex); - mVertexBuffer->getNormalStrider (normals, mGeomIndex); - mVertexBuffer->getTexCoord0Strider (tex_coords, mGeomIndex); - mVertexBuffer->getWeightStrider(vertex_weights, mGeomIndex); - mVertexBuffer->getClothWeightStrider(clothing_weights, mGeomIndex); + mVertexBuffer->getVertexStrider (vertices, mGeomIndex, mGeomCount); + mVertexBuffer->getNormalStrider (normals, mGeomIndex, mGeomCount); + mVertexBuffer->getTexCoord0Strider (tex_coords, mGeomIndex, mGeomCount); + mVertexBuffer->getWeightStrider(vertex_weights, mGeomIndex, mGeomCount); + mVertexBuffer->getClothWeightStrider(clothing_weights, mGeomIndex, mGeomCount); } return mGeomIndex; @@ -367,21 +504,19 @@ U16 LLFace::getGeometryAvatar( U16 LLFace::getGeometry(LLStrider<LLVector3> &vertices, LLStrider<LLVector3> &normals, LLStrider<LLVector2> &tex_coords, LLStrider<U16> &indicesp) { - LLMemType mt1(LLMemType::MTYPE_DRAWABLE); - if (mVertexBuffer.notNull()) { - mVertexBuffer->getVertexStrider(vertices, mGeomIndex); + mVertexBuffer->getVertexStrider(vertices, mGeomIndex, mGeomCount); if (mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL)) { - mVertexBuffer->getNormalStrider(normals, mGeomIndex); + mVertexBuffer->getNormalStrider(normals, mGeomIndex, mGeomCount); } if (mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD0)) { - mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex); + mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount); } - mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex); + mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex, mIndicesCount); } return mGeomIndex; @@ -421,16 +556,47 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color) gGL.pushMatrix(); if (mDrawablep->isActive()) { - glMultMatrixf((GLfloat*)mDrawablep->getRenderMatrix().mMatrix); + gGL.multMatrix((GLfloat*)mDrawablep->getRenderMatrix().mMatrix); } else { - glMultMatrixf((GLfloat*)mDrawablep->getRegion()->mRenderMatrix.mMatrix); + gGL.multMatrix((GLfloat*)mDrawablep->getRegion()->mRenderMatrix.mMatrix); } - glColor4fv(color.mV); - mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0); - mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex); + gGL.diffuseColor4fv(color.mV); + + if (mDrawablep->isState(LLDrawable::RIGGED)) + { + LLVOVolume* volume = mDrawablep->getVOVolume(); + if (volume) + { + LLRiggedVolume* rigged = volume->getRiggedVolume(); + if (rigged) + { + LLGLEnable offset(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(-1.f, -1.f); + gGL.multMatrix((F32*) volume->getRelativeXform().mMatrix); + const LLVolumeFace& vol_face = rigged->getVolumeFace(getTEOffset()); + LLVertexBuffer::unbind(); + glVertexPointer(3, GL_FLOAT, 16, vol_face.mPositions); + if (vol_face.mTexCoords) + { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 8, vol_face.mTexCoords); + } + gGL.syncMatrices(); + glDrawElements(GL_TRIANGLES, vol_face.mNumIndices, GL_UNSIGNED_SHORT, vol_face.mIndices); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + } + } + else + { + // cheaters sometimes prosper... + // + mVertexBuffer->setBuffer(mVertexBuffer->getTypeMask()); + mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex); + } gGL.popMatrix(); } @@ -440,8 +606,8 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color) /* removed in lieu of raycast uv detection void LLFace::renderSelectedUV() { - LLViewerTexture* red_blue_imagep = LLViewerTextureManager::getFetchedTextureFromFile("uv_test1.j2c", TRUE, LLViewerTexture::BOOST_UI); - LLViewerTexture* green_imagep = LLViewerTextureManager::getFetchedTextureFromFile("uv_test2.tga", TRUE, LLViewerTexture::BOOST_UI); + LLViewerTexture* red_blue_imagep = LLViewerTextureManager::getFetchedTextureFromFile("uv_test1.j2c", TRUE, LLGLTexture::BOOST_UI); + LLViewerTexture* green_imagep = LLViewerTextureManager::getFetchedTextureFromFile("uv_test2.tga", TRUE, LLGLTexture::BOOST_UI); LLGLSUVSelect object_select; @@ -454,17 +620,17 @@ void LLFace::renderSelectedUV() // add green dither pattern on top of red/blue gradient gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_ONE); - glMatrixMode(GL_TEXTURE); - glPushMatrix(); + gGL.matrixMode(LLRender::MM_TEXTURE); + gGL.pushMatrix(); // make green pattern repeat once per texel in red/blue texture - glScalef(256.f, 256.f, 1.f); - glMatrixMode(GL_MODELVIEW); + gGL.scalef(256.f, 256.f, 1.f); + gGL.matrixMode(LLRender::MM_MODELVIEW); renderSelected(green_imagep, LLColor4::white); - glMatrixMode(GL_TEXTURE); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); + gGL.matrixMode(LLRender::MM_TEXTURE); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA); } */ @@ -491,52 +657,55 @@ void LLFace::setDrawInfo(LLDrawInfo* draw_info) void LLFace::printDebugInfo() const { LLFacePool *poolp = getPool(); - llinfos << "Object: " << getViewerObject()->mID << llendl; + LL_INFOS() << "Object: " << getViewerObject()->mID << LL_ENDL; if (getDrawable()) { - llinfos << "Type: " << LLPrimitive::pCodeToString(getDrawable()->getVObj()->getPCode()) << llendl; + LL_INFOS() << "Type: " << LLPrimitive::pCodeToString(getDrawable()->getVObj()->getPCode()) << LL_ENDL; } if (getTexture()) { - llinfos << "Texture: " << getTexture() << " Comps: " << (U32)getTexture()->getComponents() << llendl; + LL_INFOS() << "Texture: " << getTexture() << " Comps: " << (U32)getTexture()->getComponents() << LL_ENDL; } else { - llinfos << "No texture: " << llendl; + LL_INFOS() << "No texture: " << LL_ENDL; } - llinfos << "Face: " << this << llendl; - llinfos << "State: " << getState() << llendl; - llinfos << "Geom Index Data:" << llendl; - llinfos << "--------------------" << llendl; - llinfos << "GI: " << mGeomIndex << " Count:" << mGeomCount << llendl; - llinfos << "Face Index Data:" << llendl; - llinfos << "--------------------" << llendl; - llinfos << "II: " << mIndicesIndex << " Count:" << mIndicesCount << llendl; - llinfos << llendl; - - poolp->printDebugInfo(); + LL_INFOS() << "Face: " << this << LL_ENDL; + LL_INFOS() << "State: " << getState() << LL_ENDL; + LL_INFOS() << "Geom Index Data:" << LL_ENDL; + LL_INFOS() << "--------------------" << LL_ENDL; + LL_INFOS() << "GI: " << mGeomIndex << " Count:" << mGeomCount << LL_ENDL; + LL_INFOS() << "Face Index Data:" << LL_ENDL; + LL_INFOS() << "--------------------" << LL_ENDL; + LL_INFOS() << "II: " << mIndicesIndex << " Count:" << mIndicesCount << LL_ENDL; + LL_INFOS() << LL_ENDL; - S32 pool_references = 0; - for (std::vector<LLFace*>::iterator iter = poolp->mReferences.begin(); - iter != poolp->mReferences.end(); iter++) + if (poolp) { - LLFace *facep = *iter; - if (facep == this) + poolp->printDebugInfo(); + + S32 pool_references = 0; + for (std::vector<LLFace*>::iterator iter = poolp->mReferences.begin(); + iter != poolp->mReferences.end(); iter++) { - llinfos << "Pool reference: " << pool_references << llendl; - pool_references++; + LLFace *facep = *iter; + if (facep == this) + { + LL_INFOS() << "Pool reference: " << pool_references << LL_ENDL; + pool_references++; + } } - } - if (pool_references != 1) - { - llinfos << "Incorrect number of pool references!" << llendl; + if (pool_references != 1) + { + LL_INFOS() << "Incorrect number of pool references!" << LL_ENDL; + } } #if 0 - llinfos << "Indices:" << llendl; - llinfos << "--------------------" << llendl; + LL_INFOS() << "Indices:" << LL_ENDL; + LL_INFOS() << "--------------------" << LL_ENDL; const U32 *indicesp = getRawIndices(); S32 indices_count = getIndicesCount(); @@ -544,17 +713,17 @@ void LLFace::printDebugInfo() const for (S32 i = 0; i < indices_count; i++) { - llinfos << i << ":" << indicesp[i] << ":" << (S32)(indicesp[i] - geom_start) << llendl; + LL_INFOS() << i << ":" << indicesp[i] << ":" << (S32)(indicesp[i] - geom_start) << LL_ENDL; } - llinfos << llendl; + LL_INFOS() << LL_ENDL; - llinfos << "Vertices:" << llendl; - llinfos << "--------------------" << llendl; + LL_INFOS() << "Vertices:" << LL_ENDL; + LL_INFOS() << "--------------------" << LL_ENDL; for (S32 i = 0; i < mGeomCount; i++) { - llinfos << mGeomIndex + i << ":" << poolp->getVertex(mGeomIndex + i) << llendl; + LL_INFOS() << mGeomIndex + i << ":" << poolp->getVertex(mGeomIndex + i) << LL_ENDL; } - llinfos << llendl; + LL_INFOS() << LL_ENDL; #endif } @@ -586,97 +755,154 @@ static void xform(LLVector2 &tex_coord, F32 cosAng, F32 sinAng, F32 offS, F32 of tex_coord.mV[1] = t; } +// Transform the texture coordinates for this face. +static void xform4a(LLVector4a &tex_coord, const LLVector4a& trans, const LLVector4Logical& mask, const LLVector4a& rot0, const LLVector4a& rot1, const LLVector4a& offset, const LLVector4a& scale) +{ + //tex coord is two coords, <s0, t0, s1, t1> + LLVector4a st; -BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, - const LLMatrix4& mat_vert, const LLMatrix3& mat_normal, BOOL global_volume) + // Texture transforms are done about the center of the face. + st.setAdd(tex_coord, trans); + + // Handle rotation + LLVector4a rot_st; + + // <s0 * cosAng, s0*-sinAng, s1*cosAng, s1*-sinAng> + LLVector4a s0; + s0.splat(st, 0); + LLVector4a s1; + s1.splat(st, 2); + LLVector4a ss; + ss.setSelectWithMask(mask, s1, s0); + + LLVector4a a; + a.setMul(rot0, ss); + + // <t0*sinAng, t0*cosAng, t1*sinAng, t1*cosAng> + LLVector4a t0; + t0.splat(st, 1); + LLVector4a t1; + t1.splat(st, 3); + LLVector4a tt; + tt.setSelectWithMask(mask, t1, t0); + + LLVector4a b; + b.setMul(rot1, tt); + + st.setAdd(a,b); + + // Then scale + st.mul(scale); + + // Then offset + tex_coord.setAdd(st, offset); +} + + +bool less_than_max_mag(const LLVector4a& vec) { - LLMemType mt1(LLMemType::MTYPE_DRAWABLE); + LLVector4a MAX_MAG; + MAX_MAG.splat(1024.f*1024.f); + LLVector4a val; + val.setAbs(vec); + + S32 lt = val.lessThan(MAX_MAG).getGatheredBits() & 0x7; + + return lt == 0x7; +} + +BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, + const LLMatrix4& mat_vert_in, BOOL global_volume) +{ //get bounding box - if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION)) + if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED)) { - //if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME)) - //{ //vertex buffer no longer valid - // mVertexBuffer = NULL; - // mLastVertexBuffer = NULL; - //} + //VECTORIZE THIS + LLMatrix4a mat_vert; + mat_vert.loadu(mat_vert_in); - LLVector3 min,max; + LLVector4a min,max; if (f >= volume.getNumVolumeFaces()) { - min = LLVector3(-1,-1,-1); - max = LLVector3(1,1,1); + LL_WARNS() << "Generating bounding box for invalid face index!" << LL_ENDL; + f = 0; } - else + + const LLVolumeFace &face = volume.getVolumeFace(f); + min = face.mExtents[0]; + max = face.mExtents[1]; + + llassert(less_than_max_mag(min)); + llassert(less_than_max_mag(max)); + + //min, max are in volume space, convert to drawable render space + + //get 8 corners of bounding box + LLVector4Logical mask[6]; + + for (U32 i = 0; i < 6; ++i) { - const LLVolumeFace &face = volume.getVolumeFace(f); - min = face.mExtents[0]; - max = face.mExtents[1]; + mask[i].clear(); } - //min, max are in volume space, convert to drawable render space - LLVector3 center = ((min + max) * 0.5f)*mat_vert; - LLVector3 size = ((max-min) * 0.5f); - if (!global_volume) + mask[0].setElement<2>(); //001 + mask[1].setElement<1>(); //010 + mask[2].setElement<1>(); //011 + mask[2].setElement<2>(); + mask[3].setElement<0>(); //100 + mask[4].setElement<0>(); //101 + mask[4].setElement<2>(); + mask[5].setElement<0>(); //110 + mask[5].setElement<1>(); + + LLVector4a v[8]; + + v[6] = min; + v[7] = max; + + for (U32 i = 0; i < 6; ++i) { - size.scaleVec(mDrawablep->getVObj()->getScale()); + v[i].setSelectWithMask(mask[i], min, max); } - LLMatrix3 mat = mat_normal; - LLVector3 x = mat.getFwdRow(); - LLVector3 y = mat.getLeftRow(); - LLVector3 z = mat.getUpRow(); - x.normVec(); - y.normVec(); - z.normVec(); + LLVector4a tv[8]; - mat.setRows(x,y,z); + //transform bounding box into drawable space + for (U32 i = 0; i < 8; ++i) + { + mat_vert.affineTransform(v[i], tv[i]); + } + + //find bounding box + LLVector4a& newMin = mExtents[0]; + LLVector4a& newMax = mExtents[1]; - LLQuaternion rotation = LLQuaternion(mat); - - LLVector3 v[4]; - //get 4 corners of bounding box - v[0] = (size * rotation); - v[1] = (LLVector3(-size.mV[0], -size.mV[1], size.mV[2]) * rotation); - v[2] = (LLVector3(size.mV[0], -size.mV[1], -size.mV[2]) * rotation); - v[3] = (LLVector3(-size.mV[0], size.mV[1], -size.mV[2]) * rotation); - - LLVector3& newMin = mExtents[0]; - LLVector3& newMax = mExtents[1]; - - newMin = newMax = center; - - for (U32 i = 0; i < 4; i++) + newMin = newMax = tv[0]; + + for (U32 i = 1; i < 8; ++i) { - for (U32 j = 0; j < 3; j++) - { - F32 delta = fabsf(v[i].mV[j]); - F32 min = center.mV[j] - delta; - F32 max = center.mV[j] + delta; - - if (min < newMin.mV[j]) - { - newMin.mV[j] = min; - } - - if (max > newMax.mV[j]) - { - newMax.mV[j] = max; - } - } + newMin.setMin(newMin, tv[i]); + newMax.setMax(newMax, tv[i]); } if (!mDrawablep->isActive()) - { - LLVector3 offset = mDrawablep->getRegion()->getOriginAgent(); - newMin += offset; - newMax += offset; + { // Shift position for region + LLVector4a offset; + offset.load3(mDrawablep->getRegion()->getOriginAgent().mV); + newMin.add(offset); + newMax.add(offset); } - mCenterLocal = (newMin+newMax)*0.5f; - LLVector3 tmp = (newMin - newMax) ; - mBoundingSphereRadius = tmp.length() * 0.5f ; + LLVector4a t; + t.setAdd(newMin,newMax); + t.mul(0.5f); + + mCenterLocal.set(t.getF32ptr()); + + t.setSub(newMax,newMin); + mBoundingSphereRadius = t.getLength3().getF32()*0.5f; updateCenterAgent(); } @@ -691,7 +917,7 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, // integrated with getGeometryVolume() for its texture coordinate // generation - but i'll leave that to someone more familiar // with the implications. -LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, LLVector3 position, LLVector3 normal) +LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, const LLVector4a& position, const LLVector4a& normal) { LLVector2 tc = surface_coord; @@ -703,32 +929,33 @@ LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, LLVector3 position, return surface_coord; } + //VECTORIZE THIS // see if we have a non-default mapping U8 texgen = getTextureEntry()->getTexGen(); if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) { - LLVector3 center = mDrawablep->getVOVolume()->getVolume()->getVolumeFace(mTEOffset).mCenter; + LLVector4a& center = *(mDrawablep->getVOVolume()->getVolume()->getVolumeFace(mTEOffset).mCenter); - LLVector3 scale = (mDrawablep->getVOVolume()->isVolumeGlobal()) ? LLVector3(1,1,1) : mVObjp->getScale(); - LLVector3 volume_position = mDrawablep->getVOVolume()->agentPositionToVolume(position); - volume_position.scaleVec(scale); + LLVector4a volume_position; + LLVector3 v_position(position.getF32ptr()); + + volume_position.load3(mDrawablep->getVOVolume()->agentPositionToVolume(v_position).mV); + + if (!mDrawablep->getVOVolume()->isVolumeGlobal()) + { + LLVector4a scale; + scale.load3(mVObjp->getScale().mV); + volume_position.mul(scale); + } - LLVector3 volume_normal = mDrawablep->getVOVolume()->agentDirectionToVolume(normal); - volume_normal.normalize(); + LLVector4a volume_normal; + LLVector3 v_normal(normal.getF32ptr()); + volume_normal.load3(mDrawablep->getVOVolume()->agentDirectionToVolume(v_normal).mV); + volume_normal.normalize3fast(); - switch (texgen) + if (texgen == LLTextureEntry::TEX_GEN_PLANAR) { - case LLTextureEntry::TEX_GEN_PLANAR: planarProjection(tc, volume_normal, center, volume_position); - break; - case LLTextureEntry::TEX_GEN_SPHERICAL: - sphericalProjection(tc, volume_normal, center, volume_position); - break; - case LLTextureEntry::TEX_GEN_CYLINDRICAL: - cylindricalProjection(tc, volume_normal, center, volume_position); - break; - default: - break; } } @@ -755,10 +982,19 @@ void LLFace::getPlanarProjectedParams(LLQuaternion* face_rot, LLVector3* face_po { const LLMatrix4& vol_mat = getWorldMatrix(); const LLVolumeFace& vf = getViewerObject()->getVolume()->getVolumeFace(mTEOffset); - LLVector3 normal = vf.mVertices[0].mNormal; - LLVector3 binormal = vf.mVertices[0].mBinormal; + const LLVector4a& normal4a = vf.mNormals[0]; + const LLVector4a& tangent = vf.mTangents[0]; + if (!&tangent) + { + return; + } + + LLVector4a binormal4a; + binormal4a.setCross3(normal4a, tangent); + binormal4a.mul(tangent.getF32ptr()[3]); + LLVector2 projected_binormal; - planarProjection(projected_binormal, normal, vf.mCenter, binormal); + planarProjection(projected_binormal, normal4a, *vf.mCenter, binormal4a); projected_binormal -= LLVector2(0.5f, 0.5f); // this normally happens in xform() *scale = projected_binormal.length(); // rotate binormal to match what planarProjection() thinks it is, @@ -766,6 +1002,10 @@ void LLFace::getPlanarProjectedParams(LLQuaternion* face_rot, LLVector3* face_po projected_binormal.normalize(); F32 ang = acos(projected_binormal.mV[VY]); ang = (projected_binormal.mV[VX] < 0.f) ? -ang : ang; + + //VECTORIZE THIS + LLVector3 binormal(binormal4a.getF32ptr()); + LLVector3 normal(normal4a.getF32ptr()); binormal.rotVec(ang, normal); LLQuaternion local_rot( binormal % normal, binormal, normal ); *face_rot = local_rot * vol_mat.quaternion(); @@ -818,97 +1058,215 @@ bool LLFace::calcAlignedPlanarTE(const LLFace* align_to, LLVector2* res_st_offs void LLFace::updateRebuildFlags() { - if (!mDrawablep->isState(LLDrawable::REBUILD_VOLUME)) - { - BOOL moved = TRUE; - if (mLastVertexBuffer == mVertexBuffer && - !mVertexBuffer->isEmpty()) - { //this face really doesn't need to be regenerated, try real hard not to do so - if (mLastGeomCount == mGeomCount && - mLastGeomIndex == mGeomIndex && - mLastIndicesCount == mIndicesCount && - mLastIndicesIndex == mIndicesIndex) - { //data is in same location in vertex buffer - moved = FALSE; - } - } - mLastMoveTime = gFrameTimeSeconds; - - if (moved) - { - mDrawablep->setState(LLDrawable::REBUILD_VOLUME); - } + if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME)) + { //this rebuild is zero overhead (direct consequence of some change that affects this face) + mLastUpdateTime = gFrameTimeSeconds; } else - { - mLastUpdateTime = gFrameTimeSeconds; + { //this rebuild is overhead (side effect of some change that does not affect this face) + mLastMoveTime = gFrameTimeSeconds; } } bool LLFace::canRenderAsMask() { + if (LLPipeline::sNoAlpha) + { + return true; + } + const LLTextureEntry* te = getTextureEntry(); - return ( - ( - (LLPipeline::sRenderDeferred && LLPipeline::sAutoMaskAlphaDeferred) || - - (!LLPipeline::sRenderDeferred && LLPipeline::sAutoMaskAlphaNonDeferred) - ) // do we want masks at all? - && - (te->getColor().mV[3] == 1.0f) && // can't treat as mask if we have face alpha - !(LLPipeline::sRenderDeferred && te->getFullbright()) && // hack: alpha masking renders fullbright faces invisible in deferred rendering mode, need to figure out why - for now, avoid + if( !te || !getViewerObject() || !getTexture() ) + { + return false; + } + + LLMaterial* mat = te->getMaterialParams(); + if (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND) + { + return false; + } + + if ((te->getColor().mV[3] == 1.0f) && // can't treat as mask if we have face alpha (te->getGlow() == 0.f) && // glowing masks are hard to implement - don't mask + getTexture()->getIsAlphaMask()) // texture actually qualifies for masking (lazily recalculated but expensive) + { + if (LLPipeline::sRenderDeferred) + { + if (getViewerObject()->isHUDAttachment() || te->getFullbright()) + { //hud attachments and fullbright objects are NOT subject to the deferred rendering pipe + return LLPipeline::sAutoMaskAlphaNonDeferred; + } + else + { + return LLPipeline::sAutoMaskAlphaDeferred; + } + } + else + { + return LLPipeline::sAutoMaskAlphaNonDeferred; + } + } - getTexture()->getIsAlphaMask() // texture actually qualifies for masking (lazily recalculated but expensive) - ); + return false; } -static LLFastTimer::DeclareTimer FTM_FACE_GET_GEOM("Face Geom"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_VOLUME("Volume VB Cache"); + +//static +void LLFace::cacheFaceInVRAM(const LLVolumeFace& vf) +{ + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_VOLUME); + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL; + + if (vf.mWeights) + { + mask |= LLVertexBuffer::MAP_WEIGHT4; + } + + LLVertexBuffer* buff = new LLVertexBuffer(mask, GL_STATIC_DRAW_ARB); + vf.mVertexBuffer = buff; + + buff->allocateBuffer(vf.mNumVertices, 0, true); + + LLStrider<LLVector4a> f_vert; + LLStrider<LLVector4a> f_tangent; + LLStrider<LLVector3> f_norm; + LLStrider<LLVector2> f_tc; + + buff->getTangentStrider(f_tangent); + buff->getVertexStrider(f_vert); + buff->getNormalStrider(f_norm); + buff->getTexCoord0Strider(f_tc); + + for (U32 i = 0; i < vf.mNumVertices; ++i) + { + *f_vert++ = vf.mPositions[i]; + *f_tangent++ = vf.mTangents[i]; + *f_tc++ = vf.mTexCoords[i]; + (*f_norm++).set(vf.mNormals[i].getF32ptr()); + } + + if (vf.mWeights) + { + LLStrider<LLVector4> f_wght; + buff->getWeight4Strider(f_wght); + for (U32 i = 0; i < vf.mNumVertices; ++i) + { + (*f_wght++).set(vf.mWeights[i].getF32ptr()); + } + } + + buff->flush(); +} + +//helper function for pushing primitives for transform shaders and cleaning up +//uninitialized data on the tail, plus tracking number of expected primitives +void push_for_transform(LLVertexBuffer* buff, U32 source_count, U32 dest_count) +{ + if (source_count > 0 && dest_count >= source_count) //protect against possible U32 wrapping + { + //push source primitives + buff->drawArrays(LLRender::POINTS, 0, source_count); + U32 tail = dest_count-source_count; + for (U32 i = 0; i < tail; ++i) + { //copy last source primitive into each element in tail + buff->drawArrays(LLRender::POINTS, source_count-1, 1); + } + gPipeline.mTransformFeedbackPrimitives += dest_count; + } +} + +static LLTrace::BlockTimerStatHandle FTM_FACE_GET_GEOM("Face Geom"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_POSITION("Position"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_NORMAL("Normal"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_TEXTURE("Texture"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_COLOR("Color"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_EMISSIVE("Emissive"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_WEIGHTS("Weights"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_TANGENT("Binormal"); + +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK("Face Feedback"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_POSITION("Feedback Position"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_NORMAL("Feedback Normal"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_TEXTURE("Feedback Texture"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_COLOR("Feedback Color"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_EMISSIVE("Feedback Emissive"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_BINORMAL("Feedback Binormal"); + +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_INDEX("Index"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_INDEX_TAIL("Tail"); +static LLTrace::BlockTimerStatHandle FTM_FACE_POSITION_STORE("Pos"); +static LLTrace::BlockTimerStatHandle FTM_FACE_TEXTURE_INDEX_STORE("TexIdx"); +static LLTrace::BlockTimerStatHandle FTM_FACE_POSITION_PAD("Pad"); +static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_DEFAULT("Default"); +static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_QUICK("Quick"); +static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_QUICK_NO_XFORM("No Xform"); +static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_QUICK_XFORM("Xform"); +static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_QUICK_PLANAR("Quick Planar"); BOOL LLFace::getGeometryVolume(const LLVolume& volume, const S32 &f, - const LLMatrix4& mat_vert, const LLMatrix3& mat_normal, - const U16 &index_offset) + const LLMatrix4& mat_vert_in, const LLMatrix3& mat_norm_in, + const U16 &index_offset, + bool force_rebuild) { - LLFastTimer t(FTM_FACE_GET_GEOM); + LL_RECORD_BLOCK_TIME(FTM_FACE_GET_GEOM); + llassert(verify()); const LLVolumeFace &vf = volume.getVolumeFace(f); - S32 num_vertices = (S32)vf.mVertices.size(); - S32 num_indices = LLPipeline::sUseTriStrips ? (S32)vf.mTriStrip.size() : (S32) vf.mIndices.size(); + S32 num_vertices = (S32)vf.mNumVertices; + S32 num_indices = (S32) vf.mNumIndices; + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE)) + { + updateRebuildFlags(); + } + + + //don't use map range (generates many redundant unmap calls) + bool map_range = false; //gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange; + if (mVertexBuffer.notNull()) { if (num_indices + (S32) mIndicesIndex > mVertexBuffer->getNumIndices()) { - llwarns << "Index buffer overflow!" << llendl; - llwarns << "Indices Count: " << mIndicesCount - << " VF Num Indices: " << num_indices - << " Indices Index: " << mIndicesIndex - << " VB Num Indices: " << mVertexBuffer->getNumIndices() << llendl; - llwarns << "Last Indices Count: " << mLastIndicesCount - << " Last Indices Index: " << mLastIndicesIndex - << " Face Index: " << f - << " Pool Type: " << mPoolType << llendl; + if (gDebugGL) + { + LL_WARNS() << "Index buffer overflow!" << LL_ENDL; + LL_WARNS() << "Indices Count: " << mIndicesCount + << " VF Num Indices: " << num_indices + << " Indices Index: " << mIndicesIndex + << " VB Num Indices: " << mVertexBuffer->getNumIndices() << LL_ENDL; + LL_WARNS() << " Face Index: " << f + << " Pool Type: " << mPoolType << LL_ENDL; + } return FALSE; } if (num_vertices + mGeomIndex > mVertexBuffer->getNumVerts()) { - llwarns << "Vertex buffer overflow!" << llendl; + if (gDebugGL) + { + LL_WARNS() << "Vertex buffer overflow!" << LL_ENDL; + } return FALSE; } } - LLStrider<LLVector3> vertices; - LLStrider<LLVector2> tex_coords; + LLStrider<LLVector3> vert; + LLStrider<LLVector2> tex_coords0; + LLStrider<LLVector2> tex_coords1; LLStrider<LLVector2> tex_coords2; - LLStrider<LLVector3> normals; + LLStrider<LLVector3> norm; LLStrider<LLColor4U> colors; - LLStrider<LLVector3> binormals; + LLStrider<LLVector3> tangent; LLStrider<U16> indicesp; + LLStrider<LLVector4> wght; - BOOL full_rebuild = mDrawablep->isState(LLDrawable::REBUILD_VOLUME); + BOOL full_rebuild = force_rebuild || mDrawablep->isState(LLDrawable::REBUILD_VOLUME); BOOL global_volume = mDrawablep->getVOVolume()->isVolumeGlobal(); LLVector3 scale; @@ -921,79 +1279,113 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, scale = mVObjp->getScale(); } - BOOL rebuild_pos = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_POSITION); - BOOL rebuild_color = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_COLOR); - BOOL rebuild_tcoord = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_TCOORD); - BOOL rebuild_normal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); - BOOL rebuild_binormal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_BINORMAL); + bool rebuild_pos = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_POSITION); + bool rebuild_color = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_COLOR); + bool rebuild_emissive = rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE); + bool rebuild_tcoord = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_TCOORD); + bool rebuild_normal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); + bool rebuild_tangent = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TANGENT); + bool rebuild_weights = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_WEIGHT4); const LLTextureEntry *tep = mVObjp->getTE(f); - U8 bump_code = tep ? tep->getBumpmap() : 0; + const U8 bump_code = tep ? tep->getBumpmap() : 0; + + BOOL is_static = mDrawablep->isStatic(); + BOOL is_global = is_static; - if (rebuild_pos) + LLVector3 center_sum(0.f, 0.f, 0.f); + + if (is_global) { - mVertexBuffer->getVertexStrider(vertices, mGeomIndex); + setState(GLOBAL); } - if (rebuild_normal) + else { - mVertexBuffer->getNormalStrider(normals, mGeomIndex); + clearState(GLOBAL); } - if (rebuild_binormal) + + LLColor4U color = tep->getColor(); + + if (rebuild_color) + { //decide if shiny goes in alpha channel of color + if (tep && + getPoolType() != LLDrawPool::POOL_ALPHA) // <--- alpha channel MUST contain transparency, not shiny { - mVertexBuffer->getBinormalStrider(binormals, mGeomIndex); - } + LLMaterial* mat = tep->getMaterialParams().get(); + + bool shiny_in_alpha = false; + + if (LLPipeline::sRenderDeferred) + { //store shiny in alpha if we don't have a specular map + if (!mat || mat->getSpecularID().isNull()) + { + shiny_in_alpha = true; + } + } + else + { + if (!mat || mat->getDiffuseAlphaMode() != LLMaterial::DIFFUSE_ALPHA_MODE_MASK) + { + shiny_in_alpha = true; + } + } - F32 tcoord_xoffset = 0.f ; - F32 tcoord_yoffset = 0.f ; - F32 tcoord_xscale = 1.f ; - F32 tcoord_yscale = 1.f ; - BOOL in_atlas = FALSE ; + if (shiny_in_alpha) + { - if (rebuild_tcoord) + static const GLfloat alpha[4] = + { + 0.00f, + 0.25f, + 0.5f, + 0.75f + }; + + llassert(tep->getShiny() <= 3); + color.mV[3] = U8 (alpha[tep->getShiny()] * 255); + } + } + } + + // INDICES + if (full_rebuild) { - mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex); - if (bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1)) + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_INDEX); + mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex, mIndicesCount, map_range); + + volatile __m128i* dst = (__m128i*) indicesp.get(); + __m128i* src = (__m128i*) vf.mIndices; + __m128i offset = _mm_set1_epi16(index_offset); + + S32 end = num_indices/8; + + for (S32 i = 0; i < end; i++) { - mVertexBuffer->getTexCoord1Strider(tex_coords2, mGeomIndex); + __m128i res = _mm_add_epi16(src[i], offset); + _mm_storeu_si128((__m128i*) dst++, res); } - in_atlas = isAtlasInUse() ; - if(in_atlas) { - const LLVector2* tmp = getTexCoordOffset() ; - tcoord_xoffset = tmp->mV[0] ; - tcoord_yoffset = tmp->mV[1] ; + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_INDEX_TAIL); + U16* idx = (U16*) dst; - tmp = getTexCoordScale() ; - tcoord_xscale = tmp->mV[0] ; - tcoord_yscale = tmp->mV[1] ; + for (S32 i = end*8; i < num_indices; ++i) + { + *idx++ = vf.mIndices[i]+index_offset; + } } - } - if (rebuild_color) - { - mVertexBuffer->getColorStrider(colors, mGeomIndex); - } - - F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0; - - BOOL is_static = mDrawablep->isStatic(); - BOOL is_global = is_static; - LLVector3 center_sum(0.f, 0.f, 0.f); - - if (is_global) - { - setState(GLOBAL); - } - else - { - clearState(GLOBAL); + if (map_range) + { + mVertexBuffer->flush(); + } } - - LLVector2 tmin, tmax; + LLMatrix4a mat_normal; + mat_normal.loadu(mat_norm_in); - + F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0; + bool do_xform = false; if (rebuild_tcoord) { if (tep) @@ -1005,324 +1397,801 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, mt = tep->mScaleT; cos_ang = cos(r); sin_ang = sin(r); + + if (cos_ang != 1.f || + sin_ang != 0.f || + os != 0.f || + ot != 0.f || + ms != 1.f || + mt != 1.f) + { + do_xform = true; + } + else + { + do_xform = false; + } } else { - cos_ang = 1.0f; - sin_ang = 0.0f; - os = 0.0f; - ot = 0.0f; - ms = 1.0f; - mt = 1.0f; + do_xform = false; } } - - U8 tex_mode = 0; - if (isState(TEXTURE_ANIM)) - { - LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp; - tex_mode = vobj->mTexAnimMode; + static LLCachedControl<bool> use_transform_feedback(gSavedSettings, "RenderUseTransformFeedback", false); + +#ifdef GL_TRANSFORM_FEEDBACK_BUFFER + if (use_transform_feedback && + mVertexBuffer->getUsage() == GL_DYNAMIC_COPY_ARB && + gTransformPositionProgram.mProgramObject && //transform shaders are loaded + mVertexBuffer->useVBOs() && //target buffer is in VRAM + !rebuild_weights && //TODO: add support for weights + !volume.isUnique()) //source volume is NOT flexi + { //use transform feedback to pack vertex buffer + //gGLDebugLoggingEnabled = TRUE; + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK); + LLGLEnable discard(GL_RASTERIZER_DISCARD); + LLVertexBuffer* buff = (LLVertexBuffer*) vf.mVertexBuffer.get(); + + if (vf.mVertexBuffer.isNull() || buff->getNumVerts() != vf.mNumVertices) + { + mVObjp->getVolume()->genTangents(f); + LLFace::cacheFaceInVRAM(vf); + buff = (LLVertexBuffer*) vf.mVertexBuffer.get(); + } + + LLGLSLShader* cur_shader = LLGLSLShader::sCurBoundShaderPtr; + + gGL.pushMatrix(); + gGL.loadMatrix((GLfloat*) mat_vert_in.mMatrix); - if (!tex_mode) + if (rebuild_pos) { - clearState(TEXTURE_ANIM); + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK_POSITION); + gTransformPositionProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_VERTEX, mGeomIndex, mGeomCount); + + U8 index = mTextureIndex < 255 ? mTextureIndex : 0; + + S32 val = 0; + U8* vp = (U8*) &val; + vp[0] = index; + vp[1] = 0; + vp[2] = 0; + vp[3] = 0; + + gTransformPositionProgram.uniform1i(sTextureIndexIn, val); + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_VERTEX); + + push_for_transform(buff, vf.mNumVertices, mGeomCount); + + glEndTransformFeedback(); } - else + + if (rebuild_color) { - os = ot = 0.f; - r = 0.f; - cos_ang = 1.f; - sin_ang = 0.f; - ms = mt = 1.f; - } + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK_COLOR); + gTransformColorProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_COLOR, mGeomIndex, mGeomCount); - if (getVirtualSize() >= MIN_TEX_ANIM_SIZE) - { //don't override texture transform during tc bake - tex_mode = 0; - } - } + S32 val = *((S32*) color.mV); - LLColor4U color = tep->getColor(); + gTransformColorProgram.uniform1i(sColorIn, val); + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_VERTEX); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); + } - if (rebuild_color) - { - if (tep) + if (rebuild_emissive) { - GLfloat alpha[4] = - { - 0.00f, - 0.25f, - 0.5f, - 0.75f - }; + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK_EMISSIVE); + gTransformColorProgram.bind(); - if (getPoolType() != LLDrawPool::POOL_ALPHA && (LLPipeline::sRenderDeferred || (LLPipeline::sRenderBump && tep->getShiny()))) - { - color.mV[3] = U8 (alpha[tep->getShiny()] * 255); - } + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_EMISSIVE, mGeomIndex, mGeomCount); + + U8 glow = (U8) llclamp((S32) (getTextureEntry()->getGlow()*255), 0, 255); + + S32 glow32 = glow | + (glow << 8) | + (glow << 16) | + (glow << 24); + + gTransformColorProgram.uniform1i(sColorIn, glow32); + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_VERTEX); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); } - } - // INDICES - if (full_rebuild) - { - mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex); - if (LLPipeline::sUseTriStrips) + if (rebuild_normal) { - for (U32 i = 0; i < (U32) num_indices; i++) - { - *indicesp++ = vf.mTriStrip[i] + index_offset; - } + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK_NORMAL); + gTransformNormalProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_NORMAL, mGeomIndex, mGeomCount); + + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_NORMAL); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); } - else + + if (rebuild_tangent) { - for (U32 i = 0; i < (U32) num_indices; i++) - { - *indicesp++ = vf.mIndices[i] + index_offset; - } + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_TANGENT); + gTransformTangentProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TANGENT, mGeomIndex, mGeomCount); + + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_TANGENT); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); } - } - - - //bump setup - LLVector3 binormal_dir( -sin_ang, cos_ang, 0 ); - LLVector3 bump_s_primary_light_ray; - LLVector3 bump_t_primary_light_ray; - LLQuaternion bump_quat; - if (mDrawablep->isActive()) - { - bump_quat = LLQuaternion(mDrawablep->getRenderMatrix()); - } - - if (bump_code) - { - mVObjp->getVolume()->genBinormals(f); - F32 offset_multiple; - switch( bump_code ) - { - case BE_NO_BUMP: - offset_multiple = 0.f; - break; - case BE_BRIGHTNESS: - case BE_DARKNESS: - if( mTexture.notNull() && mTexture->hasGLTexture()) - { - // Offset by approximately one texel - S32 cur_discard = mTexture->getDiscardLevel(); - S32 max_size = llmax( mTexture->getWidth(), mTexture->getHeight() ); - max_size <<= cur_discard; - const F32 ARTIFICIAL_OFFSET = 2.f; - offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size; - } - else - { - offset_multiple = 1.f/256; - } - break; + if (rebuild_tcoord) + { + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK_TEXTURE); + gTransformTexCoordProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TEXCOORD0, mGeomIndex, mGeomCount); + + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_TEXCOORD0); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); + + bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1); - default: // Standard bumpmap textures. Assumed to be 256x256 - offset_multiple = 1.f / 256; - break; + if (do_bump) + { + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TEXCOORD1, mGeomIndex, mGeomCount); + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_TEXCOORD0); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); + } } - F32 s_scale = 1.f; - F32 t_scale = 1.f; - if( tep ) + glBindBufferARB(GL_TRANSFORM_FEEDBACK_BUFFER, 0); + gGL.popMatrix(); + + if (cur_shader) { - tep->getScale( &s_scale, &t_scale ); + cur_shader->bind(); } - // Use the nudged south when coming from above sun angle, such - // that emboss mapping always shows up on the upward faces of cubes when - // it's noon (since a lot of builders build with the sun forced to noon). - LLVector3 sun_ray = gSky.mVOSkyp->mBumpSunDir; - LLVector3 moon_ray = gSky.getMoonDirection(); - LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray; - - bump_s_primary_light_ray = offset_multiple * s_scale * primary_light_ray; - bump_t_primary_light_ray = offset_multiple * t_scale * primary_light_ray; } - - U8 texgen = getTextureEntry()->getTexGen(); - if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT) - { //planar texgen needs binormals - mVObjp->getVolume()->genBinormals(f); - } - - for (S32 i = 0; i < num_vertices; i++) + else +#endif { + //if it's not fullbright and has no normals, bake sunlight based on face normal + //bool bake_sunlight = !getTextureEntry()->getFullbright() && + // !mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); + if (rebuild_tcoord) { - LLVector2 tc = vf.mVertices[i].mTexCoord; - - if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_TEXTURE); + + //bump setup + LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f ); + LLVector4a bump_s_primary_light_ray(0.f, 0.f, 0.f); + LLVector4a bump_t_primary_light_ray(0.f, 0.f, 0.f); + + LLQuaternion bump_quat; + if (mDrawablep->isActive()) { - LLVector3 vec = vf.mVertices[i].mPosition; - - vec.scaleVec(scale); + bump_quat = LLQuaternion(mDrawablep->getRenderMatrix()); + } + + if (bump_code) + { + mVObjp->getVolume()->genTangents(f); + F32 offset_multiple; + switch( bump_code ) + { + case BE_NO_BUMP: + offset_multiple = 0.f; + break; + case BE_BRIGHTNESS: + case BE_DARKNESS: + if( mTexture[LLRender::DIFFUSE_MAP].notNull() && mTexture[LLRender::DIFFUSE_MAP]->hasGLTexture()) + { + // Offset by approximately one texel + S32 cur_discard = mTexture[LLRender::DIFFUSE_MAP]->getDiscardLevel(); + S32 max_size = llmax( mTexture[LLRender::DIFFUSE_MAP]->getWidth(), mTexture[LLRender::DIFFUSE_MAP]->getHeight() ); + max_size <<= cur_discard; + const F32 ARTIFICIAL_OFFSET = 2.f; + offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size; + } + else + { + offset_multiple = 1.f/256; + } + break; - switch (texgen) + default: // Standard bumpmap textures. Assumed to be 256x256 + offset_multiple = 1.f / 256; + break; + } + + F32 s_scale = 1.f; + F32 t_scale = 1.f; + if( tep ) { - case LLTextureEntry::TEX_GEN_PLANAR: - planarProjection(tc, vf.mVertices[i].mNormal, vf.mCenter, vec); - break; - case LLTextureEntry::TEX_GEN_SPHERICAL: - sphericalProjection(tc, vf.mVertices[i].mNormal, vf.mCenter, vec); - break; - case LLTextureEntry::TEX_GEN_CYLINDRICAL: - cylindricalProjection(tc, vf.mVertices[i].mNormal, vf.mCenter, vec); - break; - default: - break; - } + tep->getScale( &s_scale, &t_scale ); + } + // Use the nudged south when coming from above sun angle, such + // that emboss mapping always shows up on the upward faces of cubes when + // it's noon (since a lot of builders build with the sun forced to noon). + LLVector3 sun_ray = gSky.mVOSkyp->mBumpSunDir; + LLVector3 moon_ray = gSky.getMoonDirection(); + LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray; + + bump_s_primary_light_ray.load3((offset_multiple * s_scale * primary_light_ray).mV); + bump_t_primary_light_ray.load3((offset_multiple * t_scale * primary_light_ray).mV); } - if (tex_mode && mTextureMatrix) - { - LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); - tmp = tmp * *mTextureMatrix; - tc.mV[0] = tmp.mV[0]; - tc.mV[1] = tmp.mV[1]; + U8 texgen = getTextureEntry()->getTexGen(); + if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT) + { //planar texgen needs binormals + mVObjp->getVolume()->genTangents(f); } - else + + U8 tex_mode = 0; + + bool tex_anim = false; + + LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp; + tex_mode = vobj->mTexAnimMode; + + if (vobj->mTextureAnimp) + { //texture animation is in play, override specular and normal map tex coords with diffuse texcoords + tex_anim = true; + } + + if (isState(TEXTURE_ANIM)) { - xform(tc, cos_ang, sin_ang, os, ot, ms, mt); + if (!tex_mode) + { + clearState(TEXTURE_ANIM); + } + else + { + os = ot = 0.f; + r = 0.f; + cos_ang = 1.f; + sin_ang = 0.f; + ms = mt = 1.f; + + do_xform = false; + } + + if (getVirtualSize() >= MIN_TEX_ANIM_SIZE || isState(LLFace::RIGGED)) + { //don't override texture transform during tc bake + tex_mode = 0; + } } - if(in_atlas) + LLVector4a scalea; + scalea.load3(scale.mV); + + LLMaterial* mat = tep->getMaterialParams().get(); + + bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1); + + if (mat && !do_bump) { - // - //manually calculate tex-coord per vertex for varying address modes. - //should be removed if shader can handle this. - // + do_bump = mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1) + || mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD2); + } + + bool do_tex_mat = tex_mode && mTextureMatrix; + + if (!do_bump) + { //not bump mapped, might be able to do a cheap update + mVertexBuffer->getTexCoord0Strider(tex_coords0, mGeomIndex, mGeomCount); - S32 int_part = 0 ; - switch(mTexture->getAddressMode()) + if (texgen != LLTextureEntry::TEX_GEN_PLANAR) { - case LLTexUnit::TAM_CLAMP: - if(tc.mV[0] < 0.f) + LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_QUICK); + if (!do_tex_mat) { - tc.mV[0] = 0.f ; + if (!do_xform) + { + LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_QUICK_NO_XFORM); + S32 tc_size = (num_vertices*2*sizeof(F32)+0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*) tex_coords0.get(), (F32*) vf.mTexCoords, tc_size); + } + else + { + LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_QUICK_XFORM); + F32* dst = (F32*) tex_coords0.get(); + LLVector4a* src = (LLVector4a*) vf.mTexCoords; + + LLVector4a trans; + trans.splat(-0.5f); + + LLVector4a rot0; + rot0.set(cos_ang, -sin_ang, cos_ang, -sin_ang); + + LLVector4a rot1; + rot1.set(sin_ang, cos_ang, sin_ang, cos_ang); + + LLVector4a scale; + scale.set(ms, mt, ms, mt); + + LLVector4a offset; + offset.set(os+0.5f, ot+0.5f, os+0.5f, ot+0.5f); + + LLVector4Logical mask; + mask.clear(); + mask.setElement<2>(); + mask.setElement<3>(); + + U32 count = num_vertices/2 + num_vertices%2; + + for (S32 i = 0; i < count; i++) + { + LLVector4a res = *src++; + xform4a(res, trans, mask, rot0, rot1, offset, scale); + res.store4a(dst); + dst += 4; + } + } } - else if(tc.mV[0] > 1.f) - { - tc.mV[0] = 1.f; + else + { //do tex mat, no texgen, no bump + for (S32 i = 0; i < num_vertices; i++) + { + LLVector2 tc(vf.mTexCoords[i]); + //LLVector4a& norm = vf.mNormals[i]; + //LLVector4a& center = *(vf.mCenter); + + LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); + tmp = tmp * *mTextureMatrix; + tc.mV[0] = tmp.mV[0]; + tc.mV[1] = tmp.mV[1]; + *tex_coords0++ = tc; + } } - - if(tc.mV[1] < 0.f) - { - tc.mV[1] = 0.f ; - } - else if(tc.mV[1] > 1.f) + } + else + { //no bump, tex gen planar + LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_QUICK_PLANAR); + if (do_tex_mat) { - tc.mV[1] = 1.f; + for (S32 i = 0; i < num_vertices; i++) + { + LLVector2 tc(vf.mTexCoords[i]); + LLVector4a& norm = vf.mNormals[i]; + LLVector4a& center = *(vf.mCenter); + LLVector4a vec = vf.mPositions[i]; + vec.mul(scalea); + planarProjection(tc, norm, center, vec); + + LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); + tmp = tmp * *mTextureMatrix; + tc.mV[0] = tmp.mV[0]; + tc.mV[1] = tmp.mV[1]; + + *tex_coords0++ = tc; + } } - break; - case LLTexUnit::TAM_MIRROR: - if(tc.mV[0] < 0.f) + else { - tc.mV[0] = -tc.mV[0] ; + for (S32 i = 0; i < num_vertices; i++) + { + LLVector2 tc(vf.mTexCoords[i]); + LLVector4a& norm = vf.mNormals[i]; + LLVector4a& center = *(vf.mCenter); + LLVector4a vec = vf.mPositions[i]; + vec.mul(scalea); + planarProjection(tc, norm, center, vec); + + xform(tc, cos_ang, sin_ang, os, ot, ms, mt); + + *tex_coords0++ = tc; + } } - int_part = (S32)tc.mV[0] ; - if(int_part & 1) //odd number + } + + if (map_range) + { + mVertexBuffer->flush(); + } + } + else + { //bump mapped or has material, just do the whole expensive loop + LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_DEFAULT); + + std::vector<LLVector2> bump_tc; + + if (mat && !mat->getNormalID().isNull()) + { //writing out normal and specular texture coordinates, not bump offsets + do_bump = false; + } + + LLStrider<LLVector2> dst; + + for (U32 ch = 0; ch < 3; ++ch) + { + switch (ch) { - tc.mV[0] = int_part + 1 - tc.mV[0] ; + case 0: + mVertexBuffer->getTexCoord0Strider(dst, mGeomIndex, mGeomCount, map_range); + break; + case 1: + if (mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1)) + { + mVertexBuffer->getTexCoord1Strider(dst, mGeomIndex, mGeomCount, map_range); + if (mat && !tex_anim) + { + r = mat->getNormalRotation(); + mat->getNormalOffset(os, ot); + mat->getNormalRepeat(ms, mt); + + cos_ang = cos(r); + sin_ang = sin(r); + + } + } + else + { + continue; + } + break; + case 2: + if (mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD2)) + { + mVertexBuffer->getTexCoord2Strider(dst, mGeomIndex, mGeomCount, map_range); + if (mat && !tex_anim) + { + r = mat->getSpecularRotation(); + mat->getSpecularOffset(os, ot); + mat->getSpecularRepeat(ms, mt); + + cos_ang = cos(r); + sin_ang = sin(r); + } + } + else + { + continue; + } + break; } - else //even number + + + for (S32 i = 0; i < num_vertices; i++) + { + LLVector2 tc(vf.mTexCoords[i]); + + LLVector4a& norm = vf.mNormals[i]; + + LLVector4a& center = *(vf.mCenter); + + if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) { - tc.mV[0] -= int_part ; + LLVector4a vec = vf.mPositions[i]; + + vec.mul(scalea); + + if (texgen == LLTextureEntry::TEX_GEN_PLANAR) + { + planarProjection(tc, norm, center, vec); + } } - if(tc.mV[1] < 0.f) + if (tex_mode && mTextureMatrix) { - tc.mV[1] = -tc.mV[1] ; + LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); + tmp = tmp * *mTextureMatrix; + tc.mV[0] = tmp.mV[0]; + tc.mV[1] = tmp.mV[1]; } - int_part = (S32)tc.mV[1] ; - if(int_part & 1) //odd number + else { - tc.mV[1] = int_part + 1 - tc.mV[1] ; + xform(tc, cos_ang, sin_ang, os, ot, ms, mt); } - else //even number + + *dst++ = tc; + if (do_bump) { - tc.mV[1] -= int_part ; + bump_tc.push_back(tc); } - break; - case LLTexUnit::TAM_WRAP: - if(tc.mV[0] > 1.f) - tc.mV[0] -= (S32)(tc.mV[0] - 0.00001f) ; - else if(tc.mV[0] < -1.f) - tc.mV[0] -= (S32)(tc.mV[0] + 0.00001f) ; - - if(tc.mV[1] > 1.f) - tc.mV[1] -= (S32)(tc.mV[1] - 0.00001f) ; - else if(tc.mV[1] < -1.f) - tc.mV[1] -= (S32)(tc.mV[1] + 0.00001f) ; - - if(tc.mV[0] < 0.f) + } + } + + if (map_range) + { + mVertexBuffer->flush(); + } + + if (!mat && do_bump) + { + mVertexBuffer->getTexCoord1Strider(tex_coords1, mGeomIndex, mGeomCount, map_range); + + for (S32 i = 0; i < num_vertices; i++) { - tc.mV[0] = 1.0f + tc.mV[0] ; + LLVector4a tangent = vf.mTangents[i]; + + LLVector4a binorm; + binorm.setCross3(vf.mNormals[i], tangent); + binorm.mul(tangent.getF32ptr()[3]); + + LLMatrix4a tangent_to_object; + tangent_to_object.setRows(tangent, binorm, vf.mNormals[i]); + LLVector4a t; + tangent_to_object.rotate(binormal_dir, t); + LLVector4a binormal; + mat_normal.rotate(t, binormal); + + //VECTORIZE THIS + if (mDrawablep->isActive()) + { + LLVector3 t; + t.set(binormal.getF32ptr()); + t *= bump_quat; + binormal.load3(t.mV); + } + + binormal.normalize3fast(); + + LLVector2 tc = bump_tc[i]; + tc += LLVector2( bump_s_primary_light_ray.dot3(tangent).getF32(), bump_t_primary_light_ray.dot3(binormal).getF32() ); + + *tex_coords1++ = tc; } - if(tc.mV[1] < 0.f) + + if (map_range) { - tc.mV[1] = 1.0f + tc.mV[1] ; + mVertexBuffer->flush(); } - break; - default: - break; } - - tc.mV[0] = tcoord_xoffset + tcoord_xscale * tc.mV[0] ; - tc.mV[1] = tcoord_yoffset + tcoord_yscale * tc.mV[1] ; } + } + + if (rebuild_pos) + { + LLVector4a* src = vf.mPositions; + //_mm_prefetch((char*)src, _MM_HINT_T0); + + LLVector4a* end = src+num_vertices; + //LLVector4a* end_64 = end-4; - *tex_coords++ = tc; + //LL_RECORD_TIME_BLOCK(FTM_FACE_GEOM_POSITION); + llassert(num_vertices > 0); - if (bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1)) - { - LLVector3 tangent = vf.mVertices[i].mBinormal % vf.mVertices[i].mNormal; + mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, map_range); + + LLMatrix4a mat_vert; + mat_vert.loadu(mat_vert_in); - LLMatrix3 tangent_to_object; - tangent_to_object.setRows(tangent, vf.mVertices[i].mBinormal, vf.mVertices[i].mNormal); - LLVector3 binormal = binormal_dir * tangent_to_object; - binormal = binormal * mat_normal; + F32* dst = (F32*) vert.get(); + F32* end_f32 = dst+mGeomCount*4; + + //_mm_prefetch((char*)dst, _MM_HINT_NTA); + //_mm_prefetch((char*)src, _MM_HINT_NTA); - if (mDrawablep->isActive()) + //_mm_prefetch((char*)dst, _MM_HINT_NTA); + + + LLVector4a res0; //,res1,res2,res3; + + LLVector4a texIdx; + + S32 index = mTextureIndex < 255 ? mTextureIndex : 0; + + F32 val = 0.f; + S32* vp = (S32*) &val; + *vp = index; + + llassert(index <= LLGLSLShader::sIndexedTextureChannels-1); + + LLVector4Logical mask; + mask.clear(); + mask.setElement<3>(); + + texIdx.set(0,0,0,val); + + LLVector4a tmp; + + { + //LL_RECORD_TIME_BLOCK(FTM_FACE_POSITION_STORE); + + /*if (num_vertices > 4) + { //more than 64 bytes + while (src < end_64) + { + _mm_prefetch((char*)src + 64, _MM_HINT_T0); + _mm_prefetch((char*)dst + 64, _MM_HINT_T0); + + mat_vert.affineTransform(*src, res0); + tmp.setSelectWithMask(mask, texIdx, res0); + tmp.store4a((F32*) dst); + + mat_vert.affineTransform(*(src+1), res1); + tmp.setSelectWithMask(mask, texIdx, res1); + tmp.store4a((F32*) dst+4); + + mat_vert.affineTransform(*(src+2), res2); + tmp.setSelectWithMask(mask, texIdx, res2); + tmp.store4a((F32*) dst+8); + + mat_vert.affineTransform(*(src+3), res3); + tmp.setSelectWithMask(mask, texIdx, res3); + tmp.store4a((F32*) dst+12); + + dst += 16; + src += 4; + } + }*/ + + while (src < end) + { + mat_vert.affineTransform(*src++, res0); + tmp.setSelectWithMask(mask, texIdx, res0); + tmp.store4a((F32*) dst); + dst += 4; + } + } + + { + //LL_RECORD_TIME_BLOCK(FTM_FACE_POSITION_PAD); + while (dst < end_f32) { - binormal *= bump_quat; + res0.store4a((F32*) dst); + dst += 4; } + } - binormal.normVec(); - tc += LLVector2( bump_s_primary_light_ray * tangent, bump_t_primary_light_ray * binormal ); - - *tex_coords2++ = tc; - } - } - - if (rebuild_pos) - { - *vertices++ = vf.mVertices[i].mPosition * mat_vert; + if (map_range) + { + mVertexBuffer->flush(); + } } + if (rebuild_normal) { - LLVector3 normal = vf.mVertices[i].mNormal * mat_normal; - normal.normVec(); + //LL_RECORD_TIME_BLOCK(FTM_FACE_GEOM_NORMAL); + mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range); + F32* normals = (F32*) norm.get(); + LLVector4a* src = vf.mNormals; + LLVector4a* end = src+num_vertices; - *normals++ = normal; + while (src < end) + { + LLVector4a normal; + mat_normal.rotate(*src++, normal); + normal.store4a(normals); + normals += 4; + } + + if (map_range) + { + mVertexBuffer->flush(); + } } - if (rebuild_binormal) + if (rebuild_tangent) { - LLVector3 binormal = vf.mVertices[i].mBinormal * mat_normal; - binormal.normVec(); - *binormals++ = binormal; + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_TANGENT); + mVertexBuffer->getTangentStrider(tangent, mGeomIndex, mGeomCount, map_range); + F32* tangents = (F32*) tangent.get(); + + mVObjp->getVolume()->genTangents(f); + + LLVector4Logical mask; + mask.clear(); + mask.setElement<3>(); + + LLVector4a* src = vf.mTangents; + LLVector4a* end = vf.mTangents+num_vertices; + + while (src < end) + { + LLVector4a tangent_out; + mat_normal.rotate(*src, tangent_out); + tangent_out.normalize3fast(); + tangent_out.setSelectWithMask(mask, *src, tangent_out); + tangent_out.store4a(tangents); + + src++; + tangents += 4; + } + + if (map_range) + { + mVertexBuffer->flush(); + } } + + if (rebuild_weights && vf.mWeights) + { + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_WEIGHTS); + mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, map_range); + F32* weights = (F32*) wght.get(); + LLVector4a::memcpyNonAliased16(weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32)); + if (map_range) + { + mVertexBuffer->flush(); + } + } + + if (rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_COLOR) ) + { + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_COLOR); + mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount, map_range); + + LLVector4a src; + + U32 vec[4]; + vec[0] = vec[1] = vec[2] = vec[3] = color.mAll; - if (rebuild_color) + src.loadua((F32*) vec); + + F32* dst = (F32*) colors.get(); + S32 num_vecs = num_vertices/4; + if (num_vertices%4 > 0) + { + ++num_vecs; + } + + for (S32 i = 0; i < num_vecs; i++) + { + src.store4a(dst); + dst += 4; + } + + if (map_range) + { + mVertexBuffer->flush(); + } + } + + if (rebuild_emissive) { - *colors++ = color; + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_EMISSIVE); + LLStrider<LLColor4U> emissive; + mVertexBuffer->getEmissiveStrider(emissive, mGeomIndex, mGeomCount, map_range); + + U8 glow = (U8) llclamp((S32) (getTextureEntry()->getGlow()*255), 0, 255); + + LLVector4a src; + + + LLColor4U glow4u = LLColor4U(0,0,0,glow); + + U32 glow32 = glow4u.mAll; + + U32 vec[4]; + vec[0] = vec[1] = vec[2] = vec[3] = glow32; + + src.loadua((F32*) vec); + + F32* dst = (F32*) emissive.get(); + S32 num_vecs = num_vertices/4; + if (num_vertices%4 > 0) + { + ++num_vecs; + } + + for (S32 i = 0; i < num_vecs; i++) + { + src.store4a(dst); + dst += 4; + } + + if (map_range) + { + mVertexBuffer->flush(); + } } } @@ -1341,11 +2210,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, mTexExtents[1][1] *= et ; } - mLastVertexBuffer = mVertexBuffer; - mLastGeomCount = mGeomCount; - mLastGeomIndex = mGeomIndex; - mLastIndicesCount = mIndicesCount; - mLastIndicesIndex = mIndicesIndex; return TRUE; } @@ -1357,9 +2221,9 @@ BOOL LLFace::hasMedia() const { return TRUE ; } - if(mTexture.notNull()) + if(mTexture[LLRender::DIFFUSE_MAP].notNull()) { - return mTexture->hasParcelMedia() ; //if has a parcel media + return mTexture[LLRender::DIFFUSE_MAP]->hasParcelMedia() ; //if has a parcel media } return FALSE ; //no media. @@ -1368,6 +2232,12 @@ BOOL LLFace::hasMedia() const const F32 LEAST_IMPORTANCE = 0.05f ; const F32 LEAST_IMPORTANCE_FOR_LARGE_IMAGE = 0.3f ; +void LLFace::resetVirtualSize() +{ + setVirtualSize(0.f); + mImportanceToCamera = 0.f; +} + F32 LLFace::getTextureVirtualSize() { F32 radius; @@ -1405,7 +2275,7 @@ F32 LLFace::getTextureVirtualSize() face_area = LLFace::adjustPixelArea(mImportanceToCamera, face_area) ; if(face_area > LLViewerTexture::sMinLargeImageSize) //if is large image, shrink face_area by considering the partial overlapping. { - if(mImportanceToCamera > LEAST_IMPORTANCE_FOR_LARGE_IMAGE && mTexture.notNull() && mTexture->isLargeImage()) + if(mImportanceToCamera > LEAST_IMPORTANCE_FOR_LARGE_IMAGE && mTexture[LLRender::DIFFUSE_MAP].notNull() && mTexture[LLRender::DIFFUSE_MAP]->isLargeImage()) { face_area *= adjustPartialOverlapPixelArea(cos_angle_to_view_dir, radius ); } @@ -1418,20 +2288,41 @@ F32 LLFace::getTextureVirtualSize() BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) { + //VECTORIZE THIS //get area of circle around face - LLVector3 center = getPositionAgent(); - LLVector3 size = (mExtents[1] - mExtents[0]) * 0.5f; + LLVector4a center; + center.load3(getPositionAgent().mV); + LLVector4a size; + size.setSub(mExtents[1], mExtents[0]); + size.mul(0.5f); + LLViewerCamera* camera = LLViewerCamera::getInstance(); - F32 size_squared = size.lengthSquared() ; - LLVector3 lookAt = center - camera->getOrigin(); - F32 dist = lookAt.normVec() ; + F32 size_squared = size.dot3(size).getF32(); + LLVector4a lookAt; + LLVector4a t; + t.load3(camera->getOrigin().mV); + lookAt.setSub(center, t); + + F32 dist = lookAt.getLength3().getF32(); + dist = llmax(dist-size.getLength3().getF32(), 0.001f); + //ramp down distance for nearby objects + if (dist < 16.f) + { + dist /= 16.f; + dist *= dist; + dist *= 16.f; + } + + lookAt.normalize3fast() ; //get area of circle around node - F32 app_angle = atanf(fsqrtf(size_squared) / dist); + F32 app_angle = atanf((F32) sqrt(size_squared) / dist); radius = app_angle*LLDrawable::sCurPixelAngle; mPixelArea = radius*radius * 3.14159f; - cos_angle_to_view_dir = lookAt * camera->getXAxis() ; + LLVector4a x_axis; + x_axis.load3(camera->getXAxis().mV); + cos_angle_to_view_dir = lookAt.dot3(x_axis).getF32(); //if has media, check if the face is out of the view frustum. if(hasMedia()) @@ -1447,7 +2338,10 @@ BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) } else { - if(dist * dist * (lookAt - camera->getXAxis()).lengthSquared() < size_squared) + LLVector4a d; + d.setSub(lookAt, x_axis); + + if(dist * dist * d.dot3(d) < size_squared) { cos_angle_to_view_dir = 1.0f ; } @@ -1520,8 +2414,6 @@ F32 LLFace::calcImportanceToCamera(F32 cos_angle_to_view_dir, F32 dist) return 0.f ; } - //F32 camera_relative_speed = camera_moving_speed * (lookAt * LLViewerCamera::getInstance()->getVelocityDir()) ; - S32 i = 0 ; for(i = 0; i < FACE_IMPORTANCE_LEVEL && dist > FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[i][0]; ++i); i = llmin(i, FACE_IMPORTANCE_LEVEL - 1) ; @@ -1562,16 +2454,7 @@ BOOL LLFace::verify(const U32* indices_array) const BOOL ok = TRUE; if( mVertexBuffer.isNull() ) - { - if( mGeomCount ) - { - // This happens before teleports as faces are torn down. - // Stop the crash in DEV-31893 with a null pointer check, - // but present this info. - // To clean up the log, the geometry could be cleared, or the - // face could otherwise be marked for no ::verify. - llinfos << "Face with no vertex buffer and " << mGeomCount << " mGeomCount" << llendl; - } + { //no vertex buffer, face is implicitly valid return TRUE; } @@ -1579,7 +2462,7 @@ BOOL LLFace::verify(const U32* indices_array) const if ((mGeomIndex + mGeomCount) > mVertexBuffer->getNumVerts()) { ok = FALSE; - llinfos << "Face not within pool range!" << llendl; + LL_INFOS() << "Face references invalid vertices!" << LL_ENDL; } S32 indices_count = (S32)getIndicesCount(); @@ -1592,9 +2475,15 @@ BOOL LLFace::verify(const U32* indices_array) const if (indices_count > LL_MAX_INDICES_COUNT) { ok = FALSE; - llinfos << "Face has bogus indices count" << llendl; + LL_INFOS() << "Face has bogus indices count" << LL_ENDL; } + if (mIndicesIndex + mIndicesCount > mVertexBuffer->getNumIndices()) + { + ok = FALSE; + LL_INFOS() << "Face references invalid indices!" << LL_ENDL; + } + #if 0 S32 geom_start = getGeomStart(); S32 geom_count = mGeomCount; @@ -1606,14 +2495,14 @@ BOOL LLFace::verify(const U32* indices_array) const S32 delta = indicesp[i] - geom_start; if (0 > delta) { - llwarns << "Face index too low!" << llendl; - llinfos << "i:" << i << " Index:" << indicesp[i] << " GStart: " << geom_start << llendl; + LL_WARNS() << "Face index too low!" << LL_ENDL; + LL_INFOS() << "i:" << i << " Index:" << indicesp[i] << " GStart: " << geom_start << LL_ENDL; ok = FALSE; } else if (delta >= geom_count) { - llwarns << "Face index too high!" << llendl; - llinfos << "i:" << i << " Index:" << indicesp[i] << " GEnd: " << geom_start + geom_count << llendl; + LL_WARNS() << "Face index too high!" << LL_ENDL; + LL_INFOS() << "i:" << i << " Index:" << indicesp[i] << " GEnd: " << geom_start + geom_count << LL_ENDL; ok = FALSE; } } @@ -1651,7 +2540,7 @@ void LLFace::renderSetColor() const { const LLColor4* color = &(getRenderColor()); - glColor4fv(color->mV); + gGL.diffuseColor4fv(color->mV); } } @@ -1686,10 +2575,10 @@ S32 LLFace::renderElements(const U16 *index_array) const } else { - glPushMatrix(); - glMultMatrixf((float*)getRenderMatrix().mMatrix); + gGL.pushMatrix(); + gGL.multMatrix((float*)getRenderMatrix().mMatrix); ret = pushVertices(index_array); - glPopMatrix(); + gGL.popMatrix(); } return ret; @@ -1728,13 +2617,13 @@ S32 LLFace::getColors(LLStrider<LLColor4U> &colors) } // llassert(mGeomIndex >= 0); - mVertexBuffer->getColorStrider(colors, mGeomIndex); + mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount); return mGeomIndex; } S32 LLFace::getIndices(LLStrider<U16> &indicesp) { - mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex); + mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex, mIndicesCount); llassert(indicesp[0] != indicesp[1]); return mIndicesIndex; } @@ -1751,155 +2640,99 @@ LLVector3 LLFace::getPositionAgent() const } } -// -//atlas -// -void LLFace::removeAtlas() +LLViewerTexture* LLFace::getTexture(U32 ch) const { - setAtlasInUse(FALSE) ; - mAtlasInfop = NULL ; -} + llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); -const LLTextureAtlas* LLFace::getAtlas()const -{ - if(mAtlasInfop) - { - return mAtlasInfop->getAtlas() ; - } - return NULL ; + return mTexture[ch] ; } -const LLVector2* LLFace::getTexCoordOffset()const +void LLFace::setVertexBuffer(LLVertexBuffer* buffer) { - if(isAtlasInUse()) - { - return mAtlasInfop->getTexCoordOffset() ; - } - return NULL ; -} -const LLVector2* LLFace::getTexCoordScale() const -{ - if(isAtlasInUse()) - { - return mAtlasInfop->getTexCoordScale() ; - } - return NULL ; + mVertexBuffer = buffer; + llassert(verify()); } -BOOL LLFace::isAtlasInUse()const +void LLFace::clearVertexBuffer() { - return mUsingAtlas ; -} - -BOOL LLFace::canUseAtlas()const -{ - //no drawable or no spatial group, do not use atlas - if(!mDrawablep || !mDrawablep->getSpatialGroup()) - { - return FALSE ; - } - - //if bump face, do not use atlas - if(getTextureEntry() && getTextureEntry()->getBumpmap()) - { - return FALSE ; - } - - //if animated texture, do not use atlas - if(isState(TEXTURE_ANIM)) - { - return FALSE ; - } - - return TRUE ; + mVertexBuffer = NULL; } -void LLFace::setAtlasInUse(BOOL flag) +//static +U32 LLFace::getRiggedDataMask(U32 type) { - //no valid atlas to use. - if(flag && (!mAtlasInfop || !mAtlasInfop->isValid())) - { - flag = FALSE ; - } - - if(!flag && !mUsingAtlas) - { - return ; - } - - // - //at this stage (flag || mUsingAtlas) is always true. - // - - //rebuild the tex coords - if(mDrawablep) - { - gPipeline.markRebuild(mDrawablep, LLDrawable::REBUILD_TCOORD); - mUsingAtlas = flag ; - } - else - { - mUsingAtlas = FALSE ; - } + static const U32 rigged_data_mask[] = { + LLDrawPoolAvatar::RIGGED_MATERIAL_MASK, + LLDrawPoolAvatar::RIGGED_MATERIAL_ALPHA_VMASK, + LLDrawPoolAvatar::RIGGED_MATERIAL_ALPHA_MASK_MASK, + LLDrawPoolAvatar::RIGGED_MATERIAL_ALPHA_EMISSIVE_MASK, + LLDrawPoolAvatar::RIGGED_SPECMAP_VMASK, + LLDrawPoolAvatar::RIGGED_SPECMAP_BLEND_MASK, + LLDrawPoolAvatar::RIGGED_SPECMAP_MASK_MASK, + LLDrawPoolAvatar::RIGGED_SPECMAP_EMISSIVE_MASK, + LLDrawPoolAvatar::RIGGED_NORMMAP_VMASK, + LLDrawPoolAvatar::RIGGED_NORMMAP_BLEND_MASK, + LLDrawPoolAvatar::RIGGED_NORMMAP_MASK_MASK, + LLDrawPoolAvatar::RIGGED_NORMMAP_EMISSIVE_MASK, + LLDrawPoolAvatar::RIGGED_NORMSPEC_VMASK, + LLDrawPoolAvatar::RIGGED_NORMSPEC_BLEND_MASK, + LLDrawPoolAvatar::RIGGED_NORMSPEC_MASK_MASK, + LLDrawPoolAvatar::RIGGED_NORMSPEC_EMISSIVE_MASK, + LLDrawPoolAvatar::RIGGED_SIMPLE_MASK, + LLDrawPoolAvatar::RIGGED_FULLBRIGHT_MASK, + LLDrawPoolAvatar::RIGGED_SHINY_MASK, + LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY_MASK, + LLDrawPoolAvatar::RIGGED_GLOW_MASK, + LLDrawPoolAvatar::RIGGED_ALPHA_MASK, + LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA_MASK, + LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP_MASK, + LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE_MASK, + }; + + llassert(type < sizeof(rigged_data_mask)/sizeof(U32)); + + return rigged_data_mask[type]; } -LLTextureAtlasSlot* LLFace::getAtlasInfo() +U32 LLFace::getRiggedVertexBufferDataMask() const { - return mAtlasInfop ; -} - -void LLFace::setAtlasInfo(LLTextureAtlasSlot* atlasp) -{ - if(mAtlasInfop != atlasp) + U32 data_mask = 0; + for (U32 i = 0; i < mRiggedIndex.size(); ++i) { - if(mAtlasInfop) + if (mRiggedIndex[i] > -1) { - //llerrs << "Atlas slot changed!" << llendl ; + data_mask |= LLFace::getRiggedDataMask(i); } - mAtlasInfop = atlasp ; } + + return data_mask; } -LLViewerTexture* LLFace::getTexture() const +S32 LLFace::getRiggedIndex(U32 type) const { - if(isAtlasInUse()) + if (mRiggedIndex.empty()) { - return (LLViewerTexture*)mAtlasInfop->getAtlas() ; + return -1; } - return mTexture ; + llassert(type < mRiggedIndex.size()); + + return mRiggedIndex[type]; } -//switch to atlas or switch back to gl texture -//return TRUE if using atlas. -BOOL LLFace::switchTexture() +void LLFace::setRiggedIndex(U32 type, S32 index) { - //no valid atlas or texture - if(!mAtlasInfop || !mAtlasInfop->isValid() || !mTexture) - { - return FALSE ; - } - - if(mTexture->getTexelsInAtlas() >= (U32)mVSize || - mTexture->getTexelsInAtlas() >= mTexture->getTexelsInGLTexture()) + if (mRiggedIndex.empty()) { - //switch to use atlas - //atlas resolution is qualified, use it. - if(!mUsingAtlas) + mRiggedIndex.resize(LLDrawPoolAvatar::NUM_RIGGED_PASSES); + for (U32 i = 0; i < mRiggedIndex.size(); ++i) { - setAtlasInUse(TRUE) ; - } - } - else //if atlas not qualified. - { - //switch back to GL texture - if(mUsingAtlas && mTexture->isGLTextureCreated() && - mTexture->getDiscardLevel() < mTexture->getDiscardLevelInAtlas()) - { - setAtlasInUse(FALSE) ; + mRiggedIndex[i] = -1; } } - return mUsingAtlas ; + llassert(type < mRiggedIndex.size()); + + mRiggedIndex[type] = index; } |