summaryrefslogtreecommitdiff
path: root/indra/newview/llvoavatar.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llvoavatar.cpp')
-rw-r--r--[-rwxr-xr-x]indra/newview/llvoavatar.cpp1428
1 files changed, 1008 insertions, 420 deletions
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 202b63dec0..0423f0e380 100755..100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -1,4 +1,4 @@
-/**
+/**
* @File llvoavatar.cpp
* @brief Implementation of LLVOAvatar class which is a derivation of LLViewerObject
*
@@ -43,6 +43,7 @@
#include "llanimationstates.h"
#include "llavatarnamecache.h"
#include "llavatarpropertiesprocessor.h"
+#include "llavatarrendernotifier.h"
#include "llexperiencecache.h"
#include "llphysicsmotion.h"
#include "llviewercontrol.h"
@@ -105,6 +106,8 @@
#include "llsdutil.h"
#include "llscenemonitor.h"
#include "llsdserialize.h"
+#include "llcallstack.h"
+#include "llrendersphere.h"
extern F32 SPEED_ADJUST_MAX;
extern F32 SPEED_ADJUST_MAX_SEC;
@@ -115,8 +118,6 @@ extern U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG;
const F32 MAX_HOVER_Z = 2.0;
const F32 MIN_HOVER_Z = -2.0;
-// #define OUTPUT_BREAST_DATA
-
using namespace LLAvatarAppearanceDefines;
//-----------------------------------------------------------------------------
@@ -160,6 +161,9 @@ const F32 HEAD_MOVEMENT_AVG_TIME = 0.9f;
const S32 MORPH_MASK_REQUESTED_DISCARD = 0;
+const F32 MAX_STANDOFF_FROM_ORIGIN = 3;
+const F32 MAX_STANDOFF_DISTANCE_CHANGE = 32;
+
// Discard level at which to switch to baked textures
// Should probably be 4 or 3, but didn't want to change it while change other logic - SJB
const S32 SWITCH_TO_BAKED_DISCARD = 5;
@@ -183,6 +187,8 @@ const F32 NAMETAG_UPDATE_THRESHOLD = 0.3f;
const F32 NAMETAG_VERTICAL_SCREEN_OFFSET = 25.f;
const F32 NAMETAG_VERT_OFFSET_WEIGHT = 0.17f;
+const U32 LLVOAvatar::VISUAL_COMPLEXITY_UNKNOWN = 0;
+
enum ERenderName
{
RENDER_NAME_NEVER,
@@ -210,26 +216,8 @@ struct LLTextureMaskData
**
**/
-//------------------------------------------------------------------------
-// LLVOAvatarBoneInfo
-// Trans/Scale/Rot etc. info about each avatar bone. Used by LLVOAvatarSkeleton.
-//------------------------------------------------------------------------
-struct LLVOAvatarCollisionVolumeInfo : public LLInitParam::Block<LLVOAvatarCollisionVolumeInfo>
-{
- LLVOAvatarCollisionVolumeInfo()
- : name("name"),
- pos("pos"),
- rot("rot"),
- scale("scale")
- {}
- Mandatory<std::string> name;
- Mandatory<LLVector3> pos,
- rot,
- scale;
-};
-
-struct LLAppearanceMessageContents
+struct LLAppearanceMessageContents: public LLRefCount
{
LLAppearanceMessageContents():
mAppearanceVersion(-1),
@@ -249,49 +237,6 @@ struct LLAppearanceMessageContents
bool mHoverOffsetWasSet;
};
-struct LLVOAvatarChildJoint : public LLInitParam::ChoiceBlock<LLVOAvatarChildJoint>
- {
- Alternative<Lazy<struct LLVOAvatarBoneInfo, IS_A_BLOCK> > bone;
- Alternative<LLVOAvatarCollisionVolumeInfo> collision_volume;
-
- LLVOAvatarChildJoint()
- : bone("bone"),
- collision_volume("collision_volume")
- {}
-};
-
-
-
-struct LLVOAvatarBoneInfo : public LLInitParam::Block<LLVOAvatarBoneInfo, LLVOAvatarCollisionVolumeInfo>
-{
- LLVOAvatarBoneInfo()
- : pivot("pivot")
- {}
-
- Mandatory<LLVector3> pivot;
- Multiple<LLVOAvatarChildJoint> children;
-};
-
-//------------------------------------------------------------------------
-// LLVOAvatarSkeletonInfo
-// Overall avatar skeleton
-//------------------------------------------------------------------------
-struct LLVOAvatarSkeletonInfo : public LLInitParam::Block<LLVOAvatarSkeletonInfo>
-{
- LLVOAvatarSkeletonInfo()
- : skeleton_root(""),
- num_bones("num_bones"),
- num_collision_volumes("num_collision_volumes"),
- version("version")
- {}
-
- Mandatory<std::string> version;
- Mandatory<S32> num_bones,
- num_collision_volumes;
- Mandatory<LLVOAvatarChildJoint> skeleton_root;
-};
-
-
//-----------------------------------------------------------------------------
// class LLBodyNoiseMotion
@@ -619,7 +564,7 @@ private:
//-----------------------------------------------------------------------------
LLAvatarAppearanceDictionary *LLVOAvatar::sAvatarDictionary = NULL;
S32 LLVOAvatar::sFreezeCounter = 0;
-U32 LLVOAvatar::sMaxVisible = 12;
+U32 LLVOAvatar::sMaxNonImpostors = 12; // overridden based on graphics setting
F32 LLVOAvatar::sRenderDistance = 256.f;
S32 LLVOAvatar::sNumVisibleAvatars = 0;
S32 LLVOAvatar::sNumLODChangesThisFrame = 0;
@@ -646,7 +591,7 @@ BOOL LLVOAvatar::sShowFootPlane = FALSE;
BOOL LLVOAvatar::sVisibleInFirstPerson = FALSE;
F32 LLVOAvatar::sLODFactor = 1.f;
F32 LLVOAvatar::sPhysicsLODFactor = 1.f;
-BOOL LLVOAvatar::sUseImpostors = FALSE;
+bool LLVOAvatar::sUseImpostors = false; // overwridden by RenderAvatarMaxNonImpostors
BOOL LLVOAvatar::sJointDebug = FALSE;
F32 LLVOAvatar::sUnbakedTime = 0.f;
F32 LLVOAvatar::sUnbakedUpdateTime = 0.f;
@@ -667,9 +612,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
LLAvatarAppearance(&gAgentWearables),
LLViewerObject(id, pcode, regionp),
mSpecialRenderMode(0),
- mAttachmentGeometryBytes(-1),
- mAttachmentSurfaceArea(-1.f),
- mReportedVisualComplexity(-1),
+ mAttachmentSurfaceArea(0.f),
+ mReportedVisualComplexity(VISUAL_COMPLEXITY_UNKNOWN),
mTurning(FALSE),
mLastSkeletonSerialNum( 0 ),
mIsSitting(FALSE),
@@ -699,12 +643,14 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mNeedsSkin(FALSE),
mLastSkinTime(0.f),
mUpdatePeriod(1),
+ mVisualComplexityStale(true),
+ mVisuallyMuteSetting(AV_RENDER_NORMALLY),
+ mMutedAVColor(LLColor4::white /* used for "uninitialize" */),
mFirstFullyVisible(TRUE),
mFullyLoaded(FALSE),
mPreviousFullyLoaded(FALSE),
mFullyLoadedInitialized(FALSE),
- mVisualComplexity(0),
- mVisualComplexityStale(TRUE),
+ mVisualComplexity(VISUAL_COMPLEXITY_UNKNOWN),
mLoadedCallbacksPaused(FALSE),
mRenderUnloadedAvatar(LLCachedControl<bool>(gSavedSettings, "RenderUnloadedAvatar", false)),
mLastRezzedStatus(-1),
@@ -715,6 +661,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mCachedMuteListUpdateTime(0),
mCachedInMuteList(false)
{
+ LL_DEBUGS("AvatarRender") << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << LL_ENDL;
+
//VTResume(); // VTune
setHoverOffset(LLVector3(0.0, 0.0, 0.0));
@@ -723,7 +671,6 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mVoiceVisualizer = ( LLVoiceVisualizer *)LLHUDManager::getInstance()->createViewerEffect( LLHUDObject::LL_HUD_EFFECT_VOICE_VISUALIZER, needsSendToSim );
LL_DEBUGS("Avatar","Message") << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << LL_ENDL;
-
mPelvisp = NULL;
mDirtyMesh = 2; // Dirty geometry, need to regenerate.
@@ -772,17 +719,10 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mDebugExistenceTimer.reset();
mLastAppearanceMessageTimer.reset();
- if(LLSceneMonitor::getInstance()->isEnabled())
+ if(LLSceneMonitor::getInstance()->isEnabled())
{
- LLSceneMonitor::getInstance()->freezeAvatar((LLCharacter*)this);
+ LLSceneMonitor::getInstance()->freezeAvatar((LLCharacter*)this);
}
-
- mCachedVisualMute = !isSelf();
- mCachedVisualMuteUpdateTime = LLFrameTimer::getTotalSeconds() + 5.0;
- mVisuallyMuteSetting = VISUAL_MUTE_NOT_SET;
-
- F32 color_value = (F32) (getID().mData[0]);
- mMutedAVColor = calcMutedAVColor(color_value, 0, 256);
}
std::string LLVOAvatar::avString() const
@@ -990,8 +930,8 @@ std::string LLVOAvatar::rezStatusToString(S32 rez_status)
{
if (rez_status==0) return "cloud";
if (rez_status==1) return "gray";
- if (rez_status==2) return "textured";
- if (rez_status==3) return "textured_and_downloaded";
+ if (rez_status==2) return "downloading";
+ if (rez_status==3) return "full";
return "unknown";
}
@@ -1103,6 +1043,7 @@ void LLVOAvatar::resetImpostors()
{
LLVOAvatar* avatar = (LLVOAvatar*) *iter;
avatar->mImpostor.release();
+ avatar->mNeedsImpostorUpdate = TRUE;
}
}
@@ -1111,7 +1052,6 @@ void LLVOAvatar::deleteCachedImages(bool clearAll)
{
if (LLViewerTexLayerSet::sHasCaches)
{
- LL_DEBUGS() << "Deleting layer set caches" << LL_ENDL;
for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
iter != LLCharacter::sInstances.end(); ++iter)
{
@@ -1142,6 +1082,9 @@ void LLVOAvatar::initClass()
gAnimLibrary.animStateSetString(ANIM_AGENT_PELVIS_FIX,"pelvis_fix");
gAnimLibrary.animStateSetString(ANIM_AGENT_TARGET,"target");
gAnimLibrary.animStateSetString(ANIM_AGENT_WALK_ADJUST,"walk_adjust");
+
+ // Where should this be set initially?
+ LLJoint::setDebugJointNames(gSavedSettings.getString("DebugAvatarJoints"));
}
@@ -1395,18 +1338,78 @@ void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
newMax.add(buffer);
}
+void render_sphere_and_line(const LLVector3& begin_pos, const LLVector3& end_pos, F32 sphere_scale, const LLVector3& occ_color, const LLVector3& visible_color)
+{
+ // Unoccluded bone portions
+ LLGLDepthTest normal_depth(GL_TRUE);
+
+ // Draw line segment for unoccluded joint
+ gGL.diffuseColor3f(visible_color[0], visible_color[1], visible_color[2]);
+
+ gGL.begin(LLRender::LINES);
+ gGL.vertex3fv(begin_pos.mV);
+ gGL.vertex3fv(end_pos.mV);
+ gGL.end();
+
+
+ // Draw sphere representing joint pos
+ gGL.pushMatrix();
+ gGL.scalef(sphere_scale, sphere_scale, sphere_scale);
+ gSphere.renderGGL();
+ gGL.popMatrix();
+
+ LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER);
+
+ // Occluded bone portions
+ gGL.diffuseColor3f(occ_color[0], occ_color[1], occ_color[2]);
+
+ gGL.begin(LLRender::LINES);
+ gGL.vertex3fv(begin_pos.mV);
+ gGL.vertex3fv(end_pos.mV);
+ gGL.end();
+
+ // Draw sphere representing joint pos
+ gGL.pushMatrix();
+ gGL.scalef(sphere_scale, sphere_scale, sphere_scale);
+ gSphere.renderGGL();
+ gGL.popMatrix();
+}
+
//-----------------------------------------------------------------------------
// renderCollisionVolumes()
//-----------------------------------------------------------------------------
void LLVOAvatar::renderCollisionVolumes()
{
std::ostringstream ostr;
+
for (S32 i = 0; i < mNumCollisionVolumes; i++)
{
- mCollisionVolumes[i].renderCollision();
ostr << mCollisionVolumes[i].getName() << ", ";
- }
+ LLAvatarJointCollisionVolume& collision_volume = mCollisionVolumes[i];
+
+ collision_volume.updateWorldMatrix();
+
+ gGL.pushMatrix();
+ gGL.multMatrix( &collision_volume.getXform()->getWorldMatrix().mMatrix[0][0] );
+
+ LLVector3 begin_pos(0,0,0);
+ LLVector3 end_pos(collision_volume.getEnd());
+ 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);
+
+ 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();
+ }
+
+
if (mNameText.notNull())
{
LLVector4a unused;
@@ -1418,6 +1421,67 @@ void LLVOAvatar::renderCollisionVolumes()
addDebugText(ostr.str());
}
+void LLVOAvatar::renderBones()
+{
+ LLGLEnable blend(GL_BLEND);
+
+ avatar_joint_list_t::iterator iter = mSkeleton.begin();
+ avatar_joint_list_t::iterator end = mSkeleton.end();
+
+ static LLVector3 BASE_COLOR_OCCLUDED(1.0f, 0.0f, 0.0f);
+ static LLVector3 BASE_COLOR_VISIBLE(0.5f, 0.5f, 0.5f);
+ static LLVector3 EXTENDED_COLOR_OCCLUDED(0.0f, 1.0f, 0.0f);
+ static LLVector3 EXTENDED_COLOR_VISIBLE(0.5f, 0.5f, 0.5f);
+ static LLVector3 RIGGED_COLOR_OCCLUDED(0.0f, 1.0f, 1.0f);
+ static LLVector3 RIGGED_COLOR_VISIBLE(0.5f, 0.5f, 0.5f);
+
+ static F32 SPHERE_SCALEF = 0.001f;
+
+ for (; iter != end; ++iter)
+ {
+ LLJoint* jointp = *iter;
+ if (!jointp)
+ {
+ continue;
+ }
+
+ jointp->updateWorldMatrix();
+ LLJoint::SupportCategory sc = jointp->getSupport();
+ LLVector3 occ_color, visible_color;
+
+ if (jointIsRiggedTo(jointp->getName()))
+ {
+ occ_color = RIGGED_COLOR_OCCLUDED;
+ visible_color = RIGGED_COLOR_VISIBLE;
+ }
+ else
+ {
+ if (sc == LLJoint::SUPPORT_BASE)
+ {
+ occ_color = BASE_COLOR_OCCLUDED;
+ visible_color = BASE_COLOR_VISIBLE;
+ }
+ else
+ {
+ occ_color = EXTENDED_COLOR_OCCLUDED;
+ visible_color = EXTENDED_COLOR_VISIBLE;
+ }
+ }
+ LLVector3 begin_pos(0,0,0);
+ LLVector3 end_pos(jointp->getEnd());
+
+ F32 sphere_scale = SPHERE_SCALEF;
+
+ gGL.pushMatrix();
+ gGL.multMatrix( &jointp->getXform()->getWorldMatrix().mMatrix[0][0] );
+
+ render_sphere_and_line(begin_pos, end_pos, sphere_scale, occ_color, visible_color);
+
+ gGL.popMatrix();
+ }
+}
+
+
void LLVOAvatar::renderJoints()
{
std::ostringstream ostr;
@@ -1508,6 +1572,7 @@ void LLVOAvatar::renderJoints()
BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
S32 face,
BOOL pick_transparent,
+ BOOL pick_rigged,
S32* face_hit,
LLVector4a* intersection,
LLVector2* tex_coord,
@@ -1524,7 +1589,7 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
for (S32 i = 0; i < mNumCollisionVolumes; ++i)
{
mCollisionVolumes[i].updateWorldMatrix();
-
+
glh::matrix4f mat((F32*) mCollisionVolumes[i].getXform()->getWorldMatrix().mMatrix);
glh::matrix4f inverse = mat.inverse();
glh::matrix4f norm_mat = inverse.transpose();
@@ -1607,6 +1672,7 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector4a& start, const LLVector4a& end,
S32 face,
BOOL pick_transparent,
+ BOOL pick_rigged,
S32* face_hit,
LLVector4a* intersection,
LLVector2* tex_coord,
@@ -1637,7 +1703,7 @@ LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector
{
LLViewerObject* attached_object = (*attachment_iter);
- if (attached_object->lineSegmentIntersect(start, local_end, face, pick_transparent, face_hit, &local_intersection, tex_coord, normal, tangent))
+ if (attached_object->lineSegmentIntersect(start, local_end, face, pick_transparent, pick_rigged, face_hit, &local_intersection, tex_coord, normal, tangent))
{
local_end = local_intersection;
if (intersection)
@@ -1732,6 +1798,127 @@ void LLVOAvatar::buildCharacter()
mMeshValid = TRUE;
}
+//-----------------------------------------------------------------------------
+// resetVisualParams()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::resetVisualParams()
+{
+ // Skeletal params
+ {
+ LLAvatarXmlInfo::skeletal_distortion_info_list_t::iterator iter;
+ for (iter = sAvatarXmlInfo->mSkeletalDistortionInfoList.begin();
+ iter != sAvatarXmlInfo->mSkeletalDistortionInfoList.end();
+ ++iter)
+ {
+ LLPolySkeletalDistortionInfo *info = (LLPolySkeletalDistortionInfo*)*iter;
+ LLPolySkeletalDistortion *param = dynamic_cast<LLPolySkeletalDistortion*>(getVisualParam(info->getID()));
+ *param = LLPolySkeletalDistortion(this);
+ llassert(param);
+ if (!param->setInfo(info))
+ {
+ llassert(false);
+ }
+ }
+ }
+
+ // Driver parameters
+ for (LLAvatarXmlInfo::driver_info_list_t::iterator iter = sAvatarXmlInfo->mDriverInfoList.begin();
+ iter != sAvatarXmlInfo->mDriverInfoList.end();
+ ++iter)
+ {
+ LLDriverParamInfo *info = *iter;
+ LLDriverParam *param = dynamic_cast<LLDriverParam*>(getVisualParam(info->getID()));
+ LLDriverParam::entry_list_t driven_list = param->getDrivenList();
+ *param = LLDriverParam(this);
+ llassert(param);
+ if (!param->setInfo(info))
+ {
+ llassert(false);
+ }
+ param->setDrivenList(driven_list);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// resetSkeleton()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::resetSkeleton()
+{
+ LL_DEBUGS("Avatar") << avString() << " reset starts" << LL_ENDL;
+ if (!mLastProcessedAppearance)
+ {
+ LL_WARNS() << "Can't reset avatar; no appearance message has been received yet." << LL_ENDL;
+ return;
+ }
+
+ // Save mPelvis state
+ //LLVector3 pelvis_pos = getJoint("mPelvis")->getPosition();
+ //LLQuaternion pelvis_rot = getJoint("mPelvis")->getRotation();
+
+ // Clear all attachment pos overrides
+ clearAttachmentPosOverrides();
+
+ // Note that we call buildSkeleton twice in this function. The first time is
+ // just to get the right scale for the collision volumes, because
+ // this will be used in setting the mJointScales for the
+ // LLPolySkeletalDistortions of which the CVs are children.
+ if( !buildSkeleton(sAvatarSkeletonInfo) )
+ {
+ LL_ERRS() << "Error resetting skeleton" << LL_ENDL;
+ }
+
+ // Reset some params to default state, without propagating changes downstream.
+ resetVisualParams();
+
+ // Now we have to reset the skeleton again, because its state
+ // got clobbered by the resetVisualParams() calls
+ // above.
+ if( !buildSkeleton(sAvatarSkeletonInfo) )
+ {
+ LL_ERRS() << "Error resetting skeleton" << LL_ENDL;
+ }
+
+ // Reset attachment points (buildSkeleton only does bones and CVs)
+ bool ignore_hud_joints = true;
+ initAttachmentPoints(ignore_hud_joints);
+
+ // Fix up collision volumes
+ for (LLVisualParam *param = getFirstVisualParam();
+ param;
+ param = getNextVisualParam())
+ {
+ LLPolyMorphTarget *poly_morph = dynamic_cast<LLPolyMorphTarget*>(param);
+ if (poly_morph)
+ {
+ // This is a kludgy way to correct for the fact that the
+ // collision volumes have been reset out from under the
+ // poly morph sliders.
+ F32 delta_weight = poly_morph->getLastWeight() - poly_morph->getDefaultWeight();
+ poly_morph->applyVolumeChanges(delta_weight);
+ }
+ }
+
+ // Reset tweakable params to preserved state
+ bool slam_params = true;
+ applyParsedAppearanceMessage(*mLastProcessedAppearance, slam_params);
+
+ updateVisualParams();
+
+ // Restore attachment pos overrides
+ rebuildAttachmentPosOverrides();
+
+ // Restore mPelvis state
+ //getJoint("mPelvis")->setRotation(pelvis_rot);
+ //getJoint("mPelvis")->setPosition(pelvis_pos);
+
+ // Restart animations BENTO - not needed? Removing this fixes a
+ // problem seen if avatar is sitting and animated relative to sit
+ // point.
+
+ //resetAnimations();
+
+ LL_DEBUGS("Avatar") << avString() << " reset ends" << LL_ENDL;
+}
//-----------------------------------------------------------------------------
// releaseMeshData()
@@ -1743,8 +1930,6 @@ void LLVOAvatar::releaseMeshData()
return;
}
- LL_DEBUGS() << "Releasing mesh data" << LL_ENDL;
-
// cleanup mesh data
for (avatar_joint_list_t::iterator iter = mMeshLOD.begin();
iter != mMeshLOD.end();
@@ -1954,17 +2139,12 @@ U32 LLVOAvatar::processUpdateMessage(LLMessageSystem *mesgsys,
// Do base class updates...
U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp);
- //LLTEContents tec;
- //S32 te_retval = parseTEMessage(mesgsys, _PREHASH_ObjectData, block_num, tec);
-
- LL_DEBUGS("Avatar") << avString() << update_type << LL_ENDL;
-
// Print out arrival information once we have name of avatar.
- if (has_name && getNVPair("FirstName"))
- {
- mDebugExistenceTimer.reset();
- debugAvatarRezTime("AvatarRezArrivedNotification","avatar arrived");
- }
+ if (has_name && getNVPair("FirstName"))
+ {
+ mDebugExistenceTimer.reset();
+ debugAvatarRezTime("AvatarRezArrivedNotification","avatar arrived");
+ }
if(retval & LLViewerObject::INVALID_UPDATE)
{
@@ -1987,7 +2167,7 @@ LLViewerFetchedTexture *LLVOAvatar::getBakedTextureImage(const U8 te, const LLUU
uuid == IMG_INVISIBLE)
{
// Should already exist, don't need to find it on sim or baked-texture host.
- result = gTextureList.findImage(uuid);
+ result = gTextureList.findImage(uuid, TEX_LIST_STANDARD);
}
if (!result)
{
@@ -2072,6 +2252,8 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
return;
}
+ LLScopedContextString str("avatar_idle_update " + getFullname());
+
checkTextureLoading() ;
// force immediate pixel area update on avatars using last frames data (before drawable or camera updates)
@@ -2132,7 +2314,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
// animate the character
// store off last frame's root position to be consistent with camera position
- LLVector3 root_pos_last = mRoot->getWorldPosition();
+ mLastRootPos = mRoot->getWorldPosition();
BOOL detailed_update = updateCharacter(agent);
static LLUICachedControl<bool> visualizers_in_calls("ShowVoiceVisualizersInCalls", false);
@@ -2150,8 +2332,8 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
idleUpdateWindEffect();
}
- idleUpdateNameTag( root_pos_last );
- idleUpdateRenderCost();
+ idleUpdateNameTag( mLastRootPos );
+ idleUpdateRenderComplexity();
}
void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
@@ -2491,19 +2673,22 @@ void LLVOAvatar::idleUpdateLoadingEffect()
// update visibility when avatar is partially loaded
if (updateIsFullyLoaded()) // changed?
{
- if (isFullyLoaded() && mFirstFullyVisible && isSelf())
- {
- LL_INFOS("Avatar") << avString() << "self isFullyLoaded, mFirstFullyVisible" << LL_ENDL;
- mFirstFullyVisible = FALSE;
- LLAppearanceMgr::instance().onFirstFullyVisible();
- }
- if (isFullyLoaded() && mFirstFullyVisible && !isSelf())
- {
- LL_INFOS("Avatar") << avString() << "other isFullyLoaded, mFirstFullyVisible" << LL_ENDL;
- mFirstFullyVisible = FALSE;
- }
if (isFullyLoaded())
{
+ if (mFirstFullyVisible)
+ {
+ mFirstFullyVisible = FALSE;
+ if (isSelf())
+ {
+ LL_INFOS("Avatar") << avString() << "self isFullyLoaded, mFirstFullyVisible" << LL_ENDL;
+ LLAppearanceMgr::instance().onFirstFullyVisible();
+ }
+ else
+ {
+ LL_INFOS("Avatar") << avString() << "other isFullyLoaded, mFirstFullyVisible" << LL_ENDL;
+ }
+ }
+
deleteParticleSource();
updateLOD();
}
@@ -2728,7 +2913,7 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name)
}
else
{
- is_muted = LLMuteList::getInstance()->isMuted(getID());
+ is_muted = isInMuteList();
}
bool is_friend = LLAvatarTracker::instance().isBuddy(getID());
bool is_cloud = getIsCloud();
@@ -3073,6 +3258,7 @@ void LLVOAvatar::idleUpdateBelowWater()
void LLVOAvatar::slamPosition()
{
gAgent.setPositionAgent(getPositionAgent());
+ // SL-315
mRoot->setWorldPosition(getPositionAgent()); // teleport
setChanged(TRANSLATED);
if (mDrawable.notNull())
@@ -3086,86 +3272,32 @@ bool LLVOAvatar::isVisuallyMuted()
{
bool muted = false;
+ // Priority order (highest priority first)
+ // * own avatar is never visually muted
+ // * if on the "always draw normally" list, draw them normally
+ // * if on the "always visually mute" list, mute them
+ // * check against the render cost and attachment limits
if (!isSelf())
{
- static LLCachedControl<U32> render_auto_mute_functions(gSavedSettings, "RenderAutoMuteFunctions", 0);
- if (render_auto_mute_functions) // Hacky debug switch for developing feature
+ if (mVisuallyMuteSetting == AV_ALWAYS_RENDER)
{
- // Priority order (highest priority first)
- // * own avatar is never visually muted
- // * if on the "always draw normally" list, draw them normally
- // * if on the "always visually mute" list, mute them
- // * draw them normally if they meet the following criteria:
- // - within the closest N avatars OR on friends list OR in an IM chat
- // - AND aren't over the thresholds
- // * otherwise visually mute all other avatars
-
- static LLCachedControl<U32> max_attachment_bytes(gSavedSettings, "RenderAutoMuteByteLimit", 0);
- static LLCachedControl<F32> max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit", 0.0);
- static LLCachedControl<U32> max_render_cost(gSavedSettings, "RenderAutoMuteRenderWeightLimit", 0);
-
- if (mVisuallyMuteSetting == ALWAYS_VISUAL_MUTE)
- { // Always want to see this AV as an impostor
- muted = true;
- }
- else if (mVisuallyMuteSetting == NEVER_VISUAL_MUTE)
- { // Never show as impostor
- muted = false;
- }
- else
- {
- F64 now = LLFrameTimer::getTotalSeconds();
-
- if (now < mCachedVisualMuteUpdateTime)
- { // Use cached mute value
- muted = mCachedVisualMute;
- }
- else
- { // Determine if visually muted or not
-
- U32 max_cost = (U32) (max_render_cost*(LLVOAvatar::sLODFactor+0.5));
-
- muted = (mAttachmentGeometryBytes > max_attachment_bytes && max_attachment_bytes > 0) ||
- (mAttachmentSurfaceArea > max_attachment_area && max_attachment_area > 0.f) ||
- (mVisualComplexity > max_cost && max_render_cost > 0);
-
- // Could be part of the grand || collection above, but yanked out to make the logic visible
- if (!muted)
- {
- if (sMaxVisible > 0)
- { // They are above the visibilty rank - mute them
- muted = (mVisibilityRank > sMaxVisible);
- }
-
- // Always draw friends or those in IMs. Needs UI?
- if ((render_auto_mute_functions & 0x02) &&
- (muted || sMaxVisible == 0)) // Don't mute friends or IMs
- {
- muted = !(LLAvatarTracker::instance().isBuddy(getID()));
- if (muted)
- { // Not a friend, so they are muted ... are they in an IM?
- LLUUID session_id = gIMMgr->computeSessionID(IM_NOTHING_SPECIAL,getID());
- muted = !gIMMgr->hasSession(session_id);
- }
- }
- }
-
- // Save visual mute state and set interval for updating
- const F64 SECONDS_BETWEEN_RENDER_AUTO_MUTE_UPDATES = 1.5;
- mCachedVisualMuteUpdateTime = now + SECONDS_BETWEEN_RENDER_AUTO_MUTE_UPDATES;
- mCachedVisualMute = muted;
- }
- }
+ muted = false;
+ }
+ else if (mVisuallyMuteSetting == AV_DO_NOT_RENDER)
+ { // Always want to see this AV as an impostor
+ muted = true;
+ }
+ else if (isInMuteList())
+ {
+ muted = true;
+ }
+ else
+ {
+ muted = isTooComplex();
}
}
- return muted || isInMuteList();
-}
-
-void LLVOAvatar::forceUpdateVisualMuteSettings()
-{
- // Set the cache time so it's updated ASAP
- mCachedVisualMuteUpdateTime = LLFrameTimer::getTotalSeconds() - 1.0;
+ return muted;
}
bool LLVOAvatar::isInMuteList()
@@ -3330,18 +3462,18 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
{ // visually muted avatars update at 16 hz
mUpdatePeriod = 16;
}
- else if (mVisibilityRank <= LLVOAvatar::sMaxVisible ||
- 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
- //impostor camera near clip plane
+ 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
+ // impostor camera near clip plane
mUpdatePeriod = 1;
}
- else if (mVisibilityRank > LLVOAvatar::sMaxVisible * 4)
+ else if ( shouldImpostor(4) )
{ //background avatars are REALLY slow updating impostors
mUpdatePeriod = 16;
}
- else if (mVisibilityRank > LLVOAvatar::sMaxVisible * 3)
+ else if ( shouldImpostor(3) )
{ //back 25% of max visible avatars are slow updating impostors
mUpdatePeriod = 8;
}
@@ -3425,6 +3557,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
mTimeLast = animation_time;
// put the pelvis at slaved position/mRotation
+ // SL-315
mRoot->setWorldPosition( getPositionAgent() ); // first frame
mRoot->setWorldRotation( getRotation() );
}
@@ -3479,6 +3612,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
if (newPosition != mRoot->getXform()->getWorldPosition())
{
mRoot->touch();
+ // SL-315
mRoot->setWorldPosition( newPosition ); // regular update
}
@@ -3642,6 +3776,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
{
LLVector3 pos = mDrawable->getPosition();
pos += getHoverOffset() * mDrawable->getRotation();
+ // SL-315
mRoot->setPosition(pos);
mRoot->setRotation(mDrawable->getRotation());
}
@@ -3672,6 +3807,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
LLVector3 pos = mRoot->getWorldPosition();
pos.mV[VZ] += off_z;
mRoot->touch();
+ // SL-315
mRoot->setWorldPosition(pos);
}
}
@@ -3925,6 +4061,10 @@ void LLVOAvatar::updateVisibility()
}
}
+ if ( visible != mVisible )
+ {
+ LL_DEBUGS("AvatarRender") << "visible was " << mVisible << " now " << visible << LL_ENDL;
+ }
mVisible = visible;
}
@@ -4114,11 +4254,9 @@ U32 LLVOAvatar::renderSkinned()
BOOL first_pass = TRUE;
if (!LLDrawPoolAvatar::sSkipOpaque)
{
- bool visually_muted = isVisuallyMuted();
-
if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender)
{
- if (isTextureVisible(TEX_HEAD_BAKED) || mIsDummy || visually_muted)
+ if (isTextureVisible(TEX_HEAD_BAKED) || mIsDummy)
{
LLViewerJoint* head_mesh = getViewerJoint(MESH_ID_HEAD);
if (head_mesh)
@@ -4128,7 +4266,7 @@ U32 LLVOAvatar::renderSkinned()
first_pass = FALSE;
}
}
- if (isTextureVisible(TEX_UPPER_BAKED) || mIsDummy || visually_muted)
+ if (isTextureVisible(TEX_UPPER_BAKED) || mIsDummy)
{
LLViewerJoint* upper_mesh = getViewerJoint(MESH_ID_UPPER_BODY);
if (upper_mesh)
@@ -4138,7 +4276,7 @@ U32 LLVOAvatar::renderSkinned()
first_pass = FALSE;
}
- if (isTextureVisible(TEX_LOWER_BAKED) || mIsDummy || visually_muted)
+ if (isTextureVisible(TEX_LOWER_BAKED) || mIsDummy)
{
LLViewerJoint* lower_mesh = getViewerJoint(MESH_ID_LOWER_BODY);
if (lower_mesh)
@@ -4197,8 +4335,8 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass)
}
// 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 ( (getImage(TEX_HAIR_BAKED, 0) && getImage(TEX_HAIR_BAKED, 0)->getID() != IMG_INVISIBLE)
+ || LLDrawPoolAlpha::sShowDebugAlpha)
{
LLViewerJoint* hair_mesh = getViewerJoint(MESH_ID_HAIR);
if (hair_mesh)
@@ -4308,7 +4446,7 @@ bool LLVOAvatar::allTexturesCompletelyDownloaded(std::set<LLUUID>& ids) const
{
for (std::set<LLUUID>::const_iterator it = ids.begin(); it != ids.end(); ++it)
{
- LLViewerFetchedTexture *imagep = gTextureList.findImage(*it);
+ LLViewerFetchedTexture *imagep = gTextureList.findImage(*it, TEX_LIST_STANDARD);
if (imagep && imagep->getDiscardLevel()!=0)
{
return false;
@@ -4380,7 +4518,7 @@ S32Bytes LLVOAvatar::totalTextureMemForUUIDS(std::set<LLUUID>& ids)
S32Bytes result(0);
for (std::set<LLUUID>::const_iterator it = ids.begin(); it != ids.end(); ++it)
{
- LLViewerFetchedTexture *imagep = gTextureList.findImage(*it);
+ LLViewerFetchedTexture *imagep = gTextureList.findImage(*it, TEX_LIST_STANDARD);
if (imagep)
{
result += imagep->getTextureMemory();
@@ -4468,7 +4606,7 @@ void LLVOAvatar::releaseOldTextures()
{
if (new_texture_ids.find(*it) == new_texture_ids.end())
{
- LLViewerFetchedTexture *imagep = gTextureList.findImage(*it);
+ LLViewerFetchedTexture *imagep = gTextureList.findImage(*it, TEX_LIST_STANDARD);
if (imagep)
{
current_texture_mem += imagep->getTextureMemory();
@@ -5144,8 +5282,66 @@ bool LLVOAvatar::getRiggedMeshID(LLViewerObject* pVO, LLUUID& mesh_id)
return false;
}
+bool LLVOAvatar::jointIsRiggedTo(const std::string& joint_name)
+{
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end();
+ ++iter)
+ {
+ 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))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool LLVOAvatar::jointIsRiggedTo(const std::string& joint_name, const LLViewerObject *vo)
+{
+ // 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)
+ {
+ LLViewerObject *childp = *it;
+ if (jointIsRiggedTo(joint_name,childp))
+ {
+ return true;
+ }
+ }
+
+ const LLVOVolume *vobj = dynamic_cast<const LLVOVolume*>(vo);
+ if (!vobj)
+ {
+ return false;
+ }
+
+ LLUUID currentId = vobj->getVolume()->getParams().getSculptID();
+ const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj );
+
+ if ( vobj && vobj->isAttachment() && vobj->isMesh() && pSkinData )
+ {
+ if (std::find(pSkinData->mJointNames.begin(), pSkinData->mJointNames.end(), joint_name) !=
+ pSkinData->mJointNames.end())
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void LLVOAvatar::clearAttachmentPosOverrides()
{
+ LLScopedContextString str("clearAttachmentPosOverrides " + getFullname());
+
//Subsequent joints are relative to pelvis
avatar_joint_list_t::iterator iter = mSkeleton.begin();
avatar_joint_list_t::iterator end = mSkeleton.end();
@@ -5158,9 +5354,44 @@ void LLVOAvatar::clearAttachmentPosOverrides()
pJoint->clearAttachmentPosOverrides();
}
}
+
+ // Attachment points
+ for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end();
+ ++iter)
+ {
+ LLViewerJointAttachment *attachment_pt = (*iter).second;
+ if (attachment_pt)
+ {
+ attachment_pt->clearAttachmentPosOverrides();
+ }
+ }
}
//-----------------------------------------------------------------------------
+// rebuildAttachmentPosOverrides
+//-----------------------------------------------------------------------------
+void LLVOAvatar::rebuildAttachmentPosOverrides()
+{
+ LLScopedContextString str("rebuildAttachmentPosOverrides " + getFullname());
+
+ // Attachment points
+ 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)
+ {
+ addAttachmentPosOverridesForObject(*at_it);
+ }
+ }
+ }
+}
+//-----------------------------------------------------------------------------
// addAttachmentPosOverridesForObject
//-----------------------------------------------------------------------------
void LLVOAvatar::addAttachmentPosOverridesForObject(LLViewerObject *vo)
@@ -5170,7 +5401,9 @@ void LLVOAvatar::addAttachmentPosOverridesForObject(LLViewerObject *vo)
{
LL_WARNS("Avatar") << "called with invalid avatar" << LL_ENDL;
}
-
+
+ LLScopedContextString str("addAttachmentPosOverridesForObject " + av->getFullname());
+
// Process all children
LLViewerObject::const_child_list_t& children = vo->getChildren();
for (LLViewerObject::const_child_list_t::const_iterator it = children.begin();
@@ -5198,9 +5431,13 @@ void LLVOAvatar::addAttachmentPosOverridesForObject(LLViewerObject *vo)
if ( vobj && vobj->isAttachment() && vobj->isMesh() && pSkinData )
{
const int bindCnt = pSkinData->mAlternateBindMatrix.size();
- if ( bindCnt > 0 )
+ const int jointCnt = pSkinData->mJointNames.size();
+ if ((bindCnt > 0) && (bindCnt != jointCnt))
+ {
+ LL_WARNS_ONCE() << "invalid mesh, bindCnt " << bindCnt << "!= jointCnt " << jointCnt << ", joint overrides will be ignored." << LL_ENDL;
+ }
+ if ((bindCnt > 0) && (bindCnt == jointCnt))
{
- const int jointCnt = pSkinData->mJointNames.size();
const F32 pelvisZOffset = pSkinData->mPelvisOffset;
const LLUUID& mesh_id = pSkinData->mMeshID;
bool fullRig = (jointCnt>=JOINT_COUNT_REQUIRED_FOR_FULLRIG) ? true : false;
@@ -5214,14 +5451,14 @@ void LLVOAvatar::addAttachmentPosOverridesForObject(LLViewerObject *vo)
{
pJoint->setId( currentId );
const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation();
- //Set the joint position
- pJoint->addAttachmentPosOverride( jointPos, mesh_id, avString() );
-
- //If joint is a pelvis then handle old/new pelvis to foot values
- if ( lookingForJoint == "mPelvis" )
- {
- pelvisGotSet = true;
- }
+ //Set the joint position
+ pJoint->addAttachmentPosOverride( jointPos, mesh_id, avString() );
+
+ //If joint is a pelvis then handle old/new pelvis to foot values
+ if ( lookingForJoint == "mPelvis" )
+ {
+ pelvisGotSet = true;
+ }
}
}
if (pelvisZOffset != 0.0F)
@@ -5241,6 +5478,98 @@ void LLVOAvatar::addAttachmentPosOverridesForObject(LLViewerObject *vo)
}
//-----------------------------------------------------------------------------
+// getAttachmentOverrideNames
+//-----------------------------------------------------------------------------
+void LLVOAvatar::getAttachmentOverrideNames(std::set<std::string>& names) const
+{
+ LLVector3 pos;
+ LLUUID mesh_id;
+
+ // Bones
+ for (avatar_joint_list_t::const_iterator iter = mSkeleton.begin();
+ iter != mSkeleton.end(); ++iter)
+ {
+ const LLJoint* pJoint = (*iter);
+ if (pJoint && pJoint->hasAttachmentPosOverride(pos,mesh_id))
+ {
+ names.insert(pJoint->getName());
+ }
+ }
+
+ // Attachment points
+ for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end();
+ ++iter)
+ {
+ const LLViewerJointAttachment *attachment_pt = (*iter).second;
+ if (attachment_pt && attachment_pt->hasAttachmentPosOverride(pos,mesh_id))
+ {
+ names.insert(attachment_pt->getName());
+ }
+ }
+
+}
+
+//-----------------------------------------------------------------------------
+// showAttachmentPosOverrides
+//-----------------------------------------------------------------------------
+void LLVOAvatar::showAttachmentPosOverrides(bool verbose) const
+{
+ std::set<std::string> joint_names;
+ getAttachmentOverrideNames(joint_names);
+ if (joint_names.size())
+ {
+ std::stringstream ss;
+ std::copy(joint_names.begin(), joint_names.end(), std::ostream_iterator<std::string>(ss, ","));
+ LL_INFOS() << getFullname() << " attachment positions defined for joints: " << ss.str() << "\n" << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS() << getFullname() << " no attachment positions defined for any joints" << "\n" << LL_ENDL;
+ }
+
+ if (!verbose)
+ {
+ return;
+ }
+
+ LLVector3 pos;
+ LLUUID mesh_id;
+ S32 count = 0;
+
+ // Bones
+ for (avatar_joint_list_t::const_iterator iter = mSkeleton.begin();
+ iter != mSkeleton.end(); ++iter)
+ {
+ const LLJoint* pJoint = (*iter);
+ if (pJoint && pJoint->hasAttachmentPosOverride(pos,mesh_id))
+ {
+ pJoint->showAttachmentPosOverrides(getFullname());
+ count++;
+ }
+ }
+
+ // Attachment points
+ for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end();
+ ++iter)
+ {
+ const LLViewerJointAttachment *attachment_pt = (*iter).second;
+ if (attachment_pt && attachment_pt->hasAttachmentPosOverride(pos,mesh_id))
+ {
+ attachment_pt->showAttachmentPosOverrides(getFullname());
+ count++;
+ }
+ }
+
+ if (count)
+ {
+ LL_DEBUGS("Avatar") << avString() << " end of pos overrides" << LL_ENDL;
+ LL_DEBUGS("Avatar") << "=================================" << LL_ENDL;
+ }
+}
+
+//-----------------------------------------------------------------------------
// resetJointPositionsOnDetach
//-----------------------------------------------------------------------------
void LLVOAvatar::resetJointPositionsOnDetach(LLViewerObject *vo)
@@ -5291,6 +5620,7 @@ void LLVOAvatar::resetJointPositionsOnDetach(const LLUUID& mesh_id)
if ( pJoint && pJoint == pJointPelvis)
{
removePelvisFixup( mesh_id );
+ // SL-315
pJoint->setPosition( LLVector3( 0.0f, 0.0f, 0.0f) );
}
}
@@ -5422,89 +5752,99 @@ BOOL LLVOAvatar::loadSkeletonNode ()
return FALSE;
}
- // ATTACHMENTS
- {
- LLAvatarXmlInfo::attachment_info_list_t::iterator iter;
- for (iter = sAvatarXmlInfo->mAttachmentInfoList.begin();
- iter != sAvatarXmlInfo->mAttachmentInfoList.end();
- ++iter)
- {
- LLAvatarXmlInfo::LLAvatarAttachmentInfo *info = *iter;
- if (!isSelf() && info->mJointName == "mScreen")
- { //don't process screen joint for other avatars
- continue;
- }
+ bool ignore_hud_joints = false;
+ initAttachmentPoints(ignore_hud_joints);
- LLViewerJointAttachment* attachment = new LLViewerJointAttachment();
+ return TRUE;
+}
- attachment->setName(info->mName);
- LLJoint *parent_joint = getJoint(info->mJointName);
- if (!parent_joint)
+//-----------------------------------------------------------------------------
+// initAttachmentPoints(): creates attachment points if needed, sets state based on avatar_lad.xml.
+//-----------------------------------------------------------------------------
+void LLVOAvatar::initAttachmentPoints(bool ignore_hud_joints)
+{
+ LLAvatarXmlInfo::attachment_info_list_t::iterator iter;
+ for (iter = sAvatarXmlInfo->mAttachmentInfoList.begin();
+ iter != sAvatarXmlInfo->mAttachmentInfoList.end();
+ ++iter)
+ {
+ LLAvatarXmlInfo::LLAvatarAttachmentInfo *info = *iter;
+ if (info->mIsHUDAttachment && (!isSelf() || ignore_hud_joints))
+ {
+ //don't process hud joint for other avatars, or when doing a skeleton reset.
+ continue;
+ }
+
+ S32 attachmentID = info->mAttachmentID;
+ if (attachmentID < 1 || attachmentID > 255)
+ {
+ LL_WARNS() << "Attachment point out of range [1-255]: " << attachmentID << " on attachment point " << info->mName << LL_ENDL;
+ continue;
+ }
+
+ LLViewerJointAttachment* attachment = NULL;
+ bool newly_created = false;
+ if (mAttachmentPoints.find(attachmentID) == mAttachmentPoints.end())
+ {
+ attachment = new LLViewerJointAttachment();
+ newly_created = true;
+ }
+ else
+ {
+ attachment = mAttachmentPoints[attachmentID];
+ }
+
+ attachment->setName(info->mName);
+ LLJoint *parent_joint = getJoint(info->mJointName);
+ if (!parent_joint)
+ {
+ // If the intended parent for attachment point is unavailable, avatar_lad.xml is corrupt.
+ LL_WARNS() << "No parent joint by name " << info->mJointName << " found for attachment point " << info->mName << LL_ENDL;
+ LL_ERRS() << "Invalid avatar_lad.xml file" << LL_ENDL;
+ }
+
+ if (info->mHasPosition)
+ {
+ attachment->setOriginalPosition(info->mPosition);
+ attachment->setDefaultPosition(info->mPosition);
+ }
+
+ if (info->mHasRotation)
+ {
+ LLQuaternion rotation;
+ rotation.setQuat(info->mRotationEuler.mV[VX] * DEG_TO_RAD,
+ info->mRotationEuler.mV[VY] * DEG_TO_RAD,
+ info->mRotationEuler.mV[VZ] * DEG_TO_RAD);
+ attachment->setRotation(rotation);
+ }
+
+ int group = info->mGroup;
+ if (group >= 0)
+ {
+ if (group < 0 || group > 9)
{
- // If the intended location for attachment point is unavailable, stick it in a default location.
- LL_INFOS() << "attachment pt " << info->mName << " using mPelvis as default parent" << LL_ENDL;
- parent_joint = getJoint("mPelvis");
+ LL_WARNS() << "Invalid group number (" << group << ") for attachment point " << info->mName << LL_ENDL;
}
- if (!parent_joint)
- {
- LL_WARNS() << "No parent joint by name " << info->mJointName << " found for attachment point " << info->mName << LL_ENDL;
- delete attachment;
- continue;
- }
-
- if (info->mHasPosition)
- {
- attachment->setOriginalPosition(info->mPosition);
- }
-
- if (info->mHasRotation)
- {
- LLQuaternion rotation;
- rotation.setQuat(info->mRotationEuler.mV[VX] * DEG_TO_RAD,
- info->mRotationEuler.mV[VY] * DEG_TO_RAD,
- info->mRotationEuler.mV[VZ] * DEG_TO_RAD);
- attachment->setRotation(rotation);
- }
-
- int group = info->mGroup;
- if (group >= 0)
- {
- if (group < 0 || group >= 9)
- {
- LL_WARNS() << "Invalid group number (" << group << ") for attachment point " << info->mName << LL_ENDL;
- }
- else
- {
- attachment->setGroup(group);
- }
- }
-
- S32 attachmentID = info->mAttachmentID;
- if (attachmentID < 1 || attachmentID > 255)
- {
- LL_WARNS() << "Attachment point out of range [1-255]: " << attachmentID << " on attachment point " << info->mName << LL_ENDL;
- delete attachment;
- continue;
- }
- if (mAttachmentPoints.find(attachmentID) != mAttachmentPoints.end())
- {
- LL_WARNS() << "Attachment point redefined with id " << attachmentID << " on attachment point " << info->mName << LL_ENDL;
- delete attachment;
- continue;
- }
-
- attachment->setPieSlice(info->mPieMenuSlice);
- attachment->setVisibleInFirstPerson(info->mVisibleFirstPerson);
- attachment->setIsHUDAttachment(info->mIsHUDAttachment);
-
- mAttachmentPoints[attachmentID] = attachment;
-
- // now add attachment joint
- parent_joint->addChild(attachment);
- }
- }
-
- return TRUE;
+ else
+ {
+ attachment->setGroup(group);
+ }
+ }
+
+ attachment->setPieSlice(info->mPieMenuSlice);
+ attachment->setVisibleInFirstPerson(info->mVisibleFirstPerson);
+ attachment->setIsHUDAttachment(info->mIsHUDAttachment);
+ // attachment can potentially be animated, needs a number.
+ attachment->setJointNum(mSkeleton.size() + attachmentID - 1);
+
+ if (newly_created)
+ {
+ mAttachmentPoints[attachmentID] = attachment;
+
+ // now add attachment joint
+ parent_joint->addChild(attachment);
+ }
+ }
}
//-----------------------------------------------------------------------------
@@ -5844,7 +6184,7 @@ const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_o
return 0;
}
- mVisualComplexityStale = TRUE;
+ updateVisualComplexity();
if (viewer_object->isSelected())
{
@@ -6000,7 +6340,7 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)
if (attachment->isObjectAttached(viewer_object))
{
- mVisualComplexityStale = TRUE;
+ updateVisualComplexity();
cleanupAttachedMesh( viewer_object );
attachment->removeObject(viewer_object);
@@ -6073,6 +6413,7 @@ void LLVOAvatar::sitOnObject(LLViewerObject *sit_object)
// objects to be not rendered for new arrivals. See EXT-6835 and EXT-1655.
sitDown(TRUE);
mRoot->getXform()->setParent(&sit_object->mDrawable->mXform); // LLVOAvatar::sitOnObject
+ // SL-315
mRoot->setPosition(getPosition());
mRoot->updateWorldMatrixChildren();
@@ -6089,10 +6430,10 @@ void LLVOAvatar::getOffObject()
{
return;
}
-
+
LLViewerObject* sit_object = (LLViewerObject*)getParent();
- if (sit_object)
+ if (sit_object)
{
stopMotionFromSource(sit_object->getID());
LLFollowCamMgr::setCameraActive(sit_object->getID(), FALSE);
@@ -6109,9 +6450,19 @@ void LLVOAvatar::getOffObject()
}
// assumes that transform will not be updated with drawable still having a parent
+ // or that drawable had no parent from the start
LLVector3 cur_position_world = mDrawable->getWorldPosition();
LLQuaternion cur_rotation_world = mDrawable->getWorldRotation();
+ if (mLastRootPos.length() >= MAX_STANDOFF_FROM_ORIGIN
+ && (cur_position_world.length() < MAX_STANDOFF_FROM_ORIGIN
+ || dist_vec(cur_position_world, mLastRootPos) > MAX_STANDOFF_DISTANCE_CHANGE))
+ {
+ // Most likely drawable got updated too early or some updates were missed - we got relative position to non-existing parent
+ // restore coordinates from cache
+ cur_position_world = mLastRootPos;
+ }
+
// set *local* position based on last *world* position, since we're unparenting the avatar
mDrawable->mXform.setPosition(cur_position_world);
mDrawable->mXform.setRotation(cur_rotation_world);
@@ -6121,6 +6472,7 @@ void LLVOAvatar::getOffObject()
sitDown(FALSE);
mRoot->getXform()->setParent(NULL); // LLVOAvatar::getOffObject
+ // SL-315
mRoot->setPosition(cur_position_world);
mRoot->setRotation(cur_rotation_world);
mRoot->getXform()->update();
@@ -6287,36 +6639,25 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color)
BOOL LLVOAvatar::isVisible() const
{
return mDrawable.notNull()
+ && (!mOrphaned || isSelf())
&& (mDrawable->isVisible() || mIsDummy);
}
// Determine if we have enough avatar data to render
-BOOL LLVOAvatar::getIsCloud() const
+bool LLVOAvatar::getIsCloud() const
{
- // Do we have a shape?
- if ((const_cast<LLVOAvatar*>(this))->visualParamWeightsAreDefault())
- {
- return TRUE;
- }
-
- if (!isTextureDefined(TEX_LOWER_BAKED) ||
- !isTextureDefined(TEX_UPPER_BAKED) ||
- !isTextureDefined(TEX_HEAD_BAKED))
- {
- return TRUE;
- }
-
- if (isTooComplex())
- {
- return TRUE;
- }
- return FALSE;
+ return ( ((const_cast<LLVOAvatar*>(this))->visualParamWeightsAreDefault())// Do we have a shape?
+ || ( !isTextureDefined(TEX_LOWER_BAKED)
+ || !isTextureDefined(TEX_UPPER_BAKED)
+ || !isTextureDefined(TEX_HEAD_BAKED)
+ )
+ );
}
void LLVOAvatar::updateRezzedStatusTimers()
{
// State machine for rezzed status. Statuses are -1 on startup, 0
- // = cloud, 1 = gray, 2 = textured, 3 = textured_and_downloaded.
+ // = cloud, 1 = gray, 2 = downloading, 3 = full.
// Purpose is to collect time data for each it takes avatar to reach
// various loading landmarks: gray, textured (partial), textured fully.
@@ -6356,6 +6697,8 @@ void LLVOAvatar::updateRezzedStatusTimers()
selfStopPhase("update_appearance_from_cof");
selfStopPhase("wear_inventory_category", false);
selfStopPhase("process_initial_wearables_update", false);
+
+ updateVisualComplexity();
}
}
mLastRezzedStatus = rez_status;
@@ -6488,7 +6831,7 @@ void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapse
// returns true if the value has changed.
BOOL LLVOAvatar::updateIsFullyLoaded()
{
- const BOOL loading = getIsCloud();
+ const bool loading = getIsCloud();
updateRezzedStatusTimers();
updateRuthTimer(loading);
return processFullyLoadedChange(loading);
@@ -6549,6 +6892,12 @@ BOOL LLVOAvatar::processFullyLoadedChange(bool loading)
mPreviousFullyLoaded = mFullyLoaded;
mFullyLoadedInitialized = TRUE;
mFullyLoadedFrameCounter++;
+
+ if (changed && isSelf())
+ {
+ // to know about outfit switching
+ LLAvatarRenderNotifier::getInstance()->updateNotificationState();
+ }
return changed;
}
@@ -6560,15 +6909,28 @@ BOOL LLVOAvatar::isFullyLoaded() const
bool LLVOAvatar::isTooComplex() const
{
- if (gSavedSettings.getS32("RenderAvatarComplexityLimit") > 0 && mVisualComplexity >= gSavedSettings.getS32("RenderAvatarComplexityLimit"))
+ bool too_complex;
+ if (isSelf() || mVisuallyMuteSetting == AV_ALWAYS_RENDER)
{
- return true;
+ too_complex = false;
+ }
+ else
+ {
+ // Determine if visually muted or not
+ static LLCachedControl<U32> max_render_cost(gSavedSettings, "RenderAvatarMaxComplexity", 0U);
+ static LLCachedControl<F32> max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit", 1000.0f);
+ // If the user has chosen unlimited max complexity, we also disregard max attachment area
+ // 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
+ || (max_attachment_area > 0.0f && mAttachmentSurfaceArea > max_attachment_area)
+ ));
}
- return false;
+ return too_complex;
}
-
//-----------------------------------------------------------------------------
// findMotion()
//-----------------------------------------------------------------------------
@@ -7157,9 +7519,10 @@ void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value)
wtype = vparam->getWearableType();
}
S32 u8_value = F32_to_U8(value,viewer_param->getMinWeight(),viewer_param->getMaxWeight());
- apr_file_printf(file, "\t\t<param id=\"%d\" name=\"%s\" value=\"%.3f\" u8=\"%d\" type=\"%s\" wearable=\"%s\"/>\n",
+ apr_file_printf(file, "\t\t<param id=\"%d\" name=\"%s\" value=\"%.3f\" u8=\"%d\" type=\"%s\" wearable=\"%s\" group=\"%d\"/>\n",
viewer_param->getID(), viewer_param->getName().c_str(), value, u8_value, type_string.c_str(),
- LLWearableType::getTypeName(LLWearableType::EType(wtype)).c_str()
+ LLWearableType::getTypeName(LLWearableType::EType(wtype)).c_str(),
+ viewer_param->getGroup()
// param_location_name(vparam->getParamLocation()).c_str()
);
}
@@ -7226,7 +7589,7 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe
U8 av_u8;
mesgsys->getU8Fast(_PREHASH_AppearanceData, _PREHASH_AppearanceVersion, av_u8, 0);
contents.mAppearanceVersion = av_u8;
- LL_DEBUGS("Avatar") << "appversion set by AppearanceData field: " << contents.mAppearanceVersion << LL_ENDL;
+ //LL_DEBUGS("Avatar") << "appversion set by AppearanceData field: " << contents.mAppearanceVersion << LL_ENDL;
mesgsys->getS32Fast(_PREHASH_AppearanceData, _PREHASH_CofVersion, contents.mCOFVersion, 0);
// For future use:
//mesgsys->getU32Fast(_PREHASH_AppearanceData, _PREHASH_Flags, appearance_flags, 0);
@@ -7238,7 +7601,7 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe
{
LLVector3 hover;
mesgsys->getVector3Fast(_PREHASH_AppearanceHover, _PREHASH_HoverHeight, hover);
- LL_DEBUGS("Avatar") << avString() << " hover received " << hover.mV[ VX ] << "," << hover.mV[ VY ] << "," << hover.mV[ VZ ] << LL_ENDL;
+ //LL_DEBUGS("Avatar") << avString() << " hover received " << hover.mV[ VX ] << "," << hover.mV[ VY ] << "," << hover.mV[ VZ ] << LL_ENDL;
contents.mHoverOffset = hover;
contents.mHoverOffsetWasSet = true;
}
@@ -7248,7 +7611,7 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe
bool drop_visual_params_debug = gSavedSettings.getBOOL("BlockSomeAvatarAppearanceVisualParams") && (ll_rand(2) == 0); // pretend that ~12% of AvatarAppearance messages arrived without a VisualParam block, for testing
if( num_blocks > 1 && !drop_visual_params_debug)
{
- LL_DEBUGS("Avatar") << avString() << " handle visual params, num_blocks " << num_blocks << LL_ENDL;
+ //LL_DEBUGS("Avatar") << avString() << " handle visual params, num_blocks " << num_blocks << LL_ENDL;
LLVisualParam* param = getFirstVisualParam();
llassert(param); // if this ever fires, we should do the same as when num_blocks<=1
@@ -7309,7 +7672,7 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe
{
S32 index = it - contents.mParams.begin();
contents.mParamAppearanceVersion = ll_round(contents.mParamWeights[index]);
- LL_DEBUGS("Avatar") << "appversion req by appearance_version param: " << contents.mParamAppearanceVersion << LL_ENDL;
+ //LL_DEBUGS("Avatar") << "appversion req by appearance_version param: " << contents.mParamAppearanceVersion << LL_ENDL;
}
}
}
@@ -7338,9 +7701,9 @@ bool resolve_appearance_version(const LLAppearanceMessageContents& contents, S32
{
appearance_version = 1;
}
- LL_DEBUGS("Avatar") << "appearance version info - field " << contents.mAppearanceVersion
- << " param: " << contents.mParamAppearanceVersion
- << " final: " << appearance_version << LL_ENDL;
+ //LL_DEBUGS("Avatar") << "appearance version info - field " << contents.mAppearanceVersion
+ // << " param: " << contents.mParamAppearanceVersion
+ // << " final: " << appearance_version << LL_ENDL;
return true;
}
@@ -7349,7 +7712,7 @@ bool resolve_appearance_version(const LLAppearanceMessageContents& contents, S32
//-----------------------------------------------------------------------------
void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
{
- LL_DEBUGS("Avatar") << "starts" << LL_ENDL;
+ static S32 largest_self_cof_seen(LLViewerInventoryCategory::VERSION_UNKNOWN);
bool enable_verbose_dumps = gSavedSettings.getBOOL("DebugAvatarAppearanceMessage");
std::string dump_prefix = getFullname() + "_" + (isSelf()?"s":"o") + "_";
@@ -7361,17 +7724,15 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
mLastAppearanceMessageTimer.reset();
- ESex old_sex = getSex();
-
- LLAppearanceMessageContents contents;
- parseAppearanceMessage(mesgsys, contents);
+ LLPointer<LLAppearanceMessageContents> contents(new LLAppearanceMessageContents);
+ parseAppearanceMessage(mesgsys, *contents);
if (enable_verbose_dumps)
{
- dumpAppearanceMsgParams(dump_prefix + "appearance_msg", contents);
+ dumpAppearanceMsgParams(dump_prefix + "appearance_msg", *contents);
}
S32 appearance_version;
- if (!resolve_appearance_version(contents, appearance_version))
+ if (!resolve_appearance_version(*contents, appearance_version))
{
LL_WARNS() << "bad appearance version info, discarding" << LL_ENDL;
return;
@@ -7383,7 +7744,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
return;
}
- S32 this_update_cof_version = contents.mCOFVersion;
+ S32 this_update_cof_version = contents->mCOFVersion;
S32 last_update_request_cof_version = mLastUpdateRequestCOFVersion;
if( isSelf() )
@@ -7391,10 +7752,19 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
LL_DEBUGS("Avatar") << "this_update_cof_version " << this_update_cof_version
<< " last_update_request_cof_version " << last_update_request_cof_version
<< " my_cof_version " << LLAppearanceMgr::instance().getCOFVersion() << LL_ENDL;
+
+ if (largest_self_cof_seen > this_update_cof_version)
+ {
+ LL_WARNS("Avatar") << "Already processed appearance for COF version " <<
+ largest_self_cof_seen << ", discarding appearance with COF " << this_update_cof_version << LL_ENDL;
+ return;
+ }
+ largest_self_cof_seen = this_update_cof_version;
+
}
else
{
- LL_DEBUGS("Avatar") << "appearance message received" << LL_ENDL;
+ //LL_DEBUGS("Avatar") << "appearance message received" << LL_ENDL;
}
// Check for stale update.
@@ -7413,7 +7783,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
}
// SUNSHINE CLEANUP - is this case OK now?
- S32 num_params = contents.mParamWeights.size();
+ S32 num_params = contents->mParamWeights.size();
if (num_params <= 1)
{
// In this case, we have no reliable basis for knowing
@@ -7425,14 +7795,28 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
}
// No backsies zone - if we get here, the message should be valid and usable, will be processed.
+ LL_INFOS("Avatar") << "Processing appearance message version " << this_update_cof_version << LL_ENDL;
// Note:
// RequestAgentUpdateAppearanceResponder::onRequestRequested()
// assumes that cof version is only updated with server-bake
// appearance messages.
mLastUpdateReceivedCOFVersion = this_update_cof_version;
-
- applyParsedTEMessage(contents.mTEContents);
+ mLastProcessedAppearance = contents;
+
+ bool slam_params = false;
+ applyParsedAppearanceMessage(*contents, slam_params);
+}
+
+void LLVOAvatar::applyParsedAppearanceMessage(LLAppearanceMessageContents& contents, bool slam_params)
+{
+ S32 num_params = contents.mParamWeights.size();
+ ESex old_sex = getSex();
+
+ if (applyParsedTEMessage(contents.mTEContents) > 0 && isChanged(TEXTURE))
+ {
+ updateVisualComplexity();
+ }
// prevent the overwriting of valid baked textures with invalid baked textures
for (U8 baked_index = 0; baked_index < mBakedTextureDatas.size(); baked_index++)
@@ -7458,8 +7842,8 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
BOOL is_first_appearance_message = !mFirstAppearanceMessageReceived;
mFirstAppearanceMessageReceived = TRUE;
- LL_DEBUGS("Avatar") << avString() << "processAvatarAppearance start " << mID
- << " first? " << is_first_appearance_message << " self? " << isSelf() << LL_ENDL;
+ //LL_DEBUGS("Avatar") << avString() << "processAvatarAppearance start " << mID
+ // << " first? " << is_first_appearance_message << " self? " << isSelf() << LL_ENDL;
if (is_first_appearance_message )
{
@@ -7472,7 +7856,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
// Apply visual params
if( num_params > 1)
{
- LL_DEBUGS("Avatar") << avString() << " handle visual params, num_params " << num_params << LL_ENDL;
+ //LL_DEBUGS("Avatar") << avString() << " handle visual params, num_params " << num_params << LL_ENDL;
BOOL params_changed = FALSE;
BOOL interp_params = FALSE;
S32 params_changed_count = 0;
@@ -7482,12 +7866,12 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
LLVisualParam* param = contents.mParams[i];
F32 newWeight = contents.mParamWeights[i];
- if (is_first_appearance_message || (param->getWeight() != newWeight))
+ if (slam_params || is_first_appearance_message || (param->getWeight() != newWeight))
{
params_changed = TRUE;
params_changed_count++;
- if(is_first_appearance_message)
+ if(is_first_appearance_message || slam_params)
{
//LL_DEBUGS("Avatar") << "param slam " << i << " " << newWeight << LL_ENDL;
param->setWeight(newWeight);
@@ -7550,7 +7934,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
// Got an update for some other avatar
// Ignore updates for self, because we have a more authoritative value in the preferences.
setHoverOffset(contents.mHoverOffset);
- LL_INFOS("Avatar") << avString() << "setting hover from message" << contents.mHoverOffset[2] << LL_ENDL;
+ LL_INFOS("Avatar") << avString() << "setting hover to " << contents.mHoverOffset[2] << LL_ENDL;
}
if (!contents.mHoverOffsetWasSet && !isSelf())
@@ -7572,7 +7956,6 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
}
updateMeshTextures();
- //if (enable_verbose_dumps) dumpArchetypeXML(dump_prefix + "process_end");
}
// static
@@ -7703,7 +8086,7 @@ void LLVOAvatar::onInitialBakedTextureLoaded( BOOL success, LLViewerFetchedTextu
if (selfp)
{
- LL_DEBUGS("Avatar") << selfp->avString() << "discard_level " << discard_level << " success " << success << " final " << final << LL_ENDL;
+ //LL_DEBUGS("Avatar") << selfp->avString() << "discard_level " << discard_level << " success " << success << " final " << final << LL_ENDL;
}
if (!success && selfp)
@@ -7721,14 +8104,14 @@ void LLVOAvatar::onBakedTextureLoaded(BOOL success,
LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src,
S32 discard_level, BOOL final, void* userdata)
{
- LL_DEBUGS("Avatar") << "onBakedTextureLoaded: " << src_vi->getID() << LL_ENDL;
+ //LL_DEBUGS("Avatar") << "onBakedTextureLoaded: " << src_vi->getID() << LL_ENDL;
LLUUID id = src_vi->getID();
LLUUID *avatar_idp = (LLUUID *)userdata;
LLVOAvatar *selfp = (LLVOAvatar *)gObjectList.findObject(*avatar_idp);
if (selfp)
{
- LL_DEBUGS("Avatar") << selfp->avString() << "discard_level " << discard_level << " success " << success << " final " << final << " id " << src_vi->getID() << LL_ENDL;
+ //LL_DEBUGS("Avatar") << selfp->avString() << "discard_level " << discard_level << " success " << success << " final " << final << " id " << src_vi->getID() << LL_ENDL;
}
if (selfp && !success)
@@ -7916,6 +8299,7 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
}
}
+ // Bones
avatar_joint_list_t::iterator iter = mSkeleton.begin();
avatar_joint_list_t::iterator end = mSkeleton.end();
for (; iter != end; ++iter)
@@ -7923,10 +8307,33 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
LLJoint* pJoint = (*iter);
const LLVector3& pos = pJoint->getPosition();
const LLVector3& scale = pJoint->getScale();
- apr_file_printf( file, "\t\t<joint name=\"%s\" position=\"%f %f %f\" scale=\"%f %f %f\"/>\n",
+ apr_file_printf( file, "\t\t<bone name=\"%s\" position=\"%f %f %f\" scale=\"%f %f %f\"/>\n",
pJoint->getName().c_str(), pos[0], pos[1], pos[2], scale[0], scale[1], scale[2]);
}
+ // Collision volumes
+ for (S32 i = 0; i < mNumCollisionVolumes; i++)
+ {
+ LLAvatarJointCollisionVolume* pJoint = &mCollisionVolumes[i];
+ const LLVector3& pos = pJoint->getPosition();
+ const LLVector3& scale = pJoint->getScale();
+ apr_file_printf( file, "\t\t<collision_volume name=\"%s\" position=\"%f %f %f\" scale=\"%f %f %f\"/>\n",
+ pJoint->getName().c_str(), pos[0], pos[1], pos[2], scale[0], scale[1], scale[2]);
+ }
+
+ // Attachment joints
+ for (LLVOAvatar::attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end(); ++iter)
+ {
+ LLViewerJointAttachment* pJoint = iter->second;
+ if (!pJoint) continue;
+ const LLVector3& pos = pJoint->getPosition();
+ const LLVector3& scale = pJoint->getScale();
+ apr_file_printf( file, "\t\t<attachment_point name=\"%s\" position=\"%f %f %f\" scale=\"%f %f %f\"/>\n",
+ pJoint->getName().c_str(), pos[0], pos[1], pos[2], scale[0], scale[1], scale[2]);
+ }
+
+ // Joint pos overrides
for (iter = mSkeleton.begin(); iter != end; ++iter)
{
LLJoint* pJoint = (*iter);
@@ -7957,6 +8364,13 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
// show the cloned params inside the wearables as well.
gAgentAvatarp->dumpWearableInfo(outfile);
}
+ LLSD args;
+ args["PATH"] = fullpath;
+ LLNotificationsUtil::add("AppearanceToXMLSaved", args);
+ }
+ else
+ {
+ LLNotificationsUtil::add("AppearanceToXMLFailed");
}
// File will close when handle goes out of scope
}
@@ -8104,7 +8518,7 @@ LLHost LLVOAvatar::getObjectHost() const
}
else
{
- return LLHost::invalid;
+ return LLHost();
}
}
@@ -8127,7 +8541,7 @@ void LLVOAvatar::updateFreezeCounter(S32 counter)
BOOL LLVOAvatar::updateLOD()
{
- if (isImpostor())
+ if (isImpostor() && 0 != mDrawable->getNumFaces() && mDrawable->getFace(0)->hasGeometry())
{
return TRUE;
}
@@ -8164,28 +8578,36 @@ U32 LLVOAvatar::getPartitionType() const
}
//static
-void LLVOAvatar::updateImpostors()
+void LLVOAvatar::updateImpostors()
{
- LLCharacter::sAllowInstancesChange = FALSE ;
+ LLCharacter::sAllowInstancesChange = FALSE;
for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
- iter != LLCharacter::sInstances.end(); ++iter)
+ iter != LLCharacter::sInstances.end(); ++iter)
{
LLVOAvatar* avatar = (LLVOAvatar*) *iter;
- if (!avatar->isDead() && avatar->needsImpostorUpdate() && avatar->isVisible() && avatar->isImpostor())
+ if (!avatar->isDead() && avatar->isVisible()
+ && (
+ (avatar->isImpostor() || LLVOAvatar::AV_DO_NOT_RENDER == avatar->getVisualMuteSettings()) && avatar->needsImpostorUpdate())
+ )
{
+ avatar->calcMutedAVColor();
gPipeline.generateImpostor(avatar);
}
}
- LLCharacter::sAllowInstancesChange = TRUE ;
+ LLCharacter::sAllowInstancesChange = TRUE;
}
BOOL LLVOAvatar::isImpostor()
{
- return (sUseImpostors && (isVisuallyMuted() || (mUpdatePeriod >= IMPOSTOR_PERIOD))) || isInMuteList() ? TRUE : FALSE;
+ return sUseImpostors && (isVisuallyMuted() || (mUpdatePeriod >= IMPOSTOR_PERIOD)) ? TRUE : FALSE;
}
+BOOL LLVOAvatar::shouldImpostor(const U32 rank_factor) const
+{
+ return (!isSelf() && sUseImpostors && mVisibilityRank > (sMaxNonImpostors * rank_factor));
+}
BOOL LLVOAvatar::needsImpostorUpdate() const
{
@@ -8226,68 +8648,170 @@ void LLVOAvatar::getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& d
angle.mV[2] = da;
}
+// static
+const U32 LLVOAvatar::IMPOSTORS_OFF = 66; /* Must equal the maximum allowed the RenderAvatarMaxNonImpostors
+ * slider in panel_preferences_graphics1.xml */
-void LLVOAvatar::idleUpdateRenderCost()
+// static
+void LLVOAvatar::updateImpostorRendering(U32 newMaxNonImpostorsValue)
{
- static LLCachedControl<U32> max_render_cost(gSavedSettings, "RenderAutoMuteRenderWeightLimit", 0);
- static const U32 ARC_LIMIT = 20000;
-
- if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_ATTACHMENT_BYTES))
- { //set debug text to attachment geometry bytes here so render cost will override
- setDebugText(llformat("%.1f KB, %.2f m^2", mAttachmentGeometryBytes/1024.f, mAttachmentSurfaceArea));
+ U32 oldmax = sMaxNonImpostors;
+ bool oldflg = sUseImpostors;
+
+ if (IMPOSTORS_OFF <= newMaxNonImpostorsValue)
+ {
+ sMaxNonImpostors = 0;
}
-
- if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME) && max_render_cost == 0)
+ else
{
- return;
+ sMaxNonImpostors = newMaxNonImpostorsValue;
}
+ // the sUseImpostors flag depends on whether or not sMaxNonImpostors is set to the no-limit value (0)
+ sUseImpostors = (0 != sMaxNonImpostors);
+ if ( oldflg != sUseImpostors )
+ {
+ LL_DEBUGS("AvatarRender")
+ << "was " << (oldflg ? "use" : "don't use" ) << " impostors (max " << oldmax << "); "
+ << "now " << (sUseImpostors ? "use" : "don't use" ) << " impostors (max " << sMaxNonImpostors << "); "
+ << LL_ENDL;
+ }
+}
- calculateUpdateRenderCost(); // Update mVisualComplexity if needed
-
- if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME))
+
+void LLVOAvatar::idleUpdateRenderComplexity()
+{
+ // Render Complexity
+ calculateUpdateRenderComplexity(); // Update mVisualComplexity if needed
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AVATAR_DRAW_INFO))
{
- std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus());
- setDebugText(llformat("%s %d", viz_string.c_str(), mVisualComplexity));
- F32 green = 1.f-llclamp(((F32) mVisualComplexity-(F32)ARC_LIMIT)/(F32)ARC_LIMIT, 0.f, 1.f);
- F32 red = llmin((F32) mVisualComplexity/(F32)ARC_LIMIT, 1.f);
- mText->setColor(LLColor4(red,green,0,1));
+ std::string info_line;
+ F32 red_level;
+ F32 green_level;
+ LLColor4 info_color;
+ LLFontGL::StyleFlags info_style;
+
+ if ( !mText )
+ {
+ initHudText();
+ mText->setFadeDistance(20.0, 5.0); // limit clutter in large crowds
+ }
+ else
+ {
+ mText->clearString(); // clear debug text
+ }
+
+ /*
+ * NOTE: the logic for whether or not each of the values below
+ * controls muting MUST match that in the isVisuallyMuted and isTooComplex methods.
+ */
+
+ static LLCachedControl<U32> max_render_cost(gSavedSettings, "RenderAvatarMaxComplexity", 0);
+ info_line = llformat("%d Complexity", mVisualComplexity);
+
+ if (max_render_cost != 0) // zero means don't care, so don't bother coloring based on this
+ {
+ green_level = 1.f-llclamp(((F32) mVisualComplexity-(F32)max_render_cost)/(F32)max_render_cost, 0.f, 1.f);
+ red_level = llmin((F32) mVisualComplexity/(F32)max_render_cost, 1.f);
+ info_color.set(red_level, green_level, 0.0, 1.0);
+ info_style = ( mVisualComplexity > max_render_cost
+ ? LLFontGL::BOLD : LLFontGL::NORMAL );
+ }
+ else
+ {
+ info_color.set(LLColor4::grey);
+ info_style = LLFontGL::NORMAL;
+ }
+ mText->addLine(info_line, info_color, info_style);
+
+ // 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_style = LLFontGL::NORMAL;
+ mText->addLine(info_line, info_color, info_style);
+
+ // Attachment Surface Area
+ static LLCachedControl<F32> max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit", 1000.0f);
+ info_line = llformat("%.0f m^2", mAttachmentSurfaceArea);
+
+ if (max_render_cost != 0 && max_attachment_area != 0) // zero means don't care, so don't bother coloring based on this
+ {
+ green_level = 1.f-llclamp((mAttachmentSurfaceArea-max_attachment_area)/max_attachment_area, 0.f, 1.f);
+ red_level = llmin(mAttachmentSurfaceArea/max_attachment_area, 1.f);
+ info_color.set(red_level, green_level, 0.0, 1.0);
+ info_style = ( mAttachmentSurfaceArea > max_attachment_area
+ ? LLFontGL::BOLD : LLFontGL::NORMAL );
+
+ }
+ else
+ {
+ 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;
+ // Set the cache time to in the past so it's updated ASAP
+ mVisualComplexityStale = true;
+}
// Calculations for mVisualComplexity value
-void LLVOAvatar::calculateUpdateRenderCost()
+void LLVOAvatar::calculateUpdateRenderComplexity()
{
- static const U32 ARC_BODY_PART_COST = 200;
+ /*****************************************************************
+ * 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;
// Diagnostic list of all textures on our avatar
static std::set<LLUUID> all_textures;
if (mVisualComplexityStale)
{
- mVisualComplexityStale = FALSE;
- U32 cost = 0;
+ U32 cost = VISUAL_COMPLEXITY_UNKNOWN;
LLVOVolume::texture_cost_t textures;
for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
{
- const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)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 +=ARC_BODY_PART_COST;
+ cost +=COMPLEXITY_BODY_PART_COST;
}
}
}
+ LL_DEBUGS("ARCdetail") << "Avatar body parts complexity: " << cost << LL_ENDL;
- for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
+ for (attachment_map_t::const_iterator attachment_point = mAttachmentPoints.begin();
+ attachment_point != mAttachmentPoints.end();
+ ++attachment_point)
{
- LLViewerJointAttachment* attachment = iter->second;
+ LLViewerJointAttachment* attachment = attachment_point->second;
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
@@ -8302,7 +8826,12 @@ void LLVOAvatar::calculateUpdateRenderCost()
const LLVOVolume* volume = drawable->getVOVolume();
if (volume)
{
- cost += volume->getRenderCost(textures);
+ U32 attachment_total_cost = 0;
+ U32 attachment_volume_cost = 0;
+ U32 attachment_texture_cost = 0;
+ U32 attachment_children_cost = 0;
+
+ attachment_volume_cost += volume->getRenderCost(textures);
const_child_list_t children = volume->getChildren();
for (const_child_list_t::const_iterator child_iter = children.begin();
@@ -8313,15 +8842,27 @@ void LLVOAvatar::calculateUpdateRenderCost()
LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj );
if (child)
{
- cost += child->getRenderCost(textures);
+ attachment_children_cost += child->getRenderCost(textures);
}
}
- for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter)
+ for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin();
+ volume_texture != textures.end();
+ ++volume_texture)
{
// add the cost of each individual texture in the linkset
- cost += iter->second;
+ attachment_texture_cost += volume_texture->second;
}
+
+ attachment_total_cost = attachment_volume_cost + attachment_texture_cost + attachment_children_cost;
+ LL_DEBUGS("ARCdetail") << "Attachment costs " << attached_object->getAttachmentItemID()
+ << " total: " << attachment_total_cost
+ << ", volume: " << attachment_volume_cost
+ << ", textures: " << attachment_texture_cost
+ << ", " << volume->numChildren()
+ << " children: " << attachment_children_cost
+ << LL_ENDL;
+ cost += attachment_total_cost;
}
}
}
@@ -8367,38 +8908,85 @@ void LLVOAvatar::calculateUpdateRenderCost()
}
}
+ if ( cost != mVisualComplexity )
+ {
+ LL_DEBUGS("AvatarRender") << "Avatar "<< getID()
+ << " complexity updated was " << mVisualComplexity << " now " << cost
+ << " reported " << mReportedVisualComplexity
+ << LL_ENDL;
+ }
+ else
+ {
+ LL_DEBUGS("AvatarRender") << "Avatar "<< getID()
+ << " complexity updated no change " << mVisualComplexity
+ << " reported " << mReportedVisualComplexity
+ << LL_ENDL;
+ }
mVisualComplexity = cost;
+ mVisualComplexityStale = false;
+
+ static LLCachedControl<U32> show_my_complexity_changes(gSavedSettings, "ShowMyComplexityChanges", 20);
+
+ if (isSelf() && show_my_complexity_changes)
+ {
+ LLAvatarRenderNotifier::getInstance()->updateNotificationAgent(mVisualComplexity);
+ }
}
}
+void LLVOAvatar::setVisualMuteSettings(VisualMuteSettings set)
+{
+ mVisuallyMuteSetting = set;
+ mNeedsImpostorUpdate = TRUE;
+}
+
-// static
-LLColor4 LLVOAvatar::calcMutedAVColor(F32 value, S32 range_low, S32 range_high)
+void LLVOAvatar::calcMutedAVColor()
{
- F32 clamped_value = llmin(value, (F32) range_high);
- clamped_value = llmax(value, (F32) range_low);
- F32 spectrum = (clamped_value / range_high); // spectrum is between 0 and 1.f
+ LLColor4 new_color(mMutedAVColor);
+ std::string change_msg;
+ LLUUID av_id(getID());
- // Array of colors. These are arranged so only one RGB color changes between each step,
- // and it loops back to red so there is an even distribution. It is not a heat map
- const S32 NUM_SPECTRUM_COLORS = 7;
- static LLColor4 * spectrum_color[NUM_SPECTRUM_COLORS] = { &LLColor4::red, &LLColor4::magenta, &LLColor4::blue, &LLColor4::cyan, &LLColor4::green, &LLColor4::yellow, &LLColor4::red };
+ if (getVisualMuteSettings() == AV_DO_NOT_RENDER)
+ {
+ // explicitly not-rendered avatars are light grey
+ new_color = LLColor4::grey3;
+ change_msg = " not rendered: color is grey3";
+ }
+ else if (LLMuteList::getInstance()->isMuted(av_id)) // the user blocked them
+ {
+ // blocked avatars are dark grey
+ new_color = LLColor4::grey4;
+ change_msg = " blocked: color is grey4";
+ }
+ else if ( mMutedAVColor == LLColor4::white || mMutedAVColor == LLColor4::grey3 || mMutedAVColor == LLColor4::grey4 )
+ {
+ // select a color based on the first byte of the agents uuid so any muted agent is always the same color
+ F32 color_value = (F32) (av_id.mData[0]);
+ F32 spectrum = (color_value / 256.0); // spectrum is between 0 and 1.f
+
+ // Array of colors. These are arranged so only one RGB color changes between each step,
+ // and it loops back to red so there is an even distribution. It is not a heat map
+ const S32 NUM_SPECTRUM_COLORS = 7;
+ static LLColor4 * spectrum_color[NUM_SPECTRUM_COLORS] = { &LLColor4::red, &LLColor4::magenta, &LLColor4::blue, &LLColor4::cyan, &LLColor4::green, &LLColor4::yellow, &LLColor4::red };
- spectrum = spectrum * (NUM_SPECTRUM_COLORS - 1); // Scale to range of number of colors
- S32 spectrum_index_1 = floor(spectrum); // Desired color will be after this index
- S32 spectrum_index_2 = spectrum_index_1 + 1; // and before this index (inclusive)
- F32 fractBetween = spectrum - (F32)(spectrum_index_1); // distance between the two indexes (0-1)
+ spectrum = spectrum * (NUM_SPECTRUM_COLORS - 1); // Scale to range of number of colors
+ S32 spectrum_index_1 = floor(spectrum); // Desired color will be after this index
+ S32 spectrum_index_2 = spectrum_index_1 + 1; // and before this index (inclusive)
+ F32 fractBetween = spectrum - (F32)(spectrum_index_1); // distance between the two indexes (0-1)
- LLColor4 new_color = lerp(*spectrum_color[spectrum_index_1], *spectrum_color[spectrum_index_2], fractBetween);
- new_color.normalize();
- new_color *= 0.7f; // Tone it down a bit
+ new_color = lerp(*spectrum_color[spectrum_index_1], *spectrum_color[spectrum_index_2], fractBetween);
+ new_color.normalize();
+ new_color *= 0.28f; // Tone it down
- //LL_INFOS() << "From value " << std::setprecision(3) << value << " returning color " << new_color
- // << " using indexes " << spectrum_index_1 << ", " << spectrum_index_2
- // << " and fractBetween " << fractBetween
- // << LL_ENDL;
+ change_msg = " over limit color ";
+ }
- return new_color;
+ if (mMutedAVColor != new_color)
+ {
+ LL_DEBUGS("AvatarRender") << "avatar "<< av_id << change_msg << std::setprecision(3) << new_color << LL_ENDL;
+ mMutedAVColor = new_color;
+ }
}
// static