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.cpp455
1 files changed, 386 insertions, 69 deletions
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index f77b48ff80..fbbf0634ff 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -76,8 +76,13 @@
#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"
const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
const F32 FORCE_CULL_AREA = 8.f;
@@ -86,6 +91,7 @@ U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG = 1;
BOOL gAnimateTextures = TRUE;
//extern BOOL gHideSelectedObjects;
+S32 LLVOVolume::sForceLOD = -1;
F32 LLVOVolume::sLODFactor = 1.f;
F32 LLVOVolume::sLODSlopDistanceFactor = 0.5f; //Changing this to zero, effectively disables the LOD transition slop
F32 LLVOVolume::sDistanceFactor = 1.0f;
@@ -1096,16 +1102,26 @@ 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();
- }
+ updateVisualComplexity();
}
// sculpt replaces generate() for sculpted surfaces
@@ -1217,16 +1233,24 @@ void LLVOVolume::sculpt()
S32 LLVOVolume::computeLODDetail(F32 distance, F32 radius)
{
S32 cur_detail;
- if (LLPipeline::sDynamicLOD)
- {
- // We've got LOD in the profile, and in the twist. Use radius.
- F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance;
- cur_detail = LLVolumeLODGroup::getDetailFromTan(ll_round(tan_angle, 0.01f));
- }
- else
- {
- cur_detail = llclamp((S32) (sqrtf(radius)*LLVOVolume::sLODFactor*4.f), 0, 3);
- }
+ // AXON TEMP REMOVE
+ if (LLVOVolume::sForceLOD>=0 && LLVOVolume::sForceLOD<=3)
+ {
+ cur_detail = LLVOVolume::sForceLOD;
+ }
+ else
+ {
+ if (LLPipeline::sDynamicLOD)
+ {
+ // We've got LOD in the profile, and in the twist. Use radius.
+ F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance;
+ cur_detail = LLVolumeLODGroup::getDetailFromTan(ll_round(tan_angle, 0.01f));
+ }
+ else
+ {
+ cur_detail = llclamp((S32) (sqrtf(radius)*LLVOVolume::sLODFactor*4.f), 0, 3);
+ }
+ }
return cur_detail;
}
@@ -1280,22 +1304,34 @@ BOOL LLVOVolume::calcLOD()
distance *= F_PI/3.f;
cur_detail = computeLODDetail(ll_round(distance, 0.01f),
- ll_round(radius, 0.01f));
-
+ ll_round(radius, 0.01f));
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TRIANGLE_COUNT) && mDrawable->getFace(0))
+ {
+ if (isRootEdit() && getChildren().size()>0)
+ {
+ S32 total_tris = recursiveGetTriangleCount();
+ setDebugText(llformat("TRIS %d TOTAL %d", getTriangleCount(), total_tris));
+ }
+ else
+ {
+ setDebugText(llformat("TRIS %d", getTriangleCount()));
+ }
+
+ }
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)
{
mAppAngle = ll_round((F32) atan2( mDrawable->getRadius(), mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f);
mLOD = cur_detail;
- return TRUE;
+
+ return TRUE;
}
return FALSE;
@@ -1312,6 +1348,15 @@ BOOL LLVOVolume::updateLOD()
if (lod_changed)
{
+#if 1
+ // AXON debugging
+ if (isAnimatedObject() && isRiggedMesh())
+ {
+ std::string vobj_name = llformat("Vol%u", (U32) this);
+ F32 est_tris = getEstTrianglesMax();
+ LL_DEBUGS("AXONLinkset") << vobj_name << " updateLOD to " << getLOD() << ", tris " << est_tris << LL_ENDL;
+ }
+#endif
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
mLODChanged = TRUE;
}
@@ -1386,7 +1431,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)
@@ -1394,6 +1440,7 @@ BOOL LLVOVolume::setParent(LLViewerObject* parent)
gPipeline.markMoved(mDrawable);
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
}
+ updateAnimatedObjectStateOnReparent(old_parent, parent);
}
return ret ;
@@ -1651,6 +1698,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;
@@ -3269,6 +3321,152 @@ 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)
+{
+ // AXON - the check against isAnySelected() is "empirically
+ // derived": doing rebuildGeom() while in selection trashes the
+ // graphics state of animated objects. Skipping this update is OK
+ // because we get another one on deselect.
+
+ 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()->removeAttachmentOverridesForObject(this);
+ }
+ else
+ {
+ // Making an animated object into a rigged mesh
+ getAvatarAncestor()->addAttachmentOverridesForObject(this);
+ }
+ }
+}
+
+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("AXON") << (U32) 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;
+#if 0
+ if (root_is_animated_flag)
+ {
+ bool root_can_be_animated = root_vol->canBeAnimatedObject();
+ bool this_can_be_animated = (root_vol == this) ? root_can_be_animated : canBeAnimatedObject();
+ if (this_can_be_animated && root_can_be_animated)
+ {
+ return true;
+ }
+ }
+ return false;
+#endif
+}
+
+// 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.
+void LLVOVolume::updateAnimatedObjectStateOnReparent(LLViewerObject *old_parent, LLViewerObject *new_parent)
+{
+ LLVOVolume *old_volp = dynamic_cast<LLVOVolume*>(old_parent);
+
+ // AXON - depending on whether animated objects can be attached,
+ // we may want to include or remove the isAvatar() check.
+ // BUG??
+ if (new_parent && !new_parent->isAvatar())
+ {
+ if (mControlAvatar.notNull())
+ {
+ LLControlAvatar *av = mControlAvatar;
+ mControlAvatar = NULL;
+ av->markForDeath();
+ }
+ // If this succeeds now, it's because the new_parent is an animated object
+ if (isAnimatedObject() && getControlAvatar())
+ {
+ getControlAvatar()->addAttachmentOverridesForObject(this);
+ }
+ }
+ 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()->removeAttachmentOverridesForObject(this);
+ }
+ }
+}
+
//----------------------------------------------------------------------------
void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point)
@@ -3330,7 +3528,7 @@ void LLVOVolume::updateRadius()
BOOL LLVOVolume::isAttachment() const
{
- return mState != 0 ;
+ return mAttachmentState != 0 ;
}
BOOL LLVOVolume::isHUDAttachment() const
@@ -3338,7 +3536,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 );
}
@@ -3441,7 +3639,7 @@ 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;
@@ -3623,6 +3821,15 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const
return (U32)shame;
}
+F32 LLVOVolume::getEstTrianglesMax() const
+{
+ if (isMesh() && getVolume())
+ {
+ return gMeshRepo.getEstTrianglesMax(getVolume()->getParams().getSculptID());
+ }
+ return 0.f;
+}
+
F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const
{
F32 radius = getScale().length()*0.5f;
@@ -3714,6 +3921,24 @@ 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);
+ // AXON This is kind of a guess. Better if we could compare
+ // the before and after flags directly. What about cases where
+ // there's no control avatar for optimization reasons?
+ bool was_enabled = (getControlAvatar() != NULL);
+ if (enabled != was_enabled)
+ {
+ LL_DEBUGS("AXON") << (U32) 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();
@@ -3727,10 +3952,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)
@@ -3840,6 +4072,21 @@ const LLMatrix4& LLVOVolume::getWorldMatrix(LLXformMatrix* xform) const
return xform->getWorldMatrix();
}
+void LLVOVolume::markForUpdate(BOOL priority)
+{
+#if 1
+ // AXON debugging
+ if (isAnimatedObject() && isRiggedMesh())
+ {
+ std::string vobj_name = llformat("Vol%u", (U32) this);
+ F32 est_tris = getEstTrianglesMax();
+ LL_DEBUGS("AXONLinkset") << vobj_name << " markForUpdate, tris " << est_tris << LL_ENDL;
+ }
+#endif
+ LLViewerObject::markForUpdate(priority);
+ mVolumeChanged = TRUE;
+}
+
LLVector3 LLVOVolume::agentPositionToVolume(const LLVector3& pos) const
{
LLVector3 ret = pos - getRenderPosition();
@@ -4092,9 +4339,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()
@@ -4124,9 +4371,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();
@@ -4134,7 +4379,6 @@ void LLVOVolume::updateRiggedVolume(bool force_update)
}
LLVOAvatar* avatar = getAvatar();
-
if (!avatar)
{
clearRiggedVolume();
@@ -4149,7 +4393,6 @@ void LLVOVolume::updateRiggedVolume(bool force_update)
}
mRiggedVolume->update(skin, avatar, volume);
-
}
static LLTrace::BlockTimerStatHandle FTM_SKIN_RIGGED("Skin");
@@ -4187,6 +4430,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);
@@ -4208,6 +4454,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;
@@ -4227,12 +4475,19 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
min = pos[0];
max = pos[1];
+ if (i==0)
+ {
+ box_min = min;
+ box_max = max;
+ }
for (U32 j = 1; j < dst_face.mNumVertices; ++j)
{
min.setMin(min, pos[j]);
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);
@@ -4252,6 +4507,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
@@ -4643,8 +4902,6 @@ static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj)
void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
{
-
-
if (group->changeLOD())
{
group->mLastUpdateDistance = group->mDistance;
@@ -4665,27 +4922,29 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
group->mBuilt = 1.f;
- LLVOAvatar* pAvatarVO = NULL;
+ LLVOAvatar *rigged_av = NULL;
LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge();
+ LLViewerObject *vobj = NULL;
+ LLVOVolume *vol_obj = NULL;
+
if (bridge)
{
+ vobj = bridge->mDrawable->getVObj();
+ vol_obj = dynamic_cast<LLVOVolume*>(vobj);
if (bridge->mAvatar.isNull())
{
- LLViewerObject* vobj = bridge->mDrawable->getVObj();
if (vobj)
{
bridge->mAvatar = vobj->getAvatar();
}
}
-
- pAvatarVO = bridge->mAvatar;
- }
-
- if (pAvatarVO)
- {
- pAvatarVO->subtractAttachmentArea( group->mSurfaceArea );
+ rigged_av = bridge->mAvatar;
}
+ if (vol_obj)
+ {
+ vol_obj->updateVisualComplexity();
+ }
group->mGeometryBytes = 0;
group->mSurfaceArea = 0;
@@ -4728,7 +4987,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();
@@ -4743,12 +5003,14 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
LLVOVolume* vobj = drawablep->getVOVolume();
-
+
if (!vobj)
{
continue;
}
+ std::string vobj_name = llformat("Vol%u", (U32) vobj);
+
if (vobj->isMesh() &&
((vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded()) || !gMeshRepo.meshRezEnabled()))
{
@@ -4762,27 +5024,77 @@ 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();
+
+#if 1
+ LL_DEBUGS("AXONLinkset") << 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()
+ << " playing " << (U32) (vobj->getControlAvatar() ? vobj->getControlAvatar()->mPlaying : false)
+ << " frame " << LLFrameTimer::getFrameCount()
+ << LL_ENDL;
+#endif
+
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);
+ // 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);
+
+ if (vobj->isAnimatedObject())
+ {
+ if (!vobj->getControlAvatar())
+ {
+ F32 tri_count = vobj->getRootEdit()->recursiveGetEstTrianglesMax();
+ if (tri_count <= 0.f)
+ {
+ LL_DEBUGS("AXON") << vobj_name << " not calling linkControlAvatar(), because no tris" << LL_ENDL;
+ }
+ else
+ {
+ LL_DEBUGS("AXON") << vobj_name << " calling linkControlAvatar()" << LL_ENDL;
+ vobj->linkControlAvatar();
+ }
+ }
+ if (vobj->getControlAvatar())
+ {
+ rigged_av = vobj->getControlAvatar();
+ rigged_av->rebuildAttachmentOverrides();
+ }
+ }
+ else
+ {
+ // Not animated but has a control avatar - probably
+ // the checkbox has changed since the last rebuild.
+ if (vobj->getControlAvatar())
+ {
+ LL_DEBUGS("AXON") << vobj_name << " calling unlinkControlAvatar()" << LL_ENDL;
+ vobj->unlinkControlAvatar();
+ }
+ }
bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic();
- bool is_rigged = false;
+ bool any_rigged_face = false;
- if (rigged && pAvatarVO)
+ if (rigged && rigged_av)
{
- pAvatarVO->addAttachmentOverridesForObject(vobj);
- if (!LLApp::isExiting() && pAvatarVO->isSelf() && debugLoggingEnabled("AvatarAttachments"))
+ rigged_av->addAttachmentOverridesForObject(vobj);
+ if (!LLApp::isExiting() && rigged_av->isSelf() && debugLoggingEnabled("AvatarAttachments"))
{
bool verbose = true;
- pAvatarVO->showAttachmentOverrides(verbose);
+ rigged_av->showAttachmentOverrides(verbose);
}
}
@@ -4802,7 +5114,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
@@ -4810,7 +5122,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);
@@ -5154,7 +5466,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
}
- if (is_rigged)
+ if (any_rigged_face)
{
if (!drawablep->isState(LLDrawable::RIGGED))
{
@@ -5168,6 +5480,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
else
{
drawablep->clearState(LLDrawable::RIGGED);
+ vobj->updateRiggedVolume();
}
}
}
@@ -5221,9 +5534,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;
@@ -5236,11 +5549,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
}
mFaceList.clear();
-
- if (pAvatarVO)
- {
- pAvatarVO->addAttachmentArea( group->mSurfaceArea );
- }
}
static LLTrace::BlockTimerStatHandle FTM_REBUILD_MESH_FLUSH("Flush Mesh");
@@ -5269,6 +5577,15 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) )
{
LLVOVolume* vobj = drawablep->getVOVolume();
+#if 1
+ // AXON debugging
+ if (vobj->isAnimatedObject() && vobj->isRiggedMesh())
+ {
+ std::string vobj_name = llformat("Vol%u", (U32) vobj);
+ F32 est_tris = vobj->getEstTrianglesMax();
+ LL_DEBUGS("AXONLinkset") << vobj_name << " rebuildMesh, tris " << est_tris << LL_ENDL;
+ }
+#endif
vobj->preRebuild();
if (drawablep->isState(LLDrawable::ANIMATED_CHILD))