summaryrefslogtreecommitdiff
path: root/indra/newview/llface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llface.cpp')
-rw-r--r--indra/newview/llface.cpp1453
1 files changed, 900 insertions, 553 deletions
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 7a0aa9244d..b6566fcbd0 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -2,31 +2,25 @@
* @file llface.cpp
* @brief LLFace class implementation
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -106,8 +100,8 @@ void planarProjection(LLVector2 &tc, const LLVector4a& normal,
LLVector4a tangent;
tangent.setCross3(binormal,normal);
- tc.mV[1] = -((tangent.dot3(vec))*2 - 0.5f);
- tc.mV[0] = 1.0f+((binormal.dot3(vec))*2 - 0.5f);
+ tc.mV[1] = -((tangent.dot3(vec).getF32())*2 - 0.5f);
+ tc.mV[0] = 1.0f+((binormal.dot3(vec).getF32())*2 - 0.5f);
}
void sphericalProjection(LLVector2 &tc, const LLVector4a& normal,
@@ -154,6 +148,7 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
{
mLastUpdateTime = gFrameTimeSeconds;
mLastMoveTime = 0.f;
+ mLastSkinTime = gFrameTimeSeconds;
mVSize = 0.f;
mPixelArea = 16.f;
mState = GLOBAL;
@@ -170,6 +165,7 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
mIndexInTex = 0;
mTexture = NULL;
mTEOffset = -1;
+ mTextureIndex = 255;
setDrawable(drawablep);
mVObjp = objp;
@@ -195,27 +191,20 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
mHasMedia = FALSE ;
}
-static LLFastTimer::DeclareTimer FTM_DESTROY_FACE("Destroy Face");
-static LLFastTimer::DeclareTimer FTM_DESTROY_TEXTURE("Texture");
-static LLFastTimer::DeclareTimer FTM_DESTROY_DRAWPOOL("Drawpool");
-static LLFastTimer::DeclareTimer FTM_DESTROY_TEXTURE_MATRIX("Texture Matrix");
-static LLFastTimer::DeclareTimer FTM_DESTROY_DRAW_INFO("Draw Info");
-static LLFastTimer::DeclareTimer FTM_DESTROY_ATLAS("Atlas");
-static LLFastTimer::DeclareTimer FTM_FACE_DEREF("Deref");
-
void LLFace::destroy()
{
- LLFastTimer t(FTM_DESTROY_FACE);
+ if (gDebugGL)
+ {
+ gPipeline.checkReferences(this);
+ }
+
if(mTexture.notNull())
{
- LLFastTimer t(FTM_DESTROY_TEXTURE);
mTexture->removeFace(this) ;
}
if (mDrawPoolp)
{
- LLFastTimer t(FTM_DESTROY_DRAWPOOL);
-
if (this->isState(LLFace::RIGGED) && mDrawPoolp->getType() == LLDrawPool::POOL_AVATAR)
{
((LLDrawPoolAvatar*) mDrawPoolp)->removeRiggedFace(this);
@@ -230,7 +219,6 @@ void LLFace::destroy()
if (mTextureMatrix)
{
- LLFastTimer t(FTM_DESTROY_TEXTURE_MATRIX);
delete mTextureMatrix;
mTextureMatrix = NULL;
@@ -245,21 +233,11 @@ void LLFace::destroy()
}
}
- {
- LLFastTimer t(FTM_DESTROY_DRAW_INFO);
- setDrawInfo(NULL);
- }
-
- {
- LLFastTimer t(FTM_DESTROY_ATLAS);
- removeAtlas();
- }
-
- {
- LLFastTimer t(FTM_FACE_DEREF);
- mDrawablep = NULL;
- mVObjp = NULL;
- }
+ setDrawInfo(NULL);
+ removeAtlas();
+
+ mDrawablep = NULL;
+ mVObjp = NULL;
}
@@ -273,6 +251,11 @@ void LLFace::setWorldMatrix(const LLMatrix4 &mat)
llerrs << "Faces on this drawable are not independently modifiable\n" << llendl;
}
+void LLFace::setPool(LLFacePool* pool)
+{
+ mDrawPoolp = pool;
+}
+
void LLFace::setPool(LLFacePool* new_pool, LLViewerTexture *texturep)
{
LLMemType mt1(LLMemType::MTYPE_DRAWABLE);
@@ -382,14 +365,7 @@ void LLFace::setSize(S32 num_vertices, S32 num_indices, bool align)
//allocate vertices in blocks of 4 for alignment
num_vertices = (num_vertices + 0x3) & ~0x3;
}
- else
- {
- if (mDrawablep->getVOVolume())
- {
- llerrs << "WTF?" << llendl;
- }
- }
-
+
if (mGeomCount != num_vertices ||
mIndicesCount != num_indices)
{
@@ -398,8 +374,48 @@ void LLFace::setSize(S32 num_vertices, S32 num_indices, bool align)
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())
+ {
+ llerrs << "Face with no texture index references indexed texture draw info." << llendl;
+ }
+ }
+ }
}
+void LLFace::setIndicesIndex(S32 idx)
+{
+ if (mIndicesIndex != idx)
+ {
+ mIndicesIndex = idx;
+ mVertexBuffer = NULL;
+ }
+}
+
//============================================================================
U16 LLFace::getGeometryAvatar(
@@ -413,11 +429,11 @@ U16 LLFace::getGeometryAvatar(
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;
@@ -430,17 +446,17 @@ U16 LLFace::getGeometry(LLStrider<LLVector3> &vertices, LLStrider<LLVector3> &no
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;
@@ -458,84 +474,6 @@ void LLFace::updateCenterAgent()
}
}
-void LLFace::renderForSelect(U32 data_mask)
-{
- if(mDrawablep.isNull() || mVertexBuffer.isNull())
- {
- return;
- }
-
- LLSpatialGroup* group = mDrawablep->getSpatialGroup();
- if (!group || group->isState(LLSpatialGroup::GEOM_DIRTY))
- {
- return;
- }
-
- if (mVObjp->mGLName)
- {
- S32 name = mVObjp->mGLName;
-
- LLColor4U color((U8)(name >> 16), (U8)(name >> 8), (U8)name);
-#if 0 // *FIX: Postponing this fix until we have texcoord pick info...
- if (mTEOffset != -1)
- {
- color.mV[VALPHA] = (U8)(getTextureEntry()->getColor().mV[VALPHA] * 255.f);
- }
-#endif
- glColor4ubv(color.mV);
-
- if (!getPool())
- {
- switch (getPoolType())
- {
- case LLDrawPool::POOL_ALPHA:
- gGL.getTexUnit(0)->bind(getTexture());
- break;
- default:
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- break;
- }
- }
-
- mVertexBuffer->setBuffer(data_mask);
-#if !LL_RELEASE_FOR_DOWNLOAD
- LLGLState::checkClientArrays("", data_mask);
-#endif
- if (mTEOffset != -1)
- {
- // mask off high 4 bits (16 total possible faces)
- color.mV[0] &= 0x0f;
- color.mV[0] |= (mTEOffset & 0x0f) << 4;
- glColor4ubv(color.mV);
- }
-
- if (mIndicesCount)
- {
- if (isState(GLOBAL))
- {
- if (mDrawablep->getVOVolume())
- {
- glPushMatrix();
- glMultMatrixf((float*) mDrawablep->getRegion()->mRenderMatrix.mMatrix);
- mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex);
- glPopMatrix();
- }
- else
- {
- mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex);
- }
- }
- else
- {
- glPushMatrix();
- glMultMatrixf((float*)getRenderMatrix().mMatrix);
- mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex);
- glPopMatrix();
- }
- }
- }
-}
-
void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
{
if (mDrawablep->getSpatialGroup() == NULL)
@@ -566,8 +504,36 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
}
glColor4fv(color.mV);
- mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
- mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex);
+
+ 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);
+ glMultMatrixf((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);
+ }
+ glDrawElements(GL_TRIANGLES, vol_face.mNumIndices, GL_UNSIGNED_SHORT, vol_face.mIndices);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ }
+ }
+ }
+ else
+ {
+ mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
+ mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex);
+ }
gGL.popMatrix();
}
@@ -652,23 +618,26 @@ void LLFace::printDebugInfo() const
llinfos << "II: " << mIndicesIndex << " Count:" << mIndicesCount << llendl;
llinfos << llendl;
- poolp->printDebugInfo();
-
- 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)
+ {
+ llinfos << "Pool reference: " << pool_references << llendl;
+ pool_references++;
+ }
}
- }
- if (pool_references != 1)
- {
- llinfos << "Incorrect number of pool references!" << llendl;
+ if (pool_references != 1)
+ {
+ llinfos << "Incorrect number of pool references!" << llendl;
+ }
}
#if 0
@@ -724,14 +693,34 @@ static void xform(LLVector2 &tex_coord, F32 cosAng, F32 sinAng, F32 offS, F32 of
}
+bool less_than_max_mag(const LLVector4a& vec)
+{
+ 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, const LLMatrix3& mat_normal, BOOL global_volume)
+ const LLMatrix4& mat_vert_in, const LLMatrix3& mat_normal_in, BOOL global_volume)
{
LLMemType mt1(LLMemType::MTYPE_DRAWABLE);
//get bounding box
- if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION))
+ if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED))
{
+ //VECTORIZE THIS
+ LLMatrix4a mat_vert;
+ mat_vert.loadu(mat_vert_in);
+
+ LLMatrix4a mat_normal;
+ mat_normal.loadu(mat_normal_in);
+
//if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME))
//{ //vertex buffer no longer valid
// mVertexBuffer = NULL;
@@ -739,82 +728,113 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
//}
//VECTORIZE THIS
- LLVector3 min,max;
+ LLVector4a min,max;
if (f >= volume.getNumVolumeFaces())
{
- min = LLVector3(-1,-1,-1);
- max = LLVector3(1,1,1);
- }
- else
- {
- const LLVolumeFace &face = volume.getVolumeFace(f);
- min.set(face.mExtents[0].getF32());
- max.set(face.mExtents[1].getF32());
+ llwarns << "Generating bounding box for invalid face index!" << llendl;
+ f = 0;
}
+ 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
- LLVector3 center = ((min + max) * 0.5f)*mat_vert;
- LLVector3 size = ((max-min) * 0.5f);
+ LLVector4a center;
+ LLVector4a t;
+ t.setAdd(min, max);
+ t.mul(0.5f);
+ mat_vert.affineTransform(t, center);
+ LLVector4a size;
+ size.setSub(max, min);
+ size.mul(0.5f);
+
+ llassert(less_than_max_mag(min));
+ llassert(less_than_max_mag(max));
+
if (!global_volume)
{
- size.scaleVec(mDrawablep->getVObj()->getScale());
+ //VECTORIZE THIS
+ LLVector4a scale;
+ scale.load3(mDrawablep->getVObj()->getScale().mV);
+ size.mul(scale);
}
- LLMatrix3 mat = mat_normal;
- LLVector3 x = mat.getFwdRow();
- LLVector3 y = mat.getLeftRow();
- LLVector3 z = mat.getUpRow();
- x.normVec();
- y.normVec();
- z.normVec();
+ mat_normal.mMatrix[0].normalize3fast();
+ mat_normal.mMatrix[1].normalize3fast();
+ mat_normal.mMatrix[2].normalize3fast();
+
+ LLVector4a v[4];
- mat.setRows(x,y,z);
+ //get 4 corners of bounding box
+ mat_normal.rotate(size,v[0]);
- LLQuaternion rotation = LLQuaternion(mat);
+ //VECTORIZE THIS
+ LLVector4a scale;
- 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);
+ scale.set(-1.f, -1.f, 1.f);
+ scale.mul(size);
+ mat_normal.rotate(scale, v[1]);
+
+ scale.set(1.f, -1.f, -1.f);
+ scale.mul(size);
+ mat_normal.rotate(scale, v[2]);
+
+ scale.set(-1.f, 1.f, -1.f);
+ scale.mul(size);
+ mat_normal.rotate(scale, v[3]);
- LLVector3& newMin = mExtents[0];
- LLVector3& newMax = mExtents[1];
+ LLVector4a& newMin = mExtents[0];
+ LLVector4a& newMax = mExtents[1];
newMin = newMax = center;
+ llassert(less_than_max_mag(center));
+
for (U32 i = 0; i < 4; 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;
- }
- }
+ LLVector4a delta;
+ delta.setAbs(v[i]);
+ LLVector4a min;
+ min.setSub(center, delta);
+ LLVector4a max;
+ max.setAdd(center, delta);
+
+ newMin.setMin(newMin,min);
+ newMax.setMax(newMax,max);
+
+ llassert(less_than_max_mag(newMin));
+ llassert(less_than_max_mag(newMax));
}
if (!mDrawablep->isActive())
{
- LLVector3 offset = mDrawablep->getRegion()->getOriginAgent();
- newMin += offset;
- newMax += offset;
+ LLVector4a offset;
+ offset.load3(mDrawablep->getRegion()->getOriginAgent().mV);
+ newMin.add(offset);
+ newMax.add(offset);
+
+ llassert(less_than_max_mag(newMin));
+ llassert(less_than_max_mag(newMax));
}
- mCenterLocal = (newMin+newMax)*0.5f;
- LLVector3 tmp = (newMin - newMax) ;
- mBoundingSphereRadius = tmp.length() * 0.5f ;
+ t.setAdd(newMin, newMax);
+ t.mul(0.5f);
+
+ llassert(less_than_max_mag(t));
+
+ //VECTORIZE THIS
+ mCenterLocal.set(t.getF32ptr());
+
+ llassert(less_than_max_mag(newMin));
+ llassert(less_than_max_mag(newMax));
+
+ t.setSub(newMax,newMin);
+ mBoundingSphereRadius = t.getLength3().getF32()*0.5f;
updateCenterAgent();
}
@@ -895,6 +915,77 @@ LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, LLVector3 position,
return tc;
}
+// Returns scale compared to default texgen, and face orientation as calculated
+// by planarProjection(). This is needed to match planar texgen parameters.
+void LLFace::getPlanarProjectedParams(LLQuaternion* face_rot, LLVector3* face_pos, F32* scale) const
+{
+ const LLMatrix4& vol_mat = getWorldMatrix();
+ const LLVolumeFace& vf = getViewerObject()->getVolume()->getVolumeFace(mTEOffset);
+ const LLVector4a& normal4a = vf.mNormals[0];
+ const LLVector4a& binormal4a = vf.mBinormals[0];
+ LLVector2 projected_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,
+ // then find rotation from that:
+ 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();
+ *face_pos = vol_mat.getTranslation();
+}
+
+// Returns the necessary texture transform to align this face's TE to align_to's TE
+bool LLFace::calcAlignedPlanarTE(const LLFace* align_to, LLVector2* res_st_offset,
+ LLVector2* res_st_scale, F32* res_st_rot) const
+{
+ if (!align_to)
+ {
+ return false;
+ }
+ const LLTextureEntry *orig_tep = align_to->getTextureEntry();
+ if ((orig_tep->getTexGen() != LLTextureEntry::TEX_GEN_PLANAR) ||
+ (getTextureEntry()->getTexGen() != LLTextureEntry::TEX_GEN_PLANAR))
+ {
+ return false;
+ }
+
+ LLVector3 orig_pos, this_pos;
+ LLQuaternion orig_face_rot, this_face_rot;
+ F32 orig_proj_scale, this_proj_scale;
+ align_to->getPlanarProjectedParams(&orig_face_rot, &orig_pos, &orig_proj_scale);
+ getPlanarProjectedParams(&this_face_rot, &this_pos, &this_proj_scale);
+
+ // The rotation of "this face's" texture:
+ LLQuaternion orig_st_rot = LLQuaternion(orig_tep->getRotation(), LLVector3::z_axis) * orig_face_rot;
+ LLQuaternion this_st_rot = orig_st_rot * ~this_face_rot;
+ F32 x_ang, y_ang, z_ang;
+ this_st_rot.getEulerAngles(&x_ang, &y_ang, &z_ang);
+ *res_st_rot = z_ang;
+
+ // Offset and scale of "this face's" texture:
+ LLVector3 centers_dist = (this_pos - orig_pos) * ~orig_st_rot;
+ LLVector3 st_scale(orig_tep->mScaleS, orig_tep->mScaleT, 1.f);
+ st_scale *= orig_proj_scale;
+ centers_dist.scaleVec(st_scale);
+ LLVector2 orig_st_offset(orig_tep->mOffsetS, orig_tep->mOffsetT);
+
+ *res_st_offset = orig_st_offset + (LLVector2)centers_dist;
+ res_st_offset->mV[VX] -= (S32)res_st_offset->mV[VX];
+ res_st_offset->mV[VY] -= (S32)res_st_offset->mV[VY];
+
+ st_scale /= this_proj_scale;
+ *res_st_scale = (LLVector2)st_scale;
+ return true;
+}
+
void LLFace::updateRebuildFlags()
{
if (!mDrawablep->isState(LLDrawable::REBUILD_VOLUME))
@@ -933,19 +1024,29 @@ bool LLFace::canRenderAsMask()
}
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->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;
}
@@ -958,6 +1059,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
bool force_rebuild)
{
LLFastTimer t(FTM_FACE_GET_GEOM);
+ llassert(verify());
const LLVolumeFace &vf = volume.getVolumeFace(f);
S32 num_vertices = (S32)vf.mNumVertices;
S32 num_indices = (S32) vf.mNumIndices;
@@ -1021,27 +1123,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
const LLTextureEntry *tep = mVObjp->getTE(f);
const U8 bump_code = tep ? tep->getBumpmap() : 0;
- if (rebuild_pos)
- {
- mVertexBuffer->getVertexStrider(vert, mGeomIndex);
- vertices = (LLVector4a*) vert.get();
- }
- if (rebuild_normal)
- {
- mVertexBuffer->getNormalStrider(norm, mGeomIndex);
- normals = (LLVector4a*) norm.get();
- }
- if (rebuild_binormal)
- {
- mVertexBuffer->getBinormalStrider(binorm, mGeomIndex);
- binormals = (LLVector4a*) binorm.get();
- }
- if (rebuild_weights)
- {
- mVertexBuffer->getWeight4Strider(wght, mGeomIndex);
- weights = (LLVector4a*) wght.get();
- }
-
F32 tcoord_xoffset = 0.f ;
F32 tcoord_yoffset = 0.f ;
F32 tcoord_xscale = 1.f ;
@@ -1050,12 +1131,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
if (rebuild_tcoord)
{
- mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex);
- if (bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1))
- {
- mVertexBuffer->getTexCoord1Strider(tex_coords2, mGeomIndex);
- }
-
in_atlas = isAtlasInUse() ;
if(in_atlas)
{
@@ -1068,12 +1143,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
tcoord_yscale = tmp->mV[1] ;
}
}
- 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;
@@ -1089,57 +1158,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
clearState(GLOBAL);
}
- LLVector2 tmin, tmax;
-
- if (rebuild_tcoord)
- {
- if (tep)
- {
- r = tep->getRotation();
- os = tep->mOffsetS;
- ot = tep->mOffsetT;
- ms = tep->mScaleS;
- mt = tep->mScaleT;
- cos_ang = cos(r);
- sin_ang = sin(r);
- }
- else
- {
- cos_ang = 1.0f;
- sin_ang = 0.0f;
- os = 0.0f;
- ot = 0.0f;
- ms = 1.0f;
- mt = 1.0f;
- }
- }
-
- U8 tex_mode = 0;
-
- if (isState(TEXTURE_ANIM))
- {
- LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp;
- tex_mode = vobj->mTexAnimMode;
-
- 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;
- }
-
- if (getVirtualSize() >= MIN_TEX_ANIM_SIZE)
- { //don't override texture transform during tc bake
- tex_mode = 0;
- }
- }
-
LLColor4U color = tep->getColor();
if (rebuild_color)
@@ -1164,7 +1182,8 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
// INDICES
if (full_rebuild)
{
- mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex);
+ mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex, mIndicesCount, true);
+
__m128i* dst = (__m128i*) indicesp.get();
__m128i* src = (__m128i*) vf.mIndices;
__m128i offset = _mm_set1_epi16(index_offset);
@@ -1181,260 +1200,451 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
{
indicesp[i] = vf.mIndices[i]+index_offset;
}
+
+ mVertexBuffer->setBuffer(0);
}
+ LLMatrix4a mat_normal;
+ mat_normal.loadu(mat_norm_in);
- //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);
+ //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);
- LLQuaternion bump_quat;
- if (mDrawablep->isActive())
- {
- bump_quat = LLQuaternion(mDrawablep->getRenderMatrix());
- }
-
- if (bump_code)
+ F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0;
+
+ if (rebuild_tcoord)
{
- mVObjp->getVolume()->genBinormals(f);
- F32 offset_multiple;
- switch( bump_code )
+ bool do_xform;
+
+ if (tep)
{
- case BE_NO_BUMP:
- offset_multiple = 0.f;
- break;
- case BE_BRIGHTNESS:
- case BE_DARKNESS:
- if( mTexture.notNull() && mTexture->hasGLTexture())
+ r = tep->getRotation();
+ os = tep->mOffsetS;
+ ot = tep->mOffsetT;
+ ms = tep->mScaleS;
+ 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)
{
- // 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;
+ do_xform = true;
}
else
{
- offset_multiple = 1.f/256;
- }
- break;
-
- default: // Standard bumpmap textures. Assumed to be 256x256
- offset_multiple = 1.f / 256;
- break;
+ do_xform = false;
+ }
}
-
- F32 s_scale = 1.f;
- F32 t_scale = 1.f;
- if( tep )
+ else
{
- tep->getScale( &s_scale, &t_scale );
+ do_xform = false;
}
- // 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 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);
- 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);
- }
+ LLQuaternion bump_quat;
+ if (mDrawablep->isActive())
+ {
+ bump_quat = LLQuaternion(mDrawablep->getRenderMatrix());
+ }
- U8 texgen = getTextureEntry()->getTexGen();
- if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT)
- { //planar texgen needs binormals
- mVObjp->getVolume()->genBinormals(f);
- }
-
- LLMatrix4a mat_normal;
- mat_normal.loadu(mat_norm_in);
-
- //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)
- {
- LLVector4a scalea;
- scalea.load3(scale.mV);
-
+ 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;
- for (S32 i = 0; i < num_vertices; i++)
- {
- LLVector2 tc(vf.mTexCoords[i]);
-
- LLVector4a& norm = vf.mNormals[i];
-
- LLVector4a& center = *(vf.mCenter);
+ default: // Standard bumpmap textures. Assumed to be 256x256
+ offset_multiple = 1.f / 256;
+ break;
+ }
- if (texgen != LLTextureEntry::TEX_GEN_DEFAULT)
+ F32 s_scale = 1.f;
+ F32 t_scale = 1.f;
+ if( tep )
{
- LLVector4a vec = vf.mPositions[i];
-
- vec.mul(scalea);
-
- switch (texgen)
- {
- case LLTextureEntry::TEX_GEN_PLANAR:
- planarProjection(tc, norm, center, vec);
- break;
- case LLTextureEntry::TEX_GEN_SPHERICAL:
- sphericalProjection(tc, norm, center, vec);
- break;
- case LLTextureEntry::TEX_GEN_CYLINDRICAL:
- cylindricalProjection(tc, norm, center, 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);
+ }
+
+ U8 texgen = getTextureEntry()->getTexGen();
+ if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT)
+ { //planar texgen needs binormals
+ mVObjp->getVolume()->genBinormals(f);
+ }
- if (tex_mode && mTextureMatrix)
+ U8 tex_mode = 0;
+
+ if (isState(TEXTURE_ANIM))
+ {
+ LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp;
+ tex_mode = vobj->mTexAnimMode;
+
+ if (!tex_mode)
{
- 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];
+ clearState(TEXTURE_ANIM);
}
else
{
- xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
+ os = ot = 0.f;
+ r = 0.f;
+ cos_ang = 1.f;
+ sin_ang = 0.f;
+ ms = mt = 1.f;
+
+ do_xform = false;
}
- if(in_atlas)
- {
- //
- //manually calculate tex-coord per vertex for varying address modes.
- //should be removed if shader can handle this.
- //
+ if (getVirtualSize() >= MIN_TEX_ANIM_SIZE)
+ { //don't override texture transform during tc bake
+ tex_mode = 0;
+ }
+ }
- S32 int_part = 0 ;
- switch(mTexture->getAddressMode())
- {
- case LLTexUnit::TAM_CLAMP:
- if(tc.mV[0] < 0.f)
- {
- tc.mV[0] = 0.f ;
- }
- else if(tc.mV[0] > 1.f)
- {
- tc.mV[0] = 1.f;
- }
+ LLVector4a scalea;
+ scalea.load3(scale.mV);
- if(tc.mV[1] < 0.f)
- {
- tc.mV[1] = 0.f ;
- }
- else if(tc.mV[1] > 1.f)
+ bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1);
+ bool do_tex_mat = tex_mode && mTextureMatrix;
+
+ if (!in_atlas && !do_bump)
+ { //not in atlas or not bump mapped, might be able to do a cheap update
+ mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount);
+
+ if (texgen != LLTextureEntry::TEX_GEN_PLANAR)
+ {
+ if (!do_tex_mat)
+ {
+ if (!do_xform)
{
- tc.mV[1] = 1.f;
+ LLVector4a::memcpyNonAliased16((F32*) tex_coords.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32));
}
- 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]);
+ xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
+ *tex_coords++ = tc;
+ }
}
- int_part = (S32)tc.mV[0] ;
- if(int_part & 1) //odd number
- {
- tc.mV[0] = int_part + 1 - tc.mV[0] ;
+ }
+ else
+ { //do tex mat, no texgen, no atlas, 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_coords++ = tc;
}
- else //even number
- {
- tc.mV[0] -= int_part ;
+ }
+ }
+ else
+ { //no bump, no atlas, tex gen planar
+ if (do_tex_mat)
+ {
+ 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_coords++ = tc;
}
+ }
+ else
+ {
+ 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);
- if(tc.mV[1] < 0.f)
- {
- tc.mV[1] = -tc.mV[1] ;
+ *tex_coords++ = tc;
}
- int_part = (S32)tc.mV[1] ;
- if(int_part & 1) //odd number
- {
- tc.mV[1] = int_part + 1 - tc.mV[1] ;
- }
- else //even number
- {
- tc.mV[1] -= int_part ;
- }
- 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)
+ }
+ }
+
+ mVertexBuffer->setBuffer(0);
+ }
+ else
+ { //either bump mapped or in atlas, just do the whole expensive loop
+ mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount, true);
+
+ std::vector<LLVector2> bump_tc;
+
+ 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)
+ {
+ LLVector4a vec = vf.mPositions[i];
+
+ vec.mul(scalea);
+
+ switch (texgen)
{
- tc.mV[0] = 1.0f + tc.mV[0] ;
- }
- if(tc.mV[1] < 0.f)
+ case LLTextureEntry::TEX_GEN_PLANAR:
+ planarProjection(tc, norm, center, vec);
+ break;
+ case LLTextureEntry::TEX_GEN_SPHERICAL:
+ sphericalProjection(tc, norm, center, vec);
+ break;
+ case LLTextureEntry::TEX_GEN_CYLINDRICAL:
+ cylindricalProjection(tc, norm, center, vec);
+ break;
+ default:
+ break;
+ }
+ }
+
+ 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];
+ }
+ else
+ {
+ xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
+ }
+
+ if(in_atlas)
+ {
+ //
+ //manually calculate tex-coord per vertex for varying address modes.
+ //should be removed if shader can handle this.
+ //
+
+ S32 int_part = 0 ;
+ switch(mTexture->getAddressMode())
{
- tc.mV[1] = 1.0f + tc.mV[1] ;
+ case LLTexUnit::TAM_CLAMP:
+ if(tc.mV[0] < 0.f)
+ {
+ tc.mV[0] = 0.f ;
+ }
+ else if(tc.mV[0] > 1.f)
+ {
+ tc.mV[0] = 1.f;
+ }
+
+ if(tc.mV[1] < 0.f)
+ {
+ tc.mV[1] = 0.f ;
+ }
+ else if(tc.mV[1] > 1.f)
+ {
+ tc.mV[1] = 1.f;
+ }
+ break;
+ case LLTexUnit::TAM_MIRROR:
+ if(tc.mV[0] < 0.f)
+ {
+ tc.mV[0] = -tc.mV[0] ;
+ }
+ int_part = (S32)tc.mV[0] ;
+ if(int_part & 1) //odd number
+ {
+ tc.mV[0] = int_part + 1 - tc.mV[0] ;
+ }
+ else //even number
+ {
+ tc.mV[0] -= int_part ;
+ }
+
+ if(tc.mV[1] < 0.f)
+ {
+ tc.mV[1] = -tc.mV[1] ;
+ }
+ int_part = (S32)tc.mV[1] ;
+ if(int_part & 1) //odd number
+ {
+ tc.mV[1] = int_part + 1 - tc.mV[1] ;
+ }
+ else //even number
+ {
+ tc.mV[1] -= int_part ;
+ }
+ 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)
+ {
+ tc.mV[0] = 1.0f + tc.mV[0] ;
+ }
+ if(tc.mV[1] < 0.f)
+ {
+ tc.mV[1] = 1.0f + tc.mV[1] ;
+ }
+ break;
+ default:
+ break;
}
- break;
- default:
- break;
+
+ tc.mV[0] = tcoord_xoffset + tcoord_xscale * tc.mV[0] ;
+ tc.mV[1] = tcoord_yoffset + tcoord_yscale * tc.mV[1] ;
+ }
+
+
+ *tex_coords++ = tc;
+ if (do_bump)
+ {
+ bump_tc.push_back(tc);
}
-
- tc.mV[0] = tcoord_xoffset + tcoord_xscale * tc.mV[0] ;
- tc.mV[1] = tcoord_yoffset + tcoord_yscale * tc.mV[1] ;
}
-
- *tex_coords++ = tc;
-
- if (bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1))
+ mVertexBuffer->setBuffer(0);
+
+
+ if (do_bump)
{
- LLVector4a tangent;
- tangent.setCross3(vf.mBinormals[i], vf.mNormals[i]);
-
- LLMatrix4a tangent_to_object;
- tangent_to_object.setRows(tangent, vf.mBinormals[i], vf.mNormals[i]);
- LLVector4a t;
- tangent_to_object.rotate(binormal_dir, t);
- LLVector4a binormal;
- mat_normal.rotate(t, binormal);
-
- //VECTORIZE THIS
- if (mDrawablep->isActive())
+ mVertexBuffer->getTexCoord1Strider(tex_coords2, mGeomIndex, mGeomCount, true);
+
+ for (S32 i = 0; i < num_vertices; i++)
{
- LLVector3 t;
- t.set(binormal.getF32());
- t *= bump_quat;
- binormal.load3(t.mV);
+ LLVector4a tangent;
+ tangent.setCross3(vf.mBinormals[i], vf.mNormals[i]);
+
+ LLMatrix4a tangent_to_object;
+ tangent_to_object.setRows(tangent, vf.mBinormals[i], 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_coords2++ = tc;
}
- binormal.normalize3fast();
- tc += LLVector2( bump_s_primary_light_ray.dot3(tangent), bump_t_primary_light_ray.dot3(binormal) );
-
- *tex_coords2++ = tc;
- }
+ mVertexBuffer->setBuffer(0);
+ }
}
}
if (rebuild_pos)
{
+ mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, true);
+ vertices = (LLVector4a*) vert.get();
+
LLMatrix4a mat_vert;
mat_vert.loadu(mat_vert_in);
- for (S32 i = 0; i < num_vertices; i++)
+ LLVector4a* src = vf.mPositions;
+ LLVector4a* dst = vertices;
+
+ LLVector4a* end = dst+num_vertices;
+ do
{
- mat_vert.affineTransform(vf.mPositions[i], vertices[i]);
+ mat_vert.affineTransform(*src++, *dst++);
+ }
+ while(dst < end);
+
+ F32 index = (F32) (mTextureIndex < 255 ? mTextureIndex : 0);
+ F32 *index_dst = (F32*) vertices;
+ F32 *index_end = (F32*) end;
+
+ index_dst += 3;
+ index_end += 3;
+ do
+ {
+ *index_dst = index;
+ index_dst += 4;
}
+ while (index_dst < index_end);
+
+ mVertexBuffer->setBuffer(0);
}
if (rebuild_normal)
{
+ mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, true);
+ normals = (LLVector4a*) norm.get();
+
for (S32 i = 0; i < num_vertices; i++)
{
LLVector4a normal;
@@ -1442,10 +1652,15 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
normal.normalize3fast();
normals[i] = normal;
}
+
+ mVertexBuffer->setBuffer(0);
}
if (rebuild_binormal)
{
+ mVertexBuffer->getBinormalStrider(binorm, mGeomIndex, mGeomCount, true);
+ binormals = (LLVector4a*) binorm.get();
+
for (S32 i = 0; i < num_vertices; i++)
{
LLVector4a binormal;
@@ -1453,24 +1668,42 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
binormal.normalize3fast();
binormals[i] = binormal;
}
+
+ mVertexBuffer->setBuffer(0);
}
if (rebuild_weights && vf.mWeights)
{
- LLVector4a::memcpyNonAliased16((F32*) weights, (F32*) vf.mWeights, num_vertices/4);
+ mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, true);
+ weights = (LLVector4a*) wght.get();
+ LLVector4a::memcpyNonAliased16((F32*) weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32));
+ mVertexBuffer->setBuffer(0);
}
if (rebuild_color)
{
+ mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount, true);
+
LLVector4a src;
- src.splat(reinterpret_cast<F32&>(color.mAll));
+ U32 vec[4];
+ vec[0] = vec[1] = vec[2] = vec[3] = color.mAll;
+
+ src.loadua((F32*) vec);
- F32* dst = (F32*) colors.get();
- for (S32 i = 0; i < num_vertices; i+=4)
+ LLVector4a* dst = (LLVector4a*) colors.get();
+ S32 num_vecs = num_vertices/4;
+ if (num_vertices%4 > 0)
+ {
+ ++num_vecs;
+ }
+
+ for (S32 i = 0; i < num_vecs; i++)
{
- LLVector4a::copy4a(dst+i, (F32*) &src);
+ dst[i] = src;
}
+
+ mVertexBuffer->setBuffer(0);
}
if (rebuild_tcoord)
@@ -1478,7 +1711,14 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
mTexExtents[0].setVec(0,0);
mTexExtents[1].setVec(1,1);
xform(mTexExtents[0], cos_ang, sin_ang, os, ot, ms, mt);
- xform(mTexExtents[1], cos_ang, sin_ang, os, ot, ms, mt);
+ xform(mTexExtents[1], cos_ang, sin_ang, os, ot, ms, mt);
+
+ F32 es = vf.mTexCoordExtents[1].mV[0] - vf.mTexCoordExtents[0].mV[0] ;
+ F32 et = vf.mTexCoordExtents[1].mV[1] - vf.mTexCoordExtents[0].mV[1] ;
+ mTexExtents[0][0] *= es ;
+ mTexExtents[1][0] *= es ;
+ mTexExtents[0][1] *= et ;
+ mTexExtents[1][1] *= et ;
}
mLastVertexBuffer = mVertexBuffer;
@@ -1514,7 +1754,7 @@ F32 LLFace::getTextureVirtualSize()
F32 cos_angle_to_view_dir;
BOOL in_frustum = calcPixelArea(cos_angle_to_view_dir, radius);
- if (mPixelArea < 0.0001f || !in_frustum)
+ if (mPixelArea < F_ALMOST_ZERO || !in_frustum)
{
setVirtualSize(0.f) ;
return 0.f;
@@ -1529,28 +1769,26 @@ F32 LLFace::getTextureVirtualSize()
texel_area = 1.f;
}
- //apply texel area to face area to get accurate ratio
- //face_area /= llclamp(texel_area, 1.f/64.f, 16.f);
- F32 face_area = mPixelArea / llclamp(texel_area, 0.015625f, 128.f);
+ F32 face_area;
+ if (mVObjp->isSculpted() && texel_area > 1.f)
+ {
+ //sculpts can break assumptions about texel area
+ face_area = mPixelArea;
+ }
+ else
+ {
+ //apply texel area to face area to get accurate ratio
+ //face_area /= llclamp(texel_area, 1.f/64.f, 16.f);
+ face_area = mPixelArea / llclamp(texel_area, 0.015625f, 128.f);
+ }
- if(face_area > LLViewerTexture::sMaxSmallImageSize)
+ 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) //if the face is not important, do not load hi-res.
- {
- static const F32 MAX_LEAST_IMPORTANCE_IMAGE_SIZE = 128.0f * 128.0f ;
- face_area = llmin(face_area * 0.5f, MAX_LEAST_IMPORTANCE_IMAGE_SIZE) ;
- }
- else if(face_area > LLViewerTexture::sMinLargeImageSize) //if is large image, shrink face_area by considering the partial overlapping.
- {
- if(mImportanceToCamera < LEAST_IMPORTANCE_FOR_LARGE_IMAGE)//if the face is not important, do not load hi-res.
- {
- face_area = LLViewerTexture::sMinLargeImageSize ;
- }
- else if(mTexture.notNull() && mTexture->isLargeImage())
- {
- face_area *= adjustPartialOverlapPixelArea(cos_angle_to_view_dir, radius );
- }
- }
+ if(mImportanceToCamera > LEAST_IMPORTANCE_FOR_LARGE_IMAGE && mTexture.notNull() && mTexture->isLargeImage())
+ {
+ face_area *= adjustPartialOverlapPixelArea(cos_angle_to_view_dir, radius );
+ }
}
setVirtualSize(face_area) ;
@@ -1560,20 +1798,32 @@ 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.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())
@@ -1589,7 +1839,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 ;
}
@@ -1677,29 +1930,42 @@ F32 LLFace::calcImportanceToCamera(F32 cos_angle_to_view_dir, F32 dist)
return importance ;
}
+//static
+F32 LLFace::adjustPixelArea(F32 importance, F32 pixel_area)
+{
+ if(pixel_area > LLViewerTexture::sMaxSmallImageSize)
+ {
+ if(importance < LEAST_IMPORTANCE) //if the face is not important, do not load hi-res.
+ {
+ static const F32 MAX_LEAST_IMPORTANCE_IMAGE_SIZE = 128.0f * 128.0f ;
+ pixel_area = llmin(pixel_area * 0.5f, MAX_LEAST_IMPORTANCE_IMAGE_SIZE) ;
+ }
+ else if(pixel_area > LLViewerTexture::sMinLargeImageSize) //if is large image, shrink face_area by considering the partial overlapping.
+ {
+ if(importance < LEAST_IMPORTANCE_FOR_LARGE_IMAGE)//if the face is not important, do not load hi-res.
+ {
+ pixel_area = LLViewerTexture::sMinLargeImageSize ;
+ }
+ }
+ }
+
+ return pixel_area ;
+}
+
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;
}
// First, check whether the face data fits within the pool's range.
- if ((mGeomIndex + mGeomCount) > mVertexBuffer->getNumVerts())
+ if ((mGeomIndex + mGeomCount) > mVertexBuffer->getRequestedVerts())
{
ok = FALSE;
- llinfos << "Face not within pool range!" << llendl;
+ llinfos << "Face references invalid vertices!" << llendl;
}
S32 indices_count = (S32)getIndicesCount();
@@ -1715,6 +1981,12 @@ BOOL LLFace::verify(const U32* indices_array) const
llinfos << "Face has bogus indices count" << llendl;
}
+ if (mIndicesIndex + mIndicesCount > mVertexBuffer->getRequestedIndices())
+ {
+ ok = FALSE;
+ llinfos << "Face references invalid indices!" << llendl;
+ }
+
#if 0
S32 geom_start = getGeomStart();
S32 geom_count = mGeomCount;
@@ -1848,13 +2120,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;
}
@@ -2023,3 +2295,78 @@ BOOL LLFace::switchTexture()
return mUsingAtlas ;
}
+
+void LLFace::setVertexBuffer(LLVertexBuffer* buffer)
+{
+ mVertexBuffer = buffer;
+ llassert(verify());
+}
+
+void LLFace::clearVertexBuffer()
+{
+ mVertexBuffer = NULL;
+ mLastVertexBuffer = NULL;
+}
+
+//static
+U32 LLFace::getRiggedDataMask(U32 type)
+{
+ static const U32 rigged_data_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];
+}
+
+U32 LLFace::getRiggedVertexBufferDataMask() const
+{
+ U32 data_mask = 0;
+ for (U32 i = 0; i < mRiggedIndex.size(); ++i)
+ {
+ if (mRiggedIndex[i] > -1)
+ {
+ data_mask |= LLFace::getRiggedDataMask(i);
+ }
+ }
+
+ return data_mask;
+}
+
+S32 LLFace::getRiggedIndex(U32 type) const
+{
+ if (mRiggedIndex.empty())
+ {
+ return -1;
+ }
+
+ llassert(type < mRiggedIndex.size());
+
+ return mRiggedIndex[type];
+}
+
+void LLFace::setRiggedIndex(U32 type, S32 index)
+{
+ if (mRiggedIndex.empty())
+ {
+ mRiggedIndex.resize(LLDrawPoolAvatar::NUM_RIGGED_PASSES);
+ for (U32 i = 0; i < mRiggedIndex.size(); ++i)
+ {
+ mRiggedIndex[i] = -1;
+ }
+ }
+
+ llassert(type < mRiggedIndex.size());
+
+ mRiggedIndex[type] = index;
+}
+