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.cpp761
1 files changed, 653 insertions, 108 deletions
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 42dfcac7a6..d4ac5bfe49 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -76,8 +76,14 @@
#include "lldatapacker.h"
#include "llviewershadermgr.h"
#include "llvoavatar.h"
+#include "llcontrolavatar.h"
+#include "llvoavatarself.h"
#include "llvocache.h"
#include "llmaterialmgr.h"
+#include "llanimationstates.h"
+#include "llinventorytype.h"
+#include "llviewerinventory.h"
+#include "llcallstack.h"
#include "llsculptidsize.h"
const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
@@ -213,6 +219,9 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
mFaceMappingChanged = FALSE;
mLOD = MIN_LOD;
+ mLODDistance = 0.0f;
+ mLODAdjustedDistance = 0.0f;
+ mLODRadius = 0.0f;
mTextureAnimp = NULL;
mVolumeChanged = FALSE;
mVObjRadius = LLVector3(1,1,0.5f).length();
@@ -225,6 +234,7 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
mLastFetchedMediaVersion = -1;
memset(&mIndexInTex, 0, sizeof(S32) * LLRender::NUM_VOLUME_TEXTURE_CHANNELS);
mMDCImplCount = 0;
+ mLastRiggingInfoLOD = -1;
}
LLVOVolume::~LLVOVolume()
@@ -310,6 +320,7 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
U32 block_num, EObjectUpdateType update_type,
LLDataPacker *dp)
{
+
LLColor4U color;
const S32 teDirtyBits = (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR|TEM_CHANGE_MEDIA);
@@ -323,6 +334,9 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
sculpt_id = sculpt_params->getSculptTexture();
sculpt_type = sculpt_params->getSculptType();
+
+ LL_DEBUGS("ObjectUpdate") << "uuid " << mID << " set sculpt_id " << sculpt_id << LL_ENDL;
+ dumpStack("ObjectUpdateStack");
}
if (!dp)
@@ -1106,16 +1120,34 @@ void LLVOVolume::updateSculptTexture()
}
+void LLVOVolume::updateVisualComplexity()
+{
+ LLVOAvatar* avatar = getAvatarAncestor();
+ if (avatar)
+ {
+ avatar->updateVisualComplexity();
+ }
+ LLVOAvatar* rigged_avatar = getAvatar();
+ if(rigged_avatar && (rigged_avatar != avatar))
+ {
+ rigged_avatar->updateVisualComplexity();
+ }
+}
+
void LLVOVolume::notifyMeshLoaded()
{
mSculptChanged = TRUE;
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
- LLVOAvatar* avatar = getAvatar();
- if (avatar)
- {
- avatar->updateVisualComplexity();
- }
+ if (getAvatar() && !isAnimatedObject())
+ {
+ getAvatar()->addAttachmentOverridesForObject(this);
+ }
+ if (getControlAvatar() && isAnimatedObject())
+ {
+ getControlAvatar()->addAttachmentOverridesForObject(this);
+ }
+ updateVisualComplexity();
}
// sculpt replaces generate() for sculpted surfaces
@@ -1240,6 +1272,46 @@ S32 LLVOVolume::computeLODDetail(F32 distance, F32 radius, F32 lod_factor)
return cur_detail;
}
+std::string get_debug_object_lod_text(LLVOVolume *rootp)
+{
+ std::string cam_dist_string = "";
+ cam_dist_string += LLStringOps::getReadableNumber(rootp->mLODDistance) + " ";
+ std::string lod_string = llformat("%d",rootp->getLOD());
+ F32 lod_radius = rootp->mLODRadius;
+ S32 cam_dist_count = 0;
+ LLViewerObject::const_child_list_t& child_list = rootp->getChildren();
+ for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin();
+ iter != child_list.end(); ++iter)
+ {
+ LLViewerObject *childp = *iter;
+ LLVOVolume *volp = dynamic_cast<LLVOVolume*>(childp);
+ if (volp)
+ {
+ lod_string += llformat("%d",volp->getLOD());
+ if (volp->isRiggedMesh())
+ {
+ // Rigged/animatable mesh. This is computed from the
+ // avatar dynamic box, so value from any vol will be
+ // the same.
+ lod_radius = volp->mLODRadius;
+ }
+ if (volp->mDrawable)
+ {
+ if (cam_dist_count < 4)
+ {
+ cam_dist_string += LLStringOps::getReadableNumber(volp->mLODDistance) + " ";
+ cam_dist_count++;
+ }
+ }
+ }
+ }
+ std::string result = llformat("lod_radius %s dists %s lods %s",
+ LLStringOps::getReadableNumber(lod_radius).c_str(),
+ cam_dist_string.c_str(),
+ lod_string.c_str());
+ return result;
+}
+
BOOL LLVOVolume::calcLOD()
{
if (mDrawable.isNull())
@@ -1264,18 +1336,60 @@ BOOL LLVOVolume::calcLOD()
}
distance = avatar->mDrawable->mDistanceWRTCamera;
- radius = avatar->getBinRadius();
+
+
+ if (avatar->isControlAvatar())
+ {
+ // MAINT-7926 Handle volumes in an animated object as a special case
+ const LLVector3* box = avatar->getLastAnimExtents();
+ LLVector3 diag = box[1] - box[0];
+ radius = diag.magVec() * 0.5f;
+ LL_DEBUGS("DynamicBox") << avatar->getFullname() << " diag " << diag << " radius " << radius << LL_ENDL;
+ }
+ else
+ {
+ // Volume in a rigged mesh attached to a regular avatar.
+ // Note this isn't really a radius, so distance calcs are off by factor of 2
+ //radius = avatar->getBinRadius();
+ // SL-937: add dynamic box handling for rigged mesh on regular avatars.
+ const LLVector3* box = avatar->getLastAnimExtents();
+ LLVector3 diag = box[1] - box[0];
+ radius = diag.magVec(); // preserve old BinRadius behavior - 2x off
+ LL_DEBUGS("DynamicBox") << avatar->getFullname() << " diag " << diag << " radius " << radius << LL_ENDL;
+ }
+ if (distance <= 0.f || radius <= 0.f)
+ {
+ LL_DEBUGS("DynamicBox","CalcLOD") << "avatar distance/radius uninitialized, skipping" << LL_ENDL;
+ return FALSE;
+ }
}
else
{
distance = mDrawable->mDistanceWRTCamera;
radius = getVolume() ? getVolume()->mLODScaleBias.scaledVec(getScale()).length() : getScale().length();
+ if (distance <= 0.f || radius <= 0.f)
+ {
+ LL_DEBUGS("DynamicBox","CalcLOD") << "non-avatar distance/radius uninitialized, skipping" << LL_ENDL;
+ return FALSE;
+ }
}
//hold onto unmodified distance for debugging
//F32 debug_distance = distance;
-
- distance *= sDistanceFactor;
+
+ mLODDistance = distance;
+ mLODRadius = radius;
+
+ if (gSavedSettings.getBOOL("DebugObjectLODs"))
+ {
+ if (getAvatar() && isRootEdit())
+ {
+ std::string debug_object_text = get_debug_object_lod_text(this);
+ setDebugText(debug_object_text);
+ }
+ }
+
+ distance *= sDistanceFactor;
F32 rampDist = LLVOVolume::sLODFactor * 2;
@@ -1296,24 +1410,47 @@ BOOL LLVOVolume::calcLOD()
lod_factor *= DEFAULT_FIELD_OF_VIEW / LLViewerCamera::getInstance()->getDefaultFOV();
}
- cur_detail = computeLODDetail(ll_round(distance, 0.01f),
- ll_round(radius, 0.01f),
- lod_factor);
+ mLODAdjustedDistance = distance;
+ if (isHUDAttachment())
+ {
+ // HUDs always show at highest detail
+ cur_detail = 3;
+ }
+ else
+ {
+ cur_detail = computeLODDetail(ll_round(distance, 0.01f), ll_round(radius, 0.01f), lod_factor);
+ }
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TRIANGLE_COUNT) && mDrawable->getFace(0))
+ {
+ if (isRootEdit())
+ {
+ S32 total_tris = recursiveGetTriangleCount();
+ S32 est_max_tris = recursiveGetEstTrianglesMax();
+ setDebugText(llformat("TRIS SHOWN %d EST %d", total_tris, est_max_tris));
+ }
+ }
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO) &&
mDrawable->getFace(0))
{
- //setDebugText(llformat("%.2f:%.2f, %d", mDrawable->mDistanceWRTCamera, radius, cur_detail));
-
- setDebugText(llformat("%d", mDrawable->getFace(0)->getTextureIndex()));
+ // This is a debug display for LODs. Please don't put the texture index here.
+ setDebugText(llformat("%d", cur_detail));
}
if (cur_detail != mLOD)
{
+ LL_DEBUGS("DynamicBox","CalcLOD") << "new LOD " << cur_detail << " change from " << mLOD
+ << " distance " << distance << " radius " << radius << " rampDist " << rampDist
+ << " drawable rigged? " << (mDrawable ? (S32) mDrawable->isState(LLDrawable::RIGGED) : (S32) -1)
+ << " mRiggedVolume " << (void*)getRiggedVolume()
+ << " distanceWRTCamera " << (mDrawable ? mDrawable->mDistanceWRTCamera : -1.f)
+ << LL_ENDL;
+
mAppAngle = ll_round((F32) atan2( mDrawable->getRadius(), mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f);
- mLOD = cur_detail;
+ mLOD = cur_detail;
- return TRUE;
+ return TRUE;
}
return FALSE;
@@ -1339,6 +1476,16 @@ BOOL LLVOVolume::updateLOD()
if (lod_changed)
{
+ if (debugLoggingEnabled("AnimatedObjectsLinkset"))
+ {
+ if (isAnimatedObject() && isRiggedMesh())
+ {
+ std::string vobj_name = llformat("Vol%p", this);
+ F32 est_tris = getEstTrianglesMax();
+ LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " updateLOD to " << getLOD() << ", tris " << est_tris << LL_ENDL;
+ }
+ }
+
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
mLODChanged = TRUE;
}
@@ -1413,7 +1560,8 @@ void LLVOVolume::updateFaceFlags()
BOOL LLVOVolume::setParent(LLViewerObject* parent)
{
BOOL ret = FALSE ;
- if (parent != getParent())
+ LLViewerObject *old_parent = (LLViewerObject*) getParent();
+ if (parent != old_parent)
{
ret = LLViewerObject::setParent(parent);
if (ret && mDrawable)
@@ -1421,6 +1569,7 @@ BOOL LLVOVolume::setParent(LLViewerObject* parent)
gPipeline.markMoved(mDrawable);
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
}
+ onReparent(old_parent, parent);
}
return ret ;
@@ -1485,14 +1634,29 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED);
- // bool rigged = false;
+ if (getRiggedVolume())
+ {
+ // MAINT-8264 - better to use the existing call in calling
+ // func LLVOVolume::updateGeometry() if we can detect when
+ // updates needed, set REBUILD_RIGGED accordingly.
+
+ // Without the flag, this will remove unused rigged volumes, which we are not currently very aggressive about.
+ updateRiggedVolume();
+ }
+
LLVolume* volume = mRiggedVolume;
if (!volume)
{
volume = getVolume();
}
- // There's no guarantee that getVolume()->getNumFaces() == mDrawable->getNumFaces()
+ bool any_valid_boxes = false;
+
+ if (getRiggedVolume())
+ {
+ LL_DEBUGS("RiggedBox") << "rebuilding box, volume face count " << getVolume()->getNumVolumeFaces() << " drawable face count " << mDrawable->getNumFaces() << LL_ENDL;
+ }
+ // There's no guarantee that getVolume()->getNumFaces() == mDrawable->getNumFaces()
for (S32 i = 0;
i < getVolume()->getNumVolumeFaces() && i < mDrawable->getNumFaces() && i < getNumTEs();
i++)
@@ -1502,15 +1666,28 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
{
continue;
}
- res &= face->genVolumeBBoxes(*volume, i,
- mRelativeXform,
- (mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global);
+
+ BOOL face_res = face->genVolumeBBoxes(*volume, i,
+ mRelativeXform,
+ (mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global);
+ res &= face_res; // note that this result is never used
+
+ // MAINT-8264 - ignore bboxes of ill-formed faces.
+ if (!face_res)
+ {
+ continue;
+ }
if (rebuild)
{
- if (i == 0)
+ if (getRiggedVolume())
+ {
+ LL_DEBUGS("RiggedBox") << "rebuilding box, face " << i << " extents " << face->mExtents[0] << ", " << face->mExtents[1] << LL_ENDL;
+ }
+ if (!any_valid_boxes)
{
min = face->mExtents[0];
max = face->mExtents[1];
+ any_valid_boxes = true;
}
else
{
@@ -1519,17 +1696,28 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
}
}
}
-
- if (rebuild)
- {
- mDrawable->setSpatialExtents(min,max);
- min.add(max);
- min.mul(0.5f);
- mDrawable->setPositionGroup(min);
- }
- updateRadius();
- mDrawable->movePartition();
+ if (any_valid_boxes)
+ {
+ if (rebuild)
+ {
+ if (getRiggedVolume())
+ {
+ LL_DEBUGS("RiggedBox") << "rebuilding got extents " << min << ", " << max << LL_ENDL;
+ }
+ mDrawable->setSpatialExtents(min,max);
+ min.add(max);
+ min.mul(0.5f);
+ mDrawable->setPositionGroup(min);
+ }
+
+ updateRadius();
+ mDrawable->movePartition();
+ }
+ else
+ {
+ LL_DEBUGS("RiggedBox") << "genBBoxes failed to find any valid face boxes" << LL_ENDL;
+ }
return res;
}
@@ -1677,6 +1865,11 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
if ((new_lod != old_lod) || mSculptChanged)
{
+ if (mDrawable->isState(LLDrawable::RIGGED))
+ {
+ updateVisualComplexity();
+ }
+
compiled = TRUE;
sNumLODChanges += new_num_faces;
@@ -3317,6 +3510,208 @@ BOOL LLVOVolume::setIsFlexible(BOOL is_flexible)
return res;
}
+const LLMeshSkinInfo* LLVOVolume::getSkinInfo() const
+{
+ if (getVolume())
+ {
+ return gMeshRepo.getSkinInfo(getVolume()->getParams().getSculptID(), this);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+// virtual
+BOOL LLVOVolume::isRiggedMesh() const
+{
+ return isMesh() && getSkinInfo();
+}
+
+//----------------------------------------------------------------------------
+U32 LLVOVolume::getExtendedMeshFlags() const
+{
+ const LLExtendedMeshParams *param_block =
+ (const LLExtendedMeshParams *)getParameterEntry(LLNetworkData::PARAMS_EXTENDED_MESH);
+ if (param_block)
+ {
+ return param_block->getFlags();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void LLVOVolume::onSetExtendedMeshFlags(U32 flags)
+{
+
+ // The isAnySelected() check was needed at one point to prevent
+ // graphics problems. These are now believed to be fixed so the
+ // check has been disabled.
+ if (/*!getRootEdit()->isAnySelected() &&*/ mDrawable.notNull())
+ {
+ // Need to trigger rebuildGeom(), which is where control avatars get created/removed
+ getRootEdit()->recursiveMarkForUpdate(TRUE);
+ }
+ if (isAttachment() && getAvatarAncestor())
+ {
+ updateVisualComplexity();
+ if (flags & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG)
+ {
+ // Making a rigged mesh into an animated object
+ getAvatarAncestor()->updateAttachmentOverrides();
+ }
+ else
+ {
+ // Making an animated object into a rigged mesh
+ getAvatarAncestor()->updateAttachmentOverrides();
+ }
+ }
+}
+
+void LLVOVolume::setExtendedMeshFlags(U32 flags)
+{
+ U32 curr_flags = getExtendedMeshFlags();
+ if (curr_flags != flags)
+ {
+ bool in_use = true;
+ setParameterEntryInUse(LLNetworkData::PARAMS_EXTENDED_MESH, in_use, true);
+ LLExtendedMeshParams *param_block =
+ (LLExtendedMeshParams *)getParameterEntry(LLNetworkData::PARAMS_EXTENDED_MESH);
+ if (param_block)
+ {
+ param_block->setFlags(flags);
+ }
+ parameterChanged(LLNetworkData::PARAMS_EXTENDED_MESH, true);
+ LL_DEBUGS("AnimatedObjects") << this
+ << " new flags " << flags << " curr_flags " << curr_flags
+ << ", calling onSetExtendedMeshFlags()"
+ << LL_ENDL;
+ onSetExtendedMeshFlags(flags);
+ }
+}
+
+bool LLVOVolume::canBeAnimatedObject() const
+{
+ F32 est_tris = recursiveGetEstTrianglesMax();
+ if (est_tris < 0 || est_tris > getAnimatedObjectMaxTris())
+ {
+ return false;
+ }
+ return true;
+}
+
+bool LLVOVolume::isAnimatedObject() const
+{
+ LLVOVolume *root_vol = (LLVOVolume*)getRootEdit();
+ bool root_is_animated_flag = root_vol->getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG;
+ return root_is_animated_flag;
+}
+
+// Called any time parenting changes for a volume. Update flags and
+// control av accordingly. This is called after parent has been
+// changed to new_parent, but before new_parent's mChildList has changed.
+
+// virtual
+void LLVOVolume::onReparent(LLViewerObject *old_parent, LLViewerObject *new_parent)
+{
+ LLVOVolume *old_volp = dynamic_cast<LLVOVolume*>(old_parent);
+
+ if (new_parent && !new_parent->isAvatar())
+ {
+ if (mControlAvatar.notNull())
+ {
+ // Here an animated object is being made the child of some
+ // other prim. Should remove the control av from the child.
+ LLControlAvatar *av = mControlAvatar;
+ mControlAvatar = NULL;
+ av->markForDeath();
+ }
+ }
+ if (old_volp && old_volp->isAnimatedObject())
+ {
+ if (old_volp->getControlAvatar())
+ {
+ // We have been removed from an animated object, need to do cleanup.
+ old_volp->getControlAvatar()->updateAttachmentOverrides();
+ old_volp->getControlAvatar()->updateAnimations();
+ }
+ }
+}
+
+// This needs to be called after onReparent(), because mChildList is
+// not updated until the end of LLViewerObject::addChild()
+
+// virtual
+void LLVOVolume::afterReparent()
+{
+ {
+ LL_DEBUGS("AnimatedObjects") << "new child added for parent "
+ << ((LLViewerObject*)getParent())->getID() << LL_ENDL;
+ }
+
+ if (isAnimatedObject() && getControlAvatar())
+ {
+ LL_DEBUGS("AnimatedObjects") << "adding attachment overrides, parent is animated object "
+ << ((LLViewerObject*)getParent())->getID() << LL_ENDL;
+
+ // MAINT-8239 - doing a full rebuild whenever parent is set
+ // makes the joint overrides load more robustly. In theory,
+ // addAttachmentOverrides should be sufficient, but in
+ // practice doing a full rebuild helps compensate for
+ // notifyMeshLoaded() not being called reliably enough.
+
+ // was: getControlAvatar()->addAttachmentOverridesForObject(this);
+ //getControlAvatar()->rebuildAttachmentOverrides();
+ getControlAvatar()->updateAnimations();
+ }
+ else
+ {
+ LL_DEBUGS("AnimatedObjects") << "not adding overrides, parent: "
+ << ((LLViewerObject*)getParent())->getID()
+ << " isAnimated: " << isAnimatedObject() << " cav "
+ << getControlAvatar() << LL_ENDL;
+ }
+}
+
+//----------------------------------------------------------------------------
+static LLTrace::BlockTimerStatHandle FTM_VOVOL_RIGGING_INFO("VOVol Rigging Info");
+
+void LLVOVolume::updateRiggingInfo()
+{
+ LL_RECORD_BLOCK_TIME(FTM_VOVOL_RIGGING_INFO);
+ if (isRiggedMesh())
+ {
+ const LLMeshSkinInfo* skin = getSkinInfo();
+ LLVOAvatar *avatar = getAvatar();
+ LLVolume *volume = getVolume();
+ if (skin && avatar && volume)
+ {
+ LL_DEBUGS("RigSpammish") << "starting, vovol " << this << " lod " << getLOD() << " last " << mLastRiggingInfoLOD << LL_ENDL;
+ if (getLOD()>mLastRiggingInfoLOD || getLOD()==3)
+ {
+ // Rigging info may need update
+ mJointRiggingInfoTab.clear();
+ for (S32 f = 0; f < volume->getNumVolumeFaces(); ++f)
+ {
+ LLVolumeFace& vol_face = volume->getVolumeFace(f);
+ LLSkinningUtil::updateRiggingInfo(skin, avatar, vol_face);
+ if (vol_face.mJointRiggingInfoTab.size()>0)
+ {
+ mJointRiggingInfoTab.merge(vol_face.mJointRiggingInfoTab);
+ }
+ }
+ // Keep the highest LOD info available.
+ mLastRiggingInfoLOD = getLOD();
+ LL_DEBUGS("RigSpammish") << "updated rigging info for LLVOVolume "
+ << this << " lod " << mLastRiggingInfoLOD
+ << LL_ENDL;
+ }
+ }
+ }
+}
+
//----------------------------------------------------------------------------
void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point)
@@ -3378,7 +3773,7 @@ void LLVOVolume::updateRadius()
BOOL LLVOVolume::isAttachment() const
{
- return mState != 0 ;
+ return mAttachmentState != 0 ;
}
BOOL LLVOVolume::isHUDAttachment() const
@@ -3386,7 +3781,7 @@ BOOL LLVOVolume::isHUDAttachment() const
// *NOTE: we assume hud attachment points are in defined range
// since this range is constant for backwards compatibility
// reasons this is probably a reasonable assumption to make
- S32 attachment_id = ATTACHMENT_ID_FROM_STATE(mState);
+ S32 attachment_id = ATTACHMENT_ID_FROM_STATE(mAttachmentState);
return ( attachment_id >= 31 && attachment_id <= 38 );
}
@@ -3466,16 +3861,25 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const
path_params = volume_params.getPathParams();
profile_params = volume_params.getProfileParams();
- F32 weighted_triangles = -1.0;
- getStreamingCost(NULL, NULL, &weighted_triangles);
-
- if (weighted_triangles > 0.0)
+ LLMeshCostData costs;
+ if (getCostData(costs))
{
- num_triangles = (U32)(weighted_triangles);
+ if (isAnimatedObject() && isRiggedMesh())
+ {
+ // Scaling here is to make animated object vs
+ // non-animated object ARC proportional to the
+ // corresponding calculations for streaming cost.
+ num_triangles = (ANIMATED_OBJECT_COST_PER_KTRI * 0.001 * costs.getEstTrisForStreamingCost())/0.06;
+ }
+ else
+ {
+ F32 radius = getScale().length()*0.5f;
+ num_triangles = costs.getRadiusWeightedTris(radius);
+ }
}
}
- if (num_triangles == 0)
+ if (num_triangles <= 0)
{
num_triangles = 4;
}
@@ -3489,12 +3893,11 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const
S32 size = gMeshRepo.getMeshSize(volume_params.getSculptID(), getLOD());
if ( size > 0)
{
- if (gMeshRepo.getSkinInfo(volume_params.getSculptID(), this))
+ if (isRiggedMesh())
{
// weighted attachment - 1 point for every 3 bytes
weighted_mesh = 1;
}
-
}
else
{
@@ -3663,6 +4066,14 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const
shame += media_faces * ARC_MEDIA_FACE_COST;
}
+ // Streaming cost for animated objects includes a fixed cost
+ // per linkset. Add a corresponding charge here translated into
+ // triangles, but not weighted by any graphics properties.
+ if (isAnimatedObject() && isRootEdit())
+ {
+ shame += (ANIMATED_OBJECT_BASE_COST/0.06) * 5.0f;
+ }
+
if (shame > mRenderComplexity_current)
{
mRenderComplexity_current = (S32)shame;
@@ -3671,16 +4082,68 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const
return (U32)shame;
}
-F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const
+F32 LLVOVolume::getEstTrianglesMax() const
{
- F32 radius = getScale().length()*0.5f;
-
- if (isMesh())
+ if (isMesh() && getVolume())
{
- return gMeshRepo.getStreamingCost(getVolume()->getParams().getSculptID(), radius, bytes, visible_bytes, mLOD, unscaled_value);
+ return gMeshRepo.getEstTrianglesMax(getVolume()->getParams().getSculptID());
}
- else
+ return 0.f;
+}
+
+F32 LLVOVolume::getEstTrianglesStreamingCost() const
+{
+ if (isMesh() && getVolume())
{
+ return gMeshRepo.getEstTrianglesStreamingCost(getVolume()->getParams().getSculptID());
+ }
+ return 0.f;
+}
+
+F32 LLVOVolume::getStreamingCost() const
+{
+ F32 radius = getScale().length()*0.5f;
+ F32 linkset_base_cost = 0.f;
+
+ LLMeshCostData costs;
+ if (getCostData(costs))
+ {
+ if (isAnimatedObject() && isRootEdit())
+ {
+ // Root object of an animated object has this to account for skeleton overhead.
+ linkset_base_cost = ANIMATED_OBJECT_BASE_COST;
+ }
+ if (isMesh())
+ {
+ if (isAnimatedObject() && isRiggedMesh())
+ {
+ return linkset_base_cost + costs.getTriangleBasedStreamingCost();
+ }
+ else
+ {
+ return linkset_base_cost + costs.getRadiusBasedStreamingCost(radius);
+ }
+ }
+ else
+ {
+ return linkset_base_cost + costs.getRadiusBasedStreamingCost(radius);
+ }
+ }
+ else
+ {
+ return 0.f;
+ }
+}
+
+// virtual
+bool LLVOVolume::getCostData(LLMeshCostData& costs) const
+{
+ if (isMesh())
+ {
+ return gMeshRepo.getCostData(getVolume()->getParams().getSculptID(), costs);
+ }
+ else
+ {
LLVolume* volume = getVolume();
S32 counts[4];
LLVolume::getLoDTriangleCounts(volume->getParams(), counts);
@@ -3691,8 +4154,8 @@ F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_v
header["medium_lod"]["size"] = counts[2] * 10;
header["high_lod"]["size"] = counts[3] * 10;
- return LLMeshRepository::getStreamingCost(header, radius, NULL, NULL, -1, unscaled_value);
- }
+ return gMeshRepo.getCostData(header, costs);
+ }
}
//static
@@ -3762,6 +4225,21 @@ void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_u
{
mVolumeImpl->onParameterChanged(param_type, data, in_use, local_origin);
}
+ if (!local_origin && param_type == LLNetworkData::PARAMS_EXTENDED_MESH)
+ {
+ U32 extended_mesh_flags = getExtendedMeshFlags();
+ bool enabled = (extended_mesh_flags & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG);
+ bool was_enabled = (getControlAvatar() != NULL);
+ if (enabled != was_enabled)
+ {
+ LL_DEBUGS("AnimatedObjects") << this
+ << " calling onSetExtendedMeshFlags, enabled " << (U32) enabled
+ << " was_enabled " << (U32) was_enabled
+ << " local_origin " << (U32) local_origin
+ << LL_ENDL;
+ onSetExtendedMeshFlags(extended_mesh_flags);
+ }
+ }
if (mDrawable.notNull())
{
BOOL is_light = getIsLight();
@@ -3775,10 +4253,17 @@ void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_u
void LLVOVolume::setSelected(BOOL sel)
{
LLViewerObject::setSelected(sel);
- if (mDrawable.notNull())
- {
- markForUpdate(TRUE);
- }
+ if (isAnimatedObject())
+ {
+ getRootEdit()->recursiveMarkForUpdate(TRUE);
+ }
+ else
+ {
+ if (mDrawable.notNull())
+ {
+ markForUpdate(TRUE);
+ }
+ }
}
void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
@@ -3888,6 +4373,22 @@ const LLMatrix4& LLVOVolume::getWorldMatrix(LLXformMatrix* xform) const
return xform->getWorldMatrix();
}
+void LLVOVolume::markForUpdate(BOOL priority)
+{
+ if (debugLoggingEnabled("AnimatedObjectsLinkset"))
+ {
+ if (isAnimatedObject() && isRiggedMesh())
+ {
+ std::string vobj_name = llformat("Vol%p", this);
+ F32 est_tris = getEstTrianglesMax();
+ LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " markForUpdate, tris " << est_tris << LL_ENDL;
+ }
+ }
+
+ LLViewerObject::markForUpdate(priority);
+ mVolumeChanged = TRUE;
+}
+
LLVector3 LLVOVolume::agentPositionToVolume(const LLVector3& pos) const
{
LLVector3 ret = pos - getRenderPosition();
@@ -4140,9 +4641,9 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
bool LLVOVolume::treatAsRigged()
{
return isSelected() &&
- isAttachment() &&
- mDrawable.notNull() &&
- mDrawable->isState(LLDrawable::RIGGED);
+ (isAttachment() || isAnimatedObject()) &&
+ mDrawable.notNull() &&
+ mDrawable->isState(LLDrawable::RIGGED);
}
LLRiggedVolume* LLVOVolume::getRiggedVolume()
@@ -4172,9 +4673,7 @@ void LLVOVolume::updateRiggedVolume(bool force_update)
}
LLVolume* volume = getVolume();
-
- const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(volume->getParams().getSculptID(), this);
-
+ const LLMeshSkinInfo* skin = getSkinInfo();
if (!skin)
{
clearRiggedVolume();
@@ -4182,7 +4681,6 @@ void LLVOVolume::updateRiggedVolume(bool force_update)
}
LLVOAvatar* avatar = getAvatar();
-
if (!avatar)
{
clearRiggedVolume();
@@ -4197,7 +4695,6 @@ void LLVOVolume::updateRiggedVolume(bool force_update)
}
mRiggedVolume->update(skin, avatar, volume);
-
}
static LLTrace::BlockTimerStatHandle FTM_SKIN_RIGGED("Skin");
@@ -4227,6 +4724,19 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
{
copyVolumeFaces(volume);
}
+ else
+ {
+ bool is_paused = avatar && avatar->areAnimationsPaused();
+ if (is_paused)
+ {
+ S32 frames_paused = LLFrameTimer::getFrameCount() - avatar->getMotionController().getPausedFrame();
+ if (frames_paused > 2)
+ {
+ return;
+ }
+ }
+ }
+
//build matrix palette
static const size_t kMaxJoints = LL_MAX_JOINTS_PER_MESH_OBJECT;
@@ -4235,6 +4745,9 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
U32 maxJoints = LLSkinningUtil::getMeshJointCount(skin);
LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, maxJoints, skin, avatar);
+ S32 rigged_vert_count = 0;
+ S32 rigged_face_count = 0;
+ LLVector4a box_min, box_max;
for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
{
const LLVolumeFace& vol_face = volume->getVolumeFace(i);
@@ -4256,6 +4769,8 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
LL_RECORD_BLOCK_TIME(FTM_SKIN_RIGGED);
U32 max_joints = LLSkinningUtil::getMaxJointCount();
+ rigged_vert_count += dst_face.mNumVertices;
+ rigged_face_count++;
for (U32 j = 0; j < dst_face.mNumVertices; ++j)
{
LLMatrix4a final_mat;
@@ -4270,11 +4785,17 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
}
//update bounding box
+ // VFExtents change
LLVector4a& min = dst_face.mExtents[0];
LLVector4a& max = dst_face.mExtents[1];
min = pos[0];
max = pos[1];
+ if (i==0)
+ {
+ box_min = min;
+ box_max = max;
+ }
for (U32 j = 1; j < dst_face.mNumVertices; ++j)
{
@@ -4282,6 +4803,9 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
max.setMax(max, pos[j]);
}
+ box_min.setMin(min,box_min);
+ box_max.setMax(max,box_max);
+
dst_face.mCenter->setAdd(dst_face.mExtents[0], dst_face.mExtents[1]);
dst_face.mCenter->mul(0.5f);
@@ -4300,6 +4824,10 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
}
}
}
+ mExtraDebugText = llformat("rigged %d/%d - box (%f %f %f) (%f %f %f)",
+ rigged_face_count, rigged_vert_count,
+ box_min[0], box_min[1], box_min[2],
+ box_max[0], box_max[1], box_max[2]);
}
U32 LLVOVolume::getPartitionType() const
@@ -4791,27 +5319,19 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
group->mBuilt = 1.f;
- LLVOAvatar* pAvatarVO = NULL;
-
LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge();
- if (bridge)
- {
- if (bridge->mAvatar.isNull())
- {
- LLViewerObject* vobj = bridge->mDrawable->getVObj();
- if (vobj)
- {
- bridge->mAvatar = vobj->getAvatar();
- }
- }
-
- pAvatarVO = bridge->mAvatar;
- }
+ LLViewerObject *vobj = NULL;
+ LLVOVolume *vol_obj = NULL;
- if (pAvatarVO)
+ if (bridge)
{
- pAvatarVO->subtractAttachmentArea( group->mSurfaceArea );
+ vobj = bridge->mDrawable->getVObj();
+ vol_obj = dynamic_cast<LLVOVolume*>(vobj);
}
+ if (vol_obj)
+ {
+ vol_obj->updateVisualComplexity();
+ }
group->mGeometryBytes = 0;
group->mSurfaceArea = 0;
@@ -4854,7 +5374,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_FACE_LIST);
//get all the faces into a list
- for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
+ for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin();
+ drawable_iter != group->getDataEnd(); ++drawable_iter)
{
LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
@@ -4869,12 +5390,14 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
LLVOVolume* vobj = drawablep->getVOVolume();
-
+
if (!vobj)
{
continue;
}
+ std::string vobj_name = llformat("Vol%p", vobj);
+
if (vobj->isMesh() &&
((vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded()) || !gMeshRepo.meshRezEnabled()))
{
@@ -4888,29 +5411,46 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
group->mSurfaceArea += volume->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]);
}
+ bool is_mesh = vobj->isMesh();
+ F32 est_tris = vobj->getEstTrianglesMax();
+
+ vobj->updateControlAvatar();
+
+ LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuilding, isAttachment: " << (U32) vobj->isAttachment()
+ << " is_mesh " << is_mesh
+ << " est_tris " << est_tris
+ << " is_animated " << vobj->isAnimatedObject()
+ << " can_animate " << vobj->canBeAnimatedObject()
+ << " cav " << vobj->getControlAvatar()
+ << " lod " << vobj->getLOD()
+ << " drawable rigged " << (drawablep->isState(LLDrawable::RIGGED))
+ << " drawable state " << drawablep->getState()
+ << " playing " << (U32) (vobj->getControlAvatar() ? vobj->getControlAvatar()->mPlaying : false)
+ << " frame " << LLFrameTimer::getFrameCount()
+ << LL_ENDL;
+
llassert_always(vobj);
vobj->updateTextureVirtualSize(true);
vobj->preRebuild();
drawablep->clearState(LLDrawable::HAS_ALPHA);
- bool rigged = vobj->isAttachment() &&
- vobj->isMesh() &&
- gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj);
-
- bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic();
-
- bool is_rigged = false;
-
- if (rigged && pAvatarVO)
+ if (vobj->isRiggedMesh() &&
+ ((vobj->isAnimatedObject() && vobj->getControlAvatar()) ||
+ (!vobj->isAnimatedObject() && vobj->getAvatar())))
{
- pAvatarVO->addAttachmentOverridesForObject(vobj);
- if (!LLApp::isExiting() && pAvatarVO->isSelf() && debugLoggingEnabled("AvatarAttachments"))
- {
- bool verbose = true;
- pAvatarVO->showAttachmentOverrides(verbose);
- }
+ vobj->getAvatar()->addAttachmentOverridesForObject(vobj, NULL, false);
}
+
+ // Standard rigged mesh attachments:
+ bool rigged = !vobj->isAnimatedObject() && vobj->isRiggedMesh() && vobj->isAttachment();
+ // Animated objects. Have to check for isRiggedMesh() to
+ // exclude static objects in animated object linksets.
+ rigged = rigged || (vobj->isAnimatedObject() && vobj->isRiggedMesh() &&
+ vobj->getControlAvatar() && vobj->getControlAvatar()->mPlaying);
+
+ bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic();
+ bool any_rigged_face = false;
//for each face
for (S32 i = 0; i < drawablep->getNumFaces(); i++)
@@ -4928,7 +5468,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
//sum up face verts and indices
drawablep->updateFaceSize(i);
- if (rigged)
+ if (rigged)
{
if (!facep->isState(LLFace::RIGGED))
{ //completely reset vertex buffer
@@ -4936,7 +5476,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
facep->setState(LLFace::RIGGED);
- is_rigged = true;
+ any_rigged_face = true;
//get drawpool of avatar with rigged face
LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);
@@ -5280,7 +5820,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
}
- if (is_rigged)
+ if (any_rigged_face)
{
if (!drawablep->isState(LLDrawable::RIGGED))
{
@@ -5294,6 +5834,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
else
{
drawablep->clearState(LLDrawable::RIGGED);
+ vobj->updateRiggedVolume();
}
}
}
@@ -5353,9 +5894,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
if(drawablep)
{
- drawablep->clearState(LLDrawable::REBUILD_ALL);
- }
- }
+ drawablep->clearState(LLDrawable::REBUILD_ALL);
+ }
+ }
}
group->mLastUpdateTime = gFrameTimeSeconds;
@@ -5368,11 +5909,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
mFaceList.clear();
-
- if (pAvatarVO)
- {
- pAvatarVO->addAttachmentArea( group->mSurfaceArea );
- }
}
static LLTrace::BlockTimerStatHandle FTM_REBUILD_MESH_FLUSH("Flush Mesh");
@@ -5401,6 +5937,15 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) )
{
LLVOVolume* vobj = drawablep->getVOVolume();
+ if (debugLoggingEnabled("AnimatedObjectsLinkset"))
+ {
+ if (vobj->isAnimatedObject() && vobj->isRiggedMesh())
+ {
+ std::string vobj_name = llformat("Vol%p", vobj);
+ F32 est_tris = vobj->getEstTrianglesMax();
+ LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuildMesh, tris " << est_tris << LL_ENDL;
+ }
+ }
if (vobj->isNoLOD()) continue;
vobj->preRebuild();