summaryrefslogtreecommitdiff
path: root/indra/newview/llvovolume.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llvovolume.cpp')
-rw-r--r--indra/newview/llvovolume.cpp1206
1 files changed, 941 insertions, 265 deletions
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index a9f3abeef8..c5e2c56e4b 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -2,31 +2,25 @@
* @file llvovolume.cpp
* @brief LLVOVolume 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$
*/
@@ -41,9 +35,11 @@
#include "llviewercontrol.h"
#include "lldir.h"
#include "llflexibleobject.h"
+#include "llfloatertools.h"
#include "llmaterialtable.h"
#include "llprimitive.h"
#include "llvolume.h"
+#include "llvolumeoctree.h"
#include "llvolumemgr.h"
#include "llvolumemessage.h"
#include "material_codes.h"
@@ -70,13 +66,16 @@
#include "llselectmgr.h"
#include "pipeline.h"
#include "llsdutil.h"
+#include "llmatrix4a.h"
#include "llmediaentry.h"
#include "llmediadataclient.h"
#include "llmeshrepository.h"
#include "llagent.h"
#include "llviewermediafocus.h"
+#include "lldatapacker.h"
+#include "llviewershadermgr.h"
#include "llvoavatar.h"
-
+#include "llvocache.h"
const S32 MIN_QUIET_FRAMES_COALESCE = 30;
const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
@@ -96,19 +95,20 @@ LLPointer<LLObjectMediaNavigateClient> LLVOVolume::sObjectMediaNavigateClient =
static LLFastTimer::DeclareTimer FTM_GEN_TRIANGLES("Generate Triangles");
static LLFastTimer::DeclareTimer FTM_GEN_VOLUME("Generate Volumes");
-static LLFastTimer::DeclareTimer FTM_BUILD_MESH("Mesh");
-static LLFastTimer::DeclareTimer FTM_MESH_VFS("VFS");
-static LLFastTimer::DeclareTimer FTM_MESH_STREAM("Stream");
-static LLFastTimer::DeclareTimer FTM_MESH_FACES("Faces");
static LLFastTimer::DeclareTimer FTM_VOLUME_TEXTURES("Volume Textures");
-
// Implementation class of LLMediaDataClientObject. See llmediadataclient.h
class LLMediaDataClientObjectImpl : public LLMediaDataClientObject
{
public:
- LLMediaDataClientObjectImpl(LLVOVolume *obj, bool isNew) : mObject(obj), mNew(isNew) {}
- LLMediaDataClientObjectImpl() { mObject = NULL; }
+ LLMediaDataClientObjectImpl(LLVOVolume *obj, bool isNew) : mObject(obj), mNew(isNew)
+ {
+ mObject->addMDCImpl();
+ }
+ ~LLMediaDataClientObjectImpl()
+ {
+ mObject->removeMDCImpl();
+ }
virtual U8 getMediaDataCount() const
{ return mObject->getNumTEs(); }
@@ -133,6 +133,18 @@ public:
}
return result;
}
+ virtual bool isCurrentMediaUrl(U8 index, const std::string &url) const
+ {
+ LLTextureEntry *te = mObject->getTE(index);
+ if (te)
+ {
+ if (te->getMediaData())
+ {
+ return (te->getMediaData()->getCurrentURL() == url);
+ }
+ }
+ return url.empty();
+ }
virtual LLUUID getID() const
{ return mObject->getID(); }
@@ -207,6 +219,7 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
mMediaImplList.resize(getNumTEs());
mLastFetchedMediaVersion = -1;
mIndexInTex = 0;
+ mMDCImplCount = 0;
}
LLVOVolume::~LLVOVolume()
@@ -232,9 +245,12 @@ void LLVOVolume::markDead()
{
if (!mDead)
{
- LLMediaDataClientObject::ptr_t obj = new LLMediaDataClientObjectImpl(const_cast<LLVOVolume*>(this), false);
- if (sObjectMediaClient) sObjectMediaClient->removeFromQueue(obj);
- if (sObjectMediaNavigateClient) sObjectMediaNavigateClient->removeFromQueue(obj);
+ if(getMDCImplCount() > 0)
+ {
+ LLMediaDataClientObject::ptr_t obj = new LLMediaDataClientObjectImpl(const_cast<LLVOVolume*>(this), false);
+ if (sObjectMediaClient) sObjectMediaClient->removeFromQueue(obj);
+ if (sObjectMediaNavigateClient) sObjectMediaNavigateClient->removeFromQueue(obj);
+ }
// Detach all media impls from this object
for(U32 i = 0 ; i < mMediaImplList.size() ; i++)
@@ -386,10 +402,12 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
// There's something bogus in the data that we're unpacking.
dp->dumpBufferToLog();
llwarns << "Flushing cache files" << llendl;
- std::string mask;
- mask = gDirUtilp->getDirDelimiter() + "*.slc";
- gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""), mask);
-// llerrs << "Bogus TE data in " << getID() << ", crashing!" << llendl;
+
+ if(LLVOCache::hasInstance() && getRegion())
+ {
+ LLVOCache::getInstance()->removeEntry(getRegion()->getHandle()) ;
+ }
+
llwarns << "Bogus TE data in " << getID() << llendl;
}
else
@@ -665,12 +683,33 @@ void LLVOVolume::updateTextures()
}
}
+BOOL LLVOVolume::isVisible() const
+{
+ if(mDrawable.notNull() && mDrawable->isVisible())
+ {
+ return TRUE ;
+ }
+
+ if(isAttachment())
+ {
+ LLViewerObject* objp = (LLViewerObject*)getParent() ;
+ while(objp && !objp->isAvatar())
+ {
+ objp = (LLViewerObject*)objp->getParent() ;
+ }
+
+ return objp && objp->mDrawable.notNull() && objp->mDrawable->isVisible() ;
+ }
+
+ return FALSE ;
+}
+
void LLVOVolume::updateTextureVirtualSize()
{
LLFastTimer ftm(FTM_VOLUME_TEXTURES);
// Update the pixel area of all faces
- if(mDrawable.isNull() || !mDrawable->isVisible())
+ if(!isVisible())
{
return ;
}
@@ -701,7 +740,7 @@ void LLVOVolume::updateTextureVirtualSize()
const LLTextureEntry *te = face->getTextureEntry();
LLViewerTexture *imagep = face->getTexture();
if (!imagep || !te ||
- face->mExtents[0] == face->mExtents[1])
+ face->mExtents[0].equals3(face->mExtents[1]))
{
continue;
}
@@ -825,15 +864,15 @@ void LLVOVolume::updateTextureVirtualSize()
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
{
- setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
+ setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize)));
}
else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
{
- setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
+ setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize)));
}
else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA))
{
- setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
+ setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize)));
}
if (mPixelArea == 0)
@@ -844,7 +883,8 @@ void LLVOVolume::updateTextureVirtualSize()
BOOL LLVOVolume::isActive() const
{
- return !mStatic || mTextureAnimp || (mVolumeImpl && mVolumeImpl->isActive());
+ return !mStatic || mTextureAnimp || (mVolumeImpl && mVolumeImpl->isActive()) ||
+ (mDrawable.notNull() && mDrawable->isActive());
}
BOOL LLVOVolume::setMaterial(const U8 material)
@@ -918,10 +958,11 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
return mDrawable;
}
-BOOL LLVOVolume::setVolume(const LLVolumeParams &params, const S32 detail, bool unique_volume)
+BOOL LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bool unique_volume)
{
- LLVolumeParams volume_params = params;
+ LLVolumeParams volume_params = params_in;
+ S32 last_lod = mVolumep.notNull() ? LLVolumeLODGroup::getVolumeDetailFromScale(mVolumep->getDetail()) : -1;
S32 lod = mLOD;
BOOL is404 = FALSE;
@@ -932,7 +973,7 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &params, const S32 detail, bool
if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
{ //meshes might not have all LODs, get the force detail to best existing LOD
- LLUUID mesh_id = params.getSculptID();
+ LLUUID mesh_id = volume_params.getSculptID();
//profile and path params don't matter for meshes
volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
@@ -989,10 +1030,10 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &params, const S32 detail, bool
updateSculptTexture();
+
if (isSculpted())
{
updateSculptTexture();
-
// if it's a mesh
if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
{
@@ -1000,12 +1041,13 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &params, const S32 detail, bool
{
//load request not yet issued, request pipeline load this mesh
LLUUID asset_id = volume_params.getSculptID();
- S32 available_lod = gMeshRepo.loadMesh(this, volume_params, lod);
+ S32 available_lod = gMeshRepo.loadMesh(this, volume_params, lod, last_lod);
if (available_lod != lod)
{
LLPrimitive::setVolume(volume_params, available_lod);
}
}
+
}
else // otherwise is sculptie
{
@@ -1018,6 +1060,7 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &params, const S32 detail, bool
return TRUE;
}
+
return FALSE;
}
@@ -1053,13 +1096,10 @@ void LLVOVolume::updateSculptTexture()
}
-
-
void LLVOVolume::notifyMeshLoaded()
{
mSculptChanged = TRUE;
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
- dirtySpatialGroup(TRUE);
}
// sculpt replaces generate() for sculpted surfaces
@@ -1165,10 +1205,26 @@ BOOL LLVOVolume::calcLOD()
S32 cur_detail = 0;
- F32 radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length();
- F32 distance = mDrawable->mDistanceWRTCamera; //llmin(mDrawable->mDistanceWRTCamera, MAX_LOD_DISTANCE);
+ F32 radius;
+ F32 distance;
+
+ if (mDrawable->isState(LLDrawable::RIGGED))
+ {
+ LLVOAvatar* avatar = getAvatar();
+ distance = avatar->mDrawable->mDistanceWRTCamera;
+ radius = avatar->getBinRadius();
+ }
+ else
+ {
+ distance = mDrawable->mDistanceWRTCamera;
+ radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length();
+ }
+
+ //hold onto unmodified distance for debugging
+ //F32 debug_distance = distance;
+
distance *= sDistanceFactor;
-
+
F32 rampDist = LLVOVolume::sLODFactor * 2;
if (distance < rampDist)
@@ -1185,6 +1241,14 @@ BOOL LLVOVolume::calcLOD()
cur_detail = computeLODDetail(llround(distance, 0.01f),
llround(radius, 0.01f));
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO))
+ {
+ //setDebugText(llformat("%.2f:%.2f, %d", debug_distance, radius, cur_detail));
+
+ setDebugText(llformat("%d", mDrawable->getFace(0)->getTextureIndex()));
+ }
+
if (cur_detail != mLOD)
{
mAppAngle = llround((F32) atan2( mDrawable->getRadius(), mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f);
@@ -1211,8 +1275,17 @@ BOOL LLVOVolume::updateLOD()
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
mLODChanged = TRUE;
}
+ else
+ {
+ F32 new_radius = getBinRadius();
+ F32 old_radius = mDrawable->getBinRadius();
+ if (new_radius < old_radius * 0.9f || new_radius > old_radius*1.1f)
+ {
+ gPipeline.markPartitionMove(mDrawable);
+ }
+ }
- lod_changed |= LLViewerObject::updateLOD();
+ lod_changed = lod_changed || LLViewerObject::updateLOD();
return lod_changed;
}
@@ -1332,9 +1405,19 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
{
BOOL res = TRUE;
- LLVector3 min,max;
+ LLVector4a min,max;
+
+ min.clear();
+ max.clear();
- BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION);
+ BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED);
+
+// bool rigged = false;
+ LLVolume* volume = mRiggedVolume;
+ if (!volume)
+ {
+ volume = getVolume();
+ }
for (S32 i = 0; i < getVolume()->getNumVolumeFaces(); i++)
{
@@ -1343,7 +1426,7 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
{
continue;
}
- res &= face->genVolumeBBoxes(*getVolume(), i,
+ res &= face->genVolumeBBoxes(*volume, i,
mRelativeXform, mRelativeXformInvTrans,
(mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global);
@@ -1356,17 +1439,8 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
}
else
{
- for (U32 i = 0; i < 3; i++)
- {
- if (face->mExtents[0].mV[i] < min.mV[i])
- {
- min.mV[i] = face->mExtents[0].mV[i];
- }
- if (face->mExtents[1].mV[i] > max.mV[i])
- {
- max.mV[i] = face->mExtents[1].mV[i];
- }
- }
+ min.setMin(min, face->mExtents[0]);
+ max.setMax(max, face->mExtents[1]);
}
}
}
@@ -1374,7 +1448,9 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
if (rebuild)
{
mDrawable->setSpatialExtents(min,max);
- mDrawable->setPositionGroup((min+max)*0.5f);
+ min.add(max);
+ min.mul(0.5f);
+ mDrawable->setPositionGroup(min);
}
updateRadius();
@@ -1401,7 +1477,21 @@ void LLVOVolume::updateRelativeXform()
LLDrawable* drawable = mDrawable;
- if (drawable->isActive())
+ if (drawable->isState(LLDrawable::RIGGED) && mRiggedVolume.notNull())
+ { //rigged volume (which is in agent space) is used for generating bounding boxes etc
+ //inverse of render matrix should go to partition space
+ mRelativeXform = getRenderMatrix();
+
+ F32* dst = (F32*) mRelativeXformInvTrans.mMatrix;
+ F32* src = (F32*) mRelativeXform.mMatrix;
+ dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2];
+ dst[3] = src[4]; dst[4] = src[5]; dst[5] = src[6];
+ dst[6] = src[8]; dst[7] = src[9]; dst[8] = src[10];
+
+ mRelativeXform.invert();
+ mRelativeXformInvTrans.transpose();
+ }
+ else if (drawable->isActive())
{
// setup relative transforms
LLQuaternion delta_rot;
@@ -1483,11 +1573,22 @@ void LLVOVolume::updateRelativeXform()
static LLFastTimer::DeclareTimer FTM_GEN_FLEX("Generate Flexies");
static LLFastTimer::DeclareTimer FTM_UPDATE_PRIMITIVES("Update Primitives");
+static LLFastTimer::DeclareTimer FTM_UPDATE_RIGGED_VOLUME("Update Rigged");
BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
{
LLFastTimer t(FTM_UPDATE_PRIMITIVES);
+ if (mDrawable->isState(LLDrawable::REBUILD_RIGGED))
+ {
+ {
+ LLFastTimer t(FTM_UPDATE_RIGGED_VOLUME);
+ updateRiggedVolume();
+ }
+ genBBoxes(FALSE);
+ mDrawable->clearState(LLDrawable::REBUILD_RIGGED);
+ }
+
if (mVolumeImpl != NULL)
{
BOOL res;
@@ -1564,6 +1665,17 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
regenFaces();
}
genBBoxes(FALSE);
+
+ if (mSculptChanged)
+ { //changes in sculpt maps can thrash an object bounding box without
+ //triggering a spatial group bounding box update -- force spatial group
+ //to update bounding boxes
+ LLSpatialGroup* group = mDrawable->getSpatialGroup();
+ if (group)
+ {
+ group->unbound();
+ }
+ }
}
}
}
@@ -1583,12 +1695,12 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
{
LLPipeline::sCompiles++;
}
-
+
mVolumeChanged = FALSE;
mLODChanged = FALSE;
mSculptChanged = FALSE;
mFaceMappingChanged = FALSE;
-
+
return LLViewerObject::updateGeometry(drawable);
}
@@ -1597,7 +1709,7 @@ void LLVOVolume::updateFaceSize(S32 idx)
LLFace* facep = mDrawable->getFace(idx);
if (idx >= getVolume()->getNumVolumeFaces())
{
- facep->setSize(0,0);
+ facep->setSize(0,0, true);
}
else
{
@@ -1872,7 +1984,7 @@ LLVector3 LLVOVolume::getApproximateFaceNormal(U8 face_id)
result.add(face.mNormals[i]);
}
- LLVector3 ret((F32*) &result.mQ);
+ LLVector3 ret(result.getF32ptr());
ret = volumeDirectionToAgent(ret);
ret.normVec();
}
@@ -2061,9 +2173,13 @@ bool LLVOVolume::hasMediaPermission(const LLMediaEntry* media_entry, MediaPermTy
}
// Group permissions
- else if (0 != (media_perms & LLMediaEntry::PERM_GROUP) && permGroupOwner())
+ else if (0 != (media_perms & LLMediaEntry::PERM_GROUP))
{
- return true;
+ LLPermissions* obj_perm = LLSelectMgr::getInstance()->findObjectPermissions(this);
+ if (obj_perm && gAgent.isInGroup(obj_perm->getGroup()))
+ {
+ return true;
+ }
}
// Owner permissions
@@ -2104,12 +2220,12 @@ void LLVOVolume::mediaNavigated(LLViewerMediaImpl *impl, LLPluginClassMedia* plu
}
else
{
- llwarns << "Couldn't find media entry!" << llendl;
+ LL_WARNS("MediaOnAPrim") << "Couldn't find media entry!" << LL_ENDL;
}
if(block_navigation)
{
- llinfos << "blocking navigate to URI " << new_location << llendl;
+ LL_INFOS("MediaOnAPrim") << "blocking navigate to URI " << new_location << LL_ENDL;
// "bounce back" to the current URL from the media entry
mediaNavigateBounceBack(face_index);
@@ -2117,7 +2233,7 @@ void LLVOVolume::mediaNavigated(LLViewerMediaImpl *impl, LLPluginClassMedia* plu
else if (sObjectMediaNavigateClient)
{
- llinfos << "broadcasting navigate with URI " << new_location << llendl;
+ LL_DEBUGS("MediaOnAPrim") << "broadcasting navigate with URI " << new_location << LL_ENDL;
sObjectMediaNavigateClient->navigate(new LLMediaDataClientObjectImpl(this, false), face_index, new_location);
}
@@ -2139,14 +2255,19 @@ void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin,
}
break;
+ case LLViewerMediaImpl::MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS:
+ // This navigate didn't change the current URL.
+ LL_DEBUGS("MediaOnAPrim") << " NOT broadcasting navigate (spurious)" << LL_ENDL;
+ break;
+
case LLViewerMediaImpl::MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED:
// This is the first location changed event after the start of a server-directed nav. Don't broadcast it.
- llinfos << " NOT broadcasting navigate (server-directed)" << llendl;
+ LL_INFOS("MediaOnAPrim") << " NOT broadcasting navigate (server-directed)" << LL_ENDL;
break;
default:
// This is a subsequent location-changed due to a redirect. Don't broadcast.
- llinfos << " NOT broadcasting navigate (redirect)" << llendl;
+ LL_INFOS("MediaOnAPrim") << " NOT broadcasting navigate (redirect)" << LL_ENDL;
break;
}
}
@@ -2163,9 +2284,14 @@ void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin,
}
break;
+ case LLViewerMediaImpl::MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS:
+ // This navigate didn't change the current URL.
+ LL_DEBUGS("MediaOnAPrim") << " NOT broadcasting navigate (spurious)" << LL_ENDL;
+ break;
+
case LLViewerMediaImpl::MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED:
// This is the the navigate complete event from a server-directed nav. Don't broadcast it.
- llinfos << " NOT broadcasting navigate (server-directed)" << llendl;
+ LL_INFOS("MediaOnAPrim") << " NOT broadcasting navigate (server-directed)" << LL_ENDL;
break;
default:
@@ -2195,7 +2321,7 @@ void LLVOVolume::removeMediaImpl(S32 texture_index)
}
//make the face referencing to mMediaImplList[texture_index] to point back to the old texture.
- if(mDrawable)
+ if(mDrawable && texture_index < mDrawable->getNumFaces())
{
LLFace* facep = mDrawable->getFace(texture_index) ;
if(facep)
@@ -2693,6 +2819,11 @@ BOOL LLVOVolume::isVolumeGlobal() const
{
return mVolumeImpl->isVolumeGlobal() ? TRUE : FALSE;
}
+ else if (mRiggedVolume.notNull())
+ {
+ return TRUE;
+ }
+
return FALSE;
}
@@ -2777,7 +2908,7 @@ void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_p
trans_mat.translate(getRegion()->getOriginAgent());
}
- volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, nodep->mSilhouetteSegments, view_vector, trans_mat, mRelativeXformInvTrans, nodep->getTESelectMask());
+ volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, view_vector, trans_mat, mRelativeXformInvTrans, nodep->getTESelectMask());
nodep->mSilhouetteExists = TRUE;
}
@@ -2808,14 +2939,7 @@ void LLVOVolume::updateRadius()
BOOL LLVOVolume::isAttachment() const
{
- if (mState == 0)
- {
- return FALSE;
- }
- else
- {
- return TRUE;
- }
+ return mState != 0 ;
}
BOOL LLVOVolume::isHUDAttachment() const
@@ -2970,6 +3094,74 @@ U32 LLVOVolume::getRenderCost(std::set<LLUUID> &textures) const
}
+F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes)
+{
+ F32 radius = getScale().length();
+
+ if (isMesh())
+ {
+ LLSD& header = gMeshRepo.getMeshHeader(getVolume()->getParams().getSculptID());
+
+ return LLMeshRepository::getStreamingCost(header, radius, bytes, visible_bytes, mLOD);
+ }
+ else
+ {
+ LLVolume* volume = getVolume();
+ S32 counts[4];
+ LLVolume::getLoDTriangleCounts(volume->getParams(), counts);
+
+ LLSD header;
+ header["lowest_lod"]["size"] = counts[0] * 10;
+ header["low_lod"]["size"] = counts[1] * 10;
+ header["medium_lod"]["size"] = counts[2] * 10;
+ header["high_lod"]["size"] = counts[3] * 10;
+
+ return LLMeshRepository::getStreamingCost(header, radius);
+ }
+}
+
+U32 LLVOVolume::getTriangleCount()
+{
+ U32 count = 0;
+ LLVolume* volume = getVolume();
+ if (volume)
+ {
+ count = volume->getNumTriangles();
+ }
+
+ return count;
+}
+
+U32 LLVOVolume::getHighLODTriangleCount()
+{
+ U32 ret = 0;
+
+ LLVolume* volume = getVolume();
+
+ if (!isSculpted())
+ {
+ LLVolume* ref = LLPrimitive::getVolumeManager()->refVolume(volume->getParams(), 3);
+ ret = ref->getNumTriangles();
+ LLPrimitive::getVolumeManager()->unrefVolume(ref);
+ }
+ else if (isMesh())
+ {
+ LLVolume* ref = LLPrimitive::getVolumeManager()->refVolume(volume->getParams(), 3);
+ if (ref->isTetrahedron() || ref->getNumVolumeFaces() == 0)
+ {
+ gMeshRepo.loadMesh(this, volume->getParams(), LLModel::LOD_HIGH);
+ }
+ ret = ref->getNumTriangles();
+ LLPrimitive::getVolumeManager()->unrefVolume(ref);
+ }
+ else
+ { //default sculpts have a constant number of triangles
+ ret = 31*2*31; //31 rows of 31 columns of quads for a 32x32 vertex patch
+ }
+
+ return ret;
+}
+
//static
void LLVOVolume::preUpdateGeom()
{
@@ -3007,7 +3199,7 @@ void LLVOVolume::setSelected(BOOL sel)
}
}
-void LLVOVolume::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax)
+void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
{
}
@@ -3017,29 +3209,11 @@ F32 LLVOVolume::getBinRadius()
F32 scale = 1.f;
- if (isSculpted())
- {
- LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
- LLUUID id = sculpt_params->getSculptTexture();
- U8 sculpt_type = sculpt_params->getSculptType();
-
- if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
- // mesh is a mesh
- {
- LLVolume* volume = getVolume();
- U32 vert_count = 0;
-
- for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
- {
- const LLVolumeFace& face = volume->getVolumeFace(i);
- vert_count += face.mNumVertices;
- }
-
- scale = 1.f/llmax(vert_count/1024.f, 1.f);
- }
- }
-
- const LLVector3* ext = mDrawable->getSpatialExtents();
+ S32 size_factor = llmax(gSavedSettings.getS32("OctreeStaticObjectSizeFactor"), 1);
+ S32 attachment_size_factor = llmax(gSavedSettings.getS32("OctreeAttachmentSizeFactor"), 1);
+ LLVector3 distance_factor = gSavedSettings.getVector3("OctreeDistanceFactor");
+ LLVector3 alpha_distance_factor = gSavedSettings.getVector3("OctreeAlphaDistanceFactor");
+ const LLVector4a* ext = mDrawable->getSpatialExtents();
BOOL shrink_wrap = mDrawable->isAnimating();
BOOL alpha_wrap = FALSE;
@@ -3068,31 +3242,31 @@ F32 LLVOVolume::getBinRadius()
radius = llmin(bounds.mV[1], bounds.mV[2]);
radius = llmin(radius, bounds.mV[0]);
radius *= 0.5f;
+ radius *= 1.f+mDrawable->mDistanceWRTCamera*alpha_distance_factor[1];
+ radius += mDrawable->mDistanceWRTCamera*alpha_distance_factor[0];
}
else if (shrink_wrap)
{
- radius = (ext[1]-ext[0]).length()*0.5f;
+ LLVector4a rad;
+ rad.setSub(ext[1], ext[0]);
+
+ radius = rad.getLength3().getF32()*0.5f;
}
else if (mDrawable->isStatic())
{
- /*if (mDrawable->getRadius() < 2.0f)
- {
- radius = 16.f;
- }
- else
- {
- radius = llmax(mDrawable->getRadius(), 32.f);
- }*/
-
- radius = (((S32) mDrawable->getRadius())/2+1)*8;
+ radius = llmax((S32) mDrawable->getRadius(), 1)*size_factor;
+ radius *= 1.f + mDrawable->mDistanceWRTCamera * distance_factor[1];
+ radius += mDrawable->mDistanceWRTCamera * distance_factor[0];
}
else if (mDrawable->getVObj()->isAttachment())
{
- radius = (((S32) (mDrawable->getRadius()*4)+1))*2;
+ radius = llmax((S32) mDrawable->getRadius(),1)*attachment_size_factor;
}
else
{
- radius = 8.f;
+ radius = mDrawable->getRadius();
+ radius *= 1.f + mDrawable->mDistanceWRTCamera * distance_factor[1];
+ radius += mDrawable->mDistanceWRTCamera * distance_factor[0];
}
return llclamp(radius*scale, 0.5f, 256.f);
@@ -3107,7 +3281,7 @@ const LLVector3 LLVOVolume::getPivotPositionAgent() const
return LLViewerObject::getPivotPositionAgent();
}
-void LLVOVolume::onShift(const LLVector3 &shift_vector)
+void LLVOVolume::onShift(const LLVector4a &shift_vector)
{
if (mVolumeImpl)
{
@@ -3184,12 +3358,38 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
BOOL ret = FALSE;
LLVolume* volume = getVolume();
+
+ bool transform = true;
+
+ if (mDrawable->isState(LLDrawable::RIGGED))
+ {
+ if (LLFloater::isVisible(gFloaterTools) && getAvatar()->isSelf())
+ {
+ updateRiggedVolume();
+ genBBoxes(FALSE);
+ volume = mRiggedVolume;
+ transform = false;
+ }
+ else
+ { //cannot pick rigged attachments on other avatars or when not in build mode
+ return FALSE;
+ }
+ }
+
if (volume)
{
LLVector3 v_start, v_end, v_dir;
- v_start = agentPositionToVolume(start);
- v_end = agentPositionToVolume(end);
+ if (transform)
+ {
+ v_start = agentPositionToVolume(start);
+ v_end = agentPositionToVolume(end);
+ }
+ else
+ {
+ v_start = start;
+ v_end = end;
+ }
LLVector3 p;
LLVector3 n;
@@ -3230,8 +3430,15 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
end_face = face+1;
}
+ bool special_cursor = specialHoverCursor();
for (S32 i = start_face; i < end_face; ++i)
{
+ if (!special_cursor && !pick_transparent && getTE(i)->getColor().mV[3] == 0.f)
+ { //don't attempt to pick completely transparent faces unless
+ //pick_transparent is true
+ continue;
+ }
+
face_hit = volume->lineSegmentIntersect(v_start, v_end, i,
&p, &tc, &n, &bn);
@@ -3249,18 +3456,40 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
if (intersection != NULL)
{
- *intersection = volumePositionToAgent(p); // must map back to agent space
+ if (transform)
+ {
+ *intersection = volumePositionToAgent(p); // must map back to agent space
+ }
+ else
+ {
+ *intersection = p;
+ }
}
if (normal != NULL)
{
- *normal = volumeDirectionToAgent(n);
+ if (transform)
+ {
+ *normal = volumeDirectionToAgent(n);
+ }
+ else
+ {
+ *normal = n;
+ }
+
(*normal).normVec();
}
if (bi_normal != NULL)
{
- *bi_normal = volumeDirectionToAgent(bn);
+ if (transform)
+ {
+ *bi_normal = volumeDirectionToAgent(bn);
+ }
+ else
+ {
+ *bi_normal = bn;
+ }
(*bi_normal).normVec();
}
@@ -3278,6 +3507,201 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
return ret;
}
+bool LLVOVolume::treatAsRigged()
+{
+ return LLFloater::isVisible(gFloaterTools) &&
+ isAttachment() &&
+ getAvatar() &&
+ getAvatar()->isSelf() &&
+ mDrawable.notNull() &&
+ mDrawable->isState(LLDrawable::RIGGED);
+}
+
+LLRiggedVolume* LLVOVolume::getRiggedVolume()
+{
+ return mRiggedVolume;
+}
+
+void LLVOVolume::clearRiggedVolume()
+{
+ if (mRiggedVolume.notNull())
+ {
+ mRiggedVolume = NULL;
+ updateRelativeXform();
+ }
+}
+
+void LLVOVolume::updateRiggedVolume()
+{
+ //Update mRiggedVolume to match current animation frame of avatar.
+ //Also update position/size in octree.
+
+ if (!treatAsRigged())
+ {
+ clearRiggedVolume();
+
+ return;
+ }
+
+ LLVolume* volume = getVolume();
+
+ const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(volume->getParams().getSculptID(), this);
+
+ if (!skin)
+ {
+ clearRiggedVolume();
+ return;
+ }
+
+ LLVOAvatar* avatar = getAvatar();
+
+ if (!avatar)
+ {
+ clearRiggedVolume();
+ return;
+ }
+
+ if (!mRiggedVolume)
+ {
+ LLVolumeParams p;
+ mRiggedVolume = new LLRiggedVolume(p);
+ updateRelativeXform();
+ }
+
+ mRiggedVolume->update(skin, avatar, volume);
+
+}
+
+static LLFastTimer::DeclareTimer FTM_SKIN_RIGGED("Skin");
+static LLFastTimer::DeclareTimer FTM_RIGGED_OCTREE("Octree");
+
+void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* volume)
+{
+ bool copy = false;
+ if (volume->getNumVolumeFaces() != getNumVolumeFaces())
+ {
+ copy = true;
+ }
+
+ for (S32 i = 0; i < volume->getNumVolumeFaces() && !copy; ++i)
+ {
+ const LLVolumeFace& src_face = volume->getVolumeFace(i);
+ const LLVolumeFace& dst_face = getVolumeFace(i);
+
+ if (src_face.mNumIndices != dst_face.mNumIndices ||
+ src_face.mNumVertices != dst_face.mNumVertices)
+ {
+ copy = true;
+ }
+ }
+
+ if (copy)
+ {
+ copyVolumeFaces(volume);
+ }
+
+ //build matrix palette
+ LLMatrix4a mp[64];
+ LLMatrix4* mat = (LLMatrix4*) mp;
+
+ for (U32 j = 0; j < skin->mJointNames.size(); ++j)
+ {
+ LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
+ if (joint)
+ {
+ mat[j] = skin->mInvBindMatrix[j];
+ mat[j] *= joint->getWorldMatrix();
+ }
+ }
+
+ for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& vol_face = volume->getVolumeFace(i);
+
+ LLVolumeFace& dst_face = mVolumeFaces[i];
+
+ LLVector4a* weight = vol_face.mWeights;
+
+ LLMatrix4a bind_shape_matrix;
+ bind_shape_matrix.loadu(skin->mBindShapeMatrix);
+
+ LLVector4a* pos = dst_face.mPositions;
+
+ {
+ LLFastTimer t(FTM_SKIN_RIGGED);
+
+ for (U32 j = 0; j < dst_face.mNumVertices; ++j)
+ {
+ LLMatrix4a final_mat;
+ final_mat.clear();
+
+ S32 idx[4];
+
+ LLVector4 wght;
+
+ F32 scale = 0.f;
+ for (U32 k = 0; k < 4; k++)
+ {
+ F32 w = weight[j][k];
+
+ idx[k] = (S32) floorf(w);
+ wght[k] = w - floorf(w);
+ scale += wght[k];
+ }
+
+ wght *= 1.f/scale;
+
+ for (U32 k = 0; k < 4; k++)
+ {
+ F32 w = wght[k];
+
+ LLMatrix4a src;
+ src.setMul(mp[idx[k]], w);
+
+ final_mat.add(src);
+ }
+
+
+ LLVector4a& v = vol_face.mPositions[j];
+ LLVector4a t;
+ LLVector4a dst;
+ bind_shape_matrix.affineTransform(v, t);
+ final_mat.affineTransform(t, dst);
+ pos[j] = dst;
+ }
+
+ //update bounding box
+ LLVector4a& min = dst_face.mExtents[0];
+ LLVector4a& max = dst_face.mExtents[1];
+
+ min = pos[0];
+ max = pos[1];
+
+ for (U32 j = 1; j < dst_face.mNumVertices; ++j)
+ {
+ min.setMin(min, pos[j]);
+ max.setMax(max, pos[j]);
+ }
+
+ dst_face.mCenter->setAdd(dst_face.mExtents[0], dst_face.mExtents[1]);
+ dst_face.mCenter->mul(0.5f);
+
+ }
+
+ {
+ LLFastTimer t(FTM_RIGGED_OCTREE);
+ delete dst_face.mOctree;
+ dst_face.mOctree = NULL;
+
+ LLVector4a size;
+ size.setSub(dst_face.mExtents[1], dst_face.mExtents[0]);
+ size.splat(size.getLength3().getF32()*0.5f);
+
+ dst_face.createOctree(1.f);
+ }
+ }
+}
+
U32 LLVOVolume::getPartitionType() const
{
if (isHUDAttachment())
@@ -3312,6 +3736,21 @@ LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep)
mSlopRatio = 0.25f;
}
+bool can_batch_texture(LLFace* facep)
+{
+ if (facep->getTextureEntry()->getBumpmap())
+ { //bump maps aren't worked into texture batching yet
+ return false;
+ }
+
+ if (facep->isState(LLFace::TEXTURE_ANIM) && facep->getVirtualSize() > MIN_TEX_ANIM_SIZE)
+ { //texture animation breaks batches
+ return false;
+ }
+
+ return true;
+}
+
void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type)
{
LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
@@ -3330,7 +3769,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
(type == LLRenderPass::PASS_INVISIBLE) ||
(type == LLRenderPass::PASS_ALPHA && facep->isState(LLFace::FULLBRIGHT));
- if (!fullbright && type != LLRenderPass::PASS_GLOW && !facep->mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL))
+ if (!fullbright && type != LLRenderPass::PASS_GLOW && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_NORMAL))
{
llwarns << "Non fullbright face has no normals!" << llendl;
return;
@@ -3352,23 +3791,46 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
else
{
model_mat = &(drawable->getRegion()->mRenderMatrix);
+ if (model_mat->isIdentity())
+ {
+ model_mat = NULL;
+ }
}
U8 bump = (type == LLRenderPass::PASS_BUMP || type == LLRenderPass::PASS_POST_BUMP) ? facep->getTextureEntry()->getBumpmap() : 0;
LLViewerTexture* tex = facep->getTexture();
- U8 glow = (U8) (facep->getTextureEntry()->getGlow() * 255);
+ U8 index = facep->getTextureIndex();
- if (facep->mVertexBuffer.isNull())
+ bool batchable = false;
+
+ if (index < 255 && idx >= 0)
{
- llerrs << "WTF?" << llendl;
+ if (index < draw_vec[idx]->mTextureList.size())
+ {
+ if (draw_vec[idx]->mTextureList[index].isNull())
+ {
+ batchable = true;
+ draw_vec[idx]->mTextureList[index] = tex;
+ }
+ else if (draw_vec[idx]->mTextureList[index] == tex)
+ { //this face's texture index can be used with this batch
+ batchable = true;
+ }
+ }
+ else
+ { //texture list can be expanded to fit this texture index
+ batchable = true;
+ }
}
+
+ U8 glow = (U8) (facep->getTextureEntry()->getGlow() * 255);
if (idx >= 0 &&
- draw_vec[idx]->mVertexBuffer == facep->mVertexBuffer &&
+ draw_vec[idx]->mVertexBuffer == facep->getVertexBuffer() &&
draw_vec[idx]->mEnd == facep->getGeomIndex()-1 &&
- (LLPipeline::sTextureBindTest || draw_vec[idx]->mTexture == tex) &&
+ (LLPipeline::sTextureBindTest || draw_vec[idx]->mTexture == tex || batchable) &&
#if LL_DARWIN
draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange &&
draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange &&
@@ -3382,6 +3844,12 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
draw_vec[idx]->mCount += facep->getIndicesCount();
draw_vec[idx]->mEnd += facep->getGeomCount();
draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, facep->getVirtualSize());
+
+ if (index >= draw_vec[idx]->mTextureList.size())
+ {
+ draw_vec[idx]->mTextureList.resize(index+1);
+ draw_vec[idx]->mTextureList[index] = tex;
+ }
draw_vec[idx]->validate();
update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[0]);
update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[1]);
@@ -3393,7 +3861,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
U32 offset = facep->getIndicesStart();
U32 count = facep->getIndicesCount();
LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset, tex,
- facep->mVertexBuffer, fullbright, bump);
+ facep->getVertexBuffer(), fullbright, bump);
draw_info->mGroup = group;
draw_info->mVSize = facep->getVirtualSize();
draw_vec.push_back(draw_info);
@@ -3412,6 +3880,11 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
draw_info->mDrawMode = LLRender::TRIANGLE_STRIP;
}
+ if (index < 255)
+ { //initialize texture list for texture batching
+ draw_info->mTextureList.resize(index+1);
+ draw_info->mTextureList[index] = tex;
+ }
draw_info->validate();
}
}
@@ -3450,7 +3923,6 @@ static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj)
return NULL;
}
-
void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
{
@@ -3489,8 +3961,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
std::vector<LLFace*> alpha_faces;
U32 useage = group->mSpatialPartition->mBufferUsage;
- U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcStride(group->mSpatialPartition->mVertexDataMask);
- U32 max_total = (gSavedSettings.getS32("RenderMaxNodeSize")*1024)/LLVertexBuffer::calcStride(group->mSpatialPartition->mVertexDataMask);
+ U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
+ U32 max_total = (gSavedSettings.getS32("RenderMaxNodeSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
max_vertices = llmin(max_vertices, (U32) 65535);
U32 cur_total = 0;
@@ -3511,6 +3983,12 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
LLVOVolume* vobj = drawablep->getVOVolume();
+
+ if (vobj->getVolume() && vobj->getVolume()->isTetrahedron() || (vobj->isMesh() && !gMeshRepo.meshRezEnabled()))
+ {
+ continue;
+ }
+
llassert_always(vobj);
vobj->updateTextureVirtualSize();
vobj->preRebuild();
@@ -3519,98 +3997,170 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
bool rigged = vobj->isAttachment() &&
vobj->isMesh() &&
- gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID());
+ gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj);
bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic();
+ bool is_rigged = false;
+
//for each face
for (S32 i = 0; i < drawablep->getNumFaces(); i++)
{
+ LLFace* facep = drawablep->getFace(i);
+
+ //ALWAYS null out vertex buffer on rebuild -- if the face lands in a render
+ // batch, it will recover its vertex buffer reference from the spatial group
+ facep->setVertexBuffer(NULL);
+
//sum up face verts and indices
drawablep->updateFaceSize(i);
- LLFace* facep = drawablep->getFace(i);
+
+
if (rigged)
{
if (!facep->isState(LLFace::RIGGED))
+ { //completely reset vertex buffer
+ facep->clearVertexBuffer();
+ }
+
+ facep->setState(LLFace::RIGGED);
+ is_rigged = true;
+
+ //get drawpool of avatar with rigged face
+ LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);
+
+ //Determine if we've received skininfo that contains an
+ //alternate bind matrix - if it does then apply the translational component
+ //to the joints of the avatar.
+ LLVOAvatar* pAvatarVO = vobj->getAvatar();
+ bool pelvisGotSet = false;
+
+ if ( pAvatarVO )
{
- facep->mVertexBuffer = NULL;
- facep->mLastVertexBuffer = NULL;
- facep->setState(LLFace::RIGGED);
-
- //get drawpool of avatar with rigged face
- LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);
+ LLUUID currentId = vobj->getVolume()->getParams().getSculptID();
+ const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj );
- if (pool)
+ if ( pSkinData )
{
- const LLTextureEntry* te = facep->getTextureEntry();
-
- //remove face from old pool if it exists
- LLDrawPool* old_pool = facep->getPool();
- if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR)
- {
- ((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep);
+ const int bindCnt = pSkinData->mAlternateBindMatrix.size();
+ if ( bindCnt > 0 )
+ {
+ const int jointCnt = pSkinData->mJointNames.size();
+ const F32 pelvisZOffset = pSkinData->mPelvisOffset;
+ bool fullRig = (jointCnt>=20) ? true : false;
+ if ( fullRig )
+ {
+ for ( int i=0; i<jointCnt; ++i )
+ {
+ std::string lookingForJoint = pSkinData->mJointNames[i].c_str();
+ //llinfos<<"joint name "<<lookingForJoint.c_str()<<llendl;
+ LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint );
+ if ( pJoint && pJoint->getId() != currentId )
+ {
+ pJoint->setId( currentId );
+ const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation();
+ //Set the joint position
+ pJoint->storeCurrentXform( jointPos );
+ //If joint is a pelvis then handle old/new pelvis to foot values
+ if ( lookingForJoint == "mPelvis" )
+ {
+ pJoint->storeCurrentXform( jointPos );
+ if ( !pAvatarVO->hasPelvisOffset() )
+ {
+ pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset );
+ //Trigger to rebuild viewer AV
+ pelvisGotSet = true;
+ }
+ }
+ }
+ }
+ }
}
+ }
+ }
+ //If we've set the pelvis to a new position we need to also rebuild some information that the
+ //viewer does at launch (e.g. body size etc.)
+ if ( pelvisGotSet )
+ {
+ pAvatarVO->postPelvisSetRecalc();
+ }
+
+ if (pool)
+ {
+ const LLTextureEntry* te = facep->getTextureEntry();
+
+ //remove face from old pool if it exists
+ LLDrawPool* old_pool = facep->getPool();
+ if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR)
+ {
+ ((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep);
+ }
- //add face to new pool
- LLViewerTexture* tex = facep->getTexture();
- U32 type = gPipeline.getPoolTypeFromTE(te, tex);
+ //add face to new pool
+ LLViewerTexture* tex = facep->getTexture();
+ U32 type = gPipeline.getPoolTypeFromTE(te, tex);
- if (type == LLDrawPool::POOL_ALPHA)
+ if (type == LLDrawPool::POOL_ALPHA)
+ {
+ if (te->getFullbright())
{
- if (te->getFullbright())
- {
- pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
- }
- else
- {
- pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
- }
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
}
- else if (te->getShiny())
+ else
{
- if (te->getFullbright())
- {
- pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY);
- }
- else
- {
- pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY);
- }
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
+ }
+ }
+ else if (te->getShiny())
+ {
+ if (te->getFullbright())
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY);
}
else
{
- if (te->getFullbright())
+ if (LLPipeline::sRenderDeferred)
{
- pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT);
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
}
else
{
- pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY);
}
}
-
- if (te->getGlow())
+ }
+ else
+ {
+ if (te->getFullbright())
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT);
+ }
+ else
{
- pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW);
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
}
+ }
- if (LLPipeline::sRenderDeferred)
+ if (te->getGlow())
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW);
+ }
+
+ if (LLPipeline::sRenderDeferred)
+ {
+ if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright())
{
- if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright())
+ if (te->getBumpmap())
{
- if (te->getBumpmap())
- {
- pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP);
- }
- else
- {
- pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE);
- }
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP);
+ }
+ else
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE);
}
}
}
-
}
continue;
@@ -3630,14 +4180,13 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0)
{
- facep->mVertexBuffer = NULL;
- facep->mLastVertexBuffer = NULL;
+ facep->clearVertexBuffer();
continue;
}
cur_total += facep->getGeomCount();
- if (facep->hasGeometry() && facep->mPixelArea > FORCE_CULL_AREA)
+ if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA)
{
const LLTextureEntry* te = facep->getTextureEntry();
LLViewerTexture* tex = facep->getTexture();
@@ -3650,7 +4199,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
}
- BOOL force_simple = (facep->mPixelArea < FORCE_SIMPLE_RENDER_AREA);
+ BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA);
U32 type = gPipeline.getPoolTypeFromTE(te, tex);
if (type != LLDrawPool::POOL_ALPHA && force_simple)
{
@@ -3736,10 +4285,18 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
else
{ //face has no renderable geometry
- facep->mVertexBuffer = NULL;
- facep->mLastVertexBuffer = NULL;
+ facep->clearVertexBuffer();
}
}
+
+ if (is_rigged)
+ {
+ drawablep->setState(LLDrawable::RIGGED);
+ }
+ else
+ {
+ drawablep->clearState(LLDrawable::RIGGED);
+ }
}
group->mBufferUsage = useage;
@@ -3750,15 +4307,24 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
U32 bump_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR;
U32 fullbright_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR;
- if (LLPipeline::sRenderDeferred)
+ bool batch_textures = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 1;
+
+ if (batch_textures)
{
bump_mask |= LLVertexBuffer::MAP_BINORMAL;
+ genDrawInfo(group, simple_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, simple_faces, FALSE, TRUE);
+ genDrawInfo(group, fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, fullbright_faces, FALSE, TRUE);
+ genDrawInfo(group, bump_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, bump_faces, FALSE, TRUE);
+ genDrawInfo(group, alpha_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, alpha_faces, TRUE, TRUE);
}
-
- genDrawInfo(group, simple_mask, simple_faces);
- genDrawInfo(group, bump_mask, bump_faces);
- genDrawInfo(group, fullbright_mask, fullbright_faces);
- genDrawInfo(group, alpha_mask, alpha_faces, TRUE);
+ else
+ {
+ genDrawInfo(group, simple_mask, simple_faces);
+ genDrawInfo(group, fullbright_mask, fullbright_faces);
+ genDrawInfo(group, bump_mask, bump_faces, FALSE, TRUE);
+ genDrawInfo(group, alpha_mask, alpha_faces, TRUE);
+ }
+
if (!LLPipeline::sDelayVBUpdate)
{
@@ -3800,29 +4366,20 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
LLFastTimer t(FTM_VOLUME_GEOM_PARTIAL);
LLDrawable* drawablep = *drawable_iter;
- if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) )
- {
- continue;
- }
-
- if (drawablep->isState(LLDrawable::REBUILD_ALL))
+ if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) )
{
LLVOVolume* vobj = drawablep->getVOVolume();
vobj->preRebuild();
+
LLVolume* volume = vobj->getVolume();
for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
{
LLFace* face = drawablep->getFace(i);
- if (face && face->mVertexBuffer.notNull())
+ if (face && face->getVertexBuffer())
{
face->getGeometryVolume(*volume, face->getTEOffset(),
vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex());
}
-
- if (!face)
- {
- llerrs << "WTF?" << llendl;
- }
}
drawablep->clearState(LLDrawable::REBUILD_ALL);
@@ -3865,9 +4422,10 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
{
LLFace* face = drawablep->getFace(i);
- if (face && face->mVertexBuffer.notNull() && face->mVertexBuffer->isLocked())
+ LLVertexBuffer* buff = face->getVertexBuffer();
+ if (face && buff && buff->isLocked())
{
- face->mVertexBuffer->setBuffer(0) ;
+ buff->setBuffer(0) ;
}
}
}
@@ -3876,22 +4434,46 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
group->clearState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO);
}
- if (group && group->isState(LLSpatialGroup::NEW_DRAWINFO))
+ llassert(!group || !group->isState(LLSpatialGroup::NEW_DRAWINFO));
+}
+
+struct CompareBatchBreakerModified
+{
+ bool operator()(const LLFace* const& lhs, const LLFace* const& rhs)
{
- llerrs << "WTF?" << llendl;
+ const LLTextureEntry* lte = lhs->getTextureEntry();
+ const LLTextureEntry* rte = rhs->getTextureEntry();
+
+ if (lte->getBumpmap() != rte->getBumpmap())
+ {
+ return lte->getBumpmap() < rte->getBumpmap();
+ }
+ else if (lte->getFullbright() != rte->getFullbright())
+ {
+ return lte->getFullbright() < rte->getFullbright();
+ }
+ else if (lte->getGlow() != rte->getGlow())
+ {
+ return lte->getGlow() < rte->getGlow();
+ }
+ else
+ {
+ return lhs->getTexture() < rhs->getTexture();
+ }
+
}
-}
+};
-void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort)
+void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort, BOOL batch_textures)
{
//calculate maximum number of vertices to store in a single buffer
- U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcStride(group->mSpatialPartition->mVertexDataMask);
+ U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
max_vertices = llmin(max_vertices, (U32) 65535);
if (!distance_sort)
{
//sort faces by things that break batches
- std::sort(faces.begin(), faces.end(), LLFace::CompareBatchBreaker());
+ std::sort(faces.begin(), faces.end(), CompareBatchBreakerModified());
}
else
{
@@ -3911,6 +4493,16 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
buffer_index = -1;
}
+ S32 texture_index_channels = gGLManager.mNumTextureImageUnits-1; //always reserve one for shiny for now just for simplicity
+
+ if (LLPipeline::sRenderDeferred && distance_sort)
+ {
+ texture_index_channels = gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels;
+ }
+
+ texture_index_channels = llmin(texture_index_channels, (S32) gSavedSettings.getU32("RenderMaxTextureIndex"));
+
+
while (face_iter != faces.end())
{
//pull off next face
@@ -3937,28 +4529,105 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
U32 index_count = facep->getIndicesCount();
U32 geom_count = facep->getGeomCount();
- //sum up vertices needed for this texture
+ //sum up vertices needed for this render batch
std::vector<LLFace*>::iterator i = face_iter;
++i;
- while (i != faces.end() &&
- (LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex)))
+ std::vector<LLViewerTexture*> texture_list;
+
+ if (batch_textures)
{
- facep = *i;
-
- if (geom_count + facep->getGeomCount() > max_vertices)
- { //cut vertex buffers on geom count too big
- break;
+ U8 cur_tex = 0;
+ facep->setTextureIndex(cur_tex);
+ texture_list.push_back(tex);
+
+ //if (can_batch_texture(facep))
+ {
+ while (i != faces.end())
+ {
+ facep = *i;
+ if (facep->getTexture() != tex)
+ {
+ if (distance_sort)
+ { //textures might be out of order, see if texture exists in current batch
+ bool found = false;
+ for (U32 tex_idx = 0; tex_idx < texture_list.size(); ++tex_idx)
+ {
+ if (facep->getTexture() == texture_list[tex_idx])
+ {
+ cur_tex = tex_idx;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ cur_tex = texture_list.size();
+ }
+ }
+ else
+ {
+ cur_tex++;
+ }
+
+ if (!can_batch_texture(facep))
+ { //face is bump mapped or has an animated texture matrix -- can't
+ //batch more than 1 texture at a time
+ break;
+ }
+
+ if (cur_tex >= texture_index_channels)
+ { //cut batches when index channels are depleted
+ break;
+ }
+
+ tex = facep->getTexture();
+
+ texture_list.push_back(tex);
+ }
+
+ if (geom_count + facep->getGeomCount() > max_vertices)
+ { //cut batches on geom count too big
+ break;
+ }
+
+ ++i;
+ index_count += facep->getIndicesCount();
+ geom_count += facep->getGeomCount();
+
+ facep->setTextureIndex(cur_tex);
+ }
}
- ++i;
- index_count += facep->getIndicesCount();
- geom_count += facep->getGeomCount();
+ tex = texture_list[0];
+ }
+ else
+ {
+ while (i != faces.end() &&
+ (LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex)))
+ {
+ facep = *i;
+
+
+ //face has no texture index
+ facep->mDrawInfo = NULL;
+ facep->setTextureIndex(255);
+
+ if (geom_count + facep->getGeomCount() > max_vertices)
+ { //cut batches on geom count too big
+ break;
+ }
+
+ ++i;
+ index_count += facep->getIndicesCount();
+ geom_count += facep->getGeomCount();
+ }
}
//create/delete/resize vertex buffer if needed
LLVertexBuffer* buffer = NULL;
- LLSpatialGroup::buffer_texture_map_t::iterator found_iter = group->mBufferMap[mask].find(tex);
+ LLSpatialGroup::buffer_texture_map_t::iterator found_iter = group->mBufferMap[mask].find(*face_iter);
if (found_iter != group->mBufferMap[mask].end())
{
@@ -3975,10 +4644,11 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
buffer->allocateBuffer(geom_count, index_count, TRUE);
}
else
- {
- if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != group->mBufferUsage)
+ { //resize pre-existing buffer
+ if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != group->mBufferUsage ||
+ buffer->getTypeMask() != mask)
{
- buffer = createVertexBuffer(group->mSpatialPartition->mVertexDataMask,
+ buffer = createVertexBuffer(mask,
group->mBufferUsage);
buffer->allocateBuffer(geom_count, index_count, TRUE);
}
@@ -3988,7 +4658,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
}
}
- buffer_map[mask][tex].push_back(buffer);
+ buffer_map[mask][*face_iter].push_back(buffer);
//add face geometry
@@ -3996,34 +4666,41 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
U16 index_offset = 0;
while (face_iter < i)
- {
+ { //update face indices for new buffer
facep = *face_iter;
- facep->mIndicesIndex = indices_index;
- facep->mGeomIndex = index_offset;
- facep->mVertexBuffer = buffer;
+ facep->setIndicesIndex(indices_index);
+ facep->setGeomIndex(index_offset);
+ facep->setVertexBuffer(buffer);
+
+ if (batch_textures && facep->getTextureIndex() == 255)
+ {
+ llerrs << "Invalid texture index." << llendl;
+ }
+
{
+ //for debugging, set last time face was updated vs moved
facep->updateRebuildFlags();
+
if (!LLPipeline::sDelayVBUpdate)
- {
+ { //copy face geometry into vertex buffer
LLDrawable* drawablep = facep->getDrawable();
LLVOVolume* vobj = drawablep->getVOVolume();
LLVolume* volume = vobj->getVolume();
U32 te_idx = facep->getTEOffset();
- if (facep->getGeometryVolume(*volume, te_idx,
- vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset))
- {
- buffer->markDirty(facep->getGeomIndex(), facep->getGeomCount(),
- facep->getIndicesStart(), facep->getIndicesCount());
- }
+ facep->getGeometryVolume(*volume, te_idx,
+ vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset);
}
}
index_offset += facep->getGeomCount();
- indices_index += facep->mIndicesCount;
+ indices_index += facep->getIndicesCount();
- BOOL force_simple = facep->mPixelArea < FORCE_SIMPLE_RENDER_AREA;
+
+ //append face to appropriate render batch
+
+ BOOL force_simple = facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA;
BOOL fullbright = facep->isState(LLFace::FULLBRIGHT);
if ((mask & LLVertexBuffer::MAP_NORMAL) == 0)
{ //paranoia check to make sure GL doesn't try to read non-existant normals
@@ -4190,18 +4867,17 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun
//sum up face verts and indices
drawablep->updateFaceSize(i);
LLFace* facep = drawablep->getFace(i);
- if (facep->hasGeometry() && facep->mPixelArea > FORCE_CULL_AREA)
+ if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA)
{
vertex_count += facep->getGeomCount();
index_count += facep->getIndicesCount();
-
+ llassert(facep->getIndicesCount() < 65536);
//remember face (for sorting)
mFaceList.push_back(facep);
}
else
{
- facep->mVertexBuffer = NULL;
- facep->mLastVertexBuffer = NULL;
+ facep->clearVertexBuffer();
}
}
}
@@ -4217,7 +4893,7 @@ LLHUDPartition::LLHUDPartition()
mLODPeriod = 1;
}
-void LLHUDPartition::shift(const LLVector3 &offset)
+void LLHUDPartition::shift(const LLVector4a &offset)
{
//HUD objects don't shift with region crossing. That would be silly.
}