diff options
Diffstat (limited to 'indra/newview/llvoavatar.cpp')
-rw-r--r--[-rwxr-xr-x] | indra/newview/llvoavatar.cpp | 1428 |
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 |