summaryrefslogtreecommitdiff
path: root/indra/newview/llvoavatar.cpp
diff options
context:
space:
mode:
authorAnchor <none@none>2018-11-28 15:16:01 -0800
committerAnchor <none@none>2018-11-28 15:16:01 -0800
commit014480a79b765587881d0c0f707a7ee191f5fe2e (patch)
tree4d759c7b996065cccb9171a51a1a3f05d04b6e31 /indra/newview/llvoavatar.cpp
parent076719013ec2dab7bf8fd1f4d1f953ab73d594e9 (diff)
parent8558ce5c600b810356010ba3cd6d534ef22f4081 (diff)
Merge
Diffstat (limited to 'indra/newview/llvoavatar.cpp')
-rw-r--r--indra/newview/llvoavatar.cpp1794
1 files changed, 1332 insertions, 462 deletions
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 2f3e8a31f8..b6b779072c 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -44,6 +44,7 @@
#include "llavatarnamecache.h"
#include "llavatarpropertiesprocessor.h"
#include "llavatarrendernotifier.h"
+#include "llcontrolavatar.h"
#include "llexperiencecache.h"
#include "llphysicsmotion.h"
#include "llviewercontrol.h"
@@ -109,6 +110,8 @@
#include "llcallstack.h"
#include "llrendersphere.h"
+#include <boost/lexical_cast.hpp>
+
extern F32 SPEED_ADJUST_MAX;
extern F32 SPEED_ADJUST_MAX_SEC;
extern F32 ANIM_SPEED_MAX;
@@ -142,7 +145,7 @@ const LLUUID ANIM_AGENT_PHYSICS_MOTION = LLUUID("7360e029-3cb8-ebc4-863e-212df44
//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------
-const F32 DELTA_TIME_MIN = 0.01f; // we clamp measured deltaTime to this
+const F32 DELTA_TIME_MIN = 0.01f; // we clamp measured delta_time to this
const F32 DELTA_TIME_MAX = 0.2f; // range to insure stability of computations.
const F32 PELVIS_LAG_FLYING = 0.22f;// pelvis follow half life while flying
@@ -617,6 +620,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
LLViewerObject(id, pcode, regionp),
mSpecialRenderMode(0),
mAttachmentSurfaceArea(0.f),
+ mAttachmentVisibleTriangleCount(0),
+ mAttachmentEstTriangleCount(0.f),
mReportedVisualComplexity(VISUAL_COMPLEXITY_UNKNOWN),
mTurning(FALSE),
mLastSkeletonSerialNum( 0 ),
@@ -625,6 +630,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mTyping(FALSE),
mMeshValid(FALSE),
mVisible(FALSE),
+ mLastImpostorUpdateFrameTime(0.f),
mWindFreq(0.f),
mRipplePhase( 0.f ),
mBelowWater(FALSE),
@@ -663,7 +669,10 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mLastUpdateRequestCOFVersion(-1),
mLastUpdateReceivedCOFVersion(-1),
mCachedMuteListUpdateTime(0),
- mCachedInMuteList(false)
+ mCachedInMuteList(false),
+ mIsControlAvatar(false),
+ mIsUIAvatar(false),
+ mEnableDefaultMotions(true)
{
LL_DEBUGS("AvatarRender") << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << LL_ENDL;
@@ -689,6 +698,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mNeedsImpostorUpdate = TRUE;
mNeedsAnimUpdate = TRUE;
+ mNeedsExtentUpdate = true;
+
mImpostorDistance = 0;
mImpostorPixelArea = 0;
@@ -718,6 +729,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mCurrentGesticulationLevel = 0;
+
mRuthTimer.reset();
mRuthDebugTimer.reset();
mDebugExistenceTimer.reset();
@@ -733,8 +745,15 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
std::string LLVOAvatar::avString() const
{
+ if (isControlAvatar())
+ {
+ return getFullname();
+ }
+ else
+ {
std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus());
return " Avatar '" + getFullname() + "' " + viz_string + " ";
+ }
}
void LLVOAvatar::debugAvatarRezTime(std::string notification_name, std::string comment)
@@ -1091,6 +1110,8 @@ void LLVOAvatar::initClass()
// Where should this be set initially?
LLJoint::setDebugJointNames(gSavedSettings.getString("DebugAvatarJoints"));
+
+ LLControlAvatar::sRegionChangedSlot = gAgent.addRegionChangedCallback(&LLControlAvatar::onRegionChanged);
}
@@ -1099,7 +1120,7 @@ void LLVOAvatar::cleanupClass()
}
// virtual
-void LLVOAvatar::initInstance(void)
+void LLVOAvatar::initInstance()
{
//-------------------------------------------------------------------------
// register motions
@@ -1170,6 +1191,8 @@ void LLVOAvatar::initInstance(void)
//VTPause(); // VTune
mVoiceVisualizer->setVoiceEnabled( LLVoiceClient::getInstance()->getVoiceEnabled( mID ) );
+
+ mInitFlags |= 1<<1;
}
// virtual
@@ -1222,8 +1245,6 @@ const LLVector3 LLVOAvatar::getRenderPosition() const
{
return getPosition() * mDrawable->getParent()->getRenderMatrix();
}
-
-
}
void LLVOAvatar::updateDrawable(BOOL force_damped)
@@ -1240,6 +1261,29 @@ void LLVOAvatar::onShift(const LLVector4a& shift_vector)
void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
{
+ if (mDrawable.isNull())
+ {
+ return;
+ }
+
+ if (mNeedsExtentUpdate)
+ {
+ calculateSpatialExtents(newMin,newMax);
+ mLastAnimExtents[0].set(newMin.getF32ptr());
+ mLastAnimExtents[1].set(newMax.getF32ptr());
+ mLastAnimBasePos = mPelvisp->getWorldPosition();
+ mNeedsExtentUpdate = false;
+ }
+ else
+ {
+ LLVector3 new_base_pos = mPelvisp->getWorldPosition();
+ LLVector3 shift = new_base_pos-mLastAnimBasePos;
+ mLastAnimExtents[0] += shift;
+ mLastAnimExtents[1] += shift;
+ mLastAnimBasePos = new_base_pos;
+
+ }
+
if (isImpostor() && !needsImpostorUpdate())
{
LLVector3 delta = getRenderPosition() -
@@ -1250,30 +1294,48 @@ void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
}
else
{
- getSpatialExtents(newMin,newMax);
- mLastAnimExtents[0].set(newMin.getF32ptr());
- mLastAnimExtents[1].set(newMax.getF32ptr());
+ newMin.load3(mLastAnimExtents[0].mV);
+ newMax.load3(mLastAnimExtents[1].mV);
LLVector4a pos_group;
pos_group.setAdd(newMin,newMax);
pos_group.mul(0.5f);
mImpostorOffset = LLVector3(pos_group.getF32ptr())-getRenderPosition();
mDrawable->setPositionGroup(pos_group);
}
-
-
}
-void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
+
+static LLTrace::BlockTimerStatHandle FTM_AVATAR_EXTENT_UPDATE("Av Upd Extent");
+
+void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
{
- LLVector4a buffer(0.25f);
+ LL_RECORD_BLOCK_TIME(FTM_AVATAR_EXTENT_UPDATE);
+
+ S32 box_detail = gSavedSettings.getS32("AvatarBoundingBoxComplexity");
+
+ // FIXME the update_min_max function used below assumes there is a
+ // known starting point, but in general there isn't. Ideally the
+ // box update logic should be modified to handle the no-point-yet
+ // case. For most models, starting with the pelvis is safe though.
+ LLVector3 zero_pos;
LLVector4a pos;
+ if (dist_vec(zero_pos, mPelvisp->getWorldPosition())<0.001)
+ {
+ // Don't use pelvis until av initialized
pos.load3(getRenderPosition().mV);
- newMin.setSub(pos, buffer);
- newMax.setAdd(pos, buffer);
+ }
+ else
+ {
+ pos.load3(mPelvisp->getWorldPosition().mV);
+ }
+ newMin = pos;
+ newMax = pos;
- float max_attachment_span = get_default_max_prim_scale() * 5.0f;
-
- //stretch bounding box by joint positions
+ //stretch bounding box by joint positions. Doing this for
+ //control avs, where the polymeshes aren't maintained or
+ //displayed, can give inaccurate boxes due to joints stuck at (0,0,0).
+ if ((box_detail>=1) && !isControlAvatar())
+ {
for (polymesh_map_t::iterator i = mPolyMeshes.begin(); i != mPolyMeshes.end(); ++i)
{
LLPolyMesh* mesh = i->second;
@@ -1285,16 +1347,21 @@ void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
}
}
- LLVector4a center, size;
- center.setAdd(newMin, newMax);
- center.mul(0.5f);
+ }
- size.setSub(newMax,newMin);
- size.mul(0.5f);
+ // Pad bounding box for starting joint, plus polymesh if
+ // applicable. Subsequent calcs should be accurate enough to not
+ // need padding.
+ LLVector4a padding(0.25);
+ newMin.sub(padding);
+ newMax.add(padding);
- mPixelArea = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance());
- //stretch bounding box by attachments
+ //stretch bounding box by static attachments
+ if (box_detail >= 2)
+ {
+ float max_attachment_span = get_default_max_prim_scale() * 5.0f;
+
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
@@ -1307,9 +1374,31 @@ void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
{
+ // Don't we need to look at children of attached_object as well?
const LLViewerObject* attached_object = (*attachment_iter);
if (attached_object && !attached_object->isHUDAttachment())
{
+ const LLVOVolume *vol = dynamic_cast<const LLVOVolume*>(attached_object);
+ if (vol && vol->isAnimatedObject())
+ {
+ // Animated objects already have a bounding box in their control av, use that.
+ // Could lag by a frame if there's no guarantee on order of processing for avatars.
+ LLControlAvatar *cav = vol->getControlAvatar();
+ if (cav)
+ {
+ LLVector4a cav_min;
+ cav_min.load3(cav->mLastAnimExtents[0].mV);
+ LLVector4a cav_max;
+ cav_max.load3(cav->mLastAnimExtents[1].mV);
+ update_min_max(newMin,newMax,cav_min);
+ update_min_max(newMin,newMax,cav_max);
+ continue;
+ }
+ }
+ if (vol && vol->isRiggedMesh())
+ {
+ continue;
+ }
LLDrawable* drawable = attached_object->mDrawable;
if (drawable && !drawable->isState(LLDrawable::RIGGED))
{
@@ -1337,11 +1426,53 @@ void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
}
}
}
+ }
- //pad bounding box
+ // Stretch bounding box by rigged mesh joint boxes
+ if (box_detail>=3)
+ {
+ updateRiggingInfo();
+ for (S32 joint_num = 0; joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS; joint_num++)
+ {
+ LLJoint *joint = getJoint(joint_num);
+ LLJointRiggingInfo *rig_info = NULL;
+ if (joint_num < mJointRiggingInfoTab.size())
+ {
+ rig_info = &mJointRiggingInfoTab[joint_num];
+ }
- newMin.sub(buffer);
- newMax.add(buffer);
+ if (joint && rig_info && rig_info->isRiggedTo())
+ {
+ LLViewerJointAttachment *as_joint_attach = dynamic_cast<LLViewerJointAttachment*>(joint);
+ if (as_joint_attach && as_joint_attach->getIsHUDAttachment())
+ {
+ // Ignore bounding box of HUD joints
+ continue;
+ }
+ LLMatrix4a mat;
+ LLVector4a new_extents[2];
+ mat.loadu(joint->getWorldMatrix());
+ matMulBoundBox(mat, rig_info->getRiggedExtents(), new_extents);
+ update_min_max(newMin, newMax, new_extents[0]);
+ update_min_max(newMin, newMax, new_extents[1]);
+ //if (isSelf())
+ //{
+ // LL_INFOS() << joint->getName() << " extents " << new_extents[0] << "," << new_extents[1] << LL_ENDL;
+ // LL_INFOS() << joint->getName() << " av box is " << newMin << "," << newMax << LL_ENDL;
+ //}
+ }
+ }
+ }
+
+ // Update pixel area
+ LLVector4a center, size;
+ center.setAdd(newMin, newMax);
+ center.mul(0.5f);
+
+ size.setSub(newMax,newMin);
+ size.mul(0.5f);
+
+ mPixelArea = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance());
}
void render_sphere_and_line(const LLVector3& begin_pos, const LLVector3& end_pos, F32 sphere_scale, const LLVector3& occ_color, const LLVector3& visible_color)
@@ -1404,13 +1535,29 @@ void LLVOAvatar::renderCollisionVolumes()
static F32 sphere_scale = 1.0f;
static F32 center_dot_scale = 0.05f;
- static LLVector3 CV_COLOR_OCCLUDED(0.0f, 0.0f, 1.0f);
- static LLVector3 CV_COLOR_VISIBLE(0.5f, 0.5f, 1.0f);
- static LLVector3 DOT_COLOR_OCCLUDED(1.0f, 1.0f, 1.0f);
- static LLVector3 DOT_COLOR_VISIBLE(1.0f, 1.0f, 1.0f);
+ static LLVector3 BLUE(0.0f, 0.0f, 1.0f);
+ static LLVector3 PASTEL_BLUE(0.5f, 0.5f, 1.0f);
+ static LLVector3 RED(1.0f, 0.0f, 0.0f);
+ static LLVector3 PASTEL_RED(1.0f, 0.5f, 0.5f);
+ static LLVector3 WHITE(1.0f, 1.0f, 1.0f);
+
- render_sphere_and_line(begin_pos, end_pos, sphere_scale, CV_COLOR_OCCLUDED, CV_COLOR_VISIBLE);
- render_sphere_and_line(begin_pos, end_pos, center_dot_scale, DOT_COLOR_OCCLUDED, DOT_COLOR_VISIBLE);
+ LLVector3 cv_color_occluded;
+ LLVector3 cv_color_visible;
+ LLVector3 dot_color_occluded(WHITE);
+ LLVector3 dot_color_visible(WHITE);
+ if (isControlAvatar())
+ {
+ cv_color_occluded = RED;
+ cv_color_visible = PASTEL_RED;
+ }
+ else
+ {
+ cv_color_occluded = BLUE;
+ cv_color_visible = PASTEL_BLUE;
+ }
+ render_sphere_and_line(begin_pos, end_pos, sphere_scale, cv_color_occluded, cv_color_visible);
+ render_sphere_and_line(begin_pos, end_pos, center_dot_scale, dot_color_occluded, dot_color_visible);
gGL.popMatrix();
}
@@ -1422,9 +1569,6 @@ void LLVOAvatar::renderCollisionVolumes()
mNameText->lineSegmentIntersect(unused, unused, unused, TRUE);
}
-
- mDebugText.clear();
- addDebugText(ostr.str());
}
void LLVOAvatar::renderBones()
@@ -1467,7 +1611,7 @@ void LLVOAvatar::renderBones()
}
else
{
- if (jointIsRiggedTo(jointp->getName()))
+ if (jointIsRiggedTo(jointp))
{
occ_color = RIGGED_COLOR_OCCLUDED;
visible_color = RIGGED_COLOR_VISIBLE;
@@ -1595,6 +1739,11 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
return FALSE;
}
+ if (isControlAvatar())
+ {
+ return FALSE;
+ }
+
if (lineSegmentBoundingBox(start, end))
{
for (S32 i = 0; i < mNumCollisionVolumes; ++i)
@@ -1680,6 +1829,7 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
return FALSE;
}
+// virtual
LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector4a& start, const LLVector4a& end,
S32 face,
BOOL pick_transparent,
@@ -1796,7 +1946,11 @@ void LLVOAvatar::buildCharacter()
mAahMorph = getVisualParam( "Express_Open_Mouth" );
}
+ // Currently disabled for control avatars (animated objects), enabled for all others.
+ if (mEnableDefaultMotions)
+ {
startDefaultMotions();
+ }
//-------------------------------------------------------------------------
// restart any currently active motions
@@ -1856,7 +2010,7 @@ void LLVOAvatar::resetVisualParams()
void LLVOAvatar::resetSkeleton(bool reset_animations)
{
LL_DEBUGS("Avatar") << avString() << " reset starts" << LL_ENDL;
- if (!mLastProcessedAppearance)
+ if (!isControlAvatar() && !mLastProcessedAppearance)
{
LL_WARNS() << "Can't reset avatar; no appearance message has been received yet." << LL_ENDL;
return;
@@ -1910,12 +2064,15 @@ void LLVOAvatar::resetSkeleton(bool reset_animations)
}
// Reset tweakable params to preserved state
+ if (mLastProcessedAppearance)
+ {
bool slam_params = true;
applyParsedAppearanceMessage(*mLastProcessedAppearance, slam_params);
+ }
updateVisualParams();
// Restore attachment pos overrides
- rebuildAttachmentOverrides();
+ updateAttachmentOverrides();
// Animations
if (reset_animations)
@@ -1942,7 +2099,7 @@ void LLVOAvatar::resetSkeleton(bool reset_animations)
//-----------------------------------------------------------------------------
void LLVOAvatar::releaseMeshData()
{
- if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || mIsDummy)
+ if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || isUIAvatar())
{
return;
}
@@ -1994,6 +2151,10 @@ void LLVOAvatar::releaseMeshData()
void LLVOAvatar::restoreMeshData()
{
llassert(!isSelf());
+ if (mDrawable.isNull())
+ {
+ return;
+ }
//LL_INFOS() << "Restoring" << LL_ENDL;
mMeshValid = TRUE;
@@ -2292,6 +2453,18 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
return;
}
+ // Update should be happening max once per frame.
+ const S32 upd_freq = 4; // force update every upd_freq frames.
+ if ((mLastAnimExtents[0]==LLVector3())||
+ (mLastAnimExtents[1])==LLVector3())
+ {
+ mNeedsExtentUpdate = true;
+ }
+ else
+ {
+ mNeedsExtentUpdate = ((LLDrawable::getCurrentFrame()+mID.mData[0])%upd_freq==0);
+ }
+
LLScopedContextString str("avatar_idle_update " + getFullname());
checkTextureLoading() ;
@@ -2304,7 +2477,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
{
LL_RECORD_BLOCK_TIME(FTM_JOINT_UPDATE);
- if (mIsSitting && getParent())
+ if (isSitting() && getParent())
{
LLViewerObject *root_object = (LLViewerObject*)getRoot();
LLDrawable* drawablep = root_object->mDrawable;
@@ -2470,7 +2643,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
// (the following version uses a tweak of "mHeadOffset" which handle sitting vs. standing)
//--------------------------------------------------------------------------------------------
- if ( mIsSitting )
+ if ( isSitting() )
{
LLVector3 headOffset = LLVector3( 0.0f, 0.0f, mHeadOffset.mV[2] );
mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot->getWorldPosition() + headOffset );
@@ -2574,8 +2747,10 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
}
else
{
- //VECTORIZE THIS
- getSpatialExtents(ext[0], ext[1]);
+ ext[0].load3(mLastAnimExtents[0].mV);
+ ext[1].load3(mLastAnimExtents[1].mV);
+ // Expensive. Just call this once per frame, in updateSpatialExtents();
+ //calculateSpatialExtents(ext[0], ext[1]);
LLVector4a diff;
diff.setSub(ext[1], mImpostorExtents[1]);
if (diff.getLength3().getF32() > 0.05f)
@@ -2594,6 +2769,8 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
}
}
+ if (mDrawable.notNull())
+ {
mDrawable->movePartition();
//force a move if sitting on an active object
@@ -2601,6 +2778,7 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
{
gPipeline.markMoved(mDrawable, TRUE);
}
+ }
}
void LLVOAvatar::idleUpdateAppearanceAnimation()
@@ -2761,7 +2939,8 @@ void LLVOAvatar::idleUpdateLoadingEffect()
LLPartData::LL_PART_EMISSIVE_MASK | // LLPartData::LL_PART_FOLLOW_SRC_MASK |
LLPartData::LL_PART_TARGET_POS_MASK );
- if (!isTooComplex()) // do not generate particles for overly-complex avatars
+ // do not generate particles for dummy or overly-complex avatars
+ if (!mIsDummy && !isTooComplex())
{
setParticleSource(particle_parameters, getID());
}
@@ -3359,13 +3538,8 @@ bool LLVOAvatar::isInMuteList()
return muted;
}
-void LLVOAvatar::updateDebugText()
+void LLVOAvatar::updateAppearanceMessageDebugText()
{
- // clear debug text
- mDebugText.clear();
-
- if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
- {
S32 central_bake_version = -1;
if (getRegion())
{
@@ -3407,7 +3581,7 @@ void LLVOAvatar::updateDebugText()
if (hover_offset[2] != 0.0)
{
debug_line += llformat(" hov_z: %.3f", hover_offset[2]);
- debug_line += llformat(" %s", (mIsSitting ? "S" : "T"));
+ debug_line += llformat(" %s", (isSitting() ? "S" : "T"));
debug_line += llformat("%s", (isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED) ? "G" : "-"));
}
LLVector3 ankle_right_pos_agent = mFootRightp->getWorldPosition();
@@ -3421,16 +3595,50 @@ void LLVOAvatar::updateDebugText()
LLVector3 pelvis_pos = mPelvisp->getPosition();
debug_line += llformat(" rp %.3f pp %.3f", root_pos[2], pelvis_pos[2]);
+ S32 is_visible = (S32) isVisible();
+ S32 is_m_visible = (S32) mVisible;
+ debug_line += llformat(" v %d/%d", is_visible, is_m_visible);
+
addDebugText(debug_line);
+}
+
+LLViewerInventoryItem* getObjectInventoryItem(LLViewerObject *vobj, LLUUID asset_id)
+{
+ LLViewerInventoryItem *item = NULL;
+
+ if (vobj)
+ {
+ if (vobj->getInventorySerial()<=0)
+ {
+ vobj->requestInventory();
}
- if (gSavedSettings.getBOOL("DebugAvatarCompositeBaked"))
+ item = vobj->getInventoryItemByAsset(asset_id);
+ }
+ return item;
+}
+
+LLViewerInventoryItem* recursiveGetObjectInventoryItem(LLViewerObject *vobj, LLUUID asset_id)
+{
+ LLViewerInventoryItem *item = getObjectInventoryItem(vobj, asset_id);
+ if (!item)
+ {
+ LLViewerObject::const_child_list_t& children = vobj->getChildren();
+ for (LLViewerObject::const_child_list_t::const_iterator it = children.begin();
+ it != children.end(); ++it)
+ {
+ LLViewerObject *childp = *it;
+ item = getObjectInventoryItem(childp, asset_id);
+ if (item)
{
- if (!mBakedTextureDebugText.empty())
- addDebugText(mBakedTextureDebugText);
+ break;
+ }
+ }
}
+ return item;
+}
- if (LLVOAvatar::sShowAnimationDebug)
- {
+void LLVOAvatar::updateAnimationDebugText()
+{
for (LLMotionController::motion_list_t::iterator iter = mMotionController.getActiveMotions().begin();
iter != mMotionController.getActiveMotions().end(); ++iter)
{
@@ -3438,7 +3646,22 @@ void LLVOAvatar::updateDebugText()
if (motionp->getMinPixelArea() < getPixelArea())
{
std::string output;
- if (motionp->getName().empty())
+ std::string motion_name = motionp->getName();
+ if (motion_name.empty())
+ {
+ if (isControlAvatar())
+ {
+ LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this);
+ // Try to get name from inventory of associated object
+ LLVOVolume *volp = control_av->mRootVolp;
+ LLViewerInventoryItem *item = recursiveGetObjectInventoryItem(volp,motionp->getID());
+ if (item)
+ {
+ motion_name = item->getName();
+ }
+ }
+ }
+ if (motion_name.empty())
{
std::string name;
if (gAgent.isGodlikeWithoutAdminMenuFakery() || isSelf())
@@ -3493,7 +3716,6 @@ void LLVOAvatar::updateDebugText()
{
name = LLUUID::null.asString();
}
-
output = llformat("%s - %d",
name.c_str(),
(U32)motionp->getPriority());
@@ -3501,12 +3723,33 @@ void LLVOAvatar::updateDebugText()
else
{
output = llformat("%s - %d",
- motionp->getName().c_str(),
+ motion_name.c_str(),
(U32)motionp->getPriority());
}
addDebugText(output);
}
}
+}
+
+void LLVOAvatar::updateDebugText()
+{
+ // Leave mDebugText uncleared here, in case a derived class has added some state first
+
+ if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
+ {
+ updateAppearanceMessageDebugText();
+ }
+
+ if (gSavedSettings.getBOOL("DebugAvatarCompositeBaked"))
+ {
+ if (!mBakedTextureDebugText.empty())
+ addDebugText(mBakedTextureDebugText);
+ }
+
+ // Develop -> Avatar -> Animation Info
+ if (LLVOAvatar::sShowAnimationDebug)
+ {
+ updateAnimationDebugText();
}
if (!mDebugText.size() && mText.notNull())
@@ -3519,50 +3762,124 @@ void LLVOAvatar::updateDebugText()
setDebugText(mDebugText);
}
mDebugText.clear();
-
}
//------------------------------------------------------------------------
-// updateCharacter()
-// called on both your avatar and other avatars
+// updateFootstepSounds
+// Factored out from updateCharacter()
+// Generate footstep sounds when feet hit the ground
//------------------------------------------------------------------------
-BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
-{
- updateDebugText();
+void LLVOAvatar::updateFootstepSounds()
+{
+ if (mIsDummy)
+ {
+ return;
+ }
- if (!mIsBuilt)
+ //-------------------------------------------------------------------------
+ // Find the ground under each foot, these are used for a variety
+ // of things that follow
+ //-------------------------------------------------------------------------
+ LLVector3 ankle_left_pos_agent = mFootLeftp->getWorldPosition();
+ LLVector3 ankle_right_pos_agent = mFootRightp->getWorldPosition();
+
+ LLVector3 ankle_left_ground_agent = ankle_left_pos_agent;
+ LLVector3 ankle_right_ground_agent = ankle_right_pos_agent;
+ LLVector3 normal;
+ resolveHeightAgent(ankle_left_pos_agent, ankle_left_ground_agent, normal);
+ resolveHeightAgent(ankle_right_pos_agent, ankle_right_ground_agent, normal);
+
+ F32 leftElev = llmax(-0.2f, ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ]);
+ F32 rightElev = llmax(-0.2f, ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]);
+
+ if (!isSitting())
{
- return FALSE;
+ //-------------------------------------------------------------------------
+ // Figure out which foot is on ground
+ //-------------------------------------------------------------------------
+ if (!mInAir)
+ {
+ if ((leftElev < 0.0f) || (rightElev < 0.0f))
+ {
+ ankle_left_pos_agent = mFootLeftp->getWorldPosition();
+ ankle_right_pos_agent = mFootRightp->getWorldPosition();
+ leftElev = ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ];
+ rightElev = ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ];
+ }
+ }
}
+
+ const LLUUID AGENT_FOOTSTEP_ANIMS[] = {ANIM_AGENT_WALK, ANIM_AGENT_RUN, ANIM_AGENT_LAND};
+ const S32 NUM_AGENT_FOOTSTEP_ANIMS = LL_ARRAY_SIZE(AGENT_FOOTSTEP_ANIMS);
- BOOL visible = isVisible();
+ if ( gAudiop && isAnyAnimationSignaled(AGENT_FOOTSTEP_ANIMS, NUM_AGENT_FOOTSTEP_ANIMS) )
+ {
+ BOOL playSound = FALSE;
+ LLVector3 foot_pos_agent;
- // For fading out the names above heads, only let the timer
- // run if we're visible.
- if (mDrawable.notNull() && !visible)
+ BOOL onGroundLeft = (leftElev <= 0.05f);
+ BOOL onGroundRight = (rightElev <= 0.05f);
+
+ // did left foot hit the ground?
+ if ( onGroundLeft && !mWasOnGroundLeft )
+ {
+ foot_pos_agent = ankle_left_pos_agent;
+ playSound = TRUE;
+ }
+
+ // did right foot hit the ground?
+ if ( onGroundRight && !mWasOnGroundRight )
{
- mTimeVisible.reset();
+ foot_pos_agent = ankle_right_pos_agent;
+ playSound = TRUE;
}
- //--------------------------------------------------------------------
- // the rest should only be done occasionally for far away avatars
- //--------------------------------------------------------------------
+ mWasOnGroundLeft = onGroundLeft;
+ mWasOnGroundRight = onGroundRight;
+
+ if ( playSound )
+ {
+ const F32 STEP_VOLUME = 0.1f;
+ const LLUUID& step_sound_id = getStepSound();
+
+ LLVector3d foot_pos_global = gAgent.getPosGlobalFromAgent(foot_pos_agent);
+
+ if (LLViewerParcelMgr::getInstance()->canHearSound(foot_pos_global)
+ && !LLMuteList::getInstance()->isMuted(getID(), LLMute::flagObjectSounds))
+ {
+ gAudiop->triggerSound(step_sound_id, getID(), STEP_VOLUME, LLAudioEngine::AUDIO_TYPE_AMBIENT, foot_pos_global);
+ }
+ }
+ }
+}
+//------------------------------------------------------------------------
+// computeUpdatePeriod()
+// Factored out from updateCharacter()
+// Set new value for mUpdatePeriod based on distance and various other factors.
+//------------------------------------------------------------------------
+void LLVOAvatar::computeUpdatePeriod()
+{
bool visually_muted = isVisuallyMuted();
- if (visible && (!isSelf() || visually_muted) && !mIsDummy && sUseImpostors && !mNeedsAnimUpdate && !sFreezeCounter)
+ if (mDrawable.notNull()
+ && isVisible()
+ && (!isSelf() || visually_muted)
+ && !isUIAvatar()
+ && sUseImpostors
+ && !mNeedsAnimUpdate
+ && !sFreezeCounter)
{
const LLVector4a* ext = mDrawable->getSpatialExtents();
LLVector4a size;
size.setSub(ext[1],ext[0]);
F32 mag = size.getLength3().getF32()*0.5f;
-
F32 impostor_area = 256.f*512.f*(8.125f - LLVOAvatar::sLODFactor*8.f);
if (visually_muted)
{ // visually muted avatars update at 16 hz
mUpdatePeriod = 16;
}
- else if ( ! shouldImpostor()
+ else if (! shouldImpostor()
|| mDrawable->mDistanceWRTCamera < 1.f + mag)
{ // first 25% of max visible avatars are not impostored
// also, don't impostor avatars whose bounding box may be penetrating the
@@ -3586,149 +3903,24 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
//nearby avatars, update the impostors more frequently.
mUpdatePeriod = 4;
}
-
- visible = (LLDrawable::getCurrentFrame()+mID.mData[0])%mUpdatePeriod == 0 ? TRUE : FALSE;
}
else
{
mUpdatePeriod = 1;
}
+}
- // don't early out for your own avatar, as we rely on your animations playing reliably
- // for example, the "turn around" animation when entering customize avatar needs to trigger
- // even when your avatar is offscreen
- if (!visible && !isSelf())
- {
- updateMotions(LLCharacter::HIDDEN_UPDATE);
- return FALSE;
- }
-
- // change animation time quanta based on avatar render load
- if (!isSelf() && !mIsDummy)
- {
- F32 time_quantum = clamp_rescale((F32)sInstances.size(), 10.f, 35.f, 0.f, 0.25f);
- F32 pixel_area_scale = clamp_rescale(mPixelArea, 100, 5000, 1.f, 0.f);
- F32 time_step = time_quantum * pixel_area_scale;
- if (time_step != 0.f)
- {
- // disable walk motion servo controller as it doesn't work with motion timesteps
- stopMotion(ANIM_AGENT_WALK_ADJUST);
- removeAnimationData("Walk Speed");
- }
- mMotionController.setTimeStep(time_step);
- // LL_INFOS() << "Setting timestep to " << time_quantum * pixel_area_scale << LL_ENDL;
- }
-
- if (getParent() && !mIsSitting)
- {
- sitOnObject((LLViewerObject*)getParent());
- }
- else if (!getParent() && mIsSitting && !isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED))
- {
- getOffObject();
- }
-
- //--------------------------------------------------------------------
- // create local variables in world coords for region position values
- //--------------------------------------------------------------------
- F32 speed;
- LLVector3 normal;
-
- LLVector3 xyVel = getVelocity();
- xyVel.mV[VZ] = 0.0f;
- speed = xyVel.length();
- // remembering the value here prevents a display glitch if the
- // animation gets toggled during this update.
- bool was_sit_ground_constrained = isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED);
-
- if (!(mIsSitting && getParent()))
- {
- // This case includes all configurations except sitting on an
- // object, so does include ground sit.
-
- //--------------------------------------------------------------------
- // get timing info
- // handle initial condition case
- //--------------------------------------------------------------------
- F32 animation_time = mAnimTimer.getElapsedTimeF32();
- if (mTimeLast == 0.0f)
- {
- mTimeLast = animation_time;
-
- // put the pelvis at slaved position/mRotation
- // SL-315
- mRoot->setWorldPosition( getPositionAgent() ); // first frame
- mRoot->setWorldRotation( getRotation() );
- }
-
- //--------------------------------------------------------------------
- // dont' let dT get larger than 1/5th of a second
- //--------------------------------------------------------------------
- F32 deltaTime = animation_time - mTimeLast;
-
- deltaTime = llclamp( deltaTime, DELTA_TIME_MIN, DELTA_TIME_MAX );
- mTimeLast = animation_time;
-
- mSpeedAccum = (mSpeedAccum * 0.95f) + (speed * 0.05f);
-
- //--------------------------------------------------------------------
- // compute the position of the avatar's root
- //--------------------------------------------------------------------
- LLVector3d root_pos;
- LLVector3d ground_under_pelvis;
-
- if (isSelf())
- {
- gAgent.setPositionAgent(getRenderPosition());
- }
-
- root_pos = gAgent.getPosGlobalFromAgent(getRenderPosition());
- root_pos.mdV[VZ] += getVisualParamWeight(AVATAR_HOVER);
-
-
- resolveHeightGlobal(root_pos, ground_under_pelvis, normal);
- F32 foot_to_ground = (F32) (root_pos.mdV[VZ] - mPelvisToFoot - ground_under_pelvis.mdV[VZ]);
- BOOL in_air = ((!LLWorld::getInstance()->getRegionFromPosGlobal(ground_under_pelvis)) ||
- foot_to_ground > FOOT_GROUND_COLLISION_TOLERANCE);
-
- if (in_air && !mInAir)
- {
- mTimeInAir.reset();
- }
- mInAir = in_air;
-
- // SL-402: with the ability to animate the position of joints
- // that affect the body size calculation, computed body size
- // can get stale much more easily. Simplest fix is to update
- // it frequently.
- // SL-427: this appears to be too frequent, moving to only do on animation state change.
- //computeBodySize();
-
- // correct for the fact that the pelvis is not necessarily the center
- // of the agent's physical representation
- root_pos.mdV[VZ] -= (0.5f * mBodySize.mV[VZ]) - mPelvisToFoot;
- if (!mIsSitting && !was_sit_ground_constrained)
- {
- root_pos += LLVector3d(getHoverOffset());
- }
-
- LLVector3 newPosition = gAgent.getPosAgentFromGlobal(root_pos);
-
-
- if (newPosition != mRoot->getXform()->getWorldPosition())
- {
- mRoot->touch();
- // SL-315
- mRoot->setWorldPosition( newPosition ); // regular update
- }
-
-
- //--------------------------------------------------------------------
- // Propagate viewer object rotation to root of avatar
- //--------------------------------------------------------------------
- if (!isAnyAnimationSignaled(AGENT_NO_ROTATE_ANIMS, NUM_AGENT_NO_ROTATE_ANIMS))
- {
+//------------------------------------------------------------------------
+// updateOrientation()
+// Factored out from updateCharacter()
+// This is used by updateCharacter() to update the avatar's orientation:
+// - updates mTurning state
+// - updates rotation of the mRoot joint in the skeleton
+// - for self, calls setControlFlags() to notify the simulator about any turns
+//------------------------------------------------------------------------
+void LLVOAvatar::updateOrientation(LLAgent& agent, F32 speed, F32 delta_time)
+{
LLQuaternion iQ;
LLVector3 upDir( 0.0f, 0.0f, 1.0f );
@@ -3785,7 +3977,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
root_rotation.getEulerAngles(&root_roll, &root_pitch, &root_yaw);
// When moving very slow, the pelvis is allowed to deviate from the
- // forward direction to allow it to hold it's position while the torso
+ // forward direction to allow it to hold its position while the torso
// and head turn. Once in motion, it must conform however.
BOOL self_in_mouselook = isSelf() && gAgentCamera.cameraMouselook();
@@ -3873,20 +4065,266 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
pelvis_lag_time = PELVIS_LAG_WALKING;
}
- F32 u = llclamp((deltaTime / pelvis_lag_time), 0.0f, 1.0f);
+ F32 u = llclamp((delta_time / pelvis_lag_time), 0.0f, 1.0f);
mRoot->setWorldRotation( slerp(u, mRoot->getWorldRotation(), wQv) );
+}
+
+//------------------------------------------------------------------------
+// updateTimeStep()
+// Factored out from updateCharacter().
+//
+// Updates the time step used by the motion controller, based on area
+// and avatar count criteria. This will also stop the
+// ANIM_AGENT_WALK_ADJUST animation under some circumstances.
+// ------------------------------------------------------------------------
+void LLVOAvatar::updateTimeStep()
+{
+ if (!isSelf() && !isUIAvatar()) // ie, non-self avatars, and animated objects will be affected.
+ {
+ // Note that sInstances counts animated objects and
+ // standard avatars in the same bucket. Is this desirable?
+ F32 time_quantum = clamp_rescale((F32)sInstances.size(), 10.f, 35.f, 0.f, 0.25f);
+ F32 pixel_area_scale = clamp_rescale(mPixelArea, 100, 5000, 1.f, 0.f);
+ F32 time_step = time_quantum * pixel_area_scale;
+ // Extrema:
+ // If number of avs is 10 or less, time_step is unmodified (flagged with 0.0).
+ // If area of av is 5000 or greater, time_step is unmodified (flagged with 0.0).
+ // If number of avs is 35 or greater, and area of av is 100 or less,
+ // time_step takes the maximum possible value of 0.25.
+ // Other situations will give values within the (0, 0.25) range.
+ if (time_step != 0.f)
+ {
+ // disable walk motion servo controller as it doesn't work with motion timesteps
+ stopMotion(ANIM_AGENT_WALK_ADJUST);
+ removeAnimationData("Walk Speed");
+ }
+ // See SL-763 - playback with altered time step does not
+ // appear to work correctly, odd behavior for distant avatars.
+ // As of 11-2017, LLMotionController::updateMotions() will
+ // ignore the value here. Need to re-enable if it's every
+ // fixed.
+ mMotionController.setTimeStep(time_step);
+ }
+}
+
+void LLVOAvatar::updateRootPositionAndRotation(LLAgent& agent, F32 speed, bool was_sit_ground_constrained)
+{
+ if (!(isSitting() && getParent()))
+ {
+ // This case includes all configurations except sitting on an
+ // object, so does include ground sit.
+
+ //--------------------------------------------------------------------
+ // get timing info
+ // handle initial condition case
+ //--------------------------------------------------------------------
+ F32 animation_time = mAnimTimer.getElapsedTimeF32();
+ if (mTimeLast == 0.0f)
+ {
+ mTimeLast = animation_time;
+
+ // Initially put the pelvis at slaved position/mRotation
+ // SL-315
+ mRoot->setWorldPosition( getPositionAgent() ); // first frame
+ mRoot->setWorldRotation( getRotation() );
+ }
+ //--------------------------------------------------------------------
+ // dont' let dT get larger than 1/5th of a second
+ //--------------------------------------------------------------------
+ F32 delta_time = animation_time - mTimeLast;
+
+ delta_time = llclamp( delta_time, DELTA_TIME_MIN, DELTA_TIME_MAX );
+ mTimeLast = animation_time;
+
+ mSpeedAccum = (mSpeedAccum * 0.95f) + (speed * 0.05f);
+
+ //--------------------------------------------------------------------
+ // compute the position of the avatar's root
+ //--------------------------------------------------------------------
+ LLVector3d root_pos;
+ LLVector3d ground_under_pelvis;
+
+ if (isSelf())
+ {
+ gAgent.setPositionAgent(getRenderPosition());
+ }
+
+ root_pos = gAgent.getPosGlobalFromAgent(getRenderPosition());
+ root_pos.mdV[VZ] += getVisualParamWeight(AVATAR_HOVER);
+
+ LLVector3 normal;
+ resolveHeightGlobal(root_pos, ground_under_pelvis, normal);
+ F32 foot_to_ground = (F32) (root_pos.mdV[VZ] - mPelvisToFoot - ground_under_pelvis.mdV[VZ]);
+ BOOL in_air = ((!LLWorld::getInstance()->getRegionFromPosGlobal(ground_under_pelvis)) ||
+ foot_to_ground > FOOT_GROUND_COLLISION_TOLERANCE);
+
+ if (in_air && !mInAir)
+ {
+ mTimeInAir.reset();
+ }
+ mInAir = in_air;
+
+ // SL-402: with the ability to animate the position of joints
+ // that affect the body size calculation, computed body size
+ // can get stale much more easily. Simplest fix is to update
+ // it frequently.
+ // SL-427: this appears to be too frequent, moving to only do on animation state change.
+ //computeBodySize();
+
+ // correct for the fact that the pelvis is not necessarily the center
+ // of the agent's physical representation
+ root_pos.mdV[VZ] -= (0.5f * mBodySize.mV[VZ]) - mPelvisToFoot;
+ if (!isSitting() && !was_sit_ground_constrained)
+ {
+ root_pos += LLVector3d(getHoverOffset());
+ }
+
+ LLControlAvatar *cav = dynamic_cast<LLControlAvatar*>(this);
+ if (cav)
+ {
+ // SL-1350: Moved to LLDrawable::updateXform()
+ cav->matchVolumeTransform();
+ }
+ else
+ {
+ LLVector3 newPosition = gAgent.getPosAgentFromGlobal(root_pos);
+ if (newPosition != mRoot->getXform()->getWorldPosition())
+ {
+ mRoot->touch();
+ // SL-315
+ mRoot->setWorldPosition( newPosition ); // regular update
+ }
+ }
+
+ //--------------------------------------------------------------------
+ // Propagate viewer object rotation to root of avatar
+ //--------------------------------------------------------------------
+ if (!isControlAvatar() && !isAnyAnimationSignaled(AGENT_NO_ROTATE_ANIMS, NUM_AGENT_NO_ROTATE_ANIMS))
+ {
+ // Rotation fixups for avatars in motion.
+ // Skip for animated objects.
+ updateOrientation(agent, speed, delta_time);
}
}
else if (mDrawable.notNull())
{
+ // Sitting on an object - mRoot is slaved to mDrawable orientation.
LLVector3 pos = mDrawable->getPosition();
pos += getHoverOffset() * mDrawable->getRotation();
// SL-315
mRoot->setPosition(pos);
mRoot->setRotation(mDrawable->getRotation());
}
+}
+
+//------------------------------------------------------------------------
+// updateCharacter()
+//
+// This is called for all avatars, so there are 4 possible situations:
+//
+// 1) Avatar is your own. In this case the class is LLVOAvatarSelf,
+// isSelf() is true, and agent specifies the corresponding agent
+// information for you. In all the other cases, agent is irrelevant
+// and it would be less confusing if it were null or something.
+//
+// 2) Avatar is controlled by another resident. Class is LLVOAvatar,
+// and isSelf() is false.
+//
+// 3) Avatar is the controller for an animated object. Class is
+// LLControlAvatar and mIsDummy is true. Avatar is a purely
+// viewer-side entity with no representation on the simulator.
+//
+// 4) Avatar is a UI avatar used in some areas of the UI, such as when
+// previewing uploaded animations. Class is LLUIAvatar, and mIsDummy
+// is true. Avatar is purely viewer-side with no representation on the
+// simulator.
+//
+//------------------------------------------------------------------------
+BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
+{
+ updateDebugText();
+
+ if (!mIsBuilt)
+ {
+ return FALSE;
+ }
+
+ BOOL visible = isVisible();
+ bool is_control_avatar = isControlAvatar(); // capture state to simplify tracing
+ bool is_attachment = false;
+ if (is_control_avatar)
+ {
+ LLControlAvatar *cav = dynamic_cast<LLControlAvatar*>(this);
+ is_attachment = cav && cav->mRootVolp && cav->mRootVolp->isAttachment(); // For attached animated objects
+ }
+
+ LLScopedContextString str("updateCharacter " + getFullname() + " is_control_avatar "
+ + boost::lexical_cast<std::string>(is_control_avatar)
+ + " is_attachment " + boost::lexical_cast<std::string>(is_attachment));
+
+ // For fading out the names above heads, only let the timer
+ // run if we're visible.
+ if (mDrawable.notNull() && !visible)
+ {
+ mTimeVisible.reset();
+ }
+
+ //--------------------------------------------------------------------
+ // The rest should only be done occasionally for far away avatars.
+ // Set mUpdatePeriod and visible based on distance and other criteria.
+ //--------------------------------------------------------------------
+ computeUpdatePeriod();
+ visible = (LLDrawable::getCurrentFrame()+mID.mData[0])%mUpdatePeriod == 0 ? TRUE : FALSE;
+
+ //--------------------------------------------------------------------
+ // Early out if not visible and not self
+ // don't early out for your own avatar, as we rely on your animations playing reliably
+ // for example, the "turn around" animation when entering customize avatar needs to trigger
+ // even when your avatar is offscreen
+ //--------------------------------------------------------------------
+ if (!visible && !isSelf())
+ {
+ updateMotions(LLCharacter::HIDDEN_UPDATE);
+ return FALSE;
+ }
+
+ //--------------------------------------------------------------------
+ // change animation time quanta based on avatar render load
+ //--------------------------------------------------------------------
+ // SL-763 the time step quantization does not currently work.
+ //updateTimeStep();
+
+ //--------------------------------------------------------------------
+ // Update sitting state based on parent and active animation info.
+ //--------------------------------------------------------------------
+ if (getParent() && !isSitting())
+ {
+ sitOnObject((LLViewerObject*)getParent());
+ }
+ else if (!getParent() && isSitting() && !isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED))
+ {
+ getOffObject();
+ }
+
+ //--------------------------------------------------------------------
+ // create local variables in world coords for region position values
+ //--------------------------------------------------------------------
+ LLVector3 xyVel = getVelocity();
+ xyVel.mV[VZ] = 0.0f;
+ F32 speed = xyVel.length();
+ // remembering the value here prevents a display glitch if the
+ // animation gets toggled during this update.
+ bool was_sit_ground_constrained = isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED);
+
+ //--------------------------------------------------------------------
+ // This does a bunch of state updating, including figuring out
+ // whether av is in the air, setting mRoot position and rotation
+ // In some cases, calls updateOrientation() for a lot of the
+ // work
+ // --------------------------------------------------------------------
+ updateRootPositionAndRotation(agent, speed, was_sit_ground_constrained);
//-------------------------------------------------------------------------
// Update character motions
@@ -3905,7 +4343,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
}
// Special handling for sitting on ground.
- if (!getParent() && (mIsSitting || was_sit_ground_constrained))
+ if (!getParent() && (isSitting() || was_sit_ground_constrained))
{
F32 off_z = LLVector3d(getHoverOffset()).mdV[VZ];
@@ -3922,90 +4360,18 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
// update head position
updateHeadOffset();
- //-------------------------------------------------------------------------
- // Find the ground under each foot, these are used for a variety
- // of things that follow
- //-------------------------------------------------------------------------
- LLVector3 ankle_left_pos_agent = mFootLeftp->getWorldPosition();
- LLVector3 ankle_right_pos_agent = mFootRightp->getWorldPosition();
-
- LLVector3 ankle_left_ground_agent = ankle_left_pos_agent;
- LLVector3 ankle_right_ground_agent = ankle_right_pos_agent;
- resolveHeightAgent(ankle_left_pos_agent, ankle_left_ground_agent, normal);
- resolveHeightAgent(ankle_right_pos_agent, ankle_right_ground_agent, normal);
-
- F32 leftElev = llmax(-0.2f, ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ]);
- F32 rightElev = llmax(-0.2f, ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]);
-
- if (!mIsSitting)
- {
- //-------------------------------------------------------------------------
- // Figure out which foot is on ground
- //-------------------------------------------------------------------------
- if (!mInAir)
- {
- if ((leftElev < 0.0f) || (rightElev < 0.0f))
- {
- ankle_left_pos_agent = mFootLeftp->getWorldPosition();
- ankle_right_pos_agent = mFootRightp->getWorldPosition();
- leftElev = ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ];
- rightElev = ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ];
- }
- }
- }
-
- //-------------------------------------------------------------------------
// Generate footstep sounds when feet hit the ground
- //-------------------------------------------------------------------------
- const LLUUID AGENT_FOOTSTEP_ANIMS[] = {ANIM_AGENT_WALK, ANIM_AGENT_RUN, ANIM_AGENT_LAND};
- const S32 NUM_AGENT_FOOTSTEP_ANIMS = LL_ARRAY_SIZE(AGENT_FOOTSTEP_ANIMS);
-
- if ( gAudiop && isAnyAnimationSignaled(AGENT_FOOTSTEP_ANIMS, NUM_AGENT_FOOTSTEP_ANIMS) )
- {
- BOOL playSound = FALSE;
- LLVector3 foot_pos_agent;
-
- BOOL onGroundLeft = (leftElev <= 0.05f);
- BOOL onGroundRight = (rightElev <= 0.05f);
-
- // did left foot hit the ground?
- if ( onGroundLeft && !mWasOnGroundLeft )
- {
- foot_pos_agent = ankle_left_pos_agent;
- playSound = TRUE;
- }
-
- // did right foot hit the ground?
- if ( onGroundRight && !mWasOnGroundRight )
- {
- foot_pos_agent = ankle_right_pos_agent;
- playSound = TRUE;
- }
-
- mWasOnGroundLeft = onGroundLeft;
- mWasOnGroundRight = onGroundRight;
-
- if ( playSound )
- {
- const F32 STEP_VOLUME = 0.1f;
- const LLUUID& step_sound_id = getStepSound();
-
- LLVector3d foot_pos_global = gAgent.getPosGlobalFromAgent(foot_pos_agent);
-
- if (LLViewerParcelMgr::getInstance()->canHearSound(foot_pos_global)
- && !LLMuteList::getInstance()->isMuted(getID(), LLMute::flagObjectSounds))
- {
- gAudiop->triggerSound(step_sound_id, getID(), STEP_VOLUME, LLAudioEngine::AUDIO_TYPE_AMBIENT, foot_pos_global);
- }
- }
- }
+ updateFootstepSounds();
+ // Update child joints as needed.
mRoot->updateWorldMatrixChildren();
- //mesh vertices need to be reskinned
+ // System avatar mesh vertices need to be reskinned.
mNeedsSkin = TRUE;
+
return TRUE;
}
+
//-----------------------------------------------------------------------------
// updateHeadOffset()
//-----------------------------------------------------------------------------
@@ -4020,7 +4386,7 @@ void LLVOAvatar::updateHeadOffset()
{
midEyePt = midEyePt * ~mDrawable->getWorldRotation();
}
- if (mIsSitting)
+ if (isSitting())
{
mHeadOffset = midEyePt;
}
@@ -4116,7 +4482,7 @@ void LLVOAvatar::updateVisibility()
if (mIsDummy)
{
- visible = TRUE;
+ visible = FALSE;
}
else if (mDrawable.isNull())
{
@@ -4230,7 +4596,8 @@ void LLVOAvatar::updateVisibility()
}
else
{
- if (mMeshValid && mMeshInvisibleTime.getElapsedTimeF32() > TIME_BEFORE_MESH_CLEANUP)
+ if (mMeshValid &&
+ (isControlAvatar() || mMeshInvisibleTime.getElapsedTimeF32() > TIME_BEFORE_MESH_CLEANUP))
{
releaseMeshData();
}
@@ -4265,6 +4632,11 @@ U32 LLVOAvatar::renderSkinned()
return num_indices;
}
+ if (mDrawable.isNull())
+ {
+ return num_indices;
+ }
+
LLFace* face = mDrawable->getFace(0);
bool needs_rebuild = !face || !face->getVertexBuffer() || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY);
@@ -4431,7 +4803,7 @@ U32 LLVOAvatar::renderSkinned()
{
if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender)
{
- if (isTextureVisible(TEX_HEAD_BAKED) || mIsDummy)
+ if (isTextureVisible(TEX_HEAD_BAKED) || isUIAvatar())
{
LLViewerJoint* head_mesh = getViewerJoint(MESH_ID_HEAD);
if (head_mesh)
@@ -4441,7 +4813,7 @@ U32 LLVOAvatar::renderSkinned()
first_pass = FALSE;
}
}
- if (isTextureVisible(TEX_UPPER_BAKED) || mIsDummy)
+ if (isTextureVisible(TEX_UPPER_BAKED) || isUIAvatar())
{
LLViewerJoint* upper_mesh = getViewerJoint(MESH_ID_UPPER_BODY);
if (upper_mesh)
@@ -4451,7 +4823,7 @@ U32 LLVOAvatar::renderSkinned()
first_pass = FALSE;
}
- if (isTextureVisible(TEX_LOWER_BAKED) || mIsDummy)
+ if (isTextureVisible(TEX_LOWER_BAKED) || isUIAvatar())
{
LLViewerJoint* lower_mesh = getViewerJoint(MESH_ID_LOWER_BODY);
if (lower_mesh)
@@ -4480,7 +4852,7 @@ U32 LLVOAvatar::renderSkinned()
U32 LLVOAvatar::renderTransparent(BOOL first_pass)
{
U32 num_indices = 0;
- if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (mIsDummy || isTextureVisible(TEX_SKIRT_BAKED)) )
+ if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (isUIAvatar() || isTextureVisible(TEX_SKIRT_BAKED)) )
{
gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.25f);
LLViewerJoint* skirt_mesh = getViewerJoint(MESH_ID_SKIRT);
@@ -4508,10 +4880,7 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass)
}
first_pass = FALSE;
}
- // Can't test for baked hair being defined, since that won't always be the case (not all viewers send baked hair)
- // TODO: 1.25 will be able to switch this logic back to calling isTextureVisible();
- if ( (getImage(TEX_HAIR_BAKED, 0) && getImage(TEX_HAIR_BAKED, 0)->getID() != IMG_INVISIBLE)
- || LLDrawPoolAlpha::sShowDebugAlpha)
+ if (isTextureVisible(TEX_HAIR_BAKED))
{
LLViewerJoint* hair_mesh = getViewerJoint(MESH_ID_HAIR);
if (hair_mesh)
@@ -4559,7 +4928,7 @@ U32 LLVOAvatar::renderRigid()
gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
}
- if (isTextureVisible(TEX_EYES_BAKED) || mIsDummy)
+ if (isTextureVisible(TEX_EYES_BAKED) || isUIAvatar())
{
LLViewerJoint* eyeball_left = getViewerJoint(MESH_ID_EYEBALL_LEFT);
LLViewerJoint* eyeball_right = getViewerJoint(MESH_ID_EYEBALL_RIGHT);
@@ -4597,6 +4966,36 @@ U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel)
left *= mImpostorDim.mV[0];
up *= mImpostorDim.mV[1];
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_IMPOSTORS))
+ {
+ LLGLEnable blend(GL_BLEND);
+ gGL.setSceneBlendType(LLRender::BT_ADD);
+ gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE);
+
+ // gGL.begin(LLRender::QUADS);
+ // gGL.vertex3fv((pos+left-up).mV);
+ // gGL.vertex3fv((pos-left-up).mV);
+ // gGL.vertex3fv((pos-left+up).mV);
+ // gGL.vertex3fv((pos+left+up).mV);
+ // gGL.end();
+
+
+ gGL.begin(LLRender::LINES);
+ gGL.color4f(1.f,1.f,1.f,1.f);
+ F32 thickness = llmax(F32(5.0f-5.0f*(gFrameTimeSeconds-mLastImpostorUpdateFrameTime)),1.0f);
+ glLineWidth(thickness);
+ gGL.vertex3fv((pos+left-up).mV);
+ gGL.vertex3fv((pos-left-up).mV);
+ gGL.vertex3fv((pos-left-up).mV);
+ gGL.vertex3fv((pos-left+up).mV);
+ gGL.vertex3fv((pos-left+up).mV);
+ gGL.vertex3fv((pos+left+up).mV);
+ gGL.vertex3fv((pos+left+up).mV);
+ gGL.vertex3fv((pos+left-up).mV);
+ gGL.end();
+ gGL.flush();
+ }
+ {
LLGLEnable test(GL_ALPHA_TEST);
gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.f);
@@ -4613,6 +5012,7 @@ U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel)
gGL.vertex3fv((pos+left+up).mV);
gGL.end();
gGL.flush();
+ }
return 6;
}
@@ -5106,11 +5506,14 @@ void LLVOAvatar::processAnimationStateChanges()
startMotion(ANIM_AGENT_WALK_ADJUST);
stopMotion(ANIM_AGENT_FLY_ADJUST);
}
- else if (mInAir && !mIsSitting)
+ else if (mInAir && !isSitting())
{
stopMotion(ANIM_AGENT_WALK_ADJUST);
+ if (mEnableDefaultMotions)
+ {
startMotion(ANIM_AGENT_FLY_ADJUST);
}
+ }
else
{
stopMotion(ANIM_AGENT_WALK_ADJUST);
@@ -5119,14 +5522,20 @@ void LLVOAvatar::processAnimationStateChanges()
if ( isAnyAnimationSignaled(AGENT_GUN_AIM_ANIMS, NUM_AGENT_GUN_AIM_ANIMS) )
{
+ if (mEnableDefaultMotions)
+ {
startMotion(ANIM_AGENT_TARGET);
+ }
stopMotion(ANIM_AGENT_BODY_NOISE);
}
else
{
stopMotion(ANIM_AGENT_TARGET);
+ if (mEnableDefaultMotions)
+ {
startMotion(ANIM_AGENT_BODY_NOISE);
}
+ }
// clear all current animations
AnimIterator anim_it;
@@ -5489,7 +5898,7 @@ bool LLVOAvatar::getRiggedMeshID(LLViewerObject* pVO, LLUUID& mesh_id)
LLVOVolume* pVObj = pVO->mDrawable->getVOVolume();
if ( pVObj )
{
- const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( pVObj->getVolume()->getParams().getSculptID(), pVObj );
+ const LLMeshSkinInfo* pSkinData = pVObj->getSkinInfo();
if (pSkinData
&& pSkinData->mJointNames.size() > JOINT_COUNT_REQUIRED_FOR_FULLRIG // full rig
&& pSkinData->mAlternateBindMatrix.size() > 0 )
@@ -5502,85 +5911,126 @@ bool LLVOAvatar::getRiggedMeshID(LLViewerObject* pVO, LLUUID& mesh_id)
return false;
}
-bool LLVOAvatar::jointIsRiggedTo(const std::string& joint_name)
+bool LLVOAvatar::jointIsRiggedTo(const LLJoint *joint) const
{
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
+ if (joint)
{
- LLViewerJointAttachment* attachment = iter->second;
- for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
- attachment_iter != attachment->mAttachedObjects.end();
- ++attachment_iter)
- {
- const LLViewerObject* attached_object = (*attachment_iter);
- if (attached_object && jointIsRiggedTo(joint_name, attached_object))
+ const LLJointRiggingInfoTab& tab = mJointRiggingInfoTab;
+ S32 joint_num = joint->getJointNum();
+ if (joint_num < tab.size() && tab[joint_num].isRiggedTo())
{
return true;
}
}
- }
return false;
}
-bool LLVOAvatar::jointIsRiggedTo(const std::string& joint_name, const LLViewerObject *vo)
+void LLVOAvatar::clearAttachmentOverrides()
{
- // Process all children
- LLViewerObject::const_child_list_t& children = vo->getChildren();
- for (LLViewerObject::const_child_list_t::const_iterator it = children.begin();
- it != children.end(); ++it)
+ LLScopedContextString str("clearAttachmentOverrides " + getFullname());
+
+ for (S32 i=0; i<LL_CHARACTER_MAX_ANIMATED_JOINTS; i++)
{
- LLViewerObject *childp = *it;
- if (jointIsRiggedTo(joint_name,childp))
+ LLJoint *pJoint = getJoint(i);
+ if (pJoint)
{
- return true;
+ pJoint->clearAttachmentPosOverrides();
+ pJoint->clearAttachmentScaleOverrides();
}
}
- const LLVOVolume *vobj = dynamic_cast<const LLVOVolume*>(vo);
- if (!vobj)
+ if (mPelvisFixups.count()>0)
+ {
+ mPelvisFixups.clear();
+ LLJoint* pJointPelvis = getJoint("mPelvis");
+ if (pJointPelvis)
{
- return false;
+ pJointPelvis->setPosition( LLVector3( 0.0f, 0.0f, 0.0f) );
+ }
+ postPelvisSetRecalc();
}
- LLUUID currentId = vobj->getVolume()->getParams().getSculptID();
- const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj );
+ mActiveOverrideMeshes.clear();
+ onActiveOverrideMeshesChanged();
+}
- if ( vobj && vobj->isAttachment() && vobj->isMesh() && pSkinData )
+//-----------------------------------------------------------------------------
+// rebuildAttachmentOverrides
+//-----------------------------------------------------------------------------
+void LLVOAvatar::rebuildAttachmentOverrides()
+{
+ LLScopedContextString str("rebuildAttachmentOverrides " + getFullname());
+
+ LL_DEBUGS("AnimatedObjects") << "rebuilding" << LL_ENDL;
+ dumpStack("AnimatedObjectsStack");
+
+ clearAttachmentOverrides();
+
+ // Handle the case that we're resetting the skeleton of an animated object.
+ LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this);
+ if (control_av)
{
- if (std::find(pSkinData->mJointNames.begin(), pSkinData->mJointNames.end(), joint_name) !=
- pSkinData->mJointNames.end())
+ LLVOVolume *volp = control_av->mRootVolp;
+ if (volp)
{
- return true;
+ LL_DEBUGS("Avatar") << volp->getID() << " adding attachment overrides for root vol, prim count "
+ << (S32) (1+volp->numChildren()) << LL_ENDL;
+ addAttachmentOverridesForObject(volp);
}
}
- return false;
+ // Attached objects
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end();
+ ++iter)
+ {
+ LLViewerJointAttachment *attachment_pt = (*iter).second;
+ if (attachment_pt)
+ {
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator at_it = attachment_pt->mAttachedObjects.begin();
+ at_it != attachment_pt->mAttachedObjects.end(); ++at_it)
+ {
+ LLViewerObject *vo = *at_it;
+ // Attached animated objects affect joints in their control
+ // avs, not the avs to which they are attached.
+ if (!vo->isAnimatedObject())
+ {
+ addAttachmentOverridesForObject(vo);
+ }
+ }
+ }
+ }
}
-void LLVOAvatar::clearAttachmentOverrides()
+//-----------------------------------------------------------------------------
+// updateAttachmentOverrides
+//
+// This is intended to give the same results as
+// rebuildAttachmentOverrides(), while avoiding redundant work.
+// -----------------------------------------------------------------------------
+void LLVOAvatar::updateAttachmentOverrides()
{
- LLScopedContextString str("clearAttachmentOverrides " + getFullname());
+ LLScopedContextString str("updateAttachmentOverrides " + getFullname());
- for (S32 i=0; i<LL_CHARACTER_MAX_ANIMATED_JOINTS; i++)
+ LL_DEBUGS("AnimatedObjects") << "updating" << LL_ENDL;
+ dumpStack("AnimatedObjectsStack");
+
+ std::set<LLUUID> meshes_seen;
+
+ // Handle the case that we're updating the skeleton of an animated object.
+ LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this);
+ if (control_av)
{
- LLJoint *pJoint = getJoint(i);
- if (pJoint)
+ LLVOVolume *volp = control_av->mRootVolp;
+ if (volp)
{
- pJoint->clearAttachmentPosOverrides();
- pJoint->clearAttachmentScaleOverrides();
+ LL_DEBUGS("Avatar") << volp->getID() << " adding attachment overrides for root vol, prim count "
+ << (S32) (1+volp->numChildren()) << LL_ENDL;
+ addAttachmentOverridesForObject(volp, &meshes_seen);
}
}
-}
-//-----------------------------------------------------------------------------
-// rebuildAttachmentOverrides
-//-----------------------------------------------------------------------------
-void LLVOAvatar::rebuildAttachmentOverrides()
-{
- LLScopedContextString str("rebuildAttachmentOverrides " + getFullname());
-
- // Attachment points
+ // Attached objects
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
@@ -5591,32 +6041,112 @@ void LLVOAvatar::rebuildAttachmentOverrides()
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator at_it = attachment_pt->mAttachedObjects.begin();
at_it != attachment_pt->mAttachedObjects.end(); ++at_it)
{
- addAttachmentOverridesForObject(*at_it);
+ LLViewerObject *vo = *at_it;
+ // Attached animated objects affect joints in their control
+ // avs, not the avs to which they are attached.
+ if (!vo->isAnimatedObject())
+ {
+ addAttachmentOverridesForObject(vo, &meshes_seen);
+ }
+ }
+ }
+ }
+ // Remove meshes that are no longer present on the skeleton
+
+ // have to work with a copy because removeAttachmentOverrides() will change mActiveOverrideMeshes.
+ std::set<LLUUID> active_override_meshes = mActiveOverrideMeshes;
+ for (std::set<LLUUID>::iterator it = active_override_meshes.begin(); it != active_override_meshes.end(); ++it)
+ {
+ if (meshes_seen.find(*it) == meshes_seen.end())
+ {
+ removeAttachmentOverridesForObject(*it);
+ }
+ }
+
+
+#ifdef ATTACHMENT_OVERRIDE_VALIDATION
+ {
+ std::vector<LLVector3OverrideMap> pos_overrides_by_joint;
+ std::vector<LLVector3OverrideMap> scale_overrides_by_joint;
+ LLVector3OverrideMap pelvis_fixups;
+
+ // Capture snapshot of override state after update
+ for (S32 joint_num = 0; joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS; joint_num++)
+ {
+ LLVector3OverrideMap pos_overrides;
+ LLJoint *joint = getJoint(joint_num);
+ if (joint)
+ {
+ pos_overrides_by_joint.push_back(joint->m_attachmentPosOverrides);
+ scale_overrides_by_joint.push_back(joint->m_attachmentScaleOverrides);
+ }
+ else
+ {
+ // No joint, use default constructed empty maps
+ pos_overrides_by_joint.push_back(LLVector3OverrideMap());
+ scale_overrides_by_joint.push_back(LLVector3OverrideMap());
+ }
+ }
+ pelvis_fixups = mPelvisFixups;
+ //dumpArchetypeXML(getFullname() + "_paranoid_updated");
+
+ // Rebuild and compare
+ rebuildAttachmentOverrides();
+ //dumpArchetypeXML(getFullname() + "_paranoid_rebuilt");
+ bool mismatched = false;
+ for (S32 joint_num = 0; joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS; joint_num++)
+ {
+ LLJoint *joint = getJoint(joint_num);
+ if (joint)
+ {
+ if (pos_overrides_by_joint[joint_num] != joint->m_attachmentPosOverrides)
+ {
+ mismatched = true;
+ }
+ if (scale_overrides_by_joint[joint_num] != joint->m_attachmentScaleOverrides)
+ {
+ mismatched = true;
}
}
}
+ if (pelvis_fixups != mPelvisFixups)
+ {
+ mismatched = true;
+ }
+ if (mismatched)
+ {
+ LL_WARNS() << "MISMATCHED ATTACHMENT OVERRIDES" << LL_ENDL;
+ }
+ }
+#endif
}
+
//-----------------------------------------------------------------------------
-// addAttachmentPosOverridesForObject
+// addAttachmentOverridesForObject
//-----------------------------------------------------------------------------
-void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo)
+void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo, std::set<LLUUID>* meshes_seen, bool recursive)
{
- LLVOAvatar *av = vo->getAvatarAncestor();
- if (!av || (av != this))
+ if (vo->getAvatar() != this && vo->getAvatarAncestor() != this)
{
LL_WARNS("Avatar") << "called with invalid avatar" << LL_ENDL;
return;
}
- LLScopedContextString str("addAttachmentOverridesForObject " + av->getFullname());
+ LLScopedContextString str("addAttachmentOverridesForObject " + getFullname());
+
+ LL_DEBUGS("AnimatedObjects") << "adding" << LL_ENDL;
+ dumpStack("AnimatedObjectsStack");
// Process all children
+ if (recursive)
+ {
LLViewerObject::const_child_list_t& children = vo->getChildren();
for (LLViewerObject::const_child_list_t::const_iterator it = children.begin();
it != children.end(); ++it)
{
LLViewerObject *childp = *it;
- addAttachmentOverridesForObject(childp);
+ addAttachmentOverridesForObject(childp, meshes_seen, true);
+ }
}
LLVOVolume *vobj = dynamic_cast<LLVOVolume*>(vo);
@@ -5626,15 +6156,18 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo)
{
return;
}
+
+ LLViewerObject *root_object = (LLViewerObject*)vobj->getRoot();
+ LL_DEBUGS("AnimatedObjects") << "trying to add attachment overrides for root object " << root_object->getID() << " prim is " << vobj << LL_ENDL;
if (vobj->isMesh() &&
((vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded()) || !gMeshRepo.meshRezEnabled()))
{
+ LL_DEBUGS("AnimatedObjects") << "failed to add attachment overrides for root object " << root_object->getID() << " mesh asset not loaded" << LL_ENDL;
return;
}
- LLUUID currentId = vobj->getVolume()->getParams().getSculptID();
- const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj );
+ const LLMeshSkinInfo* pSkinData = vobj->getSkinInfo();
- if ( vobj && vobj->isAttachment() && vobj->isMesh() && pSkinData )
+ if ( vobj && vobj->isMesh() && pSkinData )
{
const int bindCnt = pSkinData->mAlternateBindMatrix.size();
const int jointCnt = pSkinData->mJointNames.size();
@@ -5646,8 +6179,26 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo)
{
const F32 pelvisZOffset = pSkinData->mPelvisOffset;
const LLUUID& mesh_id = pSkinData->mMeshID;
+
+ if (meshes_seen)
+ {
+ meshes_seen->insert(mesh_id);
+ }
+ bool mesh_overrides_loaded = (mActiveOverrideMeshes.find(mesh_id) != mActiveOverrideMeshes.end());
+ if (mesh_overrides_loaded)
+ {
+ LL_DEBUGS("AnimatedObjects") << "skipping add attachment overrides for " << mesh_id
+ << " to root object " << root_object->getID()
+ << ", already loaded"
+ << LL_ENDL;
+ }
+ else
+ {
+ LL_DEBUGS("AnimatedObjects") << "adding attachment overrides for " << mesh_id
+ << " to root object " << root_object->getID() << LL_ENDL;
+ }
bool fullRig = (jointCnt>=JOINT_COUNT_REQUIRED_FOR_FULLRIG) ? true : false;
- if ( fullRig )
+ if ( fullRig && !mesh_overrides_loaded )
{
for ( int i=0; i<jointCnt; ++i )
{
@@ -5691,9 +6242,15 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo)
}
}
+ mActiveOverrideMeshes.insert(mesh_id);
+ onActiveOverrideMeshesChanged();
}
}
}
+ else
+ {
+ LL_DEBUGS("AnimatedObjects") << "failed to add attachment overrides for root object " << root_object->getID() << " not mesh or no pSkinData" << LL_ENDL;
+ }
//Rebuild body data if we altered joints/pelvis
if ( pelvisGotSet )
@@ -5816,14 +6373,14 @@ void LLVOAvatar::showAttachmentOverrides(bool verbose) const
}
//-----------------------------------------------------------------------------
-// resetJointsOnDetach
+// removeAttachmentOverridesForObject
//-----------------------------------------------------------------------------
-void LLVOAvatar::resetJointsOnDetach(LLViewerObject *vo)
+void LLVOAvatar::removeAttachmentOverridesForObject(LLViewerObject *vo)
{
- LLVOAvatar *av = vo->getAvatarAncestor();
- if (!av || (av != this))
+ if (vo->getAvatar() != this && vo->getAvatarAncestor() != this)
{
LL_WARNS("Avatar") << "called with invalid avatar" << LL_ENDL;
+ return;
}
// Process all children
@@ -5832,37 +6389,32 @@ void LLVOAvatar::resetJointsOnDetach(LLViewerObject *vo)
it != children.end(); ++it)
{
LLViewerObject *childp = *it;
- resetJointsOnDetach(childp);
+ removeAttachmentOverridesForObject(childp);
}
// Process self.
LLUUID mesh_id;
if (getRiggedMeshID(vo,mesh_id))
{
- resetJointsOnDetach(mesh_id);
+ removeAttachmentOverridesForObject(mesh_id);
}
}
//-----------------------------------------------------------------------------
-// resetJointsOnDetach
+// removeAttachmentOverridesForObject
//-----------------------------------------------------------------------------
-void LLVOAvatar::resetJointsOnDetach(const LLUUID& mesh_id)
+void LLVOAvatar::removeAttachmentOverridesForObject(const LLUUID& mesh_id)
{
- //Subsequent joints are relative to pelvis
- avatar_joint_list_t::iterator iter = mSkeleton.begin();
- avatar_joint_list_t::iterator end = mSkeleton.end();
-
LLJoint* pJointPelvis = getJoint("mPelvis");
-
- for (; iter != end; ++iter)
+ const std::string av_string = avString();
+ for (S32 joint_num = 0; joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS; joint_num++)
{
- LLJoint* pJoint = (*iter);
- //Reset joints except for pelvis
+ LLJoint *pJoint = getJoint(joint_num);
if ( pJoint )
{
bool dummy; // unused
- pJoint->removeAttachmentPosOverride(mesh_id, avString(),dummy);
- pJoint->removeAttachmentScaleOverride(mesh_id, avString());
+ pJoint->removeAttachmentPosOverride(mesh_id, av_string, dummy);
+ pJoint->removeAttachmentScaleOverride(mesh_id, av_string);
}
if ( pJoint && pJoint == pJointPelvis)
{
@@ -5873,6 +6425,9 @@ void LLVOAvatar::resetJointsOnDetach(const LLUUID& mesh_id)
}
postPelvisSetRecalc();
+
+ mActiveOverrideMeshes.erase(mesh_id);
+ onActiveOverrideMeshesChanged();
}
//-----------------------------------------------------------------------------
// getCharacterPosition()
@@ -5924,7 +6479,7 @@ void LLVOAvatar::getGround(const LLVector3 &in_pos_agent, LLVector3 &out_pos_age
LLVector3d z_vec(0.0f, 0.0f, 1.0f);
LLVector3d p0_global, p1_global;
- if (mIsDummy)
+ if (isUIAvatar())
{
outNorm.setVec(z_vec);
out_pos_agent = in_pos_agent;
@@ -5953,7 +6508,7 @@ F32 LLVOAvatar::getTimeDilation()
//-----------------------------------------------------------------------------
F32 LLVOAvatar::getPixelArea() const
{
- if (mIsDummy)
+ if (isUIAvatar())
{
return 100000.f;
}
@@ -6387,7 +6942,7 @@ void LLVOAvatar::removeChild(LLViewerObject *childp)
LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* viewer_object)
{
- S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getState());
+ S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getAttachmentState());
// This should never happen unless the server didn't process the attachment point
// correctly, but putting this check in here to be safe.
@@ -6450,6 +7005,11 @@ const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_o
return 0;
}
+ if (!viewer_object->isAnimatedObject())
+ {
+ updateAttachmentOverrides();
+ }
+
updateVisualComplexity();
if (viewer_object->isSelected())
@@ -6495,19 +7055,62 @@ U32 LLVOAvatar::getNumAttachments() const
//-----------------------------------------------------------------------------
// canAttachMoreObjects()
+// Returns true if we can attach <n> more objects.
//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::canAttachMoreObjects() const
+BOOL LLVOAvatar::canAttachMoreObjects(U32 n) const
{
- return (getNumAttachments() < MAX_AGENT_ATTACHMENTS);
+ return (getNumAttachments() + n) <= MAX_AGENT_ATTACHMENTS;
}
//-----------------------------------------------------------------------------
-// canAttachMoreObjects()
-// Returns true if we can attach <n> more objects.
+// getNumAnimatedObjectAttachments()
//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::canAttachMoreObjects(U32 n) const
+U32 LLVOAvatar::getNumAnimatedObjectAttachments() const
{
- return (getNumAttachments() + n) <= MAX_AGENT_ATTACHMENTS;
+ U32 num_attachments = 0;
+ for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end();
+ ++iter)
+ {
+ const LLViewerJointAttachment *attachment_pt = (*iter).second;
+ num_attachments += attachment_pt->getNumAnimatedObjects();
+ }
+ return num_attachments;
+}
+
+//-----------------------------------------------------------------------------
+// getMaxAnimatedObjectAttachments()
+// Gets from simulator feature if available, otherwise 0.
+//-----------------------------------------------------------------------------
+S32 LLVOAvatar::getMaxAnimatedObjectAttachments() const
+{
+ S32 max_attach = 0;
+ if (gSavedSettings.getBOOL("AnimatedObjectsIgnoreLimits"))
+ {
+ max_attach = MAX_AGENT_ATTACHMENTS;
+ }
+ else
+ {
+ if (gAgent.getRegion())
+ {
+ LLSD features;
+ gAgent.getRegion()->getSimulatorFeatures(features);
+ if (features.has("AnimatedObjects"))
+ {
+ max_attach = features["AnimatedObjects"]["MaxAgentAnimatedObjectAttachments"].asInteger();
+ }
+ }
+ }
+ return max_attach;
+}
+
+//-----------------------------------------------------------------------------
+// canAttachMoreAnimatedObjects()
+// Returns true if we can attach <n> more animated objects.
+//-----------------------------------------------------------------------------
+BOOL LLVOAvatar::canAttachMoreAnimatedObjects(U32 n) const
+{
+ return (getNumAnimatedObjectAttachments() + n) <= getMaxAnimatedObjectAttachments();
}
//-----------------------------------------------------------------------------
@@ -6598,7 +7201,7 @@ void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO )
LLUUID mesh_id;
if (getRiggedMeshID(pVO, mesh_id))
{
- resetJointsOnDetach(mesh_id);
+ // FIXME this seems like an odd place for this code.
if ( gAgentCamera.cameraCustomizeAvatar() )
{
gAgent.unpauseAnimation();
@@ -6622,9 +7225,14 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)
if (attachment->isObjectAttached(viewer_object))
{
updateVisualComplexity();
+ bool is_animated_object = viewer_object->isAnimatedObject();
cleanupAttachedMesh(viewer_object);
attachment->removeObject(viewer_object);
+ if (!is_animated_object)
+ {
+ updateAttachmentOverrides();
+ }
viewer_object->refreshBakeTexture();
LLViewerObject::const_child_list_t& child_list = viewer_object->getChildren();
@@ -6633,10 +7241,10 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)
{
LLViewerObject* objectp = *iter1;
if (objectp)
- {
+ {
objectp->refreshBakeTexture();
}
- }
+ }
updateMeshVisibility();
@@ -6773,7 +7381,10 @@ void LLVOAvatar::getOffObject()
mRoot->setRotation(cur_rotation_world);
mRoot->getXform()->update();
+ if (mEnableDefaultMotions)
+ {
startMotion(ANIM_AGENT_BODY_NOISE);
+ }
if (isSelf())
{
@@ -6931,6 +7542,18 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color)
updateMeshTextures();
}
+// virtual
+bool LLVOAvatar::shouldRenderRigged() const
+{
+ return true;
+}
+
+// FIXME: We have an mVisible member, set in updateVisibility(), but this
+// function doesn't return it! isVisible() and mVisible are used
+// different places for different purposes. mVisible seems to be more
+// related to whether the actual avatar mesh is shown, and isVisible()
+// to whether anything about the avatar is displayed in the scene.
+// Maybe better naming could make this clearer?
BOOL LLVOAvatar::isVisible() const
{
return mDrawable.notNull()
@@ -6941,6 +7564,11 @@ BOOL LLVOAvatar::isVisible() const
// Determine if we have enough avatar data to render
bool LLVOAvatar::getIsCloud() const
{
+ if (mIsDummy)
+ {
+ return false;
+ }
+
return ( ((const_cast<LLVOAvatar*>(this))->visualParamWeightsAreDefault())// Do we have a shape?
|| ( !isTextureDefined(TEX_LOWER_BAKED)
|| !isTextureDefined(TEX_UPPER_BAKED)
@@ -7220,7 +7848,7 @@ bool LLVOAvatar::isTooComplex() const
// so that unlimited will completely disable the overly complex impostor rendering
// yes, this leaves them vulnerable to griefing objects... their choice
too_complex = ( max_render_cost > 0
- && ( mVisualComplexity > max_render_cost
+ && (mVisualComplexity > max_render_cost
|| (max_attachment_area > 0.0f && mAttachmentSurfaceArea > max_attachment_area)
));
}
@@ -8900,8 +9528,43 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
pelvis_fixup, mesh_id.asString().c_str());
}
- apr_file_printf( file, "\t</archetype>\n" );
- apr_file_printf( file, "\n</linden_genepool>\n" );
+ LLVector3 rp = getRootJoint()->getWorldPosition();
+ LLVector4a rpv;
+ rpv.load3(rp.mV);
+
+ for (S32 joint_num = 0; joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS; joint_num++)
+ {
+ LLJoint *joint = getJoint(joint_num);
+ if (joint_num < mJointRiggingInfoTab.size())
+ {
+ LLJointRiggingInfo& rig_info = mJointRiggingInfoTab[joint_num];
+ if (rig_info.isRiggedTo())
+ {
+ LLMatrix4a mat;
+ LLVector4a new_extents[2];
+ mat.loadu(joint->getWorldMatrix());
+ matMulBoundBox(mat, rig_info.getRiggedExtents(), new_extents);
+ LLVector4a rrp[2];
+ rrp[0].setSub(new_extents[0],rpv);
+ rrp[1].setSub(new_extents[1],rpv);
+ apr_file_printf( file, "\t\t<joint_rig_info num=\"%d\" name=\"%s\" min=\"%f %f %f\" max=\"%f %f %f\" tmin=\"%f %f %f\" tmax=\"%f %f %f\"/>\n",
+ joint_num,
+ joint->getName().c_str(),
+ rig_info.getRiggedExtents()[0][0],
+ rig_info.getRiggedExtents()[0][1],
+ rig_info.getRiggedExtents()[0][2],
+ rig_info.getRiggedExtents()[1][0],
+ rig_info.getRiggedExtents()[1][1],
+ rig_info.getRiggedExtents()[1][2],
+ rrp[0][0],
+ rrp[0][1],
+ rrp[0][2],
+ rrp[1][0],
+ rrp[1][1],
+ rrp[1][2] );
+ }
+ }
+ }
bool ultra_verbose = false;
if (isSelf() && ultra_verbose)
@@ -8909,6 +9572,10 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
// show the cloned params inside the wearables as well.
gAgentAvatarp->dumpWearableInfo(outfile);
}
+
+ apr_file_printf( file, "\t</archetype>\n" );
+ apr_file_printf( file, "\n</linden_genepool>\n" );
+
LLSD args;
args["PATH"] = fullpath;
LLNotificationsUtil::add("AppearanceToXMLSaved", args);
@@ -9040,6 +9707,7 @@ void LLVOAvatar::updateRegion(LLViewerRegion *regionp)
LLViewerObject::updateRegion(regionp);
}
+// virtual
std::string LLVOAvatar::getFullname() const
{
std::string name;
@@ -9086,6 +9754,11 @@ void LLVOAvatar::updateFreezeCounter(S32 counter)
BOOL LLVOAvatar::updateLOD()
{
+ if (mDrawable.isNull())
+ {
+ return FALSE;
+ }
+
if (isImpostor() && 0 != mDrawable->getNumFaces() && mDrawable->getFace(0)->hasGeometry())
{
return TRUE;
@@ -9111,11 +9784,156 @@ BOOL LLVOAvatar::updateLOD()
return res;
}
-void LLVOAvatar::updateLODRiggedAttachments( void )
+void LLVOAvatar::updateLODRiggedAttachments()
{
updateLOD();
rebuildRiggedAttachments();
}
+
+void showRigInfoTabExtents(LLVOAvatar *avatar, LLJointRiggingInfoTab& tab, S32& count_rigged, S32& count_box)
+{
+ count_rigged = count_box = 0;
+ LLVector4a zero_vec;
+ zero_vec.clear();
+ for (S32 i=0; i<tab.size(); i++)
+ {
+ if (tab[i].isRiggedTo())
+ {
+ count_rigged++;
+ LLJoint *joint = avatar->getJoint(i);
+ LL_DEBUGS("RigSpam") << "joint " << i << " name " << joint->getName() << " box "
+ << tab[i].getRiggedExtents()[0] << ", " << tab[i].getRiggedExtents()[1] << LL_ENDL;
+ if ((!tab[i].getRiggedExtents()[0].equals3(zero_vec)) ||
+ (!tab[i].getRiggedExtents()[1].equals3(zero_vec)))
+ {
+ count_box++;
+ }
+ }
+ }
+}
+
+void LLVOAvatar::getAssociatedVolumes(std::vector<LLVOVolume*>& volumes)
+{
+ for ( LLVOAvatar::attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter )
+ {
+ LLViewerJointAttachment* attachment = iter->second;
+ LLViewerJointAttachment::attachedobjs_vec_t::iterator attach_end = attachment->mAttachedObjects.end();
+
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attach_iter = attachment->mAttachedObjects.begin();
+ attach_iter != attach_end; ++attach_iter)
+ {
+ LLViewerObject* attached_object = *attach_iter;
+ LLVOVolume *volume = dynamic_cast<LLVOVolume*>(attached_object);
+ if (volume)
+ {
+ volumes.push_back(volume);
+ if (volume->isAnimatedObject())
+ {
+ // For animated object attachment, don't need
+ // the children. Will just get bounding box
+ // from the control avatar.
+ continue;
+ }
+ }
+ LLViewerObject::const_child_list_t& children = attached_object->getChildren();
+ for (LLViewerObject::const_child_list_t::const_iterator it = children.begin();
+ it != children.end(); ++it)
+ {
+ LLViewerObject *childp = *it;
+ LLVOVolume *volume = dynamic_cast<LLVOVolume*>(childp);
+ if (volume)
+ {
+ volumes.push_back(volume);
+ }
+ }
+ }
+ }
+
+ LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this);
+ if (control_av)
+ {
+ LLVOVolume *volp = control_av->mRootVolp;
+ if (volp)
+ {
+ volumes.push_back(volp);
+ LLViewerObject::const_child_list_t& children = volp->getChildren();
+ for (LLViewerObject::const_child_list_t::const_iterator it = children.begin();
+ it != children.end(); ++it)
+ {
+ LLViewerObject *childp = *it;
+ LLVOVolume *volume = dynamic_cast<LLVOVolume*>(childp);
+ if (volume)
+ {
+ volumes.push_back(volume);
+ }
+ }
+ }
+ }
+}
+
+static LLTrace::BlockTimerStatHandle FTM_AVATAR_RIGGING_INFO_UPDATE("Av Upd Rig Info");
+static LLTrace::BlockTimerStatHandle FTM_AVATAR_RIGGING_KEY_UPDATE("Av Upd Rig Key");
+static LLTrace::BlockTimerStatHandle FTM_AVATAR_RIGGING_AVOL_UPDATE("Av Upd Avol");
+
+// virtual
+void LLVOAvatar::updateRiggingInfo()
+{
+ LL_RECORD_BLOCK_TIME(FTM_AVATAR_RIGGING_INFO_UPDATE);
+
+ LL_DEBUGS("RigSpammish") << getFullname() << " updating rig tab" << LL_ENDL;
+
+ std::vector<LLVOVolume*> volumes;
+
+ {
+ LL_RECORD_BLOCK_TIME(FTM_AVATAR_RIGGING_AVOL_UPDATE);
+ getAssociatedVolumes(volumes);
+ }
+
+ std::map<LLUUID,S32> curr_rigging_info_key;
+ {
+ LL_RECORD_BLOCK_TIME(FTM_AVATAR_RIGGING_KEY_UPDATE);
+ // Get current rigging info key
+ for (std::vector<LLVOVolume*>::iterator it = volumes.begin(); it != volumes.end(); ++it)
+ {
+ LLVOVolume *vol = *it;
+ if (vol->isMesh() && vol->getVolume())
+ {
+ const LLUUID& mesh_id = vol->getVolume()->getParams().getSculptID();
+ S32 max_lod = llmax(vol->getLOD(), vol->mLastRiggingInfoLOD);
+ curr_rigging_info_key[mesh_id] = max_lod;
+ }
+ }
+
+ // Check for key change, which indicates some change in volume composition or LOD.
+ if (curr_rigging_info_key == mLastRiggingInfoKey)
+ {
+ return;
+ }
+ }
+
+ // Something changed. Update.
+ mLastRiggingInfoKey = curr_rigging_info_key;
+ mJointRiggingInfoTab.clear();
+ for (std::vector<LLVOVolume*>::iterator it = volumes.begin(); it != volumes.end(); ++it)
+ {
+ LLVOVolume *vol = *it;
+ vol->updateRiggingInfo();
+ mJointRiggingInfoTab.merge(vol->mJointRiggingInfoTab);
+ }
+
+ //LL_INFOS() << "done update rig count is " << countRigInfoTab(mJointRiggingInfoTab) << LL_ENDL;
+ LL_DEBUGS("RigSpammish") << getFullname() << " after update rig tab:" << LL_ENDL;
+ S32 joint_count, box_count;
+ showRigInfoTabExtents(this, mJointRiggingInfoTab, joint_count, box_count);
+ LL_DEBUGS("RigSpammish") << "uses " << joint_count << " joints " << " nonzero boxes: " << box_count << LL_ENDL;
+}
+
+// virtual
+void LLVOAvatar::onActiveOverrideMeshesChanged()
+{
+ mJointRiggingInfoTab.setNeedsUpdate(true);
+}
+
U32 LLVOAvatar::getPartitionType() const
{
// Avatars merely exist as drawables in the bridge partition
@@ -9126,10 +9944,10 @@ U32 LLVOAvatar::getPartitionType() const
void LLVOAvatar::updateImpostors()
{
LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
- LLCharacter::sAllowInstancesChange = FALSE;
- for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
- iter != LLCharacter::sInstances.end(); ++iter)
+ std::vector<LLCharacter*> instances_copy = LLCharacter::sInstances;
+ for (std::vector<LLCharacter*>::iterator iter = instances_copy.begin();
+ iter != instances_copy.end(); ++iter)
{
LLVOAvatar* avatar = (LLVOAvatar*) *iter;
if (!avatar->isDead() && avatar->isVisible()
@@ -9145,6 +9963,7 @@ void LLVOAvatar::updateImpostors()
LLCharacter::sAllowInstancesChange = TRUE;
}
+// virtual
BOOL LLVOAvatar::isImpostor()
{
return sUseImpostors && (isVisuallyMuted() || (mUpdatePeriod >= IMPOSTOR_PERIOD)) ? TRUE : FALSE;
@@ -9226,6 +10045,17 @@ void LLVOAvatar::updateImpostorRendering(U32 newMaxNonImpostorsValue)
void LLVOAvatar::idleUpdateRenderComplexity()
{
+ if (isControlAvatar())
+ {
+ LLControlAvatar *cav = dynamic_cast<LLControlAvatar*>(this);
+ bool is_attachment = cav && cav->mRootVolp && cav->mRootVolp->isAttachment(); // For attached animated objects
+ if (is_attachment)
+ {
+ // ARC for animated object attachments is accounted with the avatar they're attached to.
+ return;
+ }
+ }
+
// Render Complexity
calculateUpdateRenderComplexity(); // Update mVisualComplexity if needed
@@ -9273,10 +10103,16 @@ void LLVOAvatar::idleUpdateRenderComplexity()
// Visual rank
info_line = llformat("%d rank", mVisibilityRank);
// Use grey for imposters, white for normal rendering or no impostors
- info_color.set(isImpostor() ? LLColor4::grey : LLColor4::white);
+ info_color.set(isImpostor() ? LLColor4::grey : (isControlAvatar() ? LLColor4::yellow : LLColor4::white));
info_style = LLFontGL::NORMAL;
mText->addLine(info_line, info_color, info_style);
+ // Triangle count
+ mText->addLine(std::string("VisTris ") + LLStringOps::getReadableNumber(mAttachmentVisibleTriangleCount),
+ info_color, info_style);
+ mText->addLine(std::string("EstMaxTris ") + LLStringOps::getReadableNumber(mAttachmentEstTriangleCount),
+ info_color, info_style);
+
// Attachment Surface Area
static LLCachedControl<F32> max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit", 1000.0f);
info_line = llformat("%.0f m^2", mAttachmentSurfaceArea);
@@ -9295,22 +10131,13 @@ void LLVOAvatar::idleUpdateRenderComplexity()
info_color.set(LLColor4::grey);
info_style = LLFontGL::NORMAL;
}
+
mText->addLine(info_line, info_color, info_style);
updateText(); // corrects position
}
}
-void LLVOAvatar::addAttachmentArea(F32 delta_area)
-{
- mAttachmentSurfaceArea += delta_area;
-}
-
-void LLVOAvatar::subtractAttachmentArea(F32 delta_area)
-{
- mAttachmentSurfaceArea = delta_area > mAttachmentSurfaceArea ? 0.0 : mAttachmentSurfaceArea - delta_area;
-}
-
void LLVOAvatar::updateVisualComplexity()
{
LL_DEBUGS("AvatarRender") << "avatar " << getID() << " appearance changed" << LL_ENDL;
@@ -9318,57 +10145,22 @@ void LLVOAvatar::updateVisualComplexity()
mVisualComplexityStale = true;
}
-// Calculations for mVisualComplexity value
-void LLVOAvatar::calculateUpdateRenderComplexity()
+// Account for the complexity of a single top-level object associated
+// with an avatar. This will be either an attached object or an animated
+// object.
+void LLVOAvatar::accountRenderComplexityForObject(
+ const LLViewerObject *attached_object,
+ const F32 max_attachment_complexity,
+ LLVOVolume::texture_cost_t& textures,
+ U32& cost,
+ hud_complexity_list_t& hud_complexity_list)
{
- /*****************************************************************
- * This calculation should not be modified by third party viewers,
- * since it is used to limit rendering and should be uniform for
- * everyone. If you have suggested improvements, submit them to
- * the official viewer for consideration.
- *****************************************************************/
- static const U32 COMPLEXITY_BODY_PART_COST = 200;
- static LLCachedControl<F32> max_complexity_setting(gSavedSettings,"MaxAttachmentComplexity");
- F32 max_attachment_complexity = max_complexity_setting;
- max_attachment_complexity = llmax(max_attachment_complexity, DEFAULT_MAX_ATTACHMENT_COMPLEXITY);
-
- // Diagnostic list of all textures on our avatar
- static std::set<LLUUID> all_textures;
-
- if (mVisualComplexityStale)
- {
- U32 cost = VISUAL_COMPLEXITY_UNKNOWN;
- LLVOVolume::texture_cost_t textures;
- hud_complexity_list_t hud_complexity_list;
-
- for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
+ if (attached_object && !attached_object->isHUDAttachment())
{
- const LLAvatarAppearanceDictionary::BakedEntry *baked_dict
- = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index);
- ETextureIndex tex_index = baked_dict->mTextureIndex;
- if ((tex_index != TEX_SKIRT_BAKED) || (isWearingWearableType(LLWearableType::WT_SKIRT)))
- {
- if (isTextureVisible(tex_index))
- {
- cost +=COMPLEXITY_BODY_PART_COST;
- }
- }
- }
- LL_DEBUGS("ARCdetail") << "Avatar body parts complexity: " << cost << LL_ENDL;
-
+ mAttachmentVisibleTriangleCount += attached_object->recursiveGetTriangleCount();
+ mAttachmentEstTriangleCount += attached_object->recursiveGetEstTrianglesMax();
+ mAttachmentSurfaceArea += attached_object->recursiveGetScaledSurfaceArea();
- for (attachment_map_t::const_iterator attachment_point = mAttachmentPoints.begin();
- attachment_point != mAttachmentPoints.end();
- ++attachment_point)
- {
- LLViewerJointAttachment* attachment = attachment_point->second;
- for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
- attachment_iter != attachment->mAttachedObjects.end();
- ++attachment_iter)
- {
- const LLViewerObject* attached_object = (*attachment_iter);
- if (attached_object && !attached_object->isHUDAttachment())
- {
textures.clear();
const LLDrawable* drawable = attached_object->mDrawable;
if (drawable)
@@ -9380,7 +10172,12 @@ void LLVOAvatar::calculateUpdateRenderComplexity()
F32 attachment_volume_cost = 0;
F32 attachment_texture_cost = 0;
F32 attachment_children_cost = 0;
+ const F32 animated_object_attachment_surcharge = 1000;
+ if (attached_object->isAnimatedObject())
+ {
+ attachment_volume_cost += animated_object_attachment_surcharge;
+ }
attachment_volume_cost += volume->getRenderCost(textures);
const_child_list_t children = volume->getChildren();
@@ -9424,6 +10221,8 @@ void LLVOAvatar::calculateUpdateRenderComplexity()
{
textures.clear();
+ mAttachmentSurfaceArea += attached_object->recursiveGetScaledSurfaceArea();
+
const LLVOVolume* volume = attached_object->mDrawable->getVOVolume();
if (volume)
{
@@ -9473,6 +10272,77 @@ void LLVOAvatar::calculateUpdateRenderComplexity()
hud_complexity_list.push_back(hud_object_complexity);
}
}
+}
+
+// Calculations for mVisualComplexity value
+void LLVOAvatar::calculateUpdateRenderComplexity()
+{
+ /*****************************************************************
+ * This calculation should not be modified by third party viewers,
+ * since it is used to limit rendering and should be uniform for
+ * everyone. If you have suggested improvements, submit them to
+ * the official viewer for consideration.
+ *****************************************************************/
+ static const U32 COMPLEXITY_BODY_PART_COST = 200;
+ static LLCachedControl<F32> max_complexity_setting(gSavedSettings,"MaxAttachmentComplexity");
+ F32 max_attachment_complexity = max_complexity_setting;
+ max_attachment_complexity = llmax(max_attachment_complexity, DEFAULT_MAX_ATTACHMENT_COMPLEXITY);
+
+ // Diagnostic list of all textures on our avatar
+ static std::set<LLUUID> all_textures;
+
+ if (mVisualComplexityStale)
+ {
+ U32 cost = VISUAL_COMPLEXITY_UNKNOWN;
+ LLVOVolume::texture_cost_t textures;
+ hud_complexity_list_t hud_complexity_list;
+
+ for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
+ {
+ const LLAvatarAppearanceDictionary::BakedEntry *baked_dict
+ = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index);
+ ETextureIndex tex_index = baked_dict->mTextureIndex;
+ if ((tex_index != TEX_SKIRT_BAKED) || (isWearingWearableType(LLWearableType::WT_SKIRT)))
+ {
+ if (isTextureVisible(tex_index))
+ {
+ cost +=COMPLEXITY_BODY_PART_COST;
+ }
+ }
+ }
+ LL_DEBUGS("ARCdetail") << "Avatar body parts complexity: " << cost << LL_ENDL;
+
+ mAttachmentVisibleTriangleCount = 0;
+ mAttachmentEstTriangleCount = 0.f;
+ mAttachmentSurfaceArea = 0.f;
+
+ // A standalone animated object needs to be accounted for
+ // using its associated volume. Attached animated objects
+ // will be covered by the subsequent loop over attachments.
+ LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this);
+ if (control_av)
+ {
+ LLVOVolume *volp = control_av->mRootVolp;
+ if (volp && !volp->isAttachment())
+ {
+ accountRenderComplexityForObject(volp, max_attachment_complexity,
+ textures, cost, hud_complexity_list);
+ }
+ }
+
+ // Account for complexity of all attachments.
+ for (attachment_map_t::const_iterator attachment_point = mAttachmentPoints.begin();
+ attachment_point != mAttachmentPoints.end();
+ ++attachment_point)
+ {
+ LLViewerJointAttachment* attachment = attachment_point->second;
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end();
+ ++attachment_iter)
+ {
+ const LLViewerObject* attached_object = (*attachment_iter);
+ accountRenderComplexityForObject(attached_object, max_attachment_complexity,
+ textures, cost, hud_complexity_list);
}
}