diff options
Diffstat (limited to 'indra')
78 files changed, 4159 insertions, 1008 deletions
| diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index e5089f028f..e35e4edec2 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -1723,7 +1723,7 @@ void LLAvatarAppearance::makeJointAliases(LLAvatarBoneInfo *bone_info)          }          mJointAliasMap[*i] = bone_name;      } -     +      LLAvatarBoneInfo::child_list_t::const_iterator iter;      for (iter = bone_info->mChildList.begin(); iter != bone_info->mChildList.end(); ++iter)      { @@ -1738,13 +1738,34 @@ const LLAvatarAppearance::joint_alias_map_t& LLAvatarAppearance::getJointAliases      {          LLAvatarSkeletonInfo::bone_info_list_t::const_iterator iter; -        for (iter = sAvatarSkeletonInfo->mBoneInfoList.begin(); iter != sAvatarSkeletonInfo->mBoneInfoList.end(); ++iter) +        for (iter = sAvatarSkeletonInfo->mBoneInfoList.begin();  +             iter != sAvatarSkeletonInfo->mBoneInfoList.end(); +             ++iter)          {              //LLAvatarBoneInfo *bone_info = *iter;              makeJointAliases( *iter );          } + +        LLAvatarXmlInfo::attachment_info_list_t::iterator attach_iter; +        for (attach_iter = sAvatarXmlInfo->mAttachmentInfoList.begin(); +             attach_iter != sAvatarXmlInfo->mAttachmentInfoList.end();  +             ++attach_iter) +        { +            LLAvatarXmlInfo::LLAvatarAttachmentInfo *info = *attach_iter; +            std::string bone_name = info->mName; +             +            // Also accept the name with spaces substituted with +            // underscores. This gives a mechanism for referencing such joints +            // in daes, which don't allow spaces. +            std::string sub_space_to_underscore = bone_name; +            LLStringUtil::replaceChar(sub_space_to_underscore, ' ', '_'); +            if (sub_space_to_underscore != bone_name) +            { +                mJointAliasMap[sub_space_to_underscore] = bone_name; +            } +        }      } -     +      return mJointAliasMap;  }  diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index ccd6323ed8..b6bdb652e8 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -227,7 +227,7 @@ protected:   **                    RENDERING   **/  public: -	BOOL		mIsDummy; // for special views +	BOOL		mIsDummy; // for special views and animated object controllers; local to viewer  	//--------------------------------------------------------------------  	// Morph masks diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp index a3d5679f65..07fcd99701 100644 --- a/indra/llcharacter/lljoint.cpp +++ b/indra/llcharacter/lljoint.cpp @@ -435,6 +435,19 @@ void LLJoint::addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh      //    return;      //} +#if 0 // AXON MAINT-8554 - this may be overly restrictive for large models +    LLVector3 constrained_pos = LLVector3(llclamp(pos[0],-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET), +                                          llclamp(pos[1],-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET), +                                          llclamp(pos[2],-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET)); +    if (constrained_pos != pos) +    { +        LL_DEBUGS("Avatar") << mesh_id << " joint " << getName() << " attachment pos override constrained to "  +                            << constrained_pos << " was " << pos << LL_ENDL; +    } +#else +    LLVector3 constrained_pos = pos; +#endif +          LLVector3 before_pos;      LLUUID before_mesh_id;      bool has_active_override_before = hasAttachmentPosOverride( before_pos, before_mesh_id ); @@ -446,7 +459,7 @@ void LLJoint::addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh  		}  		m_posBeforeOverrides = getPosition();  	} -	m_attachmentPosOverrides.add(mesh_id,pos); +	m_attachmentPosOverrides.add(mesh_id,constrained_pos);      LLVector3 after_pos;      LLUUID after_mesh_id;      hasAttachmentPosOverride(after_pos, after_mesh_id); @@ -455,7 +468,7 @@ void LLJoint::addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh          active_override_changed = true;           if (do_debug_joint(getName()))          { -            LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " addAttachmentPosOverride for mesh " << mesh_id << " pos " << pos << LL_ENDL; +            LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " addAttachmentPosOverride for mesh " << mesh_id << " pos " << constrained_pos << LL_ENDL;          }          updatePos(av_info);      } @@ -881,7 +894,7 @@ void LLJoint::setWorldRotation( const LLQuaternion& rot )  //--------------------------------------------------------------------  const LLVector3& LLJoint::getScale()  { -	return mXform.getScale();	 +    return mXform.getScale();  }  //-------------------------------------------------------------------- diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h index 0c8fbfebb0..8112d246f2 100644 --- a/indra/llcharacter/lljoint.h +++ b/indra/llcharacter/lljoint.h @@ -70,6 +70,16 @@ private:  	map_type m_map;  }; +inline bool operator==(const LLVector3OverrideMap& a, const LLVector3OverrideMap& b) +{ +    return a.getMap() == b.getMap(); +} + +inline bool operator!=(const LLVector3OverrideMap& a, const LLVector3OverrideMap& b) +{ +    return !(a == b); +} +  //-----------------------------------------------------------------------------  // class LLJoint  //----------------------------------------------------------------------------- diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp index 35e76f1d9d..3116403616 100644 --- a/indra/llcharacter/llmotioncontroller.cpp +++ b/indra/llcharacter/llmotioncontroller.cpp @@ -135,7 +135,7 @@ LLMotionController::LLMotionController()  	  mLastTime(0.0f),  	  mHasRunOnce(FALSE),  	  mPaused(FALSE), -	  mPauseTime(0.f), +	  mPausedFrame(0),  	  mTimeStep(0.f),  	  mTimeStepCount(0),  	  mLastInterp(0.f), @@ -814,6 +814,10 @@ void LLMotionController::updateLoadingMotions()  //-----------------------------------------------------------------------------  void LLMotionController::updateMotions(bool force_update)  { +    // SL-763: "Distant animated objects run at super fast speed" +    // The use_quantum optimization or possibly the associated code in setTimeStamp() +    // does not work as implemented. +    // Currently setting mTimeStep to nonzero is disabled elsewhere.  	BOOL use_quantum = (mTimeStep != 0.f);  	// Always update mPrevTimerElapsed @@ -1125,6 +1129,7 @@ void LLMotionController::pauseAllMotions()  	{  		//LL_INFOS() << "Pausing animations..." << LL_ENDL;  		mPaused = TRUE; +        mPausedFrame = LLFrameTimer::getFrameCount();  	}  } diff --git a/indra/llcharacter/llmotioncontroller.h b/indra/llcharacter/llmotioncontroller.h index 9d9c64f4f0..637ee4d2bb 100644 --- a/indra/llcharacter/llmotioncontroller.h +++ b/indra/llcharacter/llmotioncontroller.h @@ -148,12 +148,16 @@ public:  	void pauseAllMotions();  	void unpauseAllMotions();  	BOOL isPaused() const { return mPaused; } +    S32 getPausedFrame() const { return mPausedFrame; }  	void setTimeStep(F32 step); +    F32 getTimeStep() const { return mTimeStep; }  	void setTimeFactor(F32 time_factor);  	F32 getTimeFactor() const { return mTimeFactor; } +    F32 getAnimTime() const { return mAnimTime; } +      	motion_list_t& getActiveMotions() { return mActiveMotions; }  	void incMotionCounts(S32& num_motions, S32& num_loading_motions, S32& num_loaded_motions, S32& num_active_motions, S32& num_deprecated_motions); @@ -218,7 +222,7 @@ protected:  	F32					mLastTime;  	BOOL				mHasRunOnce;  	BOOL				mPaused; -	F32					mPauseTime; +	S32					mPausedFrame;  	F32					mTimeStep;  	S32					mTimeStepCount;  	F32					mLastInterp; diff --git a/indra/llcommon/llcallstack.h b/indra/llcommon/llcallstack.h index 1f7a7689d7..5acf04a49f 100644 --- a/indra/llcommon/llcallstack.h +++ b/indra/llcommon/llcallstack.h @@ -78,3 +78,10 @@ struct LLContextStatus  };  LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLContextStatus& context_status); + +#define dumpStack(tag) \ +    if (debugLoggingEnabled(tag)) \ +    { \ +        LLCallStack cs; \ +        LL_DEBUGS(tag) << "STACK:\n" << "====================\n" << cs << "====================" << LL_ENDL; \ +    } diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index c45db3b185..9a02fecd72 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -869,6 +869,25 @@ std::string LLStringOps::getDatetimeCode (std::string key)  	}  } +std::string LLStringOps::getReadableNumber(F64 num) +{ +    if (fabs(num)>=1e9) +    { +		return llformat("%.2lfB", num / 1e9); +    } +    else if (fabs(num)>=1e6) +    { +		return llformat("%.2lfM", num / 1e6); +    } +    else if (fabs(num)>=1e3) +    { +		return llformat("%.2lfK", num / 1e3); +    } +    else +    { +		return llformat("%.2lf", num); +    } +}  namespace LLStringFn  { diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index a4a5b393cb..68ee9db46b 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -211,6 +211,9 @@ public:  	static bool getPacificDaylightTime(void) { return sPacificDaylightTime;}  	static std::string getDatetimeCode (std::string key); + +    // Express a value like 1234567 as "1.23M"  +    static std::string getReadableNumber(F64 num);  };  /** diff --git a/indra/llmath/llmatrix4a.h b/indra/llmath/llmatrix4a.h index 216334752a..baa3a89176 100644 --- a/indra/llmath/llmatrix4a.h +++ b/indra/llmath/llmatrix4a.h @@ -176,4 +176,10 @@ inline void matMul(const LLMatrix4a &a, const LLMatrix4a &b, LLMatrix4a &res)      res.mMatrix[3] = row3;  } +inline std::ostream& operator<<(std::ostream& s, const LLMatrix4a& m) +{ +    s << "[" << m.mMatrix[0] << ", " << m.mMatrix[1] << ", " << m.mMatrix[2] << ", " << m.mMatrix[3] << "]"; +    return s; +}  +  #endif diff --git a/indra/llmath/llvector4a.h b/indra/llmath/llvector4a.h index 79d0a44551..222f3cf235 100644 --- a/indra/llmath/llvector4a.h +++ b/indra/llmath/llvector4a.h @@ -320,7 +320,7 @@ public:  	inline const LLVector4a& operator= ( const LLQuad& rhs );  	inline operator LLQuad() const;	 - +      private:  	LLQuad mQ;  } LL_ALIGN_POSTFIX(16); @@ -331,4 +331,9 @@ inline void update_min_max(LLVector4a& min, LLVector4a& max, const LLVector4a& p  	max.setMax(max, p);  } +inline std::ostream& operator<<(std::ostream& s, const LLVector4a& v) +{ +    s << "(" << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << ")"; +    return s; +}  #endif diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 648f9a8d93..4613e17605 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1,5 +1,4 @@  /**  -   * @file llvolume.cpp   *   * $LicenseInfo:firstyear=2002&license=viewerlgpl$ @@ -2638,6 +2637,7 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)  			}  			//calculate bounding box +			// VFExtents change  			LLVector4a& min = face.mExtents[0];  			LLVector4a& max = face.mExtents[1]; @@ -4767,6 +4767,7 @@ LLVolumeFace::~LLVolumeFace()  {  	ll_aligned_free_16(mExtents);  	mExtents = NULL; +	mCenter = NULL;  	freeData();  } @@ -5569,7 +5570,7 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)  	// S32 i;  	S32	grid_size = (profile.size()-1)/4; - +	// VFExtents change  	LLVector4a& min = mExtents[0];  	LLVector4a& max = mExtents[1]; @@ -5846,7 +5847,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)  	LLVector2 cuv;  	LLVector2 min_uv, max_uv; - +	// VFExtents change  	LLVector4a& min = mExtents[0];  	LLVector4a& max = mExtents[1]; @@ -6471,14 +6472,17 @@ void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMat  		if (offset == 0 && i == 0)  		{ //initialize bounding box +			// VFExtents change  			mExtents[0] = mExtents[1] = dst_pos[i];  		}  		else  		{  			//stretch bounding box +			// VFExtents change  			update_min_max(mExtents[0], mExtents[1], dst_pos[i]);  		}  	} +    LL_DEBUGS("RiggedBox") << "appendFace got extents " << mExtents[0] << ", " << mExtents[1] << " from dst_pos " << LL_ENDL;  	new_count = mNumIndices + face.mNumIndices; @@ -6641,7 +6645,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)  	{  		update_min_max(face_min, face_max, *cur_pos++);  	} - +	// VFExtents change  	mExtents[0] = face_min;  	mExtents[1] = face_max; diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp index 1ae8a6ac15..f8e11e324e 100644 --- a/indra/llmessage/message_prehash.cpp +++ b/indra/llmessage/message_prehash.cpp @@ -818,6 +818,7 @@ char const* const _PREHASH_StateSave = LLMessageStringTable::getInstance()->getS  char const* const _PREHASH_RoleData = LLMessageStringTable::getInstance()->getString("RoleData");  char const* const _PREHASH_AgentAnimation = LLMessageStringTable::getInstance()->getString("AgentAnimation");  char const* const _PREHASH_AvatarAnimation = LLMessageStringTable::getInstance()->getString("AvatarAnimation"); +char const* const _PREHASH_ObjectAnimation = LLMessageStringTable::getInstance()->getString("ObjectAnimation");  char const* const _PREHASH_LogDwellTime = LLMessageStringTable::getInstance()->getString("LogDwellTime");  char const* const _PREHASH_ParcelGodMarkAsContent = LLMessageStringTable::getInstance()->getString("ParcelGodMarkAsContent");  char const* const _PREHASH_UsePhysics = LLMessageStringTable::getInstance()->getString("UsePhysics"); diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h index 7910fde305..334236fb25 100644 --- a/indra/llmessage/message_prehash.h +++ b/indra/llmessage/message_prehash.h @@ -818,6 +818,7 @@ extern char const* const _PREHASH_StateSave;  extern char const* const _PREHASH_RoleData;  extern char const* const _PREHASH_AgentAnimation;  extern char const* const _PREHASH_AvatarAnimation; +extern char const* const _PREHASH_ObjectAnimation;  extern char const* const _PREHASH_LogDwellTime;  extern char const* const _PREHASH_ParcelGodMarkAsContent;  extern char const* const _PREHASH_UsePhysics; diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index 8401cb976e..8f75d89e5a 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -192,7 +192,7 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa  		{  			return LLModel::BAD_ELEMENT;  		} - +		// VFExtents change  		face.mExtents[0].set(v[0], v[1], v[2]);  		face.mExtents[1].set(v[0], v[1], v[2]);  	} @@ -254,6 +254,7 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa  		if (!found)  		{ +			// VFExtents change  			update_min_max(face.mExtents[0], face.mExtents[1], cv.getPosition());  			verts.push_back(cv);  			if (verts.size() >= 65535) @@ -305,6 +306,7 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa  			}  			face = LLVolumeFace(); +			// VFExtents change  			face.mExtents[0].set(v[0], v[1], v[2]);  			face.mExtents[1].set(v[0], v[1], v[2]);  			point_map.clear(); @@ -383,6 +385,7 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac  	if (pos_source)  	{  		v = pos_source->getFloat_array()->getValue(); +		// VFExtents change  		face.mExtents[0].set(v[0], v[1], v[2]);  		face.mExtents[1].set(v[0], v[1], v[2]);  	} @@ -482,6 +485,7 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac  			if (!found)  			{ +				// VFExtents change  				update_min_max(face.mExtents[0], face.mExtents[1], cv.getPosition());  				verts.push_back(cv);  				if (verts.size() >= 65535) @@ -551,6 +555,7 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac  				}  				face = LLVolumeFace(); +				// VFExtents change  				face.mExtents[0].set(v[0], v[1], v[2]);  				face.mExtents[1].set(v[0], v[1], v[2]);  				verts.clear(); @@ -734,7 +739,7 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac  	{  		return LLModel::NO_ERRORS;  	} - +	// VFExtents change  	face.mExtents[0] = verts[0].getPosition();  	face.mExtents[1] = verts[0].getPosition(); @@ -758,6 +763,7 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac  	for (std::map<LLVolumeFace::VertexData, U32>::iterator iter = vert_idx.begin(); iter != vert_idx.end(); ++iter)  	{  		new_verts[iter->second] = iter->first; +		// VFExtents change  		update_min_max(face.mExtents[0], face.mExtents[1], iter->first.getPosition());  	} diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 8fbb4f6b96..18f45d3b20 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -276,6 +276,7 @@ void LLModel::normalizeVolumeFaces()  			// We shrink the extents so  			// that they fall within  			// the unit cube. +			// VFExtents change  			face.mExtents[0].add(trans);  			face.mExtents[0].mul(scale); diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index bfa65666b5..c847cf653f 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -1599,6 +1599,8 @@ BOOL LLNetworkData::isValid(U16 param_type, U32 size)  		return (size == 17);  	case PARAMS_LIGHT_IMAGE:  		return (size == 28); +    case PARAMS_EXTENDED_MESH: +        return (size == 4);  	}  	return FALSE; @@ -2026,3 +2028,67 @@ bool LLLightImageParams::fromLLSD(LLSD& sd)  	return false;  } + +//============================================================================ + +LLExtendedMeshParams::LLExtendedMeshParams() +{ +    mType = PARAMS_EXTENDED_MESH; +	mFlags = 0; +} + +BOOL LLExtendedMeshParams::pack(LLDataPacker &dp) const +{ +	dp.packU32(mFlags, "flags"); + +	return TRUE; +} + +BOOL LLExtendedMeshParams::unpack(LLDataPacker &dp) +{ +	dp.unpackU32(mFlags, "flags"); +	 +	return TRUE; +} + +bool LLExtendedMeshParams::operator==(const LLNetworkData& data) const +{ +	if (data.mType != PARAMS_EXTENDED_MESH) +	{ +		return false; +	} +	 +	const LLExtendedMeshParams *param = (const LLExtendedMeshParams*)&data; +	if ( (param->mFlags != mFlags) ) +	{ +		return false; +	} + +	return true; +} + +void LLExtendedMeshParams::copy(const LLNetworkData& data) +{ +	const LLExtendedMeshParams *param = (LLExtendedMeshParams*)&data; +	mFlags = param->mFlags; +} + +LLSD LLExtendedMeshParams::asLLSD() const +{ +	LLSD sd; +	 +	sd["flags"] = LLSD::Integer(mFlags); +		 +	return sd; +} + +bool LLExtendedMeshParams::fromLLSD(LLSD& sd) +{ +	if (sd.has("flags")) +	{ +		setFlags( sd["flags"].asInteger()); +		return true; +	}  +	 +	return false; +} diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index 19d9d52817..9216c04229 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -106,6 +106,7 @@ public:  		PARAMS_LIGHT_IMAGE = 0x40,  		PARAMS_RESERVED = 0x50, // Used on server-side  		PARAMS_MESH     = 0x60, +        PARAMS_EXTENDED_MESH = 0x70,  	};  public: @@ -288,6 +289,27 @@ public:  }; +class LLExtendedMeshParams : public LLNetworkData +{ +protected: +	U32 mFlags; +	 +public: +	static const U32 ANIMATED_MESH_ENABLED_FLAG = 0x1 << 0; + +	LLExtendedMeshParams(); +	/*virtual*/ BOOL pack(LLDataPacker &dp) const; +	/*virtual*/ BOOL unpack(LLDataPacker &dp); +	/*virtual*/ bool operator==(const LLNetworkData& data) const; +	/*virtual*/ void copy(const LLNetworkData& data); +	LLSD asLLSD() const; +	operator LLSD() const { return asLLSD(); } +	bool fromLLSD(LLSD& sd); + +	void setFlags(const U32& flags) { mFlags = flags; } +    U32 getFlags() const { return mFlags; } +	 +};  // This code is not naming-standards compliant. Leaving it like this for  // now to make the connection to code in diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 23337ddbfb..ff3ca3055e 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -151,6 +151,7 @@ set(viewer_SOURCE_FILES      llcommunicationchannel.cpp      llcompilequeue.cpp      llconfirmationmanager.cpp +    llcontrolavatar.cpp      llconversationlog.cpp      llconversationloglist.cpp      llconversationloglistitem.cpp @@ -603,6 +604,7 @@ set(viewer_SOURCE_FILES      lltransientfloatermgr.cpp      lltranslate.cpp      lltwitterconnect.cpp +    lluiavatar.cpp      lluilistener.cpp      lluploaddialog.cpp      llurl.cpp @@ -772,6 +774,7 @@ set(viewer_HEADER_FILES      llcommunicationchannel.h      llcompilequeue.h      llconfirmationmanager.h +    llcontrolavatar.h      llconversationlog.h      llconversationloglist.h      llconversationloglistitem.h @@ -1218,6 +1221,7 @@ set(viewer_HEADER_FILES      lltranslate.h      lltwitterconnect.h      lluiconstants.h +    lluiavatar.h      lluilistener.h      lluploaddialog.h      lluploadfloaterobservers.h diff --git a/indra/newview/app_settings/logcontrol.xml b/indra/newview/app_settings/logcontrol.xml index ecd7c4bc36..ae57e125bb 100644 --- a/indra/newview/app_settings/logcontrol.xml +++ b/indra/newview/app_settings/logcontrol.xml @@ -51,6 +51,7 @@  					<key>tags</key>  						<array>  						<!-- sample entry for debugging specific items	 +                             <string>AnimatedObjects</string>  						     <string>Avatar</string>  						     <string>Inventory</string>  						     <string>SceneLoadTiming</string> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index bbd7f65383..cfdf5e546b 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -2182,6 +2182,39 @@        <key>Value</key>        <string />      </map> +  <key>DebugAnimatedObjects</key> +  <map> +    <key>Comment</key> +    <string>Show info related to animated objects</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>Boolean</string> +    <key>Value</key> +    <integer>0</integer> +  </map> +  <key>AnimatedObjectsIgnoreLimits</key> +  <map> +    <key>Comment</key> +    <string>Ignore server-enforced limits on animated objects. This is only useful for server testing.</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>Boolean</string> +    <key>Value</key> +    <integer>0</integer> +  </map> +  <key>AnimatedObjectsAllowLeftClick</key> +  <map> +    <key>Comment</key> +    <string>Allow left-click interaction with animated objects. Uncertain how much performance impact this will have.</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>Boolean</string> +    <key>Value</key> +    <integer>0</integer> +  </map>    <key>DebugAvatarAppearanceMessage</key>    <map>      <key>Comment</key> diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index c0f88ef704..08daeb0f59 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -880,7 +880,10 @@ void LLWearableHoldingPattern::onAllComplete()  			 ++it)  		{  			LLViewerObject *objectp = *it; -			gAgentAvatarp->addAttachmentOverridesForObject(objectp); +            if (!objectp->isAnimatedObject()) +            { +                gAgentAvatarp->addAttachmentOverridesForObject(objectp); +            }  		}  		// Add new attachments to match those requested. diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index ce4aab20c7..1f788b8548 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1092,7 +1092,10 @@ bool LLAppViewer::init()  		// situation to do things the Right Way. Anyone who intentionally  		// bypasses this mechanism needs no reminder that s/he's shooting  		// him/herself in the foot. -		LLNotificationsUtil::add("RunLauncher"); +		if (!beingDebugged()) +		{ +			LLNotificationsUtil::add("RunLauncher"); +		}  	}  #if LL_WINDOWS diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 48b3a1c485..de764ae300 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -646,6 +646,11 @@ bool LLAppViewerWin32::initParseCommandLine(LLCommandLineParser& clp)  	return true;  } +bool LLAppViewerWin32::beingDebugged() +{ +    return IsDebuggerPresent(); +} +  bool LLAppViewerWin32::restoreErrorTrap()  {	  	return true; diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h index 59d1ddaa3d..c5fae6a3a3 100644 --- a/indra/newview/llappviewerwin32.h +++ b/indra/newview/llappviewerwin32.h @@ -49,6 +49,7 @@ protected:  	virtual bool initHardwareTest(); // Win32 uses DX9 to test hardware.  	virtual bool initParseCommandLine(LLCommandLineParser& clp); +	virtual bool beingDebugged();  	virtual bool restoreErrorTrap();  	virtual void initCrashReporting(bool reportFreeze);  diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp new file mode 100644 index 0000000000..5a1add258c --- /dev/null +++ b/indra/newview/llcontrolavatar.cpp @@ -0,0 +1,449 @@ +/** + * @file llcontrolavatar.cpp + * @brief Implementation for special dummy avatar used to drive rigged meshes. + * + * $LicenseInfo:firstyear=2017&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2017, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llcontrolavatar.h" +#include "llagent.h" //  Get state values from here +#include "llviewerobjectlist.h" +#include "pipeline.h" +#include "llanimationstates.h" +#include "llviewercontrol.h" +#include "llmeshrepository.h" +#include "llviewerregion.h" + +LLControlAvatar::LLControlAvatar(const LLUUID& id, const LLPCode pcode, LLViewerRegion* regionp) : +    LLVOAvatar(id, pcode, regionp), +    mPlaying(false), +    mGlobalScale(1.0f), +    mMarkedForDeath(false) +{ +    mIsDummy = TRUE; +    mIsControlAvatar = true; +    mEnableDefaultMotions = false; +} + +// virtual +LLControlAvatar::~LLControlAvatar() +{ +} + +// virtual +void LLControlAvatar::initInstance() +{ +	// Potential optimizations here: avoid creating system +	// avatar mesh content since it's not used. For now we just clean some +	// things up after the fact in releaseMeshData(). +    LLVOAvatar::initInstance(); + +	createDrawable(&gPipeline); +	updateJointLODs(); +	updateGeometry(mDrawable); +	hideSkirt(); +} + +void LLControlAvatar::matchVolumeTransform() +{ +    if (mRootVolp) +    { +        if (mRootVolp->isAttachment()) +        { +            LLVOAvatar *attached_av = mRootVolp->getAvatarAncestor(); +            if (attached_av) +            { +                LLViewerJointAttachment *attach = attached_av->getTargetAttachmentPoint(mRootVolp); +                setPositionAgent(mRootVolp->getRenderPosition()); +				attach->updateWorldPRSParent(); +                LLVector3 joint_pos = attach->getWorldPosition(); +                LLQuaternion joint_rot = attach->getWorldRotation(); +                LLVector3 obj_pos = mRootVolp->mDrawable->getPosition(); +                LLQuaternion obj_rot = mRootVolp->mDrawable->getRotation(); +                obj_pos.rotVec(joint_rot); +                mRoot->setWorldPosition(obj_pos + joint_pos); +                mRoot->setWorldRotation(obj_rot * joint_rot); +                setRotation(mRoot->getRotation()); +            } +            else +            { +                LL_WARNS_ONCE() << "can't find attached av!" << LL_ENDL; +            } +        } +        else +        { +            setPositionAgent(mRootVolp->getRenderPosition()); +            LLQuaternion obj_rot = mRootVolp->getRotation(); +            LLQuaternion result_rot = obj_rot; +            setRotation(result_rot); +            mRoot->setWorldRotation(result_rot); +            mRoot->setPosition(mRootVolp->getRenderPosition()); +        } +    } +} + +void LLControlAvatar::setGlobalScale(F32 scale) +{ +    if (scale <= 0.0) +    { +        LL_WARNS() << "invalid global scale " << scale << LL_ENDL; +        return; +    } +    if (scale != mGlobalScale) +    { +        F32 adjust_scale = scale/mGlobalScale; +        LL_INFOS() << "scale " << scale << " adjustment " << adjust_scale << LL_ENDL; +        // should we be scaling from the pelvis or the root? +        recursiveScaleJoint(mPelvisp,adjust_scale); +        mGlobalScale = scale; +    } +} + +void LLControlAvatar::recursiveScaleJoint(LLJoint* joint, F32 factor) +{ +    joint->setScale(factor * joint->getScale()); +     +	for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin(); +		 iter != joint->mChildren.end(); ++iter) +	{ +		LLJoint* child = *iter; +		recursiveScaleJoint(child, factor); +	} +} + +// Based on LLViewerJointAttachment::setupDrawable(), without the attaching part. +void LLControlAvatar::updateVolumeGeom() +{ +	if (!mRootVolp->mDrawable) +		return; +	if (mRootVolp->mDrawable->isActive()) +	{ +		mRootVolp->mDrawable->makeStatic(FALSE); +	} +	mRootVolp->mDrawable->makeActive(); +	gPipeline.markMoved(mRootVolp->mDrawable); +	gPipeline.markTextured(mRootVolp->mDrawable); // face may need to change draw pool to/from POOL_HUD +	mRootVolp->mDrawable->setState(LLDrawable::USE_BACKLIGHT); + +	LLViewerObject::const_child_list_t& child_list = mRootVolp->getChildren(); +	for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); +		 iter != child_list.end(); ++iter) +	{ +		LLViewerObject* childp = *iter; +		if (childp && childp->mDrawable.notNull()) +		{ +			childp->mDrawable->setState(LLDrawable::USE_BACKLIGHT); +			gPipeline.markTextured(childp->mDrawable); // face may need to change draw pool to/from POOL_HUD +			gPipeline.markMoved(childp->mDrawable); +        } +    } + +    gPipeline.markRebuild(mRootVolp->mDrawable, LLDrawable::REBUILD_ALL, TRUE); +    mRootVolp->markForUpdate(TRUE); + +    // Note that attachment overrides aren't needed here, have already +    // been applied at the time the mControlAvatar was created, in +    // llvovolume.cpp. + +    matchVolumeTransform(); + +    // Initial exploration of allowing scaling skeleton to match root +    // prim bounding box. If enabled, would probably be controlled by +    // an additional checkbox and default to off. Not enabled for +    // initial release. + +    // What should the scale be? What we really want is the ratio +    // between the scale at which the object was originally designed +    // and rigged, and the scale to which it has been subsequently +    // modified - for example, if the object has been scaled down by a +    // factor of 2 then we should use 0.5 as the global scale. But we +    // don't have the original scale stored anywhere, just the current +    // scale. Possibilities - 1) remember the original scale +    // somewhere, 2) add another field to let the user specify the +    // global scale, 3) approximate the original scale by looking at +    // the proportions of the skeleton after joint positions have +    // been applied +     +    //LLVector3 obj_scale = obj->getScale(); +    //F32 obj_scale_z = llmax(obj_scale[2],0.1f); +    //setGlobalScale(obj_scale_z/2.0f); // roughly fit avatar height range (2m) into object height +} + +LLControlAvatar *LLControlAvatar::createControlAvatar(LLVOVolume *obj) +{ +	LLControlAvatar *cav = (LLControlAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), CO_FLAG_CONTROL_AVATAR); + +    cav->mRootVolp = obj; + +    // Sync up position/rotation with object +    cav->matchVolumeTransform(); + +    return cav; +} + +void LLControlAvatar::markForDeath() +{ +    mMarkedForDeath = true; +} + +void LLControlAvatar::idleUpdate(LLAgent &agent, const F64 &time) +{ +    if (mMarkedForDeath) +    { +        markDead(); +        mMarkedForDeath = false; +    } +    else +    { +        LLVOAvatar::idleUpdate(agent,time); +    } +} + +BOOL LLControlAvatar::updateCharacter(LLAgent &agent) +{ +    return LLVOAvatar::updateCharacter(agent); +} + +//virtual +void LLControlAvatar::updateDebugText() +{ +	if (gSavedSettings.getBOOL("DebugAnimatedObjects")) +    { +        S32 total_linkset_count = 0; +        if (mRootVolp) +        { +            total_linkset_count = 1 + mRootVolp->getChildren().size(); +        } +        std::vector<LLVOVolume*> volumes; +        getAnimatedVolumes(volumes); +        S32 animated_volume_count = volumes.size(); +        std::string active_string; +        std::string type_string; +        std::string lod_string; +        std::string animated_object_flag_string; +        S32 total_tris = 0; +        S32 total_verts = 0; +        F32 est_tris = 0.f; +        F32 est_streaming_tris = 0.f; +        F32 streaming_cost = 0.f; +         +        for (std::vector<LLVOVolume*>::iterator it = volumes.begin(); +             it != volumes.end(); ++it) +        { +            LLVOVolume *volp = *it; +            S32 verts = 0; +            total_tris += volp->getTriangleCount(&verts); +            total_verts += verts; +            est_tris += volp->getEstTrianglesMax(); +            est_streaming_tris += volp->getEstTrianglesStreamingCost(); +            streaming_cost += volp->getStreamingCost(); +            lod_string += llformat("%d",volp->getLOD()); +            if (volp && volp->mDrawable) +            { +                bool is_animated_flag = volp->getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; +                if (is_animated_flag) +                { +                    animated_object_flag_string += "1"; +                } +                else +                { +                    animated_object_flag_string += "0"; +                } +                if (volp->mDrawable->isActive()) +                { +                    active_string += "A"; +                } +                else +                { +                    active_string += "S"; +                } +                if (volp->isRiggedMesh()) +                { +                    // Rigged/animatable mesh +                    type_string += "R"; +                } +                else if (volp->isMesh()) +                { +                    // Static mesh +                    type_string += "M"; +                } +                else +                { +                    // Any other prim +                    type_string += "P"; +                } +            } +            else +            { +                active_string += "-"; +                type_string += "-"; +            } +        } +        addDebugText(llformat("CAV obj %d anim %d active %s impost %d strcst %f", +                              total_linkset_count, animated_volume_count,  +                              active_string.c_str(), (S32) isImpostor(), streaming_cost)); +        addDebugText(llformat("types %s lods %s", type_string.c_str(), lod_string.c_str())); +        addDebugText(llformat("flags %s", animated_object_flag_string.c_str())); +        addDebugText(llformat("tris %d (est %.1f, streaming %.1f), verts %d", total_tris, est_tris, est_streaming_tris, total_verts)); +        addDebugText(llformat("pxarea %s rank %d", LLStringOps::getReadableNumber(getPixelArea()).c_str(), getVisibilityRank())); +#if 0 +        std::string region_name = "no region"; +        if (mRootVolp->getRegion()) +        { +            region_name = mRootVolp->getRegion()->getName(); +        } +        std::string skel_region_name = "skel no region"; +        if (getRegion()) +        { +            skel_region_name = getRegion()->getName(); +        } +        addDebugText(llformat("region %x %s skel %x %s", +                              mRootVolp->getRegion(), region_name.c_str(), +                              getRegion(), skel_region_name.c_str())); +#endif +         +    } +    LLVOAvatar::updateDebugText(); +} + +void LLControlAvatar::getAnimatedVolumes(std::vector<LLVOVolume*>& volumes) +{ +    if (!mRootVolp) +    { +        return; +    } + +    volumes.push_back(mRootVolp); +     +	LLViewerObject::const_child_list_t& child_list = mRootVolp->getChildren(); +	for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin(); +		 iter != child_list.end(); ++iter) +	{ +		LLViewerObject* childp = *iter; +        LLVOVolume *child_volp = dynamic_cast<LLVOVolume*>(childp); +        if (child_volp && child_volp->isAnimatedObject()) +        { +            volumes.push_back(child_volp); +        } +    } +} + +// This is called after an associated object receives an animation +// message. Combine the signaled animations for all associated objects +// and process any resulting state changes. +void LLControlAvatar::updateAnimations() +{ +    if (!mRootVolp) +    { +        LL_WARNS_ONCE("AnimatedObjectsNotify") << "No root vol" << LL_ENDL; +        return; +    } + +    std::vector<LLVOVolume*> volumes; +    getAnimatedVolumes(volumes); +     +    // Rebuild mSignaledAnimations from the associated volumes. +	std::map<LLUUID, S32> anims; +    for (std::vector<LLVOVolume*>::iterator vol_it = volumes.begin(); vol_it != volumes.end(); ++vol_it) +    { +        LLVOVolume *volp = *vol_it; +        //LL_INFOS("AnimatedObjects") << "updating anim for vol " << volp->getID() << " root " << mRootVolp->getID() << LL_ENDL; +        signaled_animation_map_t& signaled_animations = LLObjectSignaledAnimationMap::instance().getMap()[volp->getID()]; +        for (std::map<LLUUID,S32>::iterator anim_it = signaled_animations.begin(); +             anim_it != signaled_animations.end(); +             ++anim_it) +        { +            std::map<LLUUID,S32>::iterator found_anim_it = anims.find(anim_it->first); +            if (found_anim_it != anims.end()) +            { +                // Animation already present, use the larger sequence id +                anims[anim_it->first] = llmax(found_anim_it->second, anim_it->second); +            } +            else +            { +                // Animation not already present, use this sequence id. +                anims[anim_it->first] = anim_it->second; +            } +            LL_DEBUGS("AnimatedObjectsNotify") << "found anim for vol " << volp->getID() << " anim " << anim_it->first << " root " << mRootVolp->getID() << LL_ENDL; +        } +    } +    if (!mPlaying) +    { +        mPlaying = true; +        if (!mRootVolp->isAnySelected()) +        { +            updateVolumeGeom(); +            mRootVolp->recursiveMarkForUpdate(TRUE); +        } +    } + +    mSignaledAnimations = anims; +    processAnimationStateChanges(); +} + +// virtual +LLViewerObject* LLControlAvatar::lineSegmentIntersectRiggedAttachments(const LLVector4a& start, const LLVector4a& end, +									  S32 face, +									  BOOL pick_transparent, +									  BOOL pick_rigged, +									  S32* face_hit, +									  LLVector4a* intersection, +									  LLVector2* tex_coord, +									  LLVector4a* normal, +									  LLVector4a* tangent) +{ +	LLViewerObject* hit = NULL; + +	if (lineSegmentBoundingBox(start, end)) +	{ +		LLVector4a local_end = end; +		LLVector4a local_intersection; + +        if (mRootVolp && +            mRootVolp->lineSegmentIntersect(start, local_end, face, pick_transparent, pick_rigged, face_hit, &local_intersection, tex_coord, normal, tangent)) +        { +            local_end = local_intersection; +            if (intersection) +            { +                *intersection = local_intersection; +            } +			 +            hit = mRootVolp; +        } +	} +		 +	return hit; +} + +// virtual +std::string LLControlAvatar::getFullname() const +{ +    if (mRootVolp) +    { +        return "AO_" + mRootVolp->getID().getString(); +    } +    else +    { +        return "AO_no_root_vol"; +    } +} diff --git a/indra/newview/llcontrolavatar.h b/indra/newview/llcontrolavatar.h new file mode 100644 index 0000000000..02244769b9 --- /dev/null +++ b/indra/newview/llcontrolavatar.h @@ -0,0 +1,99 @@ +/** + * @file llcontrolavatar.h + * @brief Special dummy avatar used to drive rigged meshes. + * + * $LicenseInfo:firstyear=2017&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2017, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#ifndef LL_CONTROLAVATAR_H +#define LL_CONTROLAVATAR_H + +#include "llvoavatar.h" +#include "llvovolume.h" + +class LLControlAvatar: +    public LLVOAvatar +{ +    LOG_CLASS(LLControlAvatar); + +public: +    LLControlAvatar(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); +	virtual void 			initInstance(); // Called after construction to initialize the class. +	virtual	~LLControlAvatar(); + +    void matchVolumeTransform(); +    void updateVolumeGeom(); +         +    void setGlobalScale(F32 scale); +    void recursiveScaleJoint(LLJoint *joint, F32 factor); +    static LLControlAvatar *createControlAvatar(LLVOVolume *obj); + +    // Delayed kill so we don't make graphics pipeline unhappy calling +    // markDead() inside other graphics pipeline operations. +    void markForDeath(); + +    virtual void idleUpdate(LLAgent &agent, const F64 &time); +	virtual BOOL updateCharacter(LLAgent &agent); + +    void getAnimatedVolumes(std::vector<LLVOVolume*>& volumes); +    void updateAnimations();   +     +	virtual LLViewerObject*	lineSegmentIntersectRiggedAttachments( +        const LLVector4a& start, const LLVector4a& end, +        S32 face = -1,                    // which face to check, -1 = ALL_SIDES +        BOOL pick_transparent = FALSE, +        BOOL pick_rigged = FALSE, +        S32* face_hit = NULL,             // which face was hit +        LLVector4a* intersection = NULL,   // return the intersection point +        LLVector2* tex_coord = NULL,      // return the texture coordinates of the intersection point +        LLVector4a* normal = NULL,         // return the surface normal at the intersection point +        LLVector4a* tangent = NULL);     // return the surface tangent at the intersection point + +	virtual void	updateDebugText(); + +    virtual std::string getFullname() const; + +    bool mPlaying; + +    F32 mGlobalScale; + +    LLVOVolume *mRootVolp; + +    bool mMarkedForDeath; + +}; + +typedef std::map<LLUUID, S32> signaled_animation_map_t; +typedef std::map<LLUUID, signaled_animation_map_t> object_signaled_animation_map_t; + +// Stores information about previously requested animations, by object id. +class LLObjectSignaledAnimationMap: public LLSingleton<LLObjectSignaledAnimationMap> +{ +    LLSINGLETON_EMPTY_CTOR(LLObjectSignaledAnimationMap);  + +public: +    object_signaled_animation_map_t mMap; + +    object_signaled_animation_map_t& getMap() { return mMap; } +}; + +#endif //LL_CONTROLAVATAR_H diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index f956023358..7e51389655 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -50,6 +50,8 @@  #include "llviewerobjectlist.h"  #include "llviewerwindow.h"  #include "llvocache.h" +#include "llcontrolavatar.h" +#include "llcallstack.h"  const F32 MIN_INTERPOLATE_DISTANCE_SQUARED = 0.001f * 0.001f;  const F32 MAX_INTERPOLATE_DISTANCE_SQUARED = 10.f * 10.f; @@ -550,7 +552,8 @@ void LLDrawable::makeStatic(BOOL warning_enabled)  	if (isState(ACTIVE) &&   		!isState(ACTIVE_CHILD) &&   		!mVObjp->isAttachment() &&  -		!mVObjp->isFlexible()) +		!mVObjp->isFlexible() && +        !mVObjp->isAnimatedObject())  	{  		clearState(ACTIVE | ANIMATED_CHILD); @@ -1084,7 +1087,8 @@ void LLDrawable::setGroup(LLViewerOctreeGroup *groupp)  	llassert(!groupp || (LLSpatialGroup*)groupp->hasElement(this));  	if (cur_groupp != groupp && getVOVolume()) -	{ //NULL out vertex buffer references for volumes on spatial group change to maintain +	{ +		//NULL out vertex buffer references for volumes on spatial group change to maintain  		//requirement that every face vertex buffer is either NULL or points to a vertex buffer  		//contained by its drawable's spatial group  		for (S32 i = 0; i < getNumFaces(); ++i) diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index f74164aea6..1ec8d97f36 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -140,7 +140,7 @@ LLViewerTexture *LLDrawPool::getDebugTexture()  	return NULL;  } -//virtual +//virtuals  void LLDrawPool::beginRenderPass( S32 pass )  {  } diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 8128790eb6..375704adff 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -109,6 +109,32 @@ LLDrawPoolAvatar::LLDrawPoolAvatar() :  {  } +LLDrawPoolAvatar::~LLDrawPoolAvatar() +{ +    if (!isDead()) +    { +        LL_WARNS() << "Destroying avatar drawpool that still contains faces" << LL_ENDL; +    } +} + +// virtual +BOOL LLDrawPoolAvatar::isDead() +{ +    if (!LLFacePool::isDead()) +    { +        return FALSE; +    } +     +	for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i) +    { +        if (mRiggedFace[i].size() > 0) +        { +            return FALSE; +        } +    } +    return TRUE; +} +   //-----------------------------------------------------------------------------  // instancePool()  //----------------------------------------------------------------------------- @@ -467,7 +493,7 @@ void LLDrawPoolAvatar::renderShadow(S32 pass)  	}  	LLVOAvatar *avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get(); -	if (avatarp->isDead() || avatarp->mIsDummy || avatarp->mDrawable.isNull()) +	if (avatarp->isDead() || avatarp->isUIAvatar() || avatarp->mDrawable.isNull())  	{  		return;  	} @@ -1707,13 +1733,7 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)  			continue;  		} -		LLUUID mesh_id = volume->getParams().getSculptID(); -		if (mesh_id.isNull()) -		{ -			continue; -		} - -		const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(mesh_id, vobj); +		const LLMeshSkinInfo* skin = vobj->getSkinInfo();  		if (!skin)  		{  			continue; @@ -1927,13 +1947,7 @@ void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar)  				continue;  			} -			LLUUID mesh_id = volume->getParams().getSculptID(); -			if (mesh_id.isNull()) -			{ -				continue; -			} - -			const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(mesh_id, vobj); +			const LLMeshSkinInfo* skin = vobj->getSkinInfo();  			if (!skin)  			{  				continue; @@ -2054,11 +2068,16 @@ LLColor3 LLDrawPoolAvatar::getDebugColor() const  void LLDrawPoolAvatar::addRiggedFace(LLFace* facep, U32 type)  { +    llassert (facep->isState(LLFace::RIGGED)); +    llassert(getType() == LLDrawPool::POOL_AVATAR); +    if (facep->getPool() && facep->getPool() != this) +    { +        LL_ERRS() << "adding rigged face that's already in another pool" << LL_ENDL; +    }  	if (type >= NUM_RIGGED_PASSES)  	{  		LL_ERRS() << "Invalid rigged face type." << LL_ENDL;  	} -  	if (facep->getRiggedIndex(type) != -1)  	{  		LL_ERRS() << "Tried to add a rigged face that's referenced elsewhere." << LL_ENDL; @@ -2071,6 +2090,12 @@ void LLDrawPoolAvatar::addRiggedFace(LLFace* facep, U32 type)  void LLDrawPoolAvatar::removeRiggedFace(LLFace* facep)  { +    llassert (facep->isState(LLFace::RIGGED)); +    llassert(getType() == LLDrawPool::POOL_AVATAR); +    if (facep->getPool() != this) +    { +        LL_ERRS() << "Tried to remove a rigged face from the wrong pool" << LL_ENDL; +    }  	facep->setPool(NULL);  	for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i) diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h index b9d2204052..45b6d71110 100644 --- a/indra/newview/lldrawpoolavatar.h +++ b/indra/newview/lldrawpoolavatar.h @@ -60,6 +60,8 @@ public:  	virtual S32 getVertexShaderLevel() const;  	LLDrawPoolAvatar(); +    ~LLDrawPoolAvatar(); +    /*virtual*/ BOOL isDead();  	static LLMatrix4& getModelView(); diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 50a4925c37..efd57ec39f 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -330,11 +330,7 @@ void LLFace::dirtyTexture()  				{  					vobj->mLODChanged = TRUE; -					LLVOAvatar* avatar = vobj->getAvatar(); -					if (avatar) -					{ //avatar render cost may have changed -						avatar->updateVisualComplexity(); -					} +                    vobj->updateVisualComplexity();  				}  				gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_VOLUME, FALSE);  			} @@ -835,6 +831,9 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,  		min = face.mExtents[0];  		max = face.mExtents[1]; +        LL_DEBUGS("RiggedBox") << "updating extents for face " << f << " starting extents " << mExtents[0] << ", " << mExtents[1] << LL_ENDL; +        LL_DEBUGS("RiggedBox") << "updating extents for face " << f << " starting vf extents " << face.mExtents[0] << ", " << face.mExtents[1] << " num verts " << face.mNumVertices << LL_ENDL; +  		llassert(less_than_max_mag(min));  		llassert(less_than_max_mag(max)); @@ -863,6 +862,14 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,  		v[6] = min;  		v[7] = max; +        // MAINT-8264 - stray vertices, especially in low LODs, cause bounding box errors. +		if (face.mNumVertices < 3)  +        { +            LL_DEBUGS("RiggedBox") << "skipping face " << f << ", bad num vertices "  +                                   << face.mNumVertices << " " << face.mNumIndices << " " << face.mWeights << LL_ENDL; +            return FALSE; +        } +          		for (U32 i = 0; i < 6; ++i)  		{  			v[i].setSelectWithMask(mask[i], min, max); @@ -870,10 +877,13 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,  		LLVector4a tv[8]; +        LL_DEBUGS("RiggedBox") << "updating extents for face " << f << " mat is " << mat_vert << LL_ENDL; +  		//transform bounding box into drawable space  		for (U32 i = 0; i < 8; ++i)  		{  			mat_vert.affineTransform(v[i], tv[i]); +            LL_DEBUGS("RiggedBox") << "updating extents for face " << f << " i " << i << " v and tv " << v[i] << ", " << tv[i] << LL_ENDL;  		}  		//find bounding box @@ -887,6 +897,7 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,  			newMin.setMin(newMin, tv[i]);  			newMax.setMax(newMax, tv[i]);  		} +        LL_DEBUGS("RiggedBox") << "updating extents for face " << f << " bbox gave extents " << mExtents[0] << ", " << mExtents[1] << LL_ENDL;  		if (!mDrawablep->isActive())  		{	// Shift position for region @@ -894,8 +905,10 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,  			offset.load3(mDrawablep->getRegion()->getOriginAgent().mV);  			newMin.add(offset);  			newMax.add(offset); +            LL_DEBUGS("RiggedBox") << "updating extents for face " << f << " not active, added offset " << offset << LL_ENDL;  		} +        LL_DEBUGS("RiggedBox") << "updated extents for face " << f << " to " << mExtents[0] << ", " << mExtents[1] << LL_ENDL;  		LLVector4a t;  		t.setAdd(newMin,newMax);  		t.mul(0.5f); diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp index ae7620f2c7..080d0ed8ea 100644 --- a/indra/newview/llfloaterbvhpreview.cpp +++ b/indra/newview/llfloaterbvhpreview.cpp @@ -1042,14 +1042,8 @@ LLPreviewAnimation::LLPreviewAnimation(S32 width, S32 height) : LLViewerDynamicT  	mCameraPitch = 0.f;  	mCameraZoom = 1.f; -	mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion()); -	mDummyAvatar->createDrawable(&gPipeline); -	mDummyAvatar->mIsDummy = TRUE; +	mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR);  	mDummyAvatar->mSpecialRenderMode = 1; -	mDummyAvatar->setPositionAgent(LLVector3::zero); -	mDummyAvatar->slamPosition(); -	mDummyAvatar->updateJointLODs(); -	mDummyAvatar->updateGeometry(mDummyAvatar->mDrawable);  	mDummyAvatar->startMotion(ANIM_AGENT_STAND, BASE_ANIM_TIME_OFFSET);  	mDummyAvatar->hideSkirt(); diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 0c2bb25e07..3c428a70f3 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -566,15 +566,8 @@ LLImagePreviewAvatar::LLImagePreviewAvatar(S32 width, S32 height) : LLViewerDyna  	mCameraPitch = 0.f;  	mCameraZoom = 1.f; -	mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion()); -	mDummyAvatar->createDrawable(&gPipeline); -	mDummyAvatar->mIsDummy = TRUE; +	mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR);  	mDummyAvatar->mSpecialRenderMode = 2; -	mDummyAvatar->setPositionAgent(LLVector3::zero); -	mDummyAvatar->slamPosition(); -	mDummyAvatar->updateJointLODs(); -	mDummyAvatar->updateGeometry(mDummyAvatar->mDrawable); -	// gPipeline.markVisible(mDummyAvatar->mDrawable, *LLViewerCamera::getInstance());  	mTextureName = 0;  } diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index da84a6b8f8..1667f01272 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1360,7 +1360,11 @@ U32 LLModelPreview::calcResourceCost()  			F32 radius = scale.length()*0.5f*debug_scale; -			streaming_cost += LLMeshRepository::getStreamingCost(ret, radius); +            LLMeshCostData costs; +            if (gMeshRepo.getCostData(ret, costs)) +            { +                streaming_cost += costs.getRadiusBasedStreamingCost(radius); +            }  		}  	} @@ -1755,9 +1759,17 @@ void LLModelPreview::getJointAliases( JointMap& joint_map)      //Joint names and aliases come from avatar_skeleton.xml      joint_map = av->getJointAliases(); -    for (S32 i = 0; i < av->mNumCollisionVolumes; i++) + +    std::vector<std::string> cv_names, attach_names; +    av->getSortedJointNames(1, cv_names); +    av->getSortedJointNames(2, attach_names); +    for (std::vector<std::string>::iterator it = cv_names.begin(); it != cv_names.end(); ++it) +    { +        joint_map[*it] = *it; +    } +    for (std::vector<std::string>::iterator it = attach_names.begin(); it != attach_names.end(); ++it)      { -        joint_map[av->mCollisionVolumes[i].getName()] = av->mCollisionVolumes[i].getName(); +        joint_map[*it] = *it;      }  } @@ -3443,16 +3455,11 @@ void LLModelPreview::update()  //-----------------------------------------------------------------------------  void LLModelPreview::createPreviewAvatar( void )  { -	mPreviewAvatar = (LLVOAvatar*)gObjectList.createObjectViewer( LL_PCODE_LEGACY_AVATAR, gAgent.getRegion() ); +	mPreviewAvatar = (LLVOAvatar*)gObjectList.createObjectViewer( LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR );  	if ( mPreviewAvatar )  	{  		mPreviewAvatar->createDrawable( &gPipeline ); -		mPreviewAvatar->mIsDummy = TRUE;  		mPreviewAvatar->mSpecialRenderMode = 1; -		mPreviewAvatar->setPositionAgent( LLVector3::zero ); -		mPreviewAvatar->slamPosition(); -		mPreviewAvatar->updateJointLODs(); -		mPreviewAvatar->updateGeometry( mPreviewAvatar->mDrawable );  		mPreviewAvatar->startMotion( ANIM_AGENT_STAND );  		mPreviewAvatar->hideSkirt();  	} diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 71a161198a..e2df30c034 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -4103,22 +4103,80 @@ void LLMeshRepository::uploadError(LLSD& args)  	mUploadErrorQ.push(args);  } -F32 LLMeshRepository::getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) +F32 LLMeshRepository::getEstTrianglesMax(LLUUID mesh_id)  { +    LLMeshCostData costs; +    if (getCostData(mesh_id, costs)) +    { +        return costs.getEstTrisMax(); +    } +    else +    { +        return 0.f; +    } +} + +F32 LLMeshRepository::getEstTrianglesStreamingCost(LLUUID mesh_id) +{ +    LLMeshCostData costs; +    if (getCostData(mesh_id, costs)) +    { +        return costs.getEstTrisForStreamingCost(); +    } +    else +    { +        return 0.f; +    } +} + +// FIXME replace with calc based on LLMeshCostData +F32 LLMeshRepository::getStreamingCostLegacy(LLUUID mesh_id, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) +{ +	F32 result = 0.f;      if (mThread && mesh_id.notNull())      {          LLMutexLock lock(mThread->mHeaderMutex);          LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id);          if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0)          { -            return getStreamingCost(iter->second, radius, bytes, bytes_visible, lod, unscaled_value); +            result  = getStreamingCostLegacy(iter->second, radius, bytes, bytes_visible, lod, unscaled_value); +        } +    } +    if (result > 0.f) +    { +        LLMeshCostData data; +        if (getCostData(mesh_id, data)) +        { +            F32 ref_streaming_cost = data.getRadiusBasedStreamingCost(radius); +            F32 ref_weighted_tris = data.getRadiusWeightedTris(radius); +            if (!is_approx_equal(ref_streaming_cost,result)) +            { +                LL_WARNS() << mesh_id << "streaming mismatch " << result << " " << ref_streaming_cost << LL_ENDL; +            } +            if (unscaled_value && !is_approx_equal(ref_weighted_tris,*unscaled_value)) +            { +                LL_WARNS() << mesh_id << "weighted_tris mismatch " << *unscaled_value << " " << ref_weighted_tris << LL_ENDL; +            } +            if (bytes && (*bytes != data.getSizeTotal())) +            { +                LL_WARNS() << mesh_id << "bytes mismatch " << *bytes << " " << data.getSizeTotal() << LL_ENDL; +            } +            if (bytes_visible && (lod >=0) && (lod < 4) && (*bytes_visible != data.getSizeByLOD(lod))) +            { +                LL_WARNS() << mesh_id << "bytes_visible mismatch " << *bytes_visible << " " << data.getSizeByLOD(lod) << LL_ENDL; +            } +        } +        else +        { +            LL_WARNS() << "getCostData failed!!!" << LL_ENDL;          }      } -    return 0.f; +    return result;  } +// FIXME replace with calc based on LLMeshCostData  //static -F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) +F32 LLMeshRepository::getStreamingCostLegacy(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value)  {  	if (header.has("404")  		|| !header.has("lowest_lod") @@ -4212,7 +4270,7 @@ F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32  	F32 weighted_avg = triangles_high*high_area +  					   triangles_mid*mid_area +  					   triangles_low*low_area + -					  triangles_lowest*lowest_area; +					   triangles_lowest*lowest_area;  	if (unscaled_value)  	{ @@ -4222,6 +4280,204 @@ F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32  	return weighted_avg/gSavedSettings.getU32("MeshTriangleBudget")*15000.f;  } +LLMeshCostData::LLMeshCostData() +{ +    mSizeByLOD.resize(4); +    mEstTrisByLOD.resize(4); + +    std::fill(mSizeByLOD.begin(), mSizeByLOD.end(), 0); +    std::fill(mEstTrisByLOD.begin(), mEstTrisByLOD.end(), 0.f); +} + +bool LLMeshCostData::init(const LLSD& header) +{ +    mSizeByLOD.resize(4); +    mEstTrisByLOD.resize(4); + +    std::fill(mSizeByLOD.begin(), mSizeByLOD.end(), 0); +    std::fill(mEstTrisByLOD.begin(), mEstTrisByLOD.end(), 0.f); +     +    S32 bytes_high = header["high_lod"]["size"].asInteger(); +    S32 bytes_med = header["medium_lod"]["size"].asInteger(); +    if (bytes_med == 0) +    { +        bytes_med = bytes_high; +    } +    S32 bytes_low = header["low_lod"]["size"].asInteger(); +    if (bytes_low == 0) +    { +        bytes_low = bytes_med; +    } +    S32 bytes_lowest = header["lowest_lod"]["size"].asInteger(); +    if (bytes_lowest == 0) +    { +        bytes_lowest = bytes_low; +    } +    mSizeByLOD[0] = bytes_lowest; +    mSizeByLOD[1] = bytes_low; +    mSizeByLOD[2] = bytes_med; +    mSizeByLOD[3] = bytes_high; + +    F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount");  //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead +    F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free" +    F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle"); + +    for (S32 i=0; i<4; i++) +    { +        mEstTrisByLOD[i] = llmax((F32) mSizeByLOD[i]-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle;  +    } + +    return true; +} + + +S32 LLMeshCostData::getSizeByLOD(S32 lod) +{ +    if (llclamp(lod,0,3) != lod) +    { +        return 0; +    } +    return mSizeByLOD[lod]; +} + +S32 LLMeshCostData::getSizeTotal() +{ +    return mSizeByLOD[0] + mSizeByLOD[1] + mSizeByLOD[2] + mSizeByLOD[3]; +} + +F32 LLMeshCostData::getEstTrisByLOD(S32 lod) +{ +    if (llclamp(lod,0,3) != lod) +    { +        return 0.f; +    } +    return mEstTrisByLOD[lod]; +} + +F32 LLMeshCostData::getEstTrisMax() +{ +    return llmax(mEstTrisByLOD[0], mEstTrisByLOD[1], mEstTrisByLOD[2], mEstTrisByLOD[3]); +} + +F32 LLMeshCostData::getRadiusWeightedTris(F32 radius) +{ +	F32 max_distance = 512.f; + +	F32 dlowest = llmin(radius/0.03f, max_distance); +	F32 dlow = llmin(radius/0.06f, max_distance); +	F32 dmid = llmin(radius/0.24f, max_distance); +	 +	F32 triangles_lowest = mEstTrisByLOD[0]; +	F32 triangles_low = mEstTrisByLOD[1]; +	F32 triangles_mid = mEstTrisByLOD[2]; +	F32 triangles_high = mEstTrisByLOD[3]; + +	F32 max_area = 102944.f; //area of circle that encompasses region (see MAINT-6559) +	F32 min_area = 1.f; + +	F32 high_area = llmin(F_PI*dmid*dmid, max_area); +	F32 mid_area = llmin(F_PI*dlow*dlow, max_area); +	F32 low_area = llmin(F_PI*dlowest*dlowest, max_area); +	F32 lowest_area = max_area; + +	lowest_area -= low_area; +	low_area -= mid_area; +	mid_area -= high_area; + +	high_area = llclamp(high_area, min_area, max_area); +	mid_area = llclamp(mid_area, min_area, max_area); +	low_area = llclamp(low_area, min_area, max_area); +	lowest_area = llclamp(lowest_area, min_area, max_area); + +	F32 total_area = high_area + mid_area + low_area + lowest_area; +	high_area /= total_area; +	mid_area /= total_area; +	low_area /= total_area; +	lowest_area /= total_area; + +	F32 weighted_avg = triangles_high*high_area + +					   triangles_mid*mid_area + +					   triangles_low*low_area + +					   triangles_lowest*lowest_area; + +    return weighted_avg; +} + +F32 LLMeshCostData::getEstTrisForStreamingCost() +{ +    LL_DEBUGS("StreamingCost") << "tris_by_lod: " +                               << mEstTrisByLOD[0] << ", " +                               << mEstTrisByLOD[1] << ", " +                               << mEstTrisByLOD[2] << ", " +                               << mEstTrisByLOD[3] << LL_ENDL; + +    F32 charged_tris = mEstTrisByLOD[3]; +    F32 allowed_tris = mEstTrisByLOD[3]; +    const F32 ENFORCE_FLOOR = 64.0f; +    for (S32 i=2; i>=0; i--) +    { +        // How many tris can we have in this LOD without affecting land impact? +        // - normally an LOD should be at most half the size of the previous one. +        // - once we reach a floor of ENFORCE_FLOOR, don't require LODs to get any smaller. +        allowed_tris = llclamp(allowed_tris/2.0f,ENFORCE_FLOOR,mEstTrisByLOD[i]); +        F32 excess_tris = mEstTrisByLOD[i]-allowed_tris; +        if (excess_tris>0.f) +        { +            LL_DEBUGS("StreamingCost") << "excess tris in lod[" << i << "] " << excess_tris << " allowed " << allowed_tris <<  LL_ENDL; +            charged_tris += excess_tris; +        } +    } +    return charged_tris; +} + +F32 LLMeshCostData::getRadiusBasedStreamingCost(F32 radius) +{ +	return getRadiusWeightedTris(radius)/gSavedSettings.getU32("MeshTriangleBudget")*15000.f; +} + +F32 LLMeshCostData::getTriangleBasedStreamingCost() +{ +    F32 result = ANIMATED_OBJECT_COST_PER_KTRI * 0.001 * getEstTrisForStreamingCost(); +    return result; +} + +bool LLMeshRepository::getCostData(LLUUID mesh_id, LLMeshCostData& data) +{ +    data = LLMeshCostData(); +     +    if (mThread && mesh_id.notNull()) +    { +        LLMutexLock lock(mThread->mHeaderMutex); +        LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); +        if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) +        { +            LLSD& header = iter->second; + +            bool header_invalid = (header.has("404") +                                   || !header.has("lowest_lod") +                                   || (header.has("version") && header["version"].asInteger() > MAX_MESH_VERSION)); +            if (!header_invalid) +            { +                return getCostData(header, data); +            } + +            return true; +        } +    } +    return false; +} + +bool LLMeshRepository::getCostData(LLSD& header, LLMeshCostData& data) +{ +    data = LLMeshCostData(); + +    if (!data.init(header)) +    { +        return false; +    } +     +    return true; +}  LLPhysicsDecomp::LLPhysicsDecomp()  : LLThread("Physics Decomp") diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index e07a00bf03..df8f5c5ff4 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -460,6 +460,60 @@ private:  	LLCore::HttpRequest::priority_t		mHttpPriority;  }; +// Params related to streaming cost, render cost, and scene complexity tracking. +class LLMeshCostData +{ +public: +    LLMeshCostData(); + +    bool init(const LLSD& header); +     +    // Size for given LOD +    S32 getSizeByLOD(S32 lod); + +    // Sum of all LOD sizes. +    S32 getSizeTotal(); + +    // Estimated triangle counts for the given LOD. +    F32 getEstTrisByLOD(S32 lod); +     +    // Estimated triangle counts for the largest LOD. Typically this +    // is also the "high" LOD, but not necessarily. +    F32 getEstTrisMax(); + +    // Triangle count as computed by original streaming cost +    // formula. Triangles in each LOD are weighted based on how +    // frequently they will be seen. +    // This was called "unscaled_value" in the original getStreamingCost() functions. +    F32 getRadiusWeightedTris(F32 radius); + +    // Triangle count used by triangle-based cost formula. Based on +    // triangles in highest LOD plus potentially partial charges for +    // lower LODs depending on complexity. +    F32 getEstTrisForStreamingCost(); + +    // Streaming cost. This should match the server-side calculation +    // for the corresponding volume. +    F32 getRadiusBasedStreamingCost(F32 radius); + +    // New streaming cost formula, currently only used for animated objects. +    F32 getTriangleBasedStreamingCost(); + +private: +    // From the "size" field of the mesh header. LOD 0=lowest, 3=highest. +    std::vector<S32> mSizeByLOD; + +    // Estimated triangle counts derived from the LOD sizes. LOD 0=lowest, 3=highest. +    std::vector<F32> mEstTrisByLOD; + +    // Estimated triangle counts for the largest LOD. Typically this +    // is also the "high" LOD, but not necessarily. +    F32 mEstTrisMax; + +    // Sum of all LOD sizes. +    S32 mSizeTotal; +}; +  class LLMeshRepository  {  public: @@ -481,8 +535,13 @@ public:  	static LLDeadmanTimer sQuiescentTimer;		// Time-to-complete-mesh-downloads after significant events -	F32 getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); -	static F32 getStreamingCost(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); +    // Estimated triangle count of the largest LOD +    F32 getEstTrianglesMax(LLUUID mesh_id); +    F32 getEstTrianglesStreamingCost(LLUUID mesh_id); +	F32 getStreamingCostLegacy(LLUUID mesh_id, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); +	static F32 getStreamingCostLegacy(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); +    bool getCostData(LLUUID mesh_id, LLMeshCostData& data); +    bool getCostData(LLSD& header, LLMeshCostData& data);  	LLMeshRepository(); @@ -593,5 +652,9 @@ public:  extern LLMeshRepository gMeshRepo; +// AXON make sure this is consistent with the final simulator-side values. +const F32 ANIMATED_OBJECT_BASE_COST = 15.0f; +const F32 ANIMATED_OBJECT_COST_PER_KTRI = 1.5f; +  #endif diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index d0dea5d044..92dd7faa7c 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -342,9 +342,24 @@ void LLPanelObject::getState( )  	}  	// can move or rotate only linked group with move permissions, or sub-object with move and modify perms +#if 0 +    // AXON REVIEW BEFORE RELEASE, behavior during edit is glitchy. +    // it's not entirely clear what the motivation is to have 3 +    // different rules for enablement. At least the difference between +    // move and rotate looks like just a parens error, have updated accordingly. +	BOOL enable_move	= objectp->permMove() && !objectp->isPermanentEnforced() && +        ((root_objectp == NULL) || !root_objectp->isPermanentEnforced()) && +        ((objectp->permModify() && !objectp->isAttachment()) || !gSavedSettings.getBOOL("EditLinkedParts")); +	BOOL enable_scale	= objectp->permMove() && !objectp->isPermanentEnforced() && +        ((root_objectp == NULL) || !root_objectp->isPermanentEnforced()) && objectp->permModify(); +	BOOL enable_rotate	= objectp->permMove() && !objectp->isPermanentEnforced() && +        ((root_objectp == NULL) || !root_objectp->isPermanentEnforced()) && +        ((objectp->permModify() && !objectp->isAttachment()) || !gSavedSettings.getBOOL("EditLinkedParts")); +#else  	BOOL enable_move	= objectp->permMove() && !objectp->isPermanentEnforced() && ((root_objectp == NULL) || !root_objectp->isPermanentEnforced()) && (objectp->permModify() || !gSavedSettings.getBOOL("EditLinkedParts"));  	BOOL enable_scale	= objectp->permMove() && !objectp->isPermanentEnforced() && ((root_objectp == NULL) || !root_objectp->isPermanentEnforced()) && objectp->permModify();  	BOOL enable_rotate	= objectp->permMove() && !objectp->isPermanentEnforced() && ((root_objectp == NULL) || !root_objectp->isPermanentEnforced()) && (objectp->permModify() || !gSavedSettings.getBOOL("EditLinkedParts")); +#endif  	S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();  	BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME )) diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index b1895bfc9b..5e7aef69f1 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -78,6 +78,8 @@  #include "llviewercontrol.h"  #include "llmeshrepository.h" +#include "llvoavatarself.h" +  #include <boost/bind.hpp>  // "Features" Tab @@ -86,6 +88,7 @@ BOOL	LLPanelVolume::postBuild()  {  	// Flexible Objects Parameters  	{ +		childSetCommitCallback("Animated Mesh Checkbox Ctrl", boost::bind(&LLPanelVolume::onCommitAnimatedMeshCheckbox, this, _1, _2), NULL);  		childSetCommitCallback("Flexible1D Checkbox Ctrl", boost::bind(&LLPanelVolume::onCommitIsFlexible, this, _1, _2), NULL);  		childSetCommitCallback("FlexNumSections",onCommitFlexible,this);  		getChild<LLUICtrl>("FlexNumSections")->setValidateBeforeCommit(precommitValidate); @@ -237,6 +240,11 @@ void LLPanelVolume::getState( )  	{  		volobjp = (LLVOVolume *)objectp;  	} +	LLVOVolume *root_volobjp = NULL; +    if (root_objectp && (root_objectp->getPCode() == LL_PCODE_VOLUME)) +    { +        root_volobjp  = (LLVOVolume *)root_objectp; +    }  	if( !objectp )  	{ @@ -260,6 +268,8 @@ void LLPanelVolume::getState( )  	BOOL editable = root_objectp->permModify() && !root_objectp->isPermanentEnforced();  	BOOL single_volume = LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME )  		&& LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1; +    BOOL single_root_volume = LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME ) &&  +        LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() == 1;  	// Select Single Message  	if (single_volume) @@ -347,7 +357,35 @@ void LLPanelVolume::getState( )  		getChildView("Light Focus")->setEnabled(false);  		getChildView("Light Ambiance")->setEnabled(false);  	} -	 + +    // Animated Mesh +	BOOL is_animated_mesh = single_root_volume && root_volobjp && root_volobjp->isAnimatedObject(); +	getChild<LLUICtrl>("Animated Mesh Checkbox Ctrl")->setValue(is_animated_mesh); +    BOOL enabled_animated_object_box = FALSE; +    if (root_volobjp && root_volobjp == volobjp) +    { +        enabled_animated_object_box = single_root_volume && root_volobjp && root_volobjp->canBeAnimatedObject() && editable;  +#if 0 +        if (!enabled_animated_object_box) +        { +            LL_INFOS() << "not enabled: srv " << single_root_volume << " root_volobjp " << (bool) root_volobjp << LL_ENDL; +            if (root_volobjp) +            { +                LL_INFOS() << " cba " << root_volobjp->canBeAnimatedObject() +                           << " editable " << editable << " permModify() " << root_volobjp->permModify() +                           << " ispermenf " << root_volobjp->isPermanentEnforced() << LL_ENDL; +            } +        } +#endif +        if (enabled_animated_object_box && !is_animated_mesh &&  +            root_volobjp->isAttachment() && !gAgentAvatarp->canAttachMoreAnimatedObjects()) +        { +            // Turning this attachment animated would cause us to exceed the limit. +            enabled_animated_object_box = false; +        } +    } +    getChildView("Animated Mesh Checkbox Ctrl")->setEnabled(enabled_animated_object_box); +  	// Flexible properties  	BOOL is_flexible = volobjp && volobjp->isFlexible();  	getChild<LLUICtrl>("Flexible1D Checkbox Ctrl")->setValue(is_flexible); @@ -587,6 +625,7 @@ void LLPanelVolume::clearCtrls()  	getChildView("Light Radius")->setEnabled(false);  	getChildView("Light Falloff")->setEnabled(false); +    getChildView("Animated Mesh Checkbox Ctrl")->setEnabled(false);  	getChildView("Flexible1D Checkbox Ctrl")->setEnabled(false);  	getChildView("FlexNumSections")->setEnabled(false);  	getChildView("FlexGravity")->setEnabled(false); @@ -896,6 +935,31 @@ void LLPanelVolume::onCommitFlexible( LLUICtrl* ctrl, void* userdata )  	self->refresh();  } +void LLPanelVolume::onCommitAnimatedMeshCheckbox(LLUICtrl *, void*) +{ +	LLViewerObject* objectp = mObject; +	if (!objectp || (objectp->getPCode() != LL_PCODE_VOLUME)) +	{ +		return; +    } +	LLVOVolume *volobjp = (LLVOVolume *)objectp; +	BOOL animated_mesh = getChild<LLUICtrl>("Animated Mesh Checkbox Ctrl")->getValue(); +    U32 flags = volobjp->getExtendedMeshFlags(); +    U32 new_flags = flags; +    if (animated_mesh) +    { +        new_flags |= LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; +    } +    else +    { +        new_flags &= ~LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; +    } +    if (new_flags != flags) +    { +        volobjp->setExtendedMeshFlags(new_flags); +    } +} +  void LLPanelVolume::onCommitIsFlexible(LLUICtrl *, void*)  {  	if (mObject->flagObjectPermanent()) diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h index e3453ae99c..66117316cf 100644 --- a/indra/newview/llpanelvolume.h +++ b/indra/newview/llpanelvolume.h @@ -63,6 +63,7 @@ public:  	static void 	onCommitLight(			LLUICtrl* ctrl, void* userdata);  	void 			onCommitIsFlexible(		LLUICtrl* ctrl, void* userdata);  	static void 	onCommitFlexible(		LLUICtrl* ctrl, void* userdata); +    void            onCommitAnimatedMeshCheckbox(LLUICtrl* ctrl, void* userdata);  	static void     onCommitPhysicsParam(       LLUICtrl* ctrl, void* userdata);  	static void 	onCommitMaterial(		LLUICtrl* ctrl, void* userdata); diff --git a/indra/newview/llsceneview.cpp b/indra/newview/llsceneview.cpp index 112fa5b4e1..f7aa63e34d 100644 --- a/indra/newview/llsceneview.cpp +++ b/indra/newview/llsceneview.cpp @@ -33,6 +33,7 @@  #include "llviewerregion.h"  #include "llagent.h"  #include "llvolumemgr.h" +#include "llmeshrepository.h"  LLSceneView* gSceneView = NULL; @@ -129,17 +130,23 @@ void LLSceneView::draw()  				visible_triangles[idx].push_back(visible);  				triangles[idx].push_back(high_triangles); -				S32 bytes = 0; -				S32 visible_bytes = 0; - -				F32 streaming = object->getStreamingCost(&bytes, &visible_bytes); -				total_streaming[idx] += streaming; -				streaming_cost[idx].push_back(streaming); +                F32 streaming = object->getStreamingCost(); +                total_streaming[idx] += streaming; +                streaming_cost[idx].push_back(streaming);  				F32 physics = object->getPhysicsCost();  				total_physics[idx] += physics;  				physics_cost[idx].push_back(physics); +				S32 bytes = 0; +				S32 visible_bytes = 0; +                LLMeshCostData costs; +                if (object->getCostData(costs)) +                { +                    bytes = costs.getSizeTotal(); +                    visible_bytes = costs.getSizeByLOD(object->getLOD()); +                } +  				total_bytes[idx] += bytes;  				total_visible_bytes[idx] += visible_bytes;  			} diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index c44aca6fa5..ce5fc7a71e 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -46,6 +46,7 @@  #include "llundo.h"  #include "lluuid.h"  #include "llvolume.h" +#include "llcontrolavatar.h"  #include "message.h"  #include "object_flags.h"  #include "llquaternion.h" @@ -645,6 +646,10 @@ void LLSelectMgr::confirmUnlinkObjects(const LLSD& notification, const LLSD& res  // otherwise. this allows the handle_link method to more finely check  // the selection and give an error message when the uer has a  // reasonable expectation for the link to work, but it will fail. +// +// For animated objects, there's additional check that if the +// selection includes at least one animated object, the total mesh +// triangle count cannot exceed the designated limit.  bool LLSelectMgr::enableLinkObjects()  {  	bool new_value = false; @@ -669,6 +674,10 @@ bool LLSelectMgr::enableLinkObjects()  			new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly);  		}  	} +    if (!LLSelectMgr::getInstance()->getSelection()->checkAnimatedObjectLinkable()) +    { +        new_value = false; +    }  	return new_value;  } @@ -6611,7 +6620,10 @@ S32 get_family_count(LLViewerObject *parent)  //-----------------------------------------------------------------------------  // updateSelectionCenter -//----------------------------------------------------------------------------- +// +// FIXME this is a grab bag of functionality only some of which has to do +// with the selection center +// -----------------------------------------------------------------------------  void LLSelectMgr::updateSelectionCenter()  {  	const F32 MOVE_SELECTION_THRESHOLD = 1.f;		//  Movement threshold in meters for updating selection @@ -6629,23 +6641,12 @@ void LLSelectMgr::updateSelectionCenter()  		mSelectionCenterGlobal.clearVec();  		mShowSelection = FALSE;  		mSelectionBBox = LLBBox();  -		mPauseRequest = NULL;  		resetAgentHUDZoom(); -  	}  	else  	{  		mSelectedObjects->mSelectType = getSelectTypeForObject(object); -		if (mSelectedObjects->mSelectType == SELECT_TYPE_ATTACHMENT && isAgentAvatarValid() && object->getParent() != NULL) -		{ -			mPauseRequest = gAgentAvatarp->requestPause(); -		} -		else -		{ -			mPauseRequest = NULL; -		} -  		if (mSelectedObjects->mSelectType != SELECT_TYPE_HUD && isAgentAvatarValid())  		{  			// reset hud ZOOM @@ -6722,6 +6723,59 @@ void LLSelectMgr::updateSelectionCenter()  	{  		gEditMenuHandler = NULL;  	} + +    pauseAssociatedAvatars(); +} + +//----------------------------------------------------------------------------- +// pauseAssociatedAvatars +// +// If the selection includes an attachment or an animated object, the +// associated avatars should pause their animations until they are no +// longer selected. +//----------------------------------------------------------------------------- +void LLSelectMgr::pauseAssociatedAvatars() +{ +    mPauseRequests.clear(); + +    for (LLObjectSelection::iterator iter = mSelectedObjects->begin(); +         iter != mSelectedObjects->end(); iter++) +    { +        LLSelectNode* node = *iter; +        LLViewerObject* object = node->getObject(); +        if (!object) +            continue; +			 +        mSelectedObjects->mSelectType = getSelectTypeForObject(object); + +        if (mSelectedObjects->mSelectType == SELECT_TYPE_ATTACHMENT &&  +            isAgentAvatarValid() && object->getParent() != NULL) +        { +            if (object->isAnimatedObject()) +            { +                // Is an animated object attachment. +                // Pause both the control avatar and the avatar it's attached to. +                if (object->getControlAvatar()) +                { +                    mPauseRequests.push_back(object->getControlAvatar()->requestPause()); +                } +                mPauseRequests.push_back(gAgentAvatarp->requestPause()); +            } +            else +            { +                // Is a regular attachment. Pause the avatar it's attached to. +                mPauseRequests.push_back(gAgentAvatarp->requestPause()); +            } +        } +        else +        { +            if (object && object->isAnimatedObject() && object->getControlAvatar()) +            { +                // Is a non-attached animated object. Pause the control avatar. +                mPauseRequests.push_back(object->getControlAvatar()->requestPause()); +            } +        } +    }  }  void LLSelectMgr::updatePointAt() @@ -7198,10 +7252,16 @@ F32 LLObjectSelection::getSelectedObjectStreamingCost(S32* total_bytes, S32* vis  		if (object)  		{ -			S32 bytes = 0; -			S32 visible = 0; -			cost += object->getStreamingCost(&bytes, &visible); +			cost += object->getStreamingCost(); +            S32 bytes = 0; +            S32 visible = 0; +            LLMeshCostData costs; +            if (object->getCostData(costs)) +            { +                bytes = costs.getSizeTotal(); +                visible = costs.getSizeByLOD(object->getLOD()); +            }  			if (total_bytes)  			{  				*total_bytes += bytes; @@ -7358,6 +7418,31 @@ bool LLObjectSelection::applyToObjects(LLSelectedObjectFunctor* func)  	return result;  } +bool LLObjectSelection::checkAnimatedObjectEstTris() +{ +    F32 est_tris = 0; +    F32 max_tris = 0; +    S32 anim_count = 0; +	for (root_iterator iter = root_begin(); iter != root_end(); ++iter) +	{ +		LLViewerObject* object = (*iter)->getObject(); +		if (!object) +			continue; +        if (object->isAnimatedObject()) +        { +            anim_count++; +        } +        est_tris += object->recursiveGetEstTrianglesMax(); +        max_tris = llmax((F32)max_tris,(F32)object->getAnimatedObjectMaxTris()); +	} +	return anim_count==0 || est_tris <= max_tris; +} + +bool LLObjectSelection::checkAnimatedObjectLinkable() +{ +    return checkAnimatedObjectEstTris(); +} +  bool LLObjectSelection::applyToRootObjects(LLSelectedObjectFunctor* func, bool firstonly)  {  	bool result = firstonly ? false : true; diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index e965dd80d5..a7c86e3ad3 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -340,6 +340,9 @@ public:  	// returns TRUE is any node is currenly worn as an attachment  	BOOL isAttachment(); +    bool checkAnimatedObjectEstTris(); +    bool checkAnimatedObjectLinkable(); +      	// Apply functors to various subsets of the selected objects  	// If firstonly is FALSE, returns the AND of all apply() calls.  	// Else returns TRUE immediately if any apply() call succeeds (i.e. OR with early exit) @@ -743,6 +746,8 @@ public:  	LLVector3d		getSelectionCenterGlobal() const	{ return mSelectionCenterGlobal; }  	void			updateSelectionCenter(); +    void pauseAssociatedAvatars(); +  	void resetAgentHUDZoom();  	void setAgentHUDZoom(F32 target_zoom, F32 current_zoom);  	void getAgentHUDZoom(F32 &target_zoom, F32 ¤t_zoom) const; @@ -844,7 +849,7 @@ private:  	LLFrameTimer			mEffectsTimer;  	BOOL					mForceSelection; -	LLAnimPauseRequest		mPauseRequest; +    std::vector<LLAnimPauseRequest>	mPauseRequests;  };  // *DEPRECATED: For callbacks or observers, use diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index d2a87ee2af..8b1a23fe89 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -29,6 +29,7 @@  #include "llspatialpartition.h"  #include "llappviewer.h" +#include "llcallstack.h"  #include "lltexturecache.h"  #include "lltexturefetch.h"  #include "llimageworker.h" @@ -777,6 +778,10 @@ F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)  		dist = eye.getLength3().getF32();  	} +    LL_DEBUGS("RiggedBox") << "calcDistance, group " << group << " camera " << origin << " obj bounds "  +                           << group->mObjectBounds[0] << ", " << group->mObjectBounds[1]  +                           << " dist " << dist << " radius " << group->mRadius << LL_ENDL; +  	if (dist < 16.f)  	{  		dist /= 16.f; @@ -808,7 +813,8 @@ F32 LLSpatialGroup::getUpdateUrgency() const  BOOL LLSpatialGroup::changeLOD()  {  	if (hasState(ALPHA_DIRTY | OBJECT_DIRTY)) -	{ ///a rebuild is going to happen, update distance and LoD +	{ +		//a rebuild is going to happen, update distance and LoD  		return TRUE;  	} @@ -816,8 +822,28 @@ BOOL LLSpatialGroup::changeLOD()  	{  		F32 ratio = (mDistance - mLastUpdateDistance)/(llmax(mLastUpdateDistance, mRadius)); +        // MAINT-8264 - this check is not robust if it needs to work +        // for bounding boxes much larger than the actual enclosed +        // objects, and using distance to box center is also +        // problematic. Consider the case that you have a large box +        // where the enclosed object is in one corner. As you zoom in +        // on the corner, the object gets much closer to the camera, +        // but the distance to the box center changes very little, and +        // an LOD change will not trigger, so object LOD gets "stuck" +        // at a too-low value. In the case of the above JIRA, the box +        // was large only due to another error, so this logic did not +        // need to be changed. +  		if (fabsf(ratio) >= getSpatialPartition()->mSlopRatio)  		{ +            LL_DEBUGS("RiggedBox") << "changeLOD true because of ratio compare " +                                   << fabsf(ratio) << " " << getSpatialPartition()->mSlopRatio << LL_ENDL; +            LL_DEBUGS("RiggedBox") << "sg " << this << "\nmDistance " << mDistance +                                   << " mLastUpdateDistance " << mLastUpdateDistance +                                   << " mRadius " << mRadius +                                   << " fab ratio " << fabsf(ratio)  +                                   << " slop " << getSpatialPartition()->mSlopRatio << LL_ENDL; +         			return TRUE;  		} @@ -869,16 +895,6 @@ void LLSpatialGroup::handleDestruction(const TreeNode* node)  		}  	} -	//clean up avatar attachment stats -	LLSpatialBridge* bridge = getSpatialPartition()->asBridge(); -	if (bridge) -	{ -		if (bridge->mAvatar.notNull()) -		{ -			bridge->mAvatar->subtractAttachmentArea(mSurfaceArea ); -		} -	} -  	clearDrawMap();  	mVertexBuffer = NULL;  	mBufferMap.clear(); @@ -2119,17 +2135,17 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)  	{  		if (drawable->isSpatialBridge())  		{ -			gGL.diffuseColor4f(1,0.5f,0,1); +			gGL.diffuseColor4f(1,0.5f,0,1); // orange  		}  		else if (drawable->getVOVolume()) -		{ -			if (drawable->isRoot()) +		{  +            if (drawable->isRoot())  			{ -				gGL.diffuseColor4f(1,1,0,1); +				gGL.diffuseColor4f(1,1,0,1); // yellow  			}  			else  			{ -				gGL.diffuseColor4f(0,1,0,1); +				gGL.diffuseColor4f(0,1,0,1); // green  			}  		}  		else if (drawable->getVObj()) @@ -2137,24 +2153,24 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)  			switch (drawable->getVObj()->getPCode())  			{  				case LLViewerObject::LL_VO_SURFACE_PATCH: -						gGL.diffuseColor4f(0,1,1,1); +                    	gGL.diffuseColor4f(0,1,1,1); // cyan  						break;  				case LLViewerObject::LL_VO_CLOUDS:  						// no longer used  						break;  				case LLViewerObject::LL_VO_PART_GROUP:  				case LLViewerObject::LL_VO_HUD_PART_GROUP: -						gGL.diffuseColor4f(0,0,1,1); +                    	gGL.diffuseColor4f(0,0,1,1); // blue  						break;  				case LLViewerObject::LL_VO_VOID_WATER:  				case LLViewerObject::LL_VO_WATER: -						gGL.diffuseColor4f(0,0.5f,1,1); +                    	gGL.diffuseColor4f(0,0.5f,1,1); // medium blue  						break;  				case LL_PCODE_LEGACY_TREE: -						gGL.diffuseColor4f(0,0.5f,0,1); +                    	gGL.diffuseColor4f(0,0.5f,0,1); // dark green  						break;  				default: -						gGL.diffuseColor4f(1,0,1,1); +                    	gGL.diffuseColor4f(1,0,1,1); // magenta  						break;  			}  		} diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 7633e46200..2594e3397c 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -466,8 +466,6 @@ public:  	virtual LLCamera transformCamera(LLCamera& camera);  	LLDrawable* mDrawable; -	LLPointer<LLVOAvatar> mAvatar; -  };  class LLCullResult  diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 62560a2fc8..b3162a7adf 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2390,6 +2390,7 @@ void register_viewer_callbacks(LLMessageSystem* msg)  	msg->setHandlerFuncFast(_PREHASH_NameValuePair,			process_name_value);  	msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair,	process_remove_name_value);  	msg->setHandlerFuncFast(_PREHASH_AvatarAnimation,		process_avatar_animation); +	msg->setHandlerFuncFast(_PREHASH_ObjectAnimation,		process_object_animation);  	msg->setHandlerFuncFast(_PREHASH_AvatarAppearance,		process_avatar_appearance);  	msg->setHandlerFuncFast(_PREHASH_CameraConstraint,		process_camera_constraint);  	msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse,		process_avatar_sit_response); diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 9fb53dc9ab..a5862d4d05 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -785,7 +785,7 @@ void LLToolDragAndDrop::dragOrDrop3D( S32 x, S32 y, MASK mask, BOOL drop, EAccep  	mDrop = drop;  	if (mDrop)  	{ -		// don't allow drag and drop onto transparent objects +		// don't allow drag and drop onto rigged or transparent objects  		pick(gViewerWindow->pickImmediate(x, y, FALSE, FALSE));  	}  	else diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index f473000657..c5ef2a791b 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -111,9 +111,11 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)      mMouseOutsideSlop = FALSE;  	mMouseDownX = x;  	mMouseDownY = y; - +    LLTimer pick_timer; +    BOOL pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick");  	//left mouse down always picks transparent (but see handleMouseUp) -	mPick = gViewerWindow->pickImmediate(x, y, TRUE, FALSE); +	mPick = gViewerWindow->pickImmediate(x, y, TRUE, pick_rigged); +    LL_INFOS() << "pick_rigged is " << (S32) pick_rigged << " pick time elapsed " << pick_timer.getElapsedTimeF32() << LL_ENDL;  	mPick.mKeyMask = mask;  	mMouseButtonDown = true; @@ -128,7 +130,10 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)  BOOL LLToolPie::handleRightMouseDown(S32 x, S32 y, MASK mask)  {  	// don't pick transparent so users can't "pay" transparent objects -	mPick = gViewerWindow->pickImmediate(x, y, /*BOOL pick_transparent*/ FALSE, /*BOOL pick_rigged*/ TRUE, /*BOOL pick_particle*/ TRUE); +	mPick = gViewerWindow->pickImmediate(x, y, +                                         /*BOOL pick_transparent*/ FALSE, +                                         /*BOOL pick_rigged*/ TRUE, +                                         /*BOOL pick_particle*/ TRUE);  	mPick.mKeyMask = mask;  	// claim not handled so UI focus stays same @@ -538,7 +543,8 @@ void LLToolPie::selectionPropertiesReceived()  BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)  { -	mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE, FALSE); +    BOOL pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); +	mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE, pick_rigged);  	LLViewerObject *parent = NULL;  	LLViewerObject *object = mHoverPick.getObject();  	LLSelectMgr::getInstance()->setHoverObject(object, mHoverPick.mObjectFace); @@ -584,7 +590,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)  	else  	{  		// perform a separate pick that detects transparent objects since they respond to 1-click actions -		LLPickInfo click_action_pick = gViewerWindow->pickImmediate(x, y, TRUE, FALSE); +		LLPickInfo click_action_pick = gViewerWindow->pickImmediate(x, y, TRUE, pick_rigged);  		LLViewerObject* click_action_object = click_action_pick.getObject(); @@ -670,6 +676,7 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)          LLPickInfo savedPick = mPick;          mPick = gViewerWindow->pickImmediate(savedPick.mMousePt.mX, savedPick.mMousePt.mY,                                               FALSE /* ignore transparent */, +                                             FALSE /* ignore rigged */,                                               FALSE /* ignore particles */);          if (!mPick.mPosGlobal.isExactlyZero()			// valid coordinates for pick @@ -759,6 +766,7 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask)          LLPickInfo savedPick = mPick;          mPick = gViewerWindow->pickImmediate(savedPick.mMousePt.mX, savedPick.mMousePt.mY,                                               FALSE /* ignore transparent */, +                                             FALSE /* ignore rigged */,                                               FALSE /* ignore particles */);          if(mPick.mPickType == LLPickInfo::PICK_OBJECT) @@ -1751,8 +1759,7 @@ BOOL LLToolPie::handleRightClickPick()  		gMenuHolder->setObjectSelection(LLSelectMgr::getInstance()->getSelection());  		bool is_other_attachment = (object->isAttachment() && !object->isHUDAttachment() && !object->permYouOwner()); -		if (object->isAvatar()  -			|| is_other_attachment) +		if (object->isAvatar() || is_other_attachment)  		{  			// Find the attachment's avatar  			while( object && object->isAttachment()) diff --git a/indra/newview/lltoolselect.cpp b/indra/newview/lltoolselect.cpp index 1fcc9a0711..550e527ba8 100644 --- a/indra/newview/lltoolselect.cpp +++ b/indra/newview/lltoolselect.cpp @@ -63,7 +63,8 @@ LLToolSelect::LLToolSelect( LLToolComposite* composite )  BOOL LLToolSelect::handleMouseDown(S32 x, S32 y, MASK mask)  {  	// do immediate pick query -	mPick = gViewerWindow->pickImmediate(x, y, TRUE, FALSE); +    BOOL pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); +	mPick = gViewerWindow->pickImmediate(x, y, TRUE, pick_rigged);  	// Pass mousedown to agent  	LLTool::handleMouseDown(x, y, mask); diff --git a/indra/newview/lltoolselectrect.cpp b/indra/newview/lltoolselectrect.cpp index 71dc8001d4..bae32f7bc0 100644 --- a/indra/newview/lltoolselectrect.cpp +++ b/indra/newview/lltoolselectrect.cpp @@ -71,7 +71,8 @@ void dialog_refresh_all(void);  BOOL LLToolSelectRect::handleMouseDown(S32 x, S32 y, MASK mask)  { -	handlePick(gViewerWindow->pickImmediate(x, y, TRUE, FALSE)); +    BOOL pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); +	handlePick(gViewerWindow->pickImmediate(x, y, TRUE /* pick_transparent */, pick_rigged));  	LLTool::handleMouseDown(x, y, mask); diff --git a/indra/newview/lluiavatar.cpp b/indra/newview/lluiavatar.cpp new file mode 100644 index 0000000000..6cc14fc49b --- /dev/null +++ b/indra/newview/lluiavatar.cpp @@ -0,0 +1,59 @@ +/** + * @file lluiavatar.cpp + * @brief Implementation for special dummy avatar used in some UI views + * + * $LicenseInfo:firstyear=2017&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2017, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "lluiavatar.h" +#include "llagent.h" //  Get state values from here +#include "llviewerobjectlist.h" +#include "pipeline.h" +#include "llanimationstates.h" +#include "llviewercontrol.h" +#include "llmeshrepository.h" +#include "llviewerregion.h" + +LLUIAvatar::LLUIAvatar(const LLUUID& id, const LLPCode pcode, LLViewerRegion* regionp) : +    LLVOAvatar(id, pcode, regionp) +{ +    mIsDummy = TRUE; +    mIsUIAvatar = true; +} + +// virtual +LLUIAvatar::~LLUIAvatar() +{ +} + +// virtual +void LLUIAvatar::initInstance() +{ +    LLVOAvatar::initInstance(); + +    createDrawable( &gPipeline ); +	setPositionAgent(LLVector3::zero); +	slamPosition(); +	updateJointLODs(); +	updateGeometry(mDrawable); +} diff --git a/indra/newview/lluiavatar.h b/indra/newview/lluiavatar.h new file mode 100644 index 0000000000..bcdffedef2 --- /dev/null +++ b/indra/newview/lluiavatar.h @@ -0,0 +1,44 @@ +/** + * @file lluiavatar.h + * @brief Special dummy avatar used in some UI views + * + * $LicenseInfo:firstyear=2017&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2017, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#ifndef LL_UIAVATAR_H +#define LL_UIAVATAR_H + +#include "llvoavatar.h" +#include "llvovolume.h" + +class LLUIAvatar: +    public LLVOAvatar +{ +    LOG_CLASS(LLUIAvatar); + +public: +    LLUIAvatar(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); +	virtual void 			initInstance(); // Called after construction to initialize the class. +	virtual	~LLUIAvatar(); +}; + +#endif //LL_CONTROLAVATAR_H diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp index 66e392ac42..cf9243a871 100644 --- a/indra/newview/llviewerjointattachment.cpp +++ b/indra/newview/llviewerjointattachment.cpp @@ -357,6 +357,25 @@ void LLViewerJointAttachment::setOriginalPosition(LLVector3& position)  }  //----------------------------------------------------------------------------- +// getNumAnimatedObjects() +//----------------------------------------------------------------------------- +S32 LLViewerJointAttachment::getNumAnimatedObjects() const +{ +    S32 count = 0; +	for (attachedobjs_vec_t::const_iterator iter = mAttachedObjects.begin(); +		 iter != mAttachedObjects.end(); +		 ++iter) +	{ +        const LLViewerObject *attached_object = *iter; +        if (attached_object->isAnimatedObject()) +        { +            count++; +        } +    } +    return count; +} + +//-----------------------------------------------------------------------------  // clampObjectPosition()  //-----------------------------------------------------------------------------  void LLViewerJointAttachment::clampObjectPosition() diff --git a/indra/newview/llviewerjointattachment.h b/indra/newview/llviewerjointattachment.h index 9addafaee1..9641ab4208 100644 --- a/indra/newview/llviewerjointattachment.h +++ b/indra/newview/llviewerjointattachment.h @@ -77,6 +77,7 @@ public:  	S32 getGroup() const { return mGroup; }  	S32 getPieSlice() const { return mPieSlice; }  	S32	getNumObjects() const { return mAttachedObjects.size(); } +	S32	getNumAnimatedObjects() const;  	void clampObjectPosition(); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index e973363e0f..6f6bf8678b 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -1077,6 +1077,10 @@ U32 info_display_from_string(std::string info_display)  	{  		return LLPipeline::RENDER_DEBUG_TEXEL_DENSITY;  	} +	else if ("triangle count" == info_display) +	{ +		return LLPipeline::RENDER_DEBUG_TRIANGLE_COUNT; +	}  	else  	{  		LL_WARNS() << "unrecognized feature name '" << info_display << "'" << LL_ENDL; @@ -1616,7 +1620,19 @@ class LLAdvancedEnableAppearanceToXML : public view_listener_t  {  	bool handleEvent(const LLSD& userdata)  	{ -		return gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"); +        LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); +        if (obj && obj->isAnimatedObject() && obj->getControlAvatar()) +        { +            return gSavedSettings.getBOOL("DebugAnimatedObjects"); +        } +        else if (obj && obj->isAttachment() && obj->getAvatar()) +        { +            return gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"); +        } +		else +		{ +			return false; +		}  	}  }; @@ -1625,8 +1641,8 @@ class LLAdvancedAppearanceToXML : public view_listener_t  	bool handleEvent(const LLSD& userdata)  	{  		std::string emptyname; -		LLVOAvatar* avatar = -			find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); +        LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); +        LLVOAvatar* avatar = obj->getAvatar();  		if (!avatar)  		{  			avatar = gAgentAvatarp; @@ -6050,7 +6066,12 @@ class LLAvatarResetSkeleton: public view_listener_t  {      bool handleEvent(const LLSD& userdata)      { -		LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); +		LLVOAvatar* avatar = NULL; +        LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); +        if (obj) +        { +            avatar = obj->getAvatar(); +        }  		if(avatar)          {              avatar->resetSkeleton(false); @@ -6059,6 +6080,20 @@ class LLAvatarResetSkeleton: public view_listener_t      }  }; +class LLAvatarEnableResetSkeleton: public view_listener_t +{ +    bool handleEvent(const LLSD& userdata) +    { +        LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); +        if (obj && obj->getAvatar()) +        { +            return true; +        } +        return false; +    } +}; + +  class LLAvatarResetSkeletonAndAnimations : public view_listener_t  {  	bool handleEvent(const LLSD& userdata) @@ -6892,7 +6927,7 @@ class LLAttachmentEnableDrop : public view_listener_t  		// Do not enable drop if all faces of object are not enabled  		if (object && LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES ))  		{ -    		S32 attachmentID  = ATTACHMENT_ID_FROM_STATE(object->getState()); +    		S32 attachmentID  = ATTACHMENT_ID_FROM_STATE(object->getAttachmentState());  			attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL);  			if (attachment) @@ -9076,6 +9111,7 @@ void initialize_menus()  	view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse");  	view_listener_t::addMenu(new LLAvatarToggleMyProfile(), "Avatar.ToggleMyProfile");  	view_listener_t::addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton"); +	view_listener_t::addMenu(new LLAvatarEnableResetSkeleton(), "Avatar.EnableResetSkeleton");  	view_listener_t::addMenu(new LLAvatarResetSkeletonAndAnimations(), "Avatar.ResetSkeletonAndAnimations");  	enable.add("Avatar.IsMyProfileOpen", boost::bind(&my_profile_visible)); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 0f326efe09..892a6e3b33 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -54,6 +54,7 @@  #include "llagentcamera.h"  #include "llcallingcard.h"  #include "llbuycurrencyhtml.h" +#include "llcontrolavatar.h"  #include "llfirstuse.h"  #include "llfloaterbump.h"  #include "llfloaterbuyland.h" @@ -102,6 +103,7 @@  #include "llviewerwindow.h"  #include "llvlmanager.h"  #include "llvoavatarself.h" +#include "llvovolume.h"  #include "llworld.h"  #include "pipeline.h"  #include "llfloaterworldmap.h" @@ -3661,23 +3663,27 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)  	LLUUID	animation_id;  	LLUUID	uuid;  	S32		anim_sequence_id; -	LLVOAvatar *avatarp; +	LLVOAvatar *avatarp = NULL;  	mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); -	//clear animation flags -	avatarp = (LLVOAvatar *)gObjectList.findObject(uuid); +	LLViewerObject *objp = gObjectList.findObject(uuid); +    if (objp) +    { +        avatarp =  objp->asAvatar(); +    }  	if (!avatarp)  	{  		// no agent by this ID...error? -		LL_WARNS("Messaging") << "Received animation state for unknown avatar" << uuid << LL_ENDL; +		LL_WARNS("Messaging") << "Received animation state for unknown avatar " << uuid << LL_ENDL;  		return;  	}  	S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList);  	S32 num_source_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationSourceList); +	//clear animation flags  	avatarp->mSignaledAnimations.clear();  	if (avatarp->isSelf()) @@ -3748,6 +3754,73 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)  	}  } + +// AXON make logging less spammy after issues resolved, before release. +void process_object_animation(LLMessageSystem *mesgsys, void **user_data) +{ +	LLUUID	animation_id; +	LLUUID	uuid; +	S32		anim_sequence_id; +	 +	mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); + +    LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for object " << uuid << LL_ENDL; + +    signaled_animation_map_t signaled_anims; +	S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList); +	LL_DEBUGS("AnimatedObjectsNotify") << "processing object animation requests, num_blocks " << num_blocks << " uuid " << uuid << LL_ENDL; +    for( S32 i = 0; i < num_blocks; i++ ) +    { +        mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); +        mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); +        signaled_anims[animation_id] = anim_sequence_id; +        LL_DEBUGS("AnimatedObjectsNotify") << "added signaled_anims animation request for object "  +                                    << uuid << " animation id " << animation_id << LL_ENDL; +    } +    LLObjectSignaledAnimationMap::instance().getMap()[uuid] = signaled_anims; +     +    LLViewerObject *objp = gObjectList.findObject(uuid); +    if (!objp) +    { +		LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for unknown object " << uuid << LL_ENDL; +        return; +    } +     +	LLVOVolume *volp = dynamic_cast<LLVOVolume*>(objp); +    if (!volp) +    { +		LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for non-volume object " << uuid << LL_ENDL; +        return; +    } + +    if (!volp->isAnimatedObject()) +    { +		LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for non-animated object " << uuid << LL_ENDL; +        return; +    } + +    volp->updateControlAvatar(); +    LLControlAvatar *avatarp = volp->getControlAvatar(); +    if (!avatarp) +    { +        LL_DEBUGS("AnimatedObjectsNotify") << "Received animation request for object with no control avatar, ignoring " << uuid << LL_ENDL; +        return; +    } +     +    if (!avatarp->mPlaying) +    { +        avatarp->mPlaying = true; +        if (!avatarp->mRootVolp->isAnySelected()) +        { +            avatarp->updateVolumeGeom(); +            avatarp->mRootVolp->recursiveMarkForUpdate(TRUE); +        } +    } +         +    avatarp->updateAnimations(); +} + +  void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data)  {  	LLUUID uuid; diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h index b0eaa37541..cef6f79812 100644 --- a/indra/newview/llviewermessage.h +++ b/indra/newview/llviewermessage.h @@ -95,6 +95,7 @@ void process_health_message(LLMessageSystem *mesgsys, void **user_data);  void process_sim_stats(LLMessageSystem *mesgsys, void **user_data);  void process_shooter_agent_hit(LLMessageSystem* msg, void** user_data);  void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data); +void process_object_animation(LLMessageSystem *mesgsys, void **user_data);  void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data);  void process_camera_constraint(LLMessageSystem *mesgsys, void **user_data);  void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 624c48e945..f33bafa03c 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -60,6 +60,7 @@  #include "llbbox.h"  #include "llbox.h"  #include "llcylinder.h" +#include "llcontrolavatar.h"  #include "lldrawable.h"  #include "llface.h"  #include "llfloaterproperties.h" @@ -69,6 +70,7 @@  #include "llselectmgr.h"  #include "llrendersphere.h"  #include "lltooldraganddrop.h" +#include "lluiavatar.h"  #include "llviewercamera.h"  #include "llviewertexturelist.h"  #include "llviewerinventory.h" @@ -103,6 +105,8 @@  #include "llfloaterperms.h"  #include "llvocache.h"  #include "llcleanup.h" +#include "llcallstack.h" +#include "llmeshrepository.h"  //#define DEBUG_UPDATE_TYPE @@ -138,8 +142,11 @@ const F32 PHYSICS_TIMESTEP = 1.f / 45.f;  static LLTrace::BlockTimerStatHandle FTM_CREATE_OBJECT("Create Object");  // static -LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) +LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, S32 flags)  { +    LL_DEBUGS("ObjectUpdate") << "creating " << id << LL_ENDL; +    dumpStack("ObjectUpdateStack"); +      	LLViewerObject *res = NULL;  	LL_RECORD_BLOCK_TIME(FTM_CREATE_OBJECT); @@ -166,6 +173,18 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco  			}  			res = gAgentAvatarp;  		} +		else if (flags & CO_FLAG_CONTROL_AVATAR) +		{ +            LLControlAvatar *control_avatar = new LLControlAvatar(id, pcode, regionp); +			control_avatar->initInstance(); +			res = control_avatar; +		} +        else if (flags & CO_FLAG_UI_AVATAR) +        { +            LLUIAvatar *ui_avatar = new LLUIAvatar(id, pcode, regionp); +            ui_avatar->initInstance(); +            res = ui_avatar; +        }  		else  		{  			LLVOAvatar *avatar = new LLVOAvatar(id, pcode, regionp);  @@ -235,6 +254,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe  	mText(),  	mHudText(""),  	mHudTextColor(LLColor4::white), +    mControlAvatar(NULL),  	mLastInterpUpdateSecs(0.f),  	mLastMessageUpdateSecs(0.f),  	mLatestRecvPacketID(0), @@ -259,7 +279,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe  	mRotTime(0.f),  	mAngularVelocityRot(),  	mPreviousRotation(), -	mState(0), +	mAttachmentState(0),  	mMedia(NULL),  	mClickAction(0),  	mObjectCost(0), @@ -365,17 +385,23 @@ void LLViewerObject::markDead()  		//LL_INFOS() << "Marking self " << mLocalID << " as dead." << LL_ENDL;  		// Root object of this hierarchy unlinks itself. -		LLVOAvatar *av = getAvatarAncestor();  		if (getParent())  		{  			((LLViewerObject *)getParent())->removeChild(this);  		}  		LLUUID mesh_id; -		if (av && LLVOAvatar::getRiggedMeshID(this,mesh_id)) -		{ -			// This case is needed for indirectly attached mesh objects. -			av->resetJointsOnDetach(mesh_id); -		} +        { +            LLVOAvatar *av = getAvatar(); +            if (av && LLVOAvatar::getRiggedMeshID(this,mesh_id)) +            { +                // This case is needed for indirectly attached mesh objects. +                av->updateAttachmentOverrides(); +            } +        } +        if (getControlAvatar()) +        { +            unlinkControlAvatar(); +        }  		// Mark itself as dead  		mDead = TRUE; @@ -676,6 +702,18 @@ void LLViewerObject::setNameValueList(const std::string& name_value_list)  	}  } +BOOL LLViewerObject::isAnySelected() const +{ +    bool any_selected = isSelected(); +    for (child_list_t::const_iterator iter = mChildList.begin(); +         iter != mChildList.end(); iter++) +    { +        const LLViewerObject* child = *iter; +        any_selected = any_selected || child->isSelected(); +    } +    return any_selected; +} +  void LLViewerObject::setSelected(BOOL sel)  {  	mUserSelected = sel; @@ -848,9 +886,18 @@ void LLViewerObject::addChild(LLViewerObject *childp)  	if(childp->setParent(this))  	{  		mChildList.push_back(childp); +        childp->afterReparent();  	}  } +void LLViewerObject::onReparent(LLViewerObject *old_parent, LLViewerObject *new_parent) +{ +} + +void LLViewerObject::afterReparent() +{ +} +  void LLViewerObject::removeChild(LLViewerObject *childp)  {  	for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i) @@ -1067,6 +1114,9 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,  {  	LL_DEBUGS_ONCE("SceneLoadTiming") << "Received viewer object data" << LL_ENDL; +    LL_DEBUGS("ObjectUpdate") << " mesgsys " << mesgsys << " dp " << dp << " id " << getID() << " update_type " << (S32) update_type << LL_ENDL; +    dumpStack("ObjectUpdateStack"); +  	U32 retval = 0x0;  	// If region is removed from the list it is also deleted. @@ -1121,10 +1171,10 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,  	F32 time_dilation = 1.f;  	if(mesgsys != NULL)  	{ -	U16 time_dilation16; -	mesgsys->getU16Fast(_PREHASH_RegionData, _PREHASH_TimeDilation, time_dilation16); -	time_dilation = ((F32) time_dilation16) / 65535.f; -	mRegionp->setTimeDilation(time_dilation); +        U16 time_dilation16; +        mesgsys->getU16Fast(_PREHASH_RegionData, _PREHASH_TimeDilation, time_dilation16); +        time_dilation = ((F32) time_dilation16) / 65535.f; +        mRegionp->setTimeDilation(time_dilation);  	}  	// this will be used to determine if we've really changed position @@ -1380,7 +1430,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,  				U8 state;  				mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num ); -				mState = state; +				mAttachmentState = state;  				// ...new objects that should come in selected need to be added to the selected list  				mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0); @@ -1650,7 +1700,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,  				U8 state;  				mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num ); -				mState = state; +				mAttachmentState = state;  				break;  			} @@ -1673,7 +1723,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,  		U8		state;  		dp->unpackU8(state, "State"); -		mState = state; +		mAttachmentState = state;  		switch(update_type)  		{ @@ -2906,6 +2956,127 @@ void LLViewerObject::fetchInventoryFromServer()  	}  } +LLControlAvatar *LLViewerObject::getControlAvatar() +{ +    return getRootEdit()->mControlAvatar.get(); +} + +LLControlAvatar *LLViewerObject::getControlAvatar() const +{ +    return getRootEdit()->mControlAvatar.get(); +} + +// Manage the control avatar state of a given object. +// Any object can be flagged as animated, but for performance reasons +// we don't want to incur the overhead of managing a control avatar +// unless this would have some user-visible consequence. That is, +// there should be at least one rigged mesh in the linkset. Operations +// that change the state of a linkset, such as linking or unlinking +// prims, can also mean that a control avatar needs to be added or +// removed. At the end, if there is a control avatar, we make sure +// that its animation state is current. +void LLViewerObject::updateControlAvatar() +{ +    LLViewerObject *root = getRootEdit(); +    bool is_animated_object = root->isAnimatedObject(); +    bool has_control_avatar = getControlAvatar(); +    if (!is_animated_object && !has_control_avatar) +    { +        return; +    } + +    bool should_have_control_avatar = false; +    if (is_animated_object) +    { +        bool any_rigged_mesh = root->isRiggedMesh(); +        LLViewerObject::const_child_list_t& child_list = root->getChildren(); +        for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin(); +             iter != child_list.end(); ++iter) +        { +            const LLViewerObject* child = *iter; +            any_rigged_mesh = any_rigged_mesh || child->isRiggedMesh(); +        } +        should_have_control_avatar = is_animated_object && any_rigged_mesh; +    } + +    if (should_have_control_avatar && !has_control_avatar) +    { +        std::string vobj_name = llformat("Vol%p", root); +        LL_DEBUGS("AnimatedObjects") << vobj_name << " calling linkControlAvatar()" << LL_ENDL; +        root->linkControlAvatar(); +    } +    if (!should_have_control_avatar && has_control_avatar) +    { +        std::string vobj_name = llformat("Vol%p", root); +        LL_DEBUGS("AnimatedObjects") << vobj_name << " calling unlinkControlAvatar()" << LL_ENDL; +        root->unlinkControlAvatar(); +    } +    if (getControlAvatar()) +    { +        getControlAvatar()->updateAnimations(); +    } +} + +void LLViewerObject::linkControlAvatar() +{ +    if (!getControlAvatar() && isRootEdit()) +    { +        LLVOVolume *volp = dynamic_cast<LLVOVolume*>(this); +        if (!volp) +        { +            LL_WARNS() << "called with null or non-volume object" << LL_ENDL; +            return; +        } +        mControlAvatar = LLControlAvatar::createControlAvatar(volp); +        LL_DEBUGS("AnimatedObjects") << volp->getID()  +                                     << " created control av for "  +                                     << (S32) (1+volp->numChildren()) << " prims" << LL_ENDL; +    } +    LLControlAvatar *cav = getControlAvatar(); +    if (cav) +    { +        cav->updateAttachmentOverrides(); +        if (!cav->mPlaying) +        { +            cav->mPlaying = true; +            if (!cav->mRootVolp->isAnySelected()) +            { +                cav->updateVolumeGeom(); +                cav->mRootVolp->recursiveMarkForUpdate(TRUE); +            } +        } +    } +    else +    { +        LL_WARNS() << "no control avatar found!" << LL_ENDL; +    } +} + +void LLViewerObject::unlinkControlAvatar() +{ +    if (getControlAvatar()) +    { +        getControlAvatar()->updateAttachmentOverrides(); +    } +    if (isRootEdit()) +    { +        // This will remove the entire linkset from the control avatar +        if (mControlAvatar) +        { +            mControlAvatar->markForDeath(); +            mControlAvatar = NULL; +        } +    } +    // For non-root prims, removing from the linkset will +    // automatically remove the control avatar connection. +} + +// virtual +bool LLViewerObject::isAnimatedObject() const +{ +    return false; +} +  struct LLFilenameAndTask  {  	LLUUID mTaskID; @@ -3515,11 +3686,66 @@ F32 LLViewerObject::getLinksetPhysicsCost()  	return mLinksetPhysicsCost;  } -F32 LLViewerObject::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const +F32 LLViewerObject::recursiveGetEstTrianglesMax() const +{ +    F32 est_tris = getEstTrianglesMax(); +    for (child_list_t::const_iterator iter = mChildList.begin(); +         iter != mChildList.end(); iter++) +    { +        const LLViewerObject* child = *iter; +        if (!child->isAvatar()) +        { +            est_tris += child->recursiveGetEstTrianglesMax(); +        } +    } +    return est_tris; +} + +S32 LLViewerObject::getAnimatedObjectMaxTris() const +{ +    S32 max_tris = 0; +    if (gSavedSettings.getBOOL("AnimatedObjectsIgnoreLimits")) // AXON REMOVE AFTER SERVER TESTING DONE +    { +        max_tris = S32_MAX; +    } +    else +    { +        if (gAgent.getRegion()) +        { +            LLSD features; +            gAgent.getRegion()->getSimulatorFeatures(features); +            if (features.has("AnimatedObjects")) +            { +                max_tris = features["AnimatedObjects"]["AnimatedObjectMaxTris"].asInteger(); +            } +        } +    } +    return max_tris; +} + +F32 LLViewerObject::getEstTrianglesMax() const +{ +    return 0.f; +} + +F32 LLViewerObject::getEstTrianglesStreamingCost() const +{ +    return 0.f; +} + +// virtual +F32 LLViewerObject::getStreamingCost() const  {  	return 0.f;  } +// virtual +bool LLViewerObject::getCostData(LLMeshCostData& costs) const +{ +    costs = LLMeshCostData(); +    return false; +} +  U32 LLViewerObject::getTriangleCount(S32* vcount) const  {  	return 0; @@ -3530,6 +3756,58 @@ U32 LLViewerObject::getHighLODTriangleCount()  	return 0;  } +U32 LLViewerObject::recursiveGetTriangleCount(S32* vcount) const +{ +    S32 total_tris = getTriangleCount(vcount); +    LLViewerObject::const_child_list_t& child_list = getChildren(); +    for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin(); +         iter != child_list.end(); ++iter) +    { +        LLViewerObject* childp = *iter; +        if (childp) +        { +            total_tris += childp->getTriangleCount(vcount); +        } +    } +    return total_tris; +} + +// This is using the stored surface area for each volume (which +// defaults to 1.0 for the case of everything except a sculpt) and +// then scaling it linearly based on the largest dimension in the +// prim's scale. Should revisit at some point. +F32 LLViewerObject::recursiveGetScaledSurfaceArea() const +{ +    F32 area = 0.f; +    const LLDrawable* drawable = mDrawable; +    if (drawable) +    { +        const LLVOVolume* volume = drawable->getVOVolume(); +        if (volume) +        { +            if (volume->getVolume()) +            { +				const LLVector3& scale = volume->getScale(); +                area += volume->getVolume()->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]); +            } +            LLViewerObject::const_child_list_t children = volume->getChildren(); +            for (LLViewerObject::const_child_list_t::const_iterator child_iter = children.begin(); +                 child_iter != children.end(); +                 ++child_iter) +            { +                LLViewerObject* child_obj = *child_iter; +                LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj ); +                if (child && child->getVolume()) +                { +                    const LLVector3& scale = child->getScale(); +                    area += child->getVolume()->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]); +                } +            } +        } +    } +    return area; +} +  void LLViewerObject::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)  {  	LLVector4a center; @@ -3633,7 +3911,6 @@ void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */)  	}  } -  void LLViewerObject::setLineWidthForWindowSize(S32 window_width)  {  	if (window_width < 700) @@ -3861,7 +4138,7 @@ const LLVector3 LLViewerObject::getRenderPosition() const  	if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED))  	{  		LLVOAvatar* avatar = getAvatar(); -		if (avatar) +		if (avatar && !getControlAvatar())  		{  			return avatar->getPositionAgent();  		} @@ -3885,7 +4162,7 @@ const LLVector3 LLViewerObject::getPivotPositionAgent() const  const LLQuaternion LLViewerObject::getRenderRotation() const  {  	LLQuaternion ret; -	if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED)) +	if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED) && !isAnimatedObject())  	{  		return ret;  	} @@ -5147,7 +5424,13 @@ LLVOAvatar* LLViewerObject::asAvatar()  	return NULL;  } -// If this object is directly or indirectly parented by an avatar, return it. +// If this object is directly or indirectly parented by an avatar, +// return it.  Normally getAvatar() is the correct function to call; +// it will give the avatar used for skinning.  The exception is with +// animated objects that are also attachments; in that case, +// getAvatar() will return the control avatar, used for skinning, and +// getAvatarAncestor will return the avatar to which the object is +// attached.  LLVOAvatar* LLViewerObject::getAvatarAncestor()  {  	LLViewerObject *pobj = (LLViewerObject*) getParent(); @@ -5486,6 +5769,11 @@ LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 para  		  new_block = new LLLightImageParams();  		  break;  	  } +      case LLNetworkData::PARAMS_EXTENDED_MESH: +      { +		  new_block = new LLExtendedMeshParams(); +		  break; +      }  	  default:  	  {  		  LL_INFOS() << "Unknown param type." << LL_ENDL; @@ -5885,6 +6173,17 @@ void LLViewerObject::updateVolume(const LLVolumeParams& volume_params)  	}  } +void LLViewerObject::recursiveMarkForUpdate(BOOL priority) +{ +    for (LLViewerObject::child_list_t::iterator iter = mChildList.begin(); +         iter != mChildList.end(); iter++) +    { +        LLViewerObject* child = *iter; +        child->markForUpdate(priority); +    } +    markForUpdate(priority); +} +  void LLViewerObject::markForUpdate(BOOL priority)  {  	if (mDrawable.notNull()) @@ -5936,6 +6235,11 @@ void LLViewerObject::setRegion(LLViewerRegion *regionp)  		child->setRegion(regionp);  	} +    if (mControlAvatar) +    { +        mControlAvatar->setRegion(regionp); +    } +  	setChanged(MOVED | SILHOUETTE);  	updateDrawable(FALSE);  } @@ -6384,6 +6688,10 @@ const std::string& LLViewerObject::getAttachmentItemName() const  //virtual  LLVOAvatar* LLViewerObject::getAvatar() const  { +    if (getControlAvatar()) +    { +        return getControlAvatar(); +    }  	if (isAttachment())  	{  		LLViewerObject* vobj = (LLViewerObject*) getParent(); diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 21c95d5533..9552d4e99e 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -47,6 +47,7 @@ class LLAgent;			// TODO: Get rid of this.  class LLAudioSource;  class LLAudioSourceVO;  class LLColor4; +class LLControlAvatar;  class LLDataPacker;  class LLDataPackerBinaryBuffer;  class LLDrawable; @@ -67,6 +68,8 @@ class LLViewerRegion;  class LLViewerTexture;  class LLWorld; +class LLMeshCostData; +  typedef enum e_object_update_type  {  	OUT_FULL, @@ -220,6 +223,8 @@ public:  	LLViewerRegion* getRegion() const				{ return mRegionp; }  	BOOL isSelected() const							{ return mUserSelected; } +    // Check whole linkset +    BOOL isAnySelected() const;  	virtual void setSelected(BOOL sel);  	const LLUUID &getID() const						{ return mID; } @@ -231,6 +236,7 @@ public:  	virtual BOOL isFlexible() const					{ return FALSE; }  	virtual BOOL isSculpted() const 				{ return FALSE; }  	virtual BOOL isMesh() const						{ return FALSE; } +	virtual BOOL isRiggedMesh() const				{ return FALSE; }  	virtual BOOL hasLightTexture() const			{ return FALSE; }  	// This method returns true if the object is over land owned by @@ -255,6 +261,8 @@ public:  	*/  	virtual BOOL setParent(LLViewerObject* parent); +    virtual void onReparent(LLViewerObject *old_parent, LLViewerObject *new_parent); +    virtual void afterReparent();  	virtual void addChild(LLViewerObject *childp);  	virtual void removeChild(LLViewerObject *childp);  	const_child_list_t& getChildren() const { 	return mChildList; } @@ -356,9 +364,17 @@ public:  	virtual void setScale(const LLVector3 &scale, BOOL damped = FALSE); -	virtual F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL, F32* unscaled_value = NULL) const; +    S32 getAnimatedObjectMaxTris() const; +    F32 recursiveGetEstTrianglesMax() const; +    virtual F32 getEstTrianglesMax() const; +    virtual F32 getEstTrianglesStreamingCost() const; +	virtual F32 getStreamingCost() const; +    virtual bool getCostData(LLMeshCostData& costs) const;  	virtual U32 getTriangleCount(S32* vcount = NULL) const;  	virtual U32 getHighLODTriangleCount(); +    F32 recursiveGetScaledSurfaceArea() const; + +    U32 recursiveGetTriangleCount(S32* vcount = NULL) const;  	void setObjectCost(F32 cost);  	F32 getObjectCost(); @@ -374,7 +390,7 @@ public:  	void sendShapeUpdate(); -	U8 getState()							{ return mState; } +	U8 getAttachmentState()							{ return mAttachmentState; }  	F32 getAppAngle() const					{ return mAppAngle; }  	F32 getPixelArea() const				{ return mPixelArea; } @@ -411,7 +427,8 @@ public:  	void setIcon(LLViewerTexture* icon_image);  	void clearIcon(); -	void markForUpdate(BOOL priority); +    void recursiveMarkForUpdate(BOOL priority); +	virtual void markForUpdate(BOOL priority);  	void updateVolume(const LLVolumeParams& volume_params);  	virtual	void updateSpatialExtents(LLVector4a& min, LLVector4a& max);  	virtual F32 getBinRadius(); @@ -685,6 +702,27 @@ public:  	static			BOOL		sUseSharedDrawables; +public: +    // Returns mControlAvatar for the edit root prim of this linkset +    LLControlAvatar *getControlAvatar(); +    LLControlAvatar *getControlAvatar() const; + +    // Create or connect to an existing control av as applicable +    void linkControlAvatar(); +    // Remove any reference to control av for this prim +    void unlinkControlAvatar(); +    // Link or unlink as needed +    void updateControlAvatar(); + +    virtual bool isAnimatedObject() const; + +    // Flags for createObject +    static const S32 CO_FLAG_CONTROL_AVATAR = 1 << 0; +    static const S32 CO_FLAG_UI_AVATAR = 1 << 1; + +protected: +    LLPointer<LLControlAvatar> mControlAvatar; +  protected:  	// delete an item in the inventory, but don't tell the  	// server. This is used internally by remove, update, and @@ -695,8 +733,7 @@ protected:  	// updateInventory.  	void doUpdateInventory(LLPointer<LLViewerInventoryItem>& item, U8 key, bool is_new); - -	static LLViewerObject *createObject(const LLUUID &id, LLPCode pcode, LLViewerRegion *regionp); +	static LLViewerObject *createObject(const LLUUID &id, LLPCode pcode, LLViewerRegion *regionp, S32 flags = 0);  	BOOL setData(const U8 *datap, const U32 data_size); @@ -784,7 +821,7 @@ protected:  	LLQuaternion	mAngularVelocityRot;		// accumulated rotation from the angular velocity computations  	LLQuaternion	mPreviousRotation; -	U8				mState;	// legacy +	U8				mAttachmentState;	// this encodes the attachment id in a somewhat complex way. 0 if not an attachment.  	LLViewerObjectMedia* mMedia;	// NULL if no media associated  	U8 mClickAction;  	F32 mObjectCost; //resource cost of this object or -1 if unknown diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index dc54346d59..46d92a079e 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -68,6 +68,7 @@  #include "u64.h"  #include "llviewertexturelist.h"  #include "lldatapacker.h" +#include "llcallstack.h"  #ifdef LL_USESYSTEMLIBS  #include <zlib.h>  #else @@ -241,6 +242,10 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp,  	}  	// ignore returned flags +    LL_DEBUGS("ObjectUpdate") << "uuid " << objectp->mID << " calling processUpdateMessage "  +                              << objectp << " just_created " << just_created << " from_cache " << from_cache << " msg " << msg << LL_ENDL; +    dumpStack("ObjectUpdateStack"); +	 	  	objectp->processUpdateMessage(msg, user_data, i, update_type, dpp);  	if (objectp->isDead()) @@ -352,7 +357,10 @@ LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry*  	if (!objectp)  	{  		objectp = createObjectFromCache(pcode, regionp, fullid, entry->getLocalID()); -		 + +        LL_DEBUGS("ObjectUpdate") << "uuid " << fullid << " created objectp " << objectp << LL_ENDL; +        dumpStack("ObjectUpdateStack"); +	 	  		if (!objectp)  		{  			LL_INFOS() << "createObject failure for object: " << fullid << LL_ENDL; @@ -471,6 +479,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  			compressed_dp.reset();  			uncompressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data); +            LL_DEBUGS("ObjectUpdate") << "got binary data from message to compressed_dpbuffer" << LL_ENDL;  			mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compressed_dpbuffer, 0, i);  			compressed_dp.assignBuffer(compressed_dpbuffer, uncompressed_length); @@ -530,6 +539,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  				// LL_WARNS() << "update for unknown localid " << local_id << " host " << gMessageSystem->getSender() << LL_ENDL;  				mNumUnknownUpdates++;  			} +            else +            { +                LL_DEBUGS("ObjectUpdate") << "Non-full, non-compressed update, obj " << local_id << ", global ID " << fullid << " from " << mesgsys->getSender() << LL_ENDL; +            }  		}  		else // OUT_FULL only?  		{ @@ -538,10 +551,19 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  			mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i);  			msg_size += sizeof(LLUUID);  			msg_size += sizeof(U32); -			// LL_INFOS() << "Full Update, obj " << local_id << ", global ID" << fullid << "from " << mesgsys->getSender() << LL_ENDL; +			LL_DEBUGS("ObjectUpdate") << "Full Update, obj " << local_id << ", global ID " << fullid << " from " << mesgsys->getSender() << LL_ENDL;  		}  		objectp = findObject(fullid); +        if (compressed) +        { +            LL_DEBUGS("ObjectUpdate") << "uuid " << fullid << " received compressed data from message (earlier in function)" << LL_ENDL; +        } +        LL_DEBUGS("ObjectUpdate") << "uuid " << fullid << " objectp " << objectp  +                                     << " update_cache " << (S32) update_cache << " compressed " << compressed +                                     << " update_type "  << update_type << LL_ENDL; +        dumpStack("ObjectUpdateStack"); +          		if(update_cache)  		{  			objectp = regionp->updateCacheEntry(local_id, objectp, update_type); @@ -616,6 +638,10 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,  #endif  			objectp = createObject(pcode, regionp, fullid, local_id, gMessageSystem->getSender()); + +            LL_DEBUGS("ObjectUpdate") << "creating object " << fullid << " result " << objectp << LL_ENDL; +            dumpStack("ObjectUpdateStack"); +  			if (!objectp)  			{  				LL_INFOS() << "createObject failure for object: " << fullid << LL_ENDL; @@ -710,12 +736,17 @@ void LLViewerObjectList::processCachedObjectUpdate(LLMessageSystem *mesgsys,  		mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, i);  		mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i);  		msg_size += sizeof(U32) * 2; -		 + +        LL_DEBUGS("ObjectUpdate") << "got probe for id " << id << " crc " << crc << LL_ENDL; +        dumpStack("ObjectUpdateStack"); +  		// Lookup data packer and add this id to cache miss lists if necessary.  		U8 cache_miss_type = LLViewerRegion::CACHE_MISS_TYPE_NONE;  		if(!regionp->probeCache(id, crc, flags, cache_miss_type))  		{  			// Cache Miss. +            LL_DEBUGS("ObjectUpdate") << "cache miss for id " << id << " crc " << crc << " miss type " << (S32) cache_miss_type << LL_ENDL; +  			recorder.cacheMissEvent(id, update_type, cache_miss_type, msg_size);  			continue; // no data packer, skip this object @@ -876,8 +907,8 @@ void LLViewerObjectList::update(LLAgent &agent)  			{  				if (idle_count >= idle_list.size())  				{ -				idle_list.push_back( objectp ); -			} +                    idle_list.push_back( objectp ); +                }  			else  				{  					idle_list[idle_count] = objectp; @@ -914,7 +945,7 @@ void LLViewerObjectList::update(LLAgent &agent)  		{  			objectp = *idle_iter;  			llassert(objectp->isActive()); -			objectp->idleUpdate(agent, frame_time); +                objectp->idleUpdate(agent, frame_time);  		}  		//update flexible objects @@ -1275,6 +1306,9 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp)  	// Cleanup any references we have to this object  	// Remove from object map so noone can look it up. +    LL_DEBUGS("ObjectUpdate") << " dereferencing id " << objectp->mID << LL_ENDL; +    dumpStack("ObjectUpdateStack"); +      	mUUIDObjectMap.erase(objectp->mID);  	//if (objectp->getRegion()) @@ -1961,12 +1995,12 @@ void LLViewerObjectList::resetObjectBeacons()  	mDebugBeacons.clear();  } -LLViewerObject *LLViewerObjectList::createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp) +LLViewerObject *LLViewerObjectList::createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp, S32 flags)  {  	LLUUID fullid;  	fullid.generate(); -	LLViewerObject *objectp = LLViewerObject::createObject(fullid, pcode, regionp); +	LLViewerObject *objectp = LLViewerObject::createObject(fullid, pcode, regionp, flags);  	if (!objectp)  	{  // 		LL_WARNS() << "Couldn't create object of type " << LLPrimitive::pCodeToString(pcode) << LL_ENDL; @@ -1986,6 +2020,9 @@ LLViewerObject *LLViewerObjectList::createObjectFromCache(const LLPCode pcode, L  {  	llassert_always(uuid.notNull()); +    LL_DEBUGS("ObjectUpdate") << "creating " << uuid << " local_id " << local_id << LL_ENDL; +    dumpStack("ObjectUpdateStack"); +      	LLViewerObject *objectp = LLViewerObject::createObject(uuid, pcode, regionp);  	if (!objectp)  	{ @@ -2020,6 +2057,9 @@ LLViewerObject *LLViewerObjectList::createObject(const LLPCode pcode, LLViewerRe  		fullid = uuid;  	} +    LL_DEBUGS("ObjectUpdate") << "createObject creating " << fullid << LL_ENDL; +    dumpStack("ObjectUpdateStack"); +  	LLViewerObject *objectp = LLViewerObject::createObject(fullid, pcode, regionp);  	if (!objectp)  	{ diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index 94c751acc6..72b2b99004 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -67,7 +67,7 @@ public:  	inline LLViewerObject *getObject(const S32 index);  	inline LLViewerObject *findObject(const LLUUID &id); -	LLViewerObject *createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp); // Create a viewer-side object +	LLViewerObject *createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp, S32 flags = 0); // Create a viewer-side object  	LLViewerObject *createObjectFromCache(const LLPCode pcode, LLViewerRegion *regionp, const LLUUID &uuid, const U32 local_id);  	LLViewerObject *createObject(const LLPCode pcode, LLViewerRegion *regionp,  								 const LLUUID &uuid, const U32 local_id, const LLHost &sender); diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp index 023f1b92ba..e7916ebd3b 100644 --- a/indra/newview/llvieweroctree.cpp +++ b/indra/newview/llvieweroctree.cpp @@ -731,7 +731,7 @@ bool LLViewerOctreeGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4  			update_min_max(newMin, newMax, minMax[0]);  			update_min_max(newMin, newMax, minMax[1]);  		} -		 +  		mObjectBounds[0].setAdd(newMin, newMax);  		mObjectBounds[0].mul(0.5f);  		mObjectBounds[1].setSub(newMax, newMin); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index eea382aac1..7979bdf335 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -78,6 +78,7 @@  #include "llcoros.h"  #include "lleventcoro.h"  #include "llcorehttputil.h" +#include "llcallstack.h"  #ifdef LL_WINDOWS  	#pragma warning(disable:4355) @@ -241,6 +242,8 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle)              LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities for region that no longer exists!" << LL_ENDL;              return; // this error condition is not recoverable.          } +        LL_DEBUGS("AppInit", "Capabilities") << "requesting seed caps for handle " << regionHandle  +                                             << " name " << regionp->getName() << LL_ENDL;          std::string url = regionp->getCapability("Seed");          if (url.empty()) @@ -269,7 +272,8 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle)          buildCapabilityNames(capabilityNames);          LL_INFOS("AppInit", "Capabilities") << "Requesting seed from " << url  -            << " (attempt #" << mSeedCapAttempts + 1 << ")" << LL_ENDL; +                                            << " region name " << regionp->getName() +                                            << " (attempt #" << mSeedCapAttempts + 1 << ")" << LL_ENDL;          regionp = NULL;          result = httpAdapter->postAndSuspend(httpRequest, url, capabilityNames); @@ -323,6 +327,8 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle)  #endif          regionp->setCapabilitiesReceived(true); +        LL_DEBUGS("AppInit", "Capabilities") << "received caps for handle " << regionHandle  +                                             << " region name " << regionp->getName() << LL_ENDL;          if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())          { @@ -1259,7 +1265,7 @@ void LLViewerRegion::updateVisibleEntries(F32 max_time)  		LLPointer<LLViewerOctreeGroup> group = *group_iter;  		if(group->getNumRefs() < 3 || //group to be deleted  			!group->getOctreeNode() || group->isEmpty()) //group empty -{ +        {  			continue;  		} @@ -2143,6 +2149,24 @@ void LLViewerRegion::getInfo(LLSD& info)  	info["Region"]["Handle"]["y"] = (LLSD::Integer)y;  } +void LLViewerRegion::requestSimulatorFeatures() +{ +    // kick off a request for simulator features +    std::string url = getCapability("SimulatorFeatures"); +    if (!url.empty()) +    { +        std::string coroname = +            LLCoros::instance().launch("LLViewerRegionImpl::requestSimulatorFeatureCoro", +                                       boost::bind(&LLViewerRegionImpl::requestSimulatorFeatureCoro, mImpl, url, getHandle())); +         +        LL_INFOS("AppInit", "SimulatorFeatures") << "Launching " << coroname << " requesting simulator features from " << url << LL_ENDL; +    } +    else +    { +        LL_WARNS("AppInit", "SimulatorFeatures") << "SimulatorFeatures cap not set" << LL_ENDL; +    } +} +  boost::signals2::connection LLViewerRegion::setSimulatorFeaturesReceivedCallback(const caps_received_signal_t::slot_type& cb)  {  	return mSimulatorFeaturesReceivedSignal.connect(cb); @@ -2220,7 +2244,7 @@ void LLViewerRegion::decodeBoundingInfo(LLVOCacheEntry* entry)  	{  		LLViewerRegion* old_regionp = ((LLDrawable*)entry->getEntry()->getDrawable())->getRegion();  		if(old_regionp != this && old_regionp) -{ +        {  			LLViewerObject* obj = ((LLDrawable*)entry->getEntry()->getDrawable())->getVObj();  			if(obj)  			{ @@ -2383,12 +2407,18 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLDataPackerB  		// we've seen this object before  		if (entry->getCRC() == crc)  		{ +            LL_DEBUGS("AnimatedObjects") << " got dupe for local_id " << local_id << LL_ENDL; +            dumpStack("AnimatedObjectsStack"); +  			// Record a hit  			entry->recordDupe();  			result = CACHE_UPDATE_DUPE;  		}  		else //CRC changed  		{ +            LL_DEBUGS("AnimatedObjects") << " got update for local_id " << local_id << LL_ENDL; +            dumpStack("AnimatedObjectsStack"); +  			// Update the cache entry  			entry->updateEntry(crc, dp); @@ -2399,6 +2429,9 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLDataPackerB  	}  	else  	{ +        LL_DEBUGS("AnimatedObjects") << " got first notification for local_id " << local_id << LL_ENDL; +        dumpStack("AnimatedObjectsStack"); +  		// we haven't seen this object before  		// Create new entry and add to map  		result = CACHE_UPDATE_ADDED; @@ -2503,7 +2536,7 @@ bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U32 flags, U8 &cache_miss  			// Record a hit  			mRegionCacheHitCount++;  			entry->recordHit(); -		cache_miss_type = CACHE_MISS_TYPE_NONE; +            cache_miss_type = CACHE_MISS_TYPE_NONE;  			entry->setUpdateFlags(flags);  			if(entry->isState(LLVOCacheEntry::ACTIVE)) @@ -2526,12 +2559,14 @@ bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U32 flags, U8 &cache_miss  			// LL_INFOS() << "CRC miss for " << local_id << LL_ENDL;  			addCacheMiss(local_id, CACHE_MISS_TYPE_CRC); +            cache_miss_type = CACHE_MISS_TYPE_CRC;  		}  	}  	else  	{  		// LL_INFOS() << "Cache miss for " << local_id << LL_ENDL;  		addCacheMiss(local_id, CACHE_MISS_TYPE_FULL); +        cache_miss_type = CACHE_MISS_TYPE_FULL;  	}  	return false; @@ -2568,6 +2603,9 @@ void LLViewerRegion::requestCacheMisses()  		msg->nextBlockFast(_PREHASH_ObjectData);  		msg->addU8Fast(_PREHASH_CacheMissType, (*iter).mType);  		msg->addU32Fast(_PREHASH_ID, (*iter).mID); + +        LL_DEBUGS("AnimatedObjects") << "Requesting cache missed object " << (*iter).mID << LL_ENDL; +          		blocks++;  		if (blocks >= 255) @@ -2868,6 +2906,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)  	capabilityNames.append("MeshUploadFlag");	  	capabilityNames.append("NavMeshGenerationStatus");  	capabilityNames.append("NewFileAgentInventory"); +	capabilityNames.append("ObjectAnimation");  	capabilityNames.append("ObjectMedia");  	capabilityNames.append("ObjectMediaNavigate");  	capabilityNames.append("ObjectNavMeshProperties"); @@ -2962,12 +3001,8 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u  	}  	else if (name == "SimulatorFeatures")  	{ -		// kick off a request for simulator features -        std::string coroname = -            LLCoros::instance().launch("LLViewerRegionImpl::requestSimulatorFeatureCoro", -            boost::bind(&LLViewerRegionImpl::requestSimulatorFeatureCoro, mImpl, url, getHandle())); - -        LL_INFOS("AppInit", "SimulatorFeatures") << "Launching " << coroname << " requesting simulator features from " << url << LL_ENDL; +        mImpl->mCapabilities["SimulatorFeatures"] = url; +        requestSimulatorFeatures();  	}  	else  	{ diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 302647215f..d5266ec873 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -305,6 +305,7 @@ public:  	bool meshUploadEnabled() const;  	// has region received its simulator features list? Requires an additional query after caps received. +    void requestSimulatorFeatures();  	void setSimulatorFeaturesReceived(bool);  	bool simulatorFeaturesReceived() const;  	boost::signals2::connection setSimulatorFeaturesReceivedCallback(const caps_received_signal_t::slot_type& cb); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index e90b4ac86c..28d1fb01ba 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -546,7 +546,14 @@ public:  								object_count++;  								S32 bytes = 0;	  								S32 visible = 0; -								cost += object->getStreamingCost(&bytes, &visible); +								cost += object->getStreamingCost(); +                                LLMeshCostData costs; +                                if (object->getCostData(costs)) +                                { +                                    bytes = costs.getSizeTotal(); +                                    visible = costs.getSizeByLOD(object->getLOD()); +                                } +  								S32 vt = 0;  								count += object->getTriangleCount(&vt);  								vcount += vt; @@ -1149,7 +1156,9 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi  				if (prim_media_dnd_enabled)  				{ -					LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY,  TRUE /*BOOL pick_transparent*/, FALSE ); +					LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, +                                                          TRUE /* pick_transparent */,  +                                                          FALSE /* pick_rigged */);  					LLUUID object_id = pick_info.getObjectID();  					S32 object_face = pick_info.mObjectFace; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index d7a24c6823..0ea29bae58 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -44,6 +44,7 @@  #include "llavatarnamecache.h"  #include "llavatarpropertiesprocessor.h"  #include "llavatarrendernotifier.h" +#include "llcontrolavatar.h"  #include "llexperiencecache.h"  #include "llphysicsmotion.h"  #include "llviewercontrol.h" @@ -109,6 +110,8 @@  #include "llcallstack.h"  #include "llrendersphere.h" +#include <boost/lexical_cast.hpp> +  extern F32 SPEED_ADJUST_MAX;  extern F32 SPEED_ADJUST_MAX_SEC;  extern F32 ANIM_SPEED_MAX; @@ -142,7 +145,7 @@ const LLUUID ANIM_AGENT_PHYSICS_MOTION = LLUUID("7360e029-3cb8-ebc4-863e-212df44  //-----------------------------------------------------------------------------  // Constants  //----------------------------------------------------------------------------- -const F32 DELTA_TIME_MIN = 0.01f;	// we clamp measured deltaTime to this +const F32 DELTA_TIME_MIN = 0.01f;	// we clamp measured delta_time to this  const F32 DELTA_TIME_MAX = 0.2f;	// range to insure stability of computations.  const F32 PELVIS_LAG_FLYING		= 0.22f;// pelvis follow half life while flying @@ -617,6 +620,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,  	LLViewerObject(id, pcode, regionp),  	mSpecialRenderMode(0),  	mAttachmentSurfaceArea(0.f), +	mAttachmentVisibleTriangleCount(0), +	mAttachmentEstTriangleCount(0.f),  	mReportedVisualComplexity(VISUAL_COMPLEXITY_UNKNOWN),  	mTurning(FALSE),  	mLastSkeletonSerialNum( 0 ), @@ -663,7 +668,10 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,  	mLastUpdateRequestCOFVersion(-1),  	mLastUpdateReceivedCOFVersion(-1),  	mCachedMuteListUpdateTime(0), -	mCachedInMuteList(false) +	mCachedInMuteList(false), +    mIsControlAvatar(false), +    mIsUIAvatar(false), +    mEnableDefaultMotions(true)  {  	LL_DEBUGS("AvatarRender") << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << LL_ENDL; @@ -718,6 +726,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,  	mCurrentGesticulationLevel = 0; +      	mRuthTimer.reset();  	mRuthDebugTimer.reset();  	mDebugExistenceTimer.reset(); @@ -733,8 +742,15 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,  std::string LLVOAvatar::avString() const  { -	std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus()); -	return " Avatar '" + getFullname() + "' " + viz_string + " "; +    if (isControlAvatar()) +    { +        return getFullname(); +    } +    else +    { +        std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus()); +        return " Avatar '" + getFullname() + "' " + viz_string + " "; +    }  }  void LLVOAvatar::debugAvatarRezTime(std::string notification_name, std::string comment) @@ -1099,7 +1115,7 @@ void LLVOAvatar::cleanupClass()  }  // virtual -void LLVOAvatar::initInstance(void) +void LLVOAvatar::initInstance()  {  	//-------------------------------------------------------------------------  	// register motions @@ -1222,8 +1238,6 @@ const LLVector3 LLVOAvatar::getRenderPosition() const  	{  		return getPosition() * mDrawable->getParent()->getRenderMatrix();  	} -	 -	  }  void LLVOAvatar::updateDrawable(BOOL force_damped) @@ -1240,6 +1254,10 @@ void LLVOAvatar::onShift(const LLVector4a& shift_vector)  void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)  { +    if (mDrawable.isNull()) +    { +        return; +    }  	if (isImpostor() && !needsImpostorUpdate())  	{  		LLVector3 delta = getRenderPosition() - @@ -1404,13 +1422,29 @@ void LLVOAvatar::renderCollisionVolumes()          static F32 sphere_scale = 1.0f;          static F32 center_dot_scale = 0.05f; -        static LLVector3 CV_COLOR_OCCLUDED(0.0f, 0.0f, 1.0f); -        static LLVector3 CV_COLOR_VISIBLE(0.5f, 0.5f, 1.0f); -        static LLVector3 DOT_COLOR_OCCLUDED(1.0f, 1.0f, 1.0f); -        static LLVector3 DOT_COLOR_VISIBLE(1.0f, 1.0f, 1.0f); +        static LLVector3 BLUE(0.0f, 0.0f, 1.0f); +        static LLVector3 PASTEL_BLUE(0.5f, 0.5f, 1.0f); +        static LLVector3 RED(1.0f, 0.0f, 0.0f); +        static LLVector3 PASTEL_RED(1.0f, 0.5f, 0.5f); +        static LLVector3 WHITE(1.0f, 1.0f, 1.0f); +         -        render_sphere_and_line(begin_pos, end_pos, sphere_scale, CV_COLOR_OCCLUDED, CV_COLOR_VISIBLE); -        render_sphere_and_line(begin_pos, end_pos, center_dot_scale, DOT_COLOR_OCCLUDED, DOT_COLOR_VISIBLE); +        LLVector3 cv_color_occluded; +        LLVector3 cv_color_visible; +        LLVector3 dot_color_occluded(WHITE); +        LLVector3 dot_color_visible(WHITE); +        if (isControlAvatar()) +        { +            cv_color_occluded = RED; +            cv_color_visible = PASTEL_RED; +        } +        else +        { +            cv_color_occluded = BLUE; +            cv_color_visible = PASTEL_BLUE; +        } +        render_sphere_and_line(begin_pos, end_pos, sphere_scale, cv_color_occluded, cv_color_visible); +        render_sphere_and_line(begin_pos, end_pos, center_dot_scale, dot_color_occluded, dot_color_visible);          gGL.popMatrix();      } @@ -1422,9 +1456,6 @@ void LLVOAvatar::renderCollisionVolumes()  		mNameText->lineSegmentIntersect(unused, unused, unused, TRUE);  	} - -	mDebugText.clear(); -	addDebugText(ostr.str());  }  void LLVOAvatar::renderBones() @@ -1595,6 +1626,11 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&  		return FALSE;  	} +    if (isControlAvatar()) +    { +        return FALSE; +    } +      	if (lineSegmentBoundingBox(start, end))  	{  		for (S32 i = 0; i < mNumCollisionVolumes; ++i) @@ -1680,6 +1716,7 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&  	return FALSE;  } +// virtual  LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector4a& start, const LLVector4a& end,  									  S32 face,  									  BOOL pick_transparent, @@ -1796,7 +1833,11 @@ void LLVOAvatar::buildCharacter()  		mAahMorph = getVisualParam( "Express_Open_Mouth" );  	} -	startDefaultMotions(); +    // Currently disabled for control avatars (animated objects), enabled for all others. +    if (mEnableDefaultMotions) +    { +        startDefaultMotions(); +    }  	//-------------------------------------------------------------------------  	// restart any currently active motions @@ -1856,7 +1897,7 @@ void LLVOAvatar::resetVisualParams()  void LLVOAvatar::resetSkeleton(bool reset_animations)  {      LL_DEBUGS("Avatar") << avString() << " reset starts" << LL_ENDL; -    if (!mLastProcessedAppearance) +    if (!isControlAvatar() && !mLastProcessedAppearance)      {          LL_WARNS() << "Can't reset avatar; no appearance message has been received yet." << LL_ENDL;          return; @@ -1910,12 +1951,15 @@ void LLVOAvatar::resetSkeleton(bool reset_animations)      }      // Reset tweakable params to preserved state -    bool slam_params = true; -    applyParsedAppearanceMessage(*mLastProcessedAppearance, slam_params); +    if (mLastProcessedAppearance) +    { +        bool slam_params = true; +        applyParsedAppearanceMessage(*mLastProcessedAppearance, slam_params); +    }      updateVisualParams();      // Restore attachment pos overrides -    rebuildAttachmentOverrides(); +    updateAttachmentOverrides();      // Animations      if (reset_animations) @@ -1942,7 +1986,7 @@ void LLVOAvatar::resetSkeleton(bool reset_animations)  //-----------------------------------------------------------------------------  void LLVOAvatar::releaseMeshData()  { -	if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || mIsDummy) +	if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || isUIAvatar())  	{  		return;  	} @@ -1962,15 +2006,15 @@ void LLVOAvatar::releaseMeshData()  		LLFace* facep = mDrawable->getFace(0);  		if (facep)  		{ -		facep->setSize(0, 0); -		for(S32 i = mNumInitFaces ; i < mDrawable->getNumFaces(); i++) -		{ -			facep = mDrawable->getFace(i); +            facep->setSize(0, 0); +            for(S32 i = mNumInitFaces ; i < mDrawable->getNumFaces(); i++) +            { +                facep = mDrawable->getFace(i);  				if (facep)  				{ -			facep->setSize(0, 0); -		} -	} +                    facep->setSize(0, 0); +                } +            }  		}  	} @@ -1994,6 +2038,10 @@ void LLVOAvatar::releaseMeshData()  void LLVOAvatar::restoreMeshData()  {  	llassert(!isSelf()); +    if (mDrawable.isNull()) +    { +        return; +    }  	//LL_INFOS() << "Restoring" << LL_ENDL;  	mMeshValid = TRUE; @@ -2303,7 +2351,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)  	{	  		LL_RECORD_BLOCK_TIME(FTM_JOINT_UPDATE); -		if (mIsSitting && getParent()) +		if (isSitting() && getParent())  		{  			LLViewerObject *root_object = (LLViewerObject*)getRoot();  			LLDrawable* drawablep = root_object->mDrawable; @@ -2469,7 +2517,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)  		// (the following version uses a tweak of "mHeadOffset" which handle sitting vs. standing)  		//-------------------------------------------------------------------------------------------- -		if ( mIsSitting ) +		if ( isSitting() )  		{  			LLVector3 headOffset = LLVector3( 0.0f, 0.0f, mHeadOffset.mV[2] );  			mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot->getWorldPosition() + headOffset ); @@ -2593,13 +2641,16 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)  		}  	} -	mDrawable->movePartition(); -	 -	//force a move if sitting on an active object -	if (getParent() && ((LLViewerObject*) getParent())->mDrawable->isActive()) -	{ -		gPipeline.markMoved(mDrawable, TRUE); -	} +    if (mDrawable.notNull()) +    { +        mDrawable->movePartition(); +         +        //force a move if sitting on an active object +        if (getParent() && ((LLViewerObject*) getParent())->mDrawable->isActive()) +        { +            gPipeline.markMoved(mDrawable, TRUE); +        } +    }  }  void LLVOAvatar::idleUpdateAppearanceAnimation() @@ -2760,7 +2811,8 @@ void LLVOAvatar::idleUpdateLoadingEffect()  																 LLPartData::LL_PART_EMISSIVE_MASK | // LLPartData::LL_PART_FOLLOW_SRC_MASK |  																 LLPartData::LL_PART_TARGET_POS_MASK ); -			if (!isTooComplex()) // do not generate particles for overly-complex avatars +			// do not generate particles for dummy or overly-complex avatars +			if (!mIsDummy && !isTooComplex())  			{  				setParticleSource(particle_parameters, getID());  			} @@ -3358,154 +3410,218 @@ bool LLVOAvatar::isInMuteList()  	return muted;  } -void LLVOAvatar::updateDebugText() +void LLVOAvatar::updateAppearanceMessageDebugText()  { -	// clear debug text -	mDebugText.clear(); +    S32 central_bake_version = -1; +    if (getRegion()) +    { +        central_bake_version = getRegion()->getCentralBakeVersion(); +    } +    bool all_baked_downloaded = allBakedTexturesCompletelyDownloaded(); +    bool all_local_downloaded = allLocalTexturesCompletelyDownloaded(); +    std::string debug_line = llformat("%s%s - mLocal: %d, mEdit: %d, mUSB: %d, CBV: %d", +                                      isSelf() ? (all_local_downloaded ? "L" : "l") : "-", +                                      all_baked_downloaded ? "B" : "b", +                                      mUseLocalAppearance, mIsEditingAppearance, +                                      1, central_bake_version); +    std::string origin_string = bakedTextureOriginInfo(); +    debug_line += " [" + origin_string + "]"; +    S32 curr_cof_version = LLAppearanceMgr::instance().getCOFVersion(); +    S32 last_request_cof_version = mLastUpdateRequestCOFVersion; +    S32 last_received_cof_version = mLastUpdateReceivedCOFVersion; +    if (isSelf()) +    { +        debug_line += llformat(" - cof: %d req: %d rcv:%d", +                               curr_cof_version, last_request_cof_version, last_received_cof_version); +        if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure")) +        { +            debug_line += " FORCING ERRS"; +        } +    } +    else +    { +        debug_line += llformat(" - cof rcv:%d", last_received_cof_version); +    } +    debug_line += llformat(" bsz-z: %.3f", mBodySize[2]); +    if (mAvatarOffset[2] != 0.0f) +    { +        debug_line += llformat("avofs-z: %.3f", mAvatarOffset[2]); +    } +    bool hover_enabled = getRegion() && getRegion()->avatarHoverHeightEnabled(); +    debug_line += hover_enabled ? " H" : " h"; +    const LLVector3& hover_offset = getHoverOffset(); +    if (hover_offset[2] != 0.0) +    { +        debug_line += llformat(" hov_z: %.3f", hover_offset[2]); +        debug_line += llformat(" %s", (isSitting() ? "S" : "T")); +        debug_line += llformat("%s", (isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED) ? "G" : "-")); +    } +    LLVector3 ankle_right_pos_agent = mFootRightp->getWorldPosition(); +    LLVector3 normal; +    LLVector3 ankle_right_ground_agent = ankle_right_pos_agent; +    resolveHeightAgent(ankle_right_pos_agent, ankle_right_ground_agent, normal); +    F32 rightElev = llmax(-0.2f, ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]); +    debug_line += llformat(" relev %.3f", rightElev); -	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) -	{ -		S32 central_bake_version = -1; -		if (getRegion()) -		{ -			central_bake_version = getRegion()->getCentralBakeVersion(); -		} -		bool all_baked_downloaded = allBakedTexturesCompletelyDownloaded(); -		bool all_local_downloaded = allLocalTexturesCompletelyDownloaded(); -		std::string debug_line = llformat("%s%s - mLocal: %d, mEdit: %d, mUSB: %d, CBV: %d", -										  isSelf() ? (all_local_downloaded ? "L" : "l") : "-", -										  all_baked_downloaded ? "B" : "b", -										  mUseLocalAppearance, mIsEditingAppearance, -										  1, central_bake_version); -		std::string origin_string = bakedTextureOriginInfo(); -		debug_line += " [" + origin_string + "]"; -		S32 curr_cof_version = LLAppearanceMgr::instance().getCOFVersion(); -		S32 last_request_cof_version = mLastUpdateRequestCOFVersion; -		S32 last_received_cof_version = mLastUpdateReceivedCOFVersion; -		if (isSelf()) -		{ -			debug_line += llformat(" - cof: %d req: %d rcv:%d", -								   curr_cof_version, last_request_cof_version, last_received_cof_version); -			if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure")) -			{ -				debug_line += " FORCING ERRS"; -			} -		} -		else -		{ -			debug_line += llformat(" - cof rcv:%d", last_received_cof_version); -		} -		debug_line += llformat(" bsz-z: %.3f", mBodySize[2]); -        if (mAvatarOffset[2] != 0.0f) +    LLVector3 root_pos = mRoot->getPosition(); +    LLVector3 pelvis_pos = mPelvisp->getPosition(); +    debug_line += llformat(" rp %.3f pp %.3f", root_pos[2], pelvis_pos[2]); + +    S32 is_visible = (S32) isVisible(); +    S32 is_m_visible = (S32) mVisible; +    debug_line += llformat(" v %d/%d", is_visible, is_m_visible); + +    addDebugText(debug_line); +} + +LLViewerInventoryItem* getObjectInventoryItem(LLViewerObject *vobj, LLUUID asset_id) +{ +    LLViewerInventoryItem *item = NULL; + +    if (vobj) +    { +        if (vobj->getInventorySerial()<=0)          { -            debug_line += llformat("avofs-z: %.3f", mAvatarOffset[2]); +            vobj->requestInventory();           } -		bool hover_enabled = getRegion() && getRegion()->avatarHoverHeightEnabled(); -		debug_line += hover_enabled ? " H" : " h"; -		const LLVector3& hover_offset = getHoverOffset(); -		if (hover_offset[2] != 0.0) -		{ -			debug_line += llformat(" hov_z: %.3f", hover_offset[2]); -			debug_line += llformat(" %s", (mIsSitting ? "S" : "T")); -			debug_line += llformat("%s", (isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED) ? "G" : "-")); -		} -        LLVector3 ankle_right_pos_agent = mFootRightp->getWorldPosition(); -		LLVector3 normal; -        LLVector3 ankle_right_ground_agent = ankle_right_pos_agent; -        resolveHeightAgent(ankle_right_pos_agent, ankle_right_ground_agent, normal); -        F32 rightElev = llmax(-0.2f, ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]); -        debug_line += llformat(" relev %.3f", rightElev); +        item = vobj->getInventoryItemByAsset(asset_id); +    } +    return item; +} + +LLViewerInventoryItem* recursiveGetObjectInventoryItem(LLViewerObject *vobj, LLUUID asset_id) +{ +    LLViewerInventoryItem *item = getObjectInventoryItem(vobj, asset_id); +    if (!item) +    { +        LLViewerObject::const_child_list_t& children = vobj->getChildren(); +        for (LLViewerObject::const_child_list_t::const_iterator it = children.begin(); +             it != children.end(); ++it) +        { +            LLViewerObject *childp = *it; +            item = getObjectInventoryItem(childp, asset_id); +            if (item) +            { +                break; +            } +        } +    } +    return item; +} + +void LLVOAvatar::updateAnimationDebugText() +{ +    for (LLMotionController::motion_list_t::iterator iter = mMotionController.getActiveMotions().begin(); +         iter != mMotionController.getActiveMotions().end(); ++iter) +    { +        LLMotion* motionp = *iter; +        if (motionp->getMinPixelArea() < getPixelArea()) +        { +            std::string output; +            std::string motion_name = motionp->getName(); +            if (motion_name.empty()) +            { +                if (isControlAvatar()) +                { +                    LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this); +                    // Try to get name from inventory of associated object +                    LLVOVolume *volp = control_av->mRootVolp; +                    LLViewerInventoryItem *item = recursiveGetObjectInventoryItem(volp,motionp->getID()); +                    if (item) +                    { +                        motion_name = item->getName(); +                    } +                } +            } +            if (motion_name.empty()) +            { +                std::string name; +                if (gAgent.isGodlikeWithoutAdminMenuFakery() || isSelf()) +                { +                    name = motionp->getID().asString(); +                    LLVOAvatar::AnimSourceIterator anim_it = mAnimationSources.begin(); +                    for (; anim_it != mAnimationSources.end(); ++anim_it) +                    { +                        if (anim_it->second == motionp->getID()) +                        { +                            LLViewerObject* object = gObjectList.findObject(anim_it->first); +                            if (!object) +                            { +                                break; +                            } +                            if (object->isAvatar()) +                            { +                                if (mMotionController.mIsSelf) +                                { +                                    // Searching inventory by asset id is really long +                                    // so just mark as inventory +                                    // Also item is likely to be named by LLPreviewAnim +                                    name += "(inventory)"; +                                } +                            } +                            else +                            { +                                LLViewerInventoryItem* item = NULL; +                                if (!object->isInventoryDirty()) +                                { +                                    item = object->getInventoryItemByAsset(motionp->getID()); +                                } +                                if (item) +                                { +                                    name = item->getName(); +                                } +                                else if (object->isAttachment()) +                                { +                                    name += "(" + getAttachmentItemName() + ")"; +                                } +                                else +                                { +                                    // in-world object, name or content unknown +                                    name += "(in-world)"; +                                } +                            } +                            break; +                        } +                    } +                } +                else +                { +                    name = LLUUID::null.asString(); +                } +                output = llformat("%s - %d", +                                  name.c_str(), +                                  (U32)motionp->getPriority()); +            } +            else +            { +                output = llformat("%s - %d", +                                  motion_name.c_str(), +                                  (U32)motionp->getPriority()); +            } +            addDebugText(output); +        } +    } +} -        LLVector3 root_pos = mRoot->getPosition(); -        LLVector3 pelvis_pos = mPelvisp->getPosition(); -        debug_line += llformat(" rp %.3f pp %.3f", root_pos[2], pelvis_pos[2]); +void LLVOAvatar::updateDebugText() +{ +    // Leave mDebugText uncleared here, in case a derived class has added some state first -		addDebugText(debug_line); +	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) +	{ +        updateAppearanceMessageDebugText();  	} +  	if (gSavedSettings.getBOOL("DebugAvatarCompositeBaked"))  	{  		if (!mBakedTextureDebugText.empty())  			addDebugText(mBakedTextureDebugText);  	} +    // Develop -> Avatar -> Animation Info  	if (LLVOAvatar::sShowAnimationDebug)  	{ -		for (LLMotionController::motion_list_t::iterator iter = mMotionController.getActiveMotions().begin(); -			 iter != mMotionController.getActiveMotions().end(); ++iter) -		{ -			LLMotion* motionp = *iter; -			if (motionp->getMinPixelArea() < getPixelArea()) -			{ -				std::string output; -				if (motionp->getName().empty()) -				{ -					std::string name; -					if (gAgent.isGodlikeWithoutAdminMenuFakery() || isSelf()) -					{ -						name = motionp->getID().asString(); -						LLVOAvatar::AnimSourceIterator anim_it = mAnimationSources.begin(); -						for (; anim_it != mAnimationSources.end(); ++anim_it) -						{ -							if (anim_it->second == motionp->getID()) -							{ -								LLViewerObject* object = gObjectList.findObject(anim_it->first); -								if (!object) -								{ -									break; -								} -								if (object->isAvatar()) -								{ -									if (mMotionController.mIsSelf) -									{ -										// Searching inventory by asset id is really long -										// so just mark as inventory -										// Also item is likely to be named by LLPreviewAnim -										name += "(inventory)"; -									} -								} -								else -								{ -									LLViewerInventoryItem* item = NULL; -									if (!object->isInventoryDirty()) -									{ -										item = object->getInventoryItemByAsset(motionp->getID()); -									} -									if (item) -									{ -										name = item->getName(); -									} -									else if (object->isAttachment()) -									{ -										name += "(" + getAttachmentItemName() + ")"; -									} -									else -									{ -										// in-world object, name or content unknown -										name += "(in-world)"; -									} -								} -								break; -							} -						} -					} -					else -					{ -						name = LLUUID::null.asString(); -					} - -					output = llformat("%s - %d", -							  name.c_str(), -							  (U32)motionp->getPriority()); -				} -				else -				{ -					output = llformat("%s - %d", -							  motionp->getName().c_str(), -							  (U32)motionp->getPriority()); -				} -				addDebugText(output); -			} -		} +        updateAnimationDebugText();  	}  	if (!mDebugText.size() && mText.notNull()) @@ -3517,51 +3633,125 @@ void LLVOAvatar::updateDebugText()  	{  		setDebugText(mDebugText);  	} -	mDebugText.clear(); - +    mDebugText.clear();  }  //------------------------------------------------------------------------ -// updateCharacter() -// called on both your avatar and other avatars +// updateFootstepSounds +// Factored out from updateCharacter() +// Generate footstep sounds when feet hit the ground  //------------------------------------------------------------------------ -BOOL LLVOAvatar::updateCharacter(LLAgent &agent) -{	 -	updateDebugText(); -	 -	if (!mIsBuilt) -	{ -		return FALSE; -	} +void LLVOAvatar::updateFootstepSounds() +{ +    if (mIsDummy) +    { +        return; +    } +     +	//------------------------------------------------------------------------- +	// Find the ground under each foot, these are used for a variety +	// of things that follow +	//------------------------------------------------------------------------- +	LLVector3 ankle_left_pos_agent = mFootLeftp->getWorldPosition(); +	LLVector3 ankle_right_pos_agent = mFootRightp->getWorldPosition(); -	BOOL visible = isVisible(); +	LLVector3 ankle_left_ground_agent = ankle_left_pos_agent; +	LLVector3 ankle_right_ground_agent = ankle_right_pos_agent; +    LLVector3 normal; +	resolveHeightAgent(ankle_left_pos_agent, ankle_left_ground_agent, normal); +	resolveHeightAgent(ankle_right_pos_agent, ankle_right_ground_agent, normal); -	// For fading out the names above heads, only let the timer -	// run if we're visible. -	if (mDrawable.notNull() && !visible) +	F32 leftElev = llmax(-0.2f, ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ]); +	F32 rightElev = llmax(-0.2f, ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]); + +	if (!isSitting())  	{ -		mTimeVisible.reset(); +		//------------------------------------------------------------------------- +		// Figure out which foot is on ground +		//------------------------------------------------------------------------- +		if (!mInAir) +		{ +			if ((leftElev < 0.0f) || (rightElev < 0.0f)) +			{ +				ankle_left_pos_agent = mFootLeftp->getWorldPosition(); +				ankle_right_pos_agent = mFootRightp->getWorldPosition(); +				leftElev = ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ]; +				rightElev = ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]; +			} +		}  	} +	 +	const LLUUID AGENT_FOOTSTEP_ANIMS[] = {ANIM_AGENT_WALK, ANIM_AGENT_RUN, ANIM_AGENT_LAND}; +	const S32 NUM_AGENT_FOOTSTEP_ANIMS = LL_ARRAY_SIZE(AGENT_FOOTSTEP_ANIMS); -	//-------------------------------------------------------------------- -	// the rest should only be done occasionally for far away avatars -	//-------------------------------------------------------------------- +	if ( gAudiop && isAnyAnimationSignaled(AGENT_FOOTSTEP_ANIMS, NUM_AGENT_FOOTSTEP_ANIMS) ) +	{ +		BOOL playSound = FALSE; +		LLVector3 foot_pos_agent; + +		BOOL onGroundLeft = (leftElev <= 0.05f); +		BOOL onGroundRight = (rightElev <= 0.05f); + +		// did left foot hit the ground? +		if ( onGroundLeft && !mWasOnGroundLeft ) +		{ +			foot_pos_agent = ankle_left_pos_agent; +			playSound = TRUE; +		} + +		// did right foot hit the ground? +		if ( onGroundRight && !mWasOnGroundRight ) +		{ +			foot_pos_agent = ankle_right_pos_agent; +			playSound = TRUE; +		} + +		mWasOnGroundLeft = onGroundLeft; +		mWasOnGroundRight = onGroundRight; + +		if ( playSound ) +		{ +			const F32 STEP_VOLUME = 0.1f; +			const LLUUID& step_sound_id = getStepSound(); + +			LLVector3d foot_pos_global = gAgent.getPosGlobalFromAgent(foot_pos_agent); + +			if (LLViewerParcelMgr::getInstance()->canHearSound(foot_pos_global) +				&& !LLMuteList::getInstance()->isMuted(getID(), LLMute::flagObjectSounds)) +			{ +				gAudiop->triggerSound(step_sound_id, getID(), STEP_VOLUME, LLAudioEngine::AUDIO_TYPE_AMBIENT, foot_pos_global); +			} +		} +	} +} +//------------------------------------------------------------------------ +// computeUpdatePeriod() +// Factored out from updateCharacter() +// Set new value for mUpdatePeriod based on distance and various other factors. +//------------------------------------------------------------------------ +void LLVOAvatar::computeUpdatePeriod() +{  	bool visually_muted = isVisuallyMuted(); -	if (visible && (!isSelf() || visually_muted) && !mIsDummy && sUseImpostors && !mNeedsAnimUpdate && !sFreezeCounter) +	if (mDrawable.notNull() +        && isVisible()  +        && (!isSelf() || visually_muted) +        && !isUIAvatar() +        && sUseImpostors +        && !mNeedsAnimUpdate  +        && !sFreezeCounter)  	{  		const LLVector4a* ext = mDrawable->getSpatialExtents();  		LLVector4a size;  		size.setSub(ext[1],ext[0]);  		F32 mag = size.getLength3().getF32()*0.5f; -  		F32 impostor_area = 256.f*512.f*(8.125f - LLVOAvatar::sLODFactor*8.f);  		if (visually_muted)  		{ // visually muted avatars update at 16 hz  			mUpdatePeriod = 16;  		} -		else if (   ! shouldImpostor() +		else if (! shouldImpostor()  				 || mDrawable->mDistanceWRTCamera < 1.f + mag)  		{   // first 25% of max visible avatars are not impostored  			// also, don't impostor avatars whose bounding box may be penetrating the  @@ -3585,63 +3775,214 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)  			//nearby avatars, update the impostors more frequently.  			mUpdatePeriod = 4;  		} - -		visible = (LLDrawable::getCurrentFrame()+mID.mData[0])%mUpdatePeriod == 0 ? TRUE : FALSE;  	}  	else  	{  		mUpdatePeriod = 1;  	} +} -	// don't early out for your own avatar, as we rely on your animations playing reliably -	// for example, the "turn around" animation when entering customize avatar needs to trigger -	// even when your avatar is offscreen -	if (!visible && !isSelf()) -	{ -		updateMotions(LLCharacter::HIDDEN_UPDATE); -		return FALSE; -	} +//------------------------------------------------------------------------ +// updateOrientation() +// Factored out from updateCharacter() +// This is used by updateCharacter() to update the avatar's orientation: +// - updates mTurning state +// - updates rotation of the mRoot joint in the skeleton +// - for self, calls setControlFlags() to notify the simulator about any turns +//------------------------------------------------------------------------ +void LLVOAvatar::updateOrientation(LLAgent& agent, F32 speed, F32 delta_time) +{ +    LLQuaternion iQ; +    LLVector3 upDir( 0.0f, 0.0f, 1.0f ); +			 +    // Compute a forward direction vector derived from the primitive rotation +    // and the velocity vector.  When walking or jumping, don't let body deviate +    // more than 90 from the view, if necessary, flip the velocity vector. -	// change animation time quanta based on avatar render load -	if (!isSelf() && !mIsDummy) +    LLVector3 primDir; +    if (isSelf()) +    { +        primDir = agent.getAtAxis() - projected_vec(agent.getAtAxis(), agent.getReferenceUpVector()); +        primDir.normalize(); +    } +    else +    { +        primDir = getRotation().getMatrix3().getFwdRow(); +    } +    LLVector3 velDir = getVelocity(); +    velDir.normalize(); +    if ( mSignaledAnimations.find(ANIM_AGENT_WALK) != mSignaledAnimations.end()) +    { +        F32 vpD = velDir * primDir; +        if (vpD < -0.5f) +        { +            velDir *= -1.0f; +        } +    } +    LLVector3 fwdDir = lerp(primDir, velDir, clamp_rescale(speed, 0.5f, 2.0f, 0.0f, 1.0f)); +    if (isSelf() && gAgentCamera.cameraMouselook()) +    { +        // make sure fwdDir stays in same general direction as primdir +        if (gAgent.getFlying()) +        { +            fwdDir = LLViewerCamera::getInstance()->getAtAxis(); +        } +        else +        { +            LLVector3 at_axis = LLViewerCamera::getInstance()->getAtAxis(); +            LLVector3 up_vector = gAgent.getReferenceUpVector(); +            at_axis -= up_vector * (at_axis * up_vector); +            at_axis.normalize(); +					 +            F32 dot = fwdDir * at_axis; +            if (dot < 0.f) +            { +                fwdDir -= 2.f * at_axis * dot; +                fwdDir.normalize(); +            } +        } +    } + +    LLQuaternion root_rotation = mRoot->getWorldMatrix().quaternion(); +    F32 root_roll, root_pitch, root_yaw; +    root_rotation.getEulerAngles(&root_roll, &root_pitch, &root_yaw); + +    // When moving very slow, the pelvis is allowed to deviate from the +    // forward direction to allow it to hold its position while the torso +    // and head turn.  Once in motion, it must conform however. +    BOOL self_in_mouselook = isSelf() && gAgentCamera.cameraMouselook(); + +    LLVector3 pelvisDir( mRoot->getWorldMatrix().getFwdRow4().mV ); + +    static LLCachedControl<F32> s_pelvis_rot_threshold_slow(gSavedSettings, "AvatarRotateThresholdSlow", 60.0); +    static LLCachedControl<F32> s_pelvis_rot_threshold_fast(gSavedSettings, "AvatarRotateThresholdFast", 2.0); + +    F32 pelvis_rot_threshold = clamp_rescale(speed, 0.1f, 1.0f, s_pelvis_rot_threshold_slow, s_pelvis_rot_threshold_fast); +						 +    if (self_in_mouselook) +    { +        pelvis_rot_threshold *= MOUSELOOK_PELVIS_FOLLOW_FACTOR; +    } +    pelvis_rot_threshold *= DEG_TO_RAD; + +    F32 angle = angle_between( pelvisDir, fwdDir ); + +    // The avatar's root is allowed to have a yaw that deviates widely +    // from the forward direction, but if roll or pitch are off even +    // a little bit we need to correct the rotation. +    if(root_roll < 1.f * DEG_TO_RAD +       && root_pitch < 5.f * DEG_TO_RAD) +    { +        // smaller correction vector means pelvis follows prim direction more closely +        if (!mTurning && angle > pelvis_rot_threshold*0.75f) +        { +            mTurning = TRUE; +        } + +        // use tighter threshold when turning +        if (mTurning) +        { +            pelvis_rot_threshold *= 0.4f; +        } + +        // am I done turning? +        if (angle < pelvis_rot_threshold) +        { +            mTurning = FALSE; +        } + +        LLVector3 correction_vector = (pelvisDir - fwdDir) * clamp_rescale(angle, pelvis_rot_threshold*0.75f, pelvis_rot_threshold, 1.0f, 0.0f); +        fwdDir += correction_vector; +    } +    else +    { +        mTurning = FALSE; +    } + +    // Now compute the full world space rotation for the whole body (wQv) +    LLVector3 leftDir = upDir % fwdDir; +    leftDir.normalize(); +    fwdDir = leftDir % upDir; +    LLQuaternion wQv( fwdDir, leftDir, upDir ); + +    if (isSelf() && mTurning) +    { +        if ((fwdDir % pelvisDir) * upDir > 0.f) +        { +            gAgent.setControlFlags(AGENT_CONTROL_TURN_RIGHT); +        } +        else +        { +            gAgent.setControlFlags(AGENT_CONTROL_TURN_LEFT); +        } +    } + +    // Set the root rotation, but do so incrementally so that it +    // lags in time by some fixed amount. +    //F32 u = LLSmoothInterpolation::getInterpolant(PELVIS_LAG); +    F32 pelvis_lag_time = 0.f; +    if (self_in_mouselook) +    { +        pelvis_lag_time = PELVIS_LAG_MOUSELOOK; +    } +    else if (mInAir) +    { +        pelvis_lag_time = PELVIS_LAG_FLYING; +        // increase pelvis lag time when moving slowly +        pelvis_lag_time *= clamp_rescale(mSpeedAccum, 0.f, 15.f, 3.f, 1.f); +    } +    else +    { +        pelvis_lag_time = PELVIS_LAG_WALKING; +    } + +    F32 u = llclamp((delta_time / pelvis_lag_time), 0.0f, 1.0f);	 + +    mRoot->setWorldRotation( slerp(u, mRoot->getWorldRotation(), wQv) ); +} + +//------------------------------------------------------------------------ +// updateTimeStep() +// Factored out from updateCharacter(). +// +// Updates the time step used by the motion controller, based on area +// and avatar count criteria.  This will also stop the +// ANIM_AGENT_WALK_ADJUST animation under some circumstances. +// ------------------------------------------------------------------------ +void LLVOAvatar::updateTimeStep() +{ +	if (!isSelf() && !isUIAvatar()) // ie, non-self avatars, and animated objects will be affected.  	{ +        // Note that sInstances counts animated objects and +        // standard avatars in the same bucket. Is this desirable?  		F32 time_quantum = clamp_rescale((F32)sInstances.size(), 10.f, 35.f, 0.f, 0.25f);  		F32 pixel_area_scale = clamp_rescale(mPixelArea, 100, 5000, 1.f, 0.f);  		F32 time_step = time_quantum * pixel_area_scale; +        // Extrema: +        //   If number of avs is 10 or less, time_step is unmodified (flagged with 0.0). +        //   If area of av is 5000 or greater, time_step is unmodified (flagged with 0.0). +        //   If number of avs is 35 or greater, and area of av is 100 or less, +        //   time_step takes the maximum possible value of 0.25. +        //   Other situations will give values within the (0, 0.25) range.  		if (time_step != 0.f)  		{  			// disable walk motion servo controller as it doesn't work with motion timesteps  			stopMotion(ANIM_AGENT_WALK_ADJUST);  			removeAnimationData("Walk Speed");  		} +        // See SL-763 - playback with altered time step does not +        // appear to work correctly, odd behavior for distant avatars. +        // As of 11-2017, LLMotionController::updateMotions() will +        // ignore the value here. Need to re-enable if it's every +        // fixed.  		mMotionController.setTimeStep(time_step); -		//		LL_INFOS() << "Setting timestep to " << time_quantum * pixel_area_scale << LL_ENDL;  	} +} -	if (getParent() && !mIsSitting) -	{ -		sitOnObject((LLViewerObject*)getParent()); -	} -	else if (!getParent() && mIsSitting && !isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED)) -	{ -		getOffObject(); -	} - -	//-------------------------------------------------------------------- -	// create local variables in world coords for region position values -	//-------------------------------------------------------------------- -	F32 speed; -	LLVector3 normal; - -	LLVector3 xyVel = getVelocity(); -	xyVel.mV[VZ] = 0.0f; -	speed = xyVel.length(); -	// remembering the value here prevents a display glitch if the -	// animation gets toggled during this update. -	bool was_sit_ground_constrained = isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED); -	 -	if (!(mIsSitting && getParent())) +void LLVOAvatar::updateRootPositionAndRotation(LLAgent& agent, F32 speed, bool was_sit_ground_constrained)  +{ +	if (!(isSitting() && getParent()))  	{  		// This case includes all configurations except sitting on an  		// object, so does include ground sit. @@ -3655,7 +3996,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)  		{  			mTimeLast = animation_time; -			// put the pelvis at slaved position/mRotation +			// Initially put the pelvis at slaved position/mRotation  			// SL-315  			mRoot->setWorldPosition( getPositionAgent() ); // first frame  			mRoot->setWorldRotation( getRotation() ); @@ -3664,9 +4005,9 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)  		//--------------------------------------------------------------------  		// dont' let dT get larger than 1/5th of a second  		//-------------------------------------------------------------------- -		F32 deltaTime = animation_time - mTimeLast; +		F32 delta_time = animation_time - mTimeLast; -		deltaTime = llclamp( deltaTime, DELTA_TIME_MIN, DELTA_TIME_MAX ); +		delta_time = llclamp( delta_time, DELTA_TIME_MIN, DELTA_TIME_MAX );  		mTimeLast = animation_time;  		mSpeedAccum = (mSpeedAccum * 0.95f) + (speed * 0.05f); @@ -3685,7 +4026,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)  		root_pos = gAgent.getPosGlobalFromAgent(getRenderPosition());  		root_pos.mdV[VZ] += getVisualParamWeight(AVATAR_HOVER); - +        LLVector3 normal;  		resolveHeightGlobal(root_pos, ground_under_pelvis, normal);  		F32 foot_to_ground = (F32) (root_pos.mdV[VZ] - mPelvisToFoot - ground_under_pelvis.mdV[VZ]);				  		BOOL in_air = ((!LLWorld::getInstance()->getRegionFromPosGlobal(ground_under_pelvis)) ||  @@ -3707,185 +4048,154 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)  		// correct for the fact that the pelvis is not necessarily the center   		// of the agent's physical representation  		root_pos.mdV[VZ] -= (0.5f * mBodySize.mV[VZ]) - mPelvisToFoot; -		if (!mIsSitting && !was_sit_ground_constrained) +		if (!isSitting() && !was_sit_ground_constrained)  		{  			root_pos += LLVector3d(getHoverOffset());  		} -		 -		LLVector3 newPosition = gAgent.getPosAgentFromGlobal(root_pos); - - -		if (newPosition != mRoot->getXform()->getWorldPosition()) -		{		 -			mRoot->touch(); -			// SL-315 -			mRoot->setWorldPosition( newPosition ); // regular update				 -		} +        LLControlAvatar *cav = dynamic_cast<LLControlAvatar*>(this); +        if (cav) +        { +            cav->matchVolumeTransform(); +        } +        else +        { +            LLVector3 newPosition = gAgent.getPosAgentFromGlobal(root_pos); +            if (newPosition != mRoot->getXform()->getWorldPosition()) +            {		 +                mRoot->touch(); +                // SL-315 +                mRoot->setWorldPosition( newPosition ); // regular update				 +            } +        }  		//--------------------------------------------------------------------  		// Propagate viewer object rotation to root of avatar  		//-------------------------------------------------------------------- -		if (!isAnyAnimationSignaled(AGENT_NO_ROTATE_ANIMS, NUM_AGENT_NO_ROTATE_ANIMS)) +		if (!isControlAvatar() && !isAnyAnimationSignaled(AGENT_NO_ROTATE_ANIMS, NUM_AGENT_NO_ROTATE_ANIMS))  		{ -			LLQuaternion iQ; -			LLVector3 upDir( 0.0f, 0.0f, 1.0f ); -			 -			// Compute a forward direction vector derived from the primitive rotation -			// and the velocity vector.  When walking or jumping, don't let body deviate -			// more than 90 from the view, if necessary, flip the velocity vector. - -			LLVector3 primDir; -			if (isSelf()) -			{ -				primDir = agent.getAtAxis() - projected_vec(agent.getAtAxis(), agent.getReferenceUpVector()); -				primDir.normalize(); -			} -			else -			{ -				primDir = getRotation().getMatrix3().getFwdRow(); -			} -			LLVector3 velDir = getVelocity(); -			velDir.normalize(); -			if ( mSignaledAnimations.find(ANIM_AGENT_WALK) != mSignaledAnimations.end()) -			{ -				F32 vpD = velDir * primDir; -				if (vpD < -0.5f) -				{ -					velDir *= -1.0f; -				} -			} -			LLVector3 fwdDir = lerp(primDir, velDir, clamp_rescale(speed, 0.5f, 2.0f, 0.0f, 1.0f)); -			if (isSelf() && gAgentCamera.cameraMouselook()) -			{ -				// make sure fwdDir stays in same general direction as primdir -				if (gAgent.getFlying()) -				{ -					fwdDir = LLViewerCamera::getInstance()->getAtAxis(); -				} -				else -				{ -					LLVector3 at_axis = LLViewerCamera::getInstance()->getAtAxis(); -					LLVector3 up_vector = gAgent.getReferenceUpVector(); -					at_axis -= up_vector * (at_axis * up_vector); -					at_axis.normalize(); -					 -					F32 dot = fwdDir * at_axis; -					if (dot < 0.f) -					{ -						fwdDir -= 2.f * at_axis * dot; -						fwdDir.normalize(); -					} -				} -			} - -			LLQuaternion root_rotation = mRoot->getWorldMatrix().quaternion(); -			F32 root_roll, root_pitch, root_yaw; -			root_rotation.getEulerAngles(&root_roll, &root_pitch, &root_yaw); - -			// When moving very slow, the pelvis is allowed to deviate from the -			// forward direction to allow it to hold it's position while the torso -			// and head turn.  Once in motion, it must conform however. -			BOOL self_in_mouselook = isSelf() && gAgentCamera.cameraMouselook(); - -			LLVector3 pelvisDir( mRoot->getWorldMatrix().getFwdRow4().mV ); - -			static LLCachedControl<F32> s_pelvis_rot_threshold_slow(gSavedSettings, "AvatarRotateThresholdSlow", 60.0); -			static LLCachedControl<F32> s_pelvis_rot_threshold_fast(gSavedSettings, "AvatarRotateThresholdFast", 2.0); - -			F32 pelvis_rot_threshold = clamp_rescale(speed, 0.1f, 1.0f, s_pelvis_rot_threshold_slow, s_pelvis_rot_threshold_fast); -						 -			if (self_in_mouselook) -			{ -				pelvis_rot_threshold *= MOUSELOOK_PELVIS_FOLLOW_FACTOR; -			} -			pelvis_rot_threshold *= DEG_TO_RAD; - -			F32 angle = angle_between( pelvisDir, fwdDir ); - -			// The avatar's root is allowed to have a yaw that deviates widely -			// from the forward direction, but if roll or pitch are off even -			// a little bit we need to correct the rotation. -			if(root_roll < 1.f * DEG_TO_RAD -			   && root_pitch < 5.f * DEG_TO_RAD) -			{ -				// smaller correction vector means pelvis follows prim direction more closely -				if (!mTurning && angle > pelvis_rot_threshold*0.75f) -				{ -					mTurning = TRUE; -				} - -				// use tighter threshold when turning -				if (mTurning) -				{ -					pelvis_rot_threshold *= 0.4f; -				} - -				// am I done turning? -				if (angle < pelvis_rot_threshold) -				{ -					mTurning = FALSE; -				} - -				LLVector3 correction_vector = (pelvisDir - fwdDir) * clamp_rescale(angle, pelvis_rot_threshold*0.75f, pelvis_rot_threshold, 1.0f, 0.0f); -				fwdDir += correction_vector; -			} -			else -			{ -				mTurning = FALSE; -			} - -			// Now compute the full world space rotation for the whole body (wQv) -			LLVector3 leftDir = upDir % fwdDir; -			leftDir.normalize(); -			fwdDir = leftDir % upDir; -			LLQuaternion wQv( fwdDir, leftDir, upDir ); - -			if (isSelf() && mTurning) -			{ -				if ((fwdDir % pelvisDir) * upDir > 0.f) -				{ -					gAgent.setControlFlags(AGENT_CONTROL_TURN_RIGHT); -				} -				else -				{ -					gAgent.setControlFlags(AGENT_CONTROL_TURN_LEFT); -				} -			} - -			// Set the root rotation, but do so incrementally so that it -			// lags in time by some fixed amount. -			//F32 u = LLSmoothInterpolation::getInterpolant(PELVIS_LAG); -			F32 pelvis_lag_time = 0.f; -			if (self_in_mouselook) -			{ -				pelvis_lag_time = PELVIS_LAG_MOUSELOOK; -			} -			else if (mInAir) -			{ -				pelvis_lag_time = PELVIS_LAG_FLYING; -				// increase pelvis lag time when moving slowly -				pelvis_lag_time *= clamp_rescale(mSpeedAccum, 0.f, 15.f, 3.f, 1.f); -			} -			else -			{ -				pelvis_lag_time = PELVIS_LAG_WALKING; -			} - -			F32 u = llclamp((deltaTime / pelvis_lag_time), 0.0f, 1.0f);	 - -			mRoot->setWorldRotation( slerp(u, mRoot->getWorldRotation(), wQv) ); -			 +            // Rotation fixups for avatars in motion. +            // Skip for animated objects. +            updateOrientation(agent, speed, delta_time);  		}  	}  	else if (mDrawable.notNull())  	{ +        // Sitting on an object - mRoot is slaved to mDrawable orientation.  		LLVector3 pos = mDrawable->getPosition();  		pos += getHoverOffset() * mDrawable->getRotation();  		// SL-315  		mRoot->setPosition(pos);  		mRoot->setRotation(mDrawable->getRotation());  	} +} + +//------------------------------------------------------------------------ +// updateCharacter() +// +// This is called for all avatars, so there are 4 possible situations: +// +// 1) Avatar is your own. In this case the class is LLVOAvatarSelf, +// isSelf() is true, and agent specifies the corresponding agent +// information for you. In all the other cases, agent is irrelevant +// and it would be less confusing if it were null or something. +// +// 2) Avatar is controlled by another resident. Class is LLVOAvatar, +// and isSelf() is false. +// +// 3) Avatar is the controller for an animated object. Class is +// LLControlAvatar and mIsDummy is true. Avatar is a purely +// viewer-side entity with no representation on the simulator. +// +// 4) Avatar is a UI avatar used in some areas of the UI, such as when +// previewing uploaded animations. Class is LLUIAvatar, and mIsDummy +// is true. Avatar is purely viewer-side with no representation on the +// simulator. +// +//------------------------------------------------------------------------ +BOOL LLVOAvatar::updateCharacter(LLAgent &agent) +{	 +	updateDebugText(); +	 +	if (!mIsBuilt) +	{ +		return FALSE; +	} + +	BOOL visible = isVisible(); +    bool is_control_avatar = isControlAvatar(); // capture state to simplify tracing +	bool is_attachment = false; +	if (is_control_avatar) +	{ +        LLControlAvatar *cav = dynamic_cast<LLControlAvatar*>(this); +		is_attachment = cav && cav->mRootVolp && cav->mRootVolp->isAttachment(); // For attached animated objects +	} + +    LLScopedContextString str("updateCharacter " + getFullname() + " is_control_avatar " +                              + boost::lexical_cast<std::string>(is_control_avatar)  +                              + " is_attachment " + boost::lexical_cast<std::string>(is_attachment)); + +	// For fading out the names above heads, only let the timer +	// run if we're visible. +	if (mDrawable.notNull() && !visible) +	{ +		mTimeVisible.reset(); +	} + +	//-------------------------------------------------------------------- +	// The rest should only be done occasionally for far away avatars. +    // Set mUpdatePeriod and visible based on distance and other criteria. +	//-------------------------------------------------------------------- +    computeUpdatePeriod(); +    visible = (LLDrawable::getCurrentFrame()+mID.mData[0])%mUpdatePeriod == 0 ? TRUE : FALSE; + +	//-------------------------------------------------------------------- +    // Early out if not visible and not self +	// don't early out for your own avatar, as we rely on your animations playing reliably +	// for example, the "turn around" animation when entering customize avatar needs to trigger +	// even when your avatar is offscreen +	//-------------------------------------------------------------------- +	if (!visible && !isSelf()) +	{ +		updateMotions(LLCharacter::HIDDEN_UPDATE); +		return FALSE; +	} + +	//-------------------------------------------------------------------- +	// change animation time quanta based on avatar render load +	//-------------------------------------------------------------------- +    // SL-763 the time step quantization does not currently work. +    //updateTimeStep(); +     +	//-------------------------------------------------------------------- +    // Update sitting state based on parent and active animation info. +	//-------------------------------------------------------------------- +	if (getParent() && !isSitting()) +	{ +		sitOnObject((LLViewerObject*)getParent()); +	} +	else if (!getParent() && isSitting() && !isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED)) +	{ +		getOffObject(); +	} + +	//-------------------------------------------------------------------- +	// create local variables in world coords for region position values +	//-------------------------------------------------------------------- +	LLVector3 xyVel = getVelocity(); +	xyVel.mV[VZ] = 0.0f; +	F32 speed = xyVel.length(); +	// remembering the value here prevents a display glitch if the +	// animation gets toggled during this update. +	bool was_sit_ground_constrained = isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED); + +	//-------------------------------------------------------------------- +    // This does a bunch of state updating, including figuring out +    // whether av is in the air, setting mRoot position and rotation +    // In some cases, calls updateOrientation() for a lot of the +    // work +    // -------------------------------------------------------------------- +    updateRootPositionAndRotation(agent, speed, was_sit_ground_constrained);  	//-------------------------------------------------------------------------  	// Update character motions @@ -3904,7 +4214,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)  	}  	// Special handling for sitting on ground. -	if (!getParent() && (mIsSitting || was_sit_ground_constrained)) +	if (!getParent() && (isSitting() || was_sit_ground_constrained))  	{  		F32 off_z = LLVector3d(getHoverOffset()).mdV[VZ]; @@ -3921,90 +4231,18 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)  	// update head position  	updateHeadOffset(); -	//------------------------------------------------------------------------- -	// Find the ground under each foot, these are used for a variety -	// of things that follow -	//------------------------------------------------------------------------- -	LLVector3 ankle_left_pos_agent = mFootLeftp->getWorldPosition(); -	LLVector3 ankle_right_pos_agent = mFootRightp->getWorldPosition(); - -	LLVector3 ankle_left_ground_agent = ankle_left_pos_agent; -	LLVector3 ankle_right_ground_agent = ankle_right_pos_agent; -	resolveHeightAgent(ankle_left_pos_agent, ankle_left_ground_agent, normal); -	resolveHeightAgent(ankle_right_pos_agent, ankle_right_ground_agent, normal); - -	F32 leftElev = llmax(-0.2f, ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ]); -	F32 rightElev = llmax(-0.2f, ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]); - -	if (!mIsSitting) -	{ -		//------------------------------------------------------------------------- -		// Figure out which foot is on ground -		//------------------------------------------------------------------------- -		if (!mInAir) -		{ -			if ((leftElev < 0.0f) || (rightElev < 0.0f)) -			{ -				ankle_left_pos_agent = mFootLeftp->getWorldPosition(); -				ankle_right_pos_agent = mFootRightp->getWorldPosition(); -				leftElev = ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ]; -				rightElev = ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]; -			} -		} -	} -	 -	//-------------------------------------------------------------------------  	// Generate footstep sounds when feet hit the ground -	//------------------------------------------------------------------------- -	const LLUUID AGENT_FOOTSTEP_ANIMS[] = {ANIM_AGENT_WALK, ANIM_AGENT_RUN, ANIM_AGENT_LAND}; -	const S32 NUM_AGENT_FOOTSTEP_ANIMS = LL_ARRAY_SIZE(AGENT_FOOTSTEP_ANIMS); - -	if ( gAudiop && isAnyAnimationSignaled(AGENT_FOOTSTEP_ANIMS, NUM_AGENT_FOOTSTEP_ANIMS) ) -	{ -		BOOL playSound = FALSE; -		LLVector3 foot_pos_agent; - -		BOOL onGroundLeft = (leftElev <= 0.05f); -		BOOL onGroundRight = (rightElev <= 0.05f); - -		// did left foot hit the ground? -		if ( onGroundLeft && !mWasOnGroundLeft ) -		{ -			foot_pos_agent = ankle_left_pos_agent; -			playSound = TRUE; -		} - -		// did right foot hit the ground? -		if ( onGroundRight && !mWasOnGroundRight ) -		{ -			foot_pos_agent = ankle_right_pos_agent; -			playSound = TRUE; -		} - -		mWasOnGroundLeft = onGroundLeft; -		mWasOnGroundRight = onGroundRight; - -		if ( playSound ) -		{ -			const F32 STEP_VOLUME = 0.1f; -			const LLUUID& step_sound_id = getStepSound(); - -			LLVector3d foot_pos_global = gAgent.getPosGlobalFromAgent(foot_pos_agent); - -			if (LLViewerParcelMgr::getInstance()->canHearSound(foot_pos_global) -				&& !LLMuteList::getInstance()->isMuted(getID(), LLMute::flagObjectSounds)) -			{ -				gAudiop->triggerSound(step_sound_id, getID(), STEP_VOLUME, LLAudioEngine::AUDIO_TYPE_AMBIENT, foot_pos_global); -			} -		} -	} +    updateFootstepSounds(); +	// Update child joints as needed.  	mRoot->updateWorldMatrixChildren(); -	//mesh vertices need to be reskinned -	mNeedsSkin = TRUE; +	// System avatar mesh vertices need to be reskinned. +    mNeedsSkin = TRUE; +  	return TRUE;  } +  //-----------------------------------------------------------------------------  // updateHeadOffset()  //----------------------------------------------------------------------------- @@ -4019,7 +4257,7 @@ void LLVOAvatar::updateHeadOffset()  	{  		midEyePt = midEyePt * ~mDrawable->getWorldRotation();  	} -	if (mIsSitting) +	if (isSitting())  	{  		mHeadOffset = midEyePt;	  	} @@ -4115,7 +4353,7 @@ void LLVOAvatar::updateVisibility()  	if (mIsDummy)  	{ -		visible = TRUE; +		visible = FALSE;  	}  	else if (mDrawable.isNull())  	{ @@ -4229,7 +4467,8 @@ void LLVOAvatar::updateVisibility()  	}  	else  	{ -		if (mMeshValid && mMeshInvisibleTime.getElapsedTimeF32() > TIME_BEFORE_MESH_CLEANUP) +		if (mMeshValid && +            (isControlAvatar() || mMeshInvisibleTime.getElapsedTimeF32() > TIME_BEFORE_MESH_CLEANUP))  		{  			releaseMeshData();  		} @@ -4264,6 +4503,11 @@ U32 LLVOAvatar::renderSkinned()  		return num_indices;  	} +    if (mDrawable.isNull()) +    { +		return num_indices; +    } +  	LLFace* face = mDrawable->getFace(0);  	bool needs_rebuild = !face || !face->getVertexBuffer() || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY); @@ -4430,7 +4674,7 @@ U32 LLVOAvatar::renderSkinned()  		{  			if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender)  			{ -				if (isTextureVisible(TEX_HEAD_BAKED) || mIsDummy) +				if (isTextureVisible(TEX_HEAD_BAKED) || isUIAvatar())  				{  					LLViewerJoint* head_mesh = getViewerJoint(MESH_ID_HEAD);  					if (head_mesh) @@ -4440,7 +4684,7 @@ U32 LLVOAvatar::renderSkinned()  					first_pass = FALSE;  				}  			} -			if (isTextureVisible(TEX_UPPER_BAKED) || mIsDummy) +			if (isTextureVisible(TEX_UPPER_BAKED) || isUIAvatar())  			{  				LLViewerJoint* upper_mesh = getViewerJoint(MESH_ID_UPPER_BODY);  				if (upper_mesh) @@ -4450,7 +4694,7 @@ U32 LLVOAvatar::renderSkinned()  				first_pass = FALSE;  			} -			if (isTextureVisible(TEX_LOWER_BAKED) || mIsDummy) +			if (isTextureVisible(TEX_LOWER_BAKED) || isUIAvatar())  			{  				LLViewerJoint* lower_mesh = getViewerJoint(MESH_ID_LOWER_BODY);  				if (lower_mesh) @@ -4479,7 +4723,7 @@ U32 LLVOAvatar::renderSkinned()  U32 LLVOAvatar::renderTransparent(BOOL first_pass)  {  	U32 num_indices = 0; -	if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (mIsDummy || isTextureVisible(TEX_SKIRT_BAKED)) ) +	if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (isUIAvatar() || isTextureVisible(TEX_SKIRT_BAKED)) )  	{  		gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.25f);  		LLViewerJoint* skirt_mesh = getViewerJoint(MESH_ID_SKIRT); @@ -4507,18 +4751,15 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass)  			}  			first_pass = FALSE;  		} -		// Can't test for baked hair being defined, since that won't always be the case (not all viewers send baked hair) -		// TODO: 1.25 will be able to switch this logic back to calling isTextureVisible(); -		if ( (getImage(TEX_HAIR_BAKED, 0) && getImage(TEX_HAIR_BAKED, 0)->getID() != IMG_INVISIBLE) -			|| LLDrawPoolAlpha::sShowDebugAlpha)		 -		{ -			LLViewerJoint* hair_mesh = getViewerJoint(MESH_ID_HAIR); -			if (hair_mesh) -			{ -				num_indices += hair_mesh->render(mAdjustedPixelArea, first_pass, mIsDummy); -			} -			first_pass = FALSE; -		} +		if (isTextureVisible(TEX_HAIR_BAKED)) +        { +            LLViewerJoint* hair_mesh = getViewerJoint(MESH_ID_HAIR); +            if (hair_mesh) +            { +                num_indices += hair_mesh->render(mAdjustedPixelArea, first_pass, mIsDummy); +            } +            first_pass = FALSE; +        }  		if (LLPipeline::sImpostorRender)  		{  			gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); @@ -4558,7 +4799,7 @@ U32 LLVOAvatar::renderRigid()  		gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);  	} -	if (isTextureVisible(TEX_EYES_BAKED)  || mIsDummy) +	if (isTextureVisible(TEX_EYES_BAKED)  || isUIAvatar())  	{  		LLViewerJoint* eyeball_left = getViewerJoint(MESH_ID_EYEBALL_LEFT);  		LLViewerJoint* eyeball_right = getViewerJoint(MESH_ID_EYEBALL_RIGHT); @@ -5105,10 +5346,13 @@ void LLVOAvatar::processAnimationStateChanges()  		startMotion(ANIM_AGENT_WALK_ADJUST);  		stopMotion(ANIM_AGENT_FLY_ADJUST);  	} -	else if (mInAir && !mIsSitting) +	else if (mInAir && !isSitting())  	{  		stopMotion(ANIM_AGENT_WALK_ADJUST); -		startMotion(ANIM_AGENT_FLY_ADJUST); +        if (mEnableDefaultMotions) +        { +            startMotion(ANIM_AGENT_FLY_ADJUST); +        }  	}  	else  	{ @@ -5118,13 +5362,19 @@ void LLVOAvatar::processAnimationStateChanges()  	if ( isAnyAnimationSignaled(AGENT_GUN_AIM_ANIMS, NUM_AGENT_GUN_AIM_ANIMS) )  	{ -		startMotion(ANIM_AGENT_TARGET); +        if (mEnableDefaultMotions) +        { +            startMotion(ANIM_AGENT_TARGET); +        }  		stopMotion(ANIM_AGENT_BODY_NOISE);  	}  	else  	{  		stopMotion(ANIM_AGENT_TARGET); -		startMotion(ANIM_AGENT_BODY_NOISE); +        if (mEnableDefaultMotions) +        { +            startMotion(ANIM_AGENT_BODY_NOISE); +        }  	}  	// clear all current animations @@ -5483,14 +5733,14 @@ bool LLVOAvatar::getRiggedMeshID(LLViewerObject* pVO, LLUUID& mesh_id)  		LLVOVolume* pVObj = pVO->mDrawable->getVOVolume();  		if ( pVObj )  		{ -			const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( pVObj->getVolume()->getParams().getSculptID(), pVObj ); +			const LLMeshSkinInfo* pSkinData = pVObj->getSkinInfo();  			if (pSkinData   				&& pSkinData->mJointNames.size() > JOINT_COUNT_REQUIRED_FOR_FULLRIG	// full rig  				&& pSkinData->mAlternateBindMatrix.size() > 0 ) -					{				 -						mesh_id = pSkinData->mMeshID; -						return true; -					} +            {				 +                mesh_id = pSkinData->mMeshID; +                return true; +            }  		}  	}  	return false; @@ -5537,8 +5787,7 @@ bool LLVOAvatar::jointIsRiggedTo(const std::string& joint_name, const LLViewerOb  		return false;  	} -	LLUUID currentId = vobj->getVolume()->getParams().getSculptID();						 -	const LLMeshSkinInfo*  pSkinData = gMeshRepo.getSkinInfo( currentId, vobj ); +	const LLMeshSkinInfo* pSkinData = vobj->getSkinInfo();  	if ( vobj && vobj->isAttachment() && vobj->isMesh() && pSkinData )  	{ @@ -5556,6 +5805,8 @@ void LLVOAvatar::clearAttachmentOverrides()  {      LLScopedContextString str("clearAttachmentOverrides " + getFullname()); +    mActiveOverrideMeshes.clear(); +          for (S32 i=0; i<LL_CHARACTER_MAX_ANIMATED_JOINTS; i++)      {          LLJoint *pJoint = getJoint(i); @@ -5565,6 +5816,17 @@ void LLVOAvatar::clearAttachmentOverrides()  			pJoint->clearAttachmentScaleOverrides();          }      } + +    if (mPelvisFixups.count()>0) +    { +        mPelvisFixups.clear(); +        LLJoint* pJointPelvis = getJoint("mPelvis"); +        if (pJointPelvis) +        { +			pJointPelvis->setPosition( LLVector3( 0.0f, 0.0f, 0.0f) ); +        } +        postPelvisSetRecalc();	 +    }  }  //----------------------------------------------------------------------------- @@ -5574,7 +5836,25 @@ void LLVOAvatar::rebuildAttachmentOverrides()  {      LLScopedContextString str("rebuildAttachmentOverrides " + getFullname()); -    // Attachment points +    LL_DEBUGS("AnimatedObjects") << "rebuilding" << LL_ENDL; +    dumpStack("AnimatedObjectsStack"); +     +    clearAttachmentOverrides(); + +    // Handle the case that we're resetting the skeleton of an animated object. +    LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this); +    if (control_av) +    { +        LLVOVolume *volp = control_av->mRootVolp; +        if (volp) +        { +            LL_DEBUGS("Avatar") << volp->getID() << " adding attachment overrides for root vol, prim count "  +                                << (S32) (1+volp->numChildren()) << LL_ENDL; +            addAttachmentOverridesForObject(volp); +        } +    } + +    // Attached objects  	for (attachment_map_t::iterator iter = mAttachmentPoints.begin();  		 iter != mAttachmentPoints.end();  		 ++iter) @@ -5585,33 +5865,170 @@ void LLVOAvatar::rebuildAttachmentOverrides()              for (LLViewerJointAttachment::attachedobjs_vec_t::iterator at_it = attachment_pt->mAttachedObjects.begin();  				 at_it != attachment_pt->mAttachedObjects.end(); ++at_it)              { -                addAttachmentOverridesForObject(*at_it); +                LLViewerObject *vo = *at_it; +                // Attached animated objects affect joints in their control +                // avs, not the avs to which they are attached. +                if (!vo->isAnimatedObject()) +                { +                    addAttachmentOverridesForObject(vo); +                }              }          }      }  } +  //----------------------------------------------------------------------------- -// addAttachmentPosOverridesForObject -//----------------------------------------------------------------------------- -void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo) +// updateAttachmentOverrides +// +// This is intended to give the same results as +// rebuildAttachmentOverrides(), while avoiding redundant work. +// ----------------------------------------------------------------------------- +void LLVOAvatar::updateAttachmentOverrides()  { -	LLVOAvatar *av = vo->getAvatarAncestor(); -	if (!av || (av != this)) +    const bool paranoid_checking = false; 	// AXON remove when testing done + +    if (paranoid_checking) +    { +        //dumpArchetypeXML(getFullname() + "_paranoid_before"); +    } + +    LLScopedContextString str("updateAttachmentOverrides " + getFullname()); + +    LL_DEBUGS("AnimatedObjects") << "updating" << LL_ENDL; +    dumpStack("AnimatedObjectsStack"); + +    std::set<LLUUID> meshes_seen; +     +    // Handle the case that we're updating the skeleton of an animated object. +    LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this); +    if (control_av) +    { +        LLVOVolume *volp = control_av->mRootVolp; +        if (volp) +        { +            LL_DEBUGS("Avatar") << volp->getID() << " adding attachment overrides for root vol, prim count "  +                                << (S32) (1+volp->numChildren()) << LL_ENDL; +            addAttachmentOverridesForObject(volp, &meshes_seen); +        } +    } + +    // Attached objects +	for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); +		 iter != mAttachmentPoints.end(); +		 ++iter)  	{ +		LLViewerJointAttachment *attachment_pt = (*iter).second; +        if (attachment_pt) +        { +            for (LLViewerJointAttachment::attachedobjs_vec_t::iterator at_it = attachment_pt->mAttachedObjects.begin(); +				 at_it != attachment_pt->mAttachedObjects.end(); ++at_it) +            { +                LLViewerObject *vo = *at_it; +                // Attached animated objects affect joints in their control +                // avs, not the avs to which they are attached. +                if (!vo->isAnimatedObject()) +                { +                    addAttachmentOverridesForObject(vo, &meshes_seen); +                } +            } +        } +    } +    // Remove meshes that are no longer present on the skeleton + +	// have to work with a copy because removeAttachmentOverrides() will change mActiveOverrideMeshes. +    std::set<LLUUID> active_override_meshes = mActiveOverrideMeshes;  +    for (std::set<LLUUID>::iterator it = active_override_meshes.begin(); it != active_override_meshes.end(); ++it) +    { +        if (meshes_seen.find(*it) == meshes_seen.end()) +        { +            removeAttachmentOverridesForObject(*it); +        } +    } + + +    if (paranoid_checking) +    { +        std::vector<LLVector3OverrideMap> pos_overrides_by_joint; +        std::vector<LLVector3OverrideMap> scale_overrides_by_joint; +        LLVector3OverrideMap pelvis_fixups; + +        // Capture snapshot of override state after update +        for (S32 joint_num = 0; joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS; joint_num++) +        { +            LLVector3OverrideMap pos_overrides; +            LLJoint *joint = getJoint(joint_num); +            if (joint) +            { +                pos_overrides_by_joint.push_back(joint->m_attachmentPosOverrides); +                scale_overrides_by_joint.push_back(joint->m_attachmentScaleOverrides); +            } +            else +            { +                // No joint, use default constructed empty maps +                pos_overrides_by_joint.push_back(LLVector3OverrideMap()); +                scale_overrides_by_joint.push_back(LLVector3OverrideMap()); +            } +        } +        pelvis_fixups = mPelvisFixups; +        //dumpArchetypeXML(getFullname() + "_paranoid_updated"); + +        // Rebuild and compare +        rebuildAttachmentOverrides(); +        //dumpArchetypeXML(getFullname() + "_paranoid_rebuilt"); +        bool mismatched = false; +        for (S32 joint_num = 0; joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS; joint_num++) +        { +            LLJoint *joint = getJoint(joint_num); +            if (joint) +            { +                if (pos_overrides_by_joint[joint_num] != joint->m_attachmentPosOverrides) +                { +                    mismatched = true; +                } +                if (scale_overrides_by_joint[joint_num] != joint->m_attachmentScaleOverrides) +                { +                    mismatched = true; +                } +            } +        } +        if (pelvis_fixups != mPelvisFixups) +        { +            mismatched = true; +        } +        if (mismatched) +        { +            LL_WARNS() << "MISMATCHED ATTACHMENT OVERRIDES, compare paranoid log files" << LL_ENDL; +        } +    } +} + +//----------------------------------------------------------------------------- +// addAttachmentOverridesForObject +//----------------------------------------------------------------------------- +void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo, std::set<LLUUID>* meshes_seen, bool recursive) +{ +    if (vo->getAvatar() != this && vo->getAvatarAncestor() != this) +    {  		LL_WARNS("Avatar") << "called with invalid avatar" << LL_ENDL;          return; -	} +    } -    LLScopedContextString str("addAttachmentOverridesForObject " + av->getFullname()); +    LLScopedContextString str("addAttachmentOverridesForObject " + getFullname()); +     +    LL_DEBUGS("AnimatedObjects") << "adding" << LL_ENDL; +    dumpStack("AnimatedObjectsStack");  	// Process all children -	LLViewerObject::const_child_list_t& children = vo->getChildren(); -	for (LLViewerObject::const_child_list_t::const_iterator it = children.begin(); -		 it != children.end(); ++it) -	{ -		LLViewerObject *childp = *it; -		addAttachmentOverridesForObject(childp); -	} +    if (recursive) +    { +        LLViewerObject::const_child_list_t& children = vo->getChildren(); +        for (LLViewerObject::const_child_list_t::const_iterator it = children.begin(); +             it != children.end(); ++it) +        { +            LLViewerObject *childp = *it; +            addAttachmentOverridesForObject(childp, meshes_seen, true); +        } +    }  	LLVOVolume *vobj = dynamic_cast<LLVOVolume*>(vo);  	bool pelvisGotSet = false; @@ -5620,15 +6037,18 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo)  	{  		return;  	} + +	LLViewerObject *root_object = (LLViewerObject*)vobj->getRoot(); +    LL_DEBUGS("AnimatedObjects") << "trying to add attachment overrides for root object " << root_object->getID() << " prim is " << vobj << LL_ENDL;  	if (vobj->isMesh() &&  		((vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded()) || !gMeshRepo.meshRezEnabled()))  	{ +        LL_DEBUGS("AnimatedObjects") << "failed to add attachment overrides for root object " << root_object->getID() << " mesh asset not loaded" << LL_ENDL;  		return;  	} -	LLUUID currentId = vobj->getVolume()->getParams().getSculptID();						 -	const LLMeshSkinInfo*  pSkinData = gMeshRepo.getSkinInfo( currentId, vobj ); +	const LLMeshSkinInfo*  pSkinData = vobj->getSkinInfo(); -	if ( vobj && vobj->isAttachment() && vobj->isMesh() && pSkinData ) +	if ( vobj && vobj->isMesh() && pSkinData )  	{  		const int bindCnt = pSkinData->mAlternateBindMatrix.size();								          const int jointCnt = pSkinData->mJointNames.size(); @@ -5640,9 +6060,29 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo)  		{					  			const F32 pelvisZOffset = pSkinData->mPelvisOffset;  			const LLUUID& mesh_id = pSkinData->mMeshID; + +            if (meshes_seen) +            { +                meshes_seen->insert(mesh_id); +            } +            bool mesh_overrides_loaded = (mActiveOverrideMeshes.find(mesh_id) != mActiveOverrideMeshes.end()); +            if (mesh_overrides_loaded) +            { +                LL_DEBUGS("AnimatedObjects") << "skipping add attachment overrides for " << mesh_id  +                                             << " to root object " << root_object->getID() +                                             << ", already loaded" +                                             << LL_ENDL; +            } +            else +            { +                LL_DEBUGS("AnimatedObjects") << "adding attachment overrides for " << mesh_id  +                                             << " to root object " << root_object->getID() << LL_ENDL; +            }  			bool fullRig = (jointCnt>=JOINT_COUNT_REQUIRED_FOR_FULLRIG) ? true : false;								 -			if ( fullRig ) +			if ( fullRig && !mesh_overrides_loaded )  			{								 +                mActiveOverrideMeshes.insert(mesh_id); +                  				for ( int i=0; i<jointCnt; ++i )  				{  					std::string lookingForJoint = pSkinData->mJointNames[i].c_str(); @@ -5688,6 +6128,10 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo)  			}							  		}  	} +    else +    { +        LL_DEBUGS("AnimatedObjects") << "failed to add attachment overrides for root object " << root_object->getID() << " not mesh or no pSkinData" << LL_ENDL; +    }  	//Rebuild body data if we altered joints/pelvis  	if ( pelvisGotSet )  @@ -5810,14 +6254,14 @@ void LLVOAvatar::showAttachmentOverrides(bool verbose) const  }  //----------------------------------------------------------------------------- -// resetJointsOnDetach +// removeAttachmentOverridesForObject  //----------------------------------------------------------------------------- -void LLVOAvatar::resetJointsOnDetach(LLViewerObject *vo) +void LLVOAvatar::removeAttachmentOverridesForObject(LLViewerObject *vo)  { -	LLVOAvatar *av = vo->getAvatarAncestor(); -	if (!av || (av != this)) +    if (vo->getAvatar() != this && vo->getAvatarAncestor() != this)  	{  		LL_WARNS("Avatar") << "called with invalid avatar" << LL_ENDL; +        return;  	}  	// Process all children @@ -5826,37 +6270,34 @@ void LLVOAvatar::resetJointsOnDetach(LLViewerObject *vo)  		 it != children.end(); ++it)  	{  		LLViewerObject *childp = *it; -		resetJointsOnDetach(childp); +		removeAttachmentOverridesForObject(childp);  	}  	// Process self.  	LLUUID mesh_id;  	if (getRiggedMeshID(vo,mesh_id))  	{ -		resetJointsOnDetach(mesh_id); +		removeAttachmentOverridesForObject(mesh_id);  	}  }  //----------------------------------------------------------------------------- -// resetJointsOnDetach +// removeAttachmentOverridesForObject  //----------------------------------------------------------------------------- -void LLVOAvatar::resetJointsOnDetach(const LLUUID& mesh_id) +void LLVOAvatar::removeAttachmentOverridesForObject(const LLUUID& mesh_id)  {	 -	//Subsequent joints are relative to pelvis -	avatar_joint_list_t::iterator iter = mSkeleton.begin(); -	avatar_joint_list_t::iterator end  = mSkeleton.end(); +    mActiveOverrideMeshes.erase(mesh_id);  	LLJoint* pJointPelvis = getJoint("mPelvis"); -	 -	for (; iter != end; ++iter) -	{ -		LLJoint* pJoint = (*iter); -		//Reset joints except for pelvis +    const std::string av_string = avString(); +    for (S32 joint_num = 0; joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS; joint_num++) +    { +        LLJoint *pJoint = getJoint(joint_num);  		if ( pJoint )  		{			              bool dummy; // unused -			pJoint->removeAttachmentPosOverride(mesh_id, avString(),dummy); -			pJoint->removeAttachmentScaleOverride(mesh_id, avString()); +			pJoint->removeAttachmentPosOverride(mesh_id, av_string, dummy); +			pJoint->removeAttachmentScaleOverride(mesh_id, av_string);  		}		  		if ( pJoint && pJoint == pJointPelvis)  		{ @@ -5918,7 +6359,7 @@ void LLVOAvatar::getGround(const LLVector3 &in_pos_agent, LLVector3 &out_pos_age  	LLVector3d z_vec(0.0f, 0.0f, 1.0f);  	LLVector3d p0_global, p1_global; -	if (mIsDummy) +	if (isUIAvatar())  	{  		outNorm.setVec(z_vec);  		out_pos_agent = in_pos_agent; @@ -5947,7 +6388,7 @@ F32 LLVOAvatar::getTimeDilation()  //-----------------------------------------------------------------------------  F32 LLVOAvatar::getPixelArea() const  { -	if (mIsDummy) +	if (isUIAvatar())  	{  		return 100000.f;  	} @@ -6362,7 +6803,7 @@ void LLVOAvatar::removeChild(LLViewerObject *childp)  LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* viewer_object)  { -	S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getState()); +	S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getAttachmentState());  	// This should never happen unless the server didn't process the attachment point  	// correctly, but putting this check in here to be safe. @@ -6425,6 +6866,11 @@ const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_o  		return 0;  	} +    if (!viewer_object->isAnimatedObject()) +    { +        updateAttachmentOverrides(); +    } +  	updateVisualComplexity();  	if (viewer_object->isSelected()) @@ -6454,19 +6900,63 @@ U32 LLVOAvatar::getNumAttachments() const  //-----------------------------------------------------------------------------  // canAttachMoreObjects() +// Returns true if we can attach <n> more objects.  //----------------------------------------------------------------------------- -BOOL LLVOAvatar::canAttachMoreObjects() const +BOOL LLVOAvatar::canAttachMoreObjects(U32 n) const  { -	return (getNumAttachments() < MAX_AGENT_ATTACHMENTS); +	return (getNumAttachments() + n) <= MAX_AGENT_ATTACHMENTS;  }  //----------------------------------------------------------------------------- -// canAttachMoreObjects() -// Returns true if we can attach <n> more objects. +// getNumAnimatedObjectAttachments()  //----------------------------------------------------------------------------- -BOOL LLVOAvatar::canAttachMoreObjects(U32 n) const +U32 LLVOAvatar::getNumAnimatedObjectAttachments() const  { -	return (getNumAttachments() + n) <= MAX_AGENT_ATTACHMENTS; +	U32 num_attachments = 0; +	for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); +		 iter != mAttachmentPoints.end(); +		 ++iter) +	{ +		const LLViewerJointAttachment *attachment_pt = (*iter).second; +		num_attachments += attachment_pt->getNumAnimatedObjects(); +	} +	return num_attachments; +} + +//----------------------------------------------------------------------------- +// getMaxAnimatedObjectAttachments() +// Gets from simulator feature if available, otherwise 0. +//----------------------------------------------------------------------------- +S32 LLVOAvatar::getMaxAnimatedObjectAttachments() const +{ +    S32 max_attach = 0; +    // AXON REMOVE AFTER SERVER TESTING DONE +    if (gSavedSettings.getBOOL("AnimatedObjectsIgnoreLimits")) +    { +        max_attach = MAX_AGENT_ATTACHMENTS; +    } +    else +    { +        if (gAgent.getRegion()) +        { +            LLSD features; +            gAgent.getRegion()->getSimulatorFeatures(features); +            if (features.has("AnimatedObjects")) +            { +                max_attach = features["AnimatedObjects"]["MaxAgentAnimatedObjectAttachments"].asInteger(); +            } +        } +    } +    return max_attach; +} + +//----------------------------------------------------------------------------- +// canAttachMoreAnimatedObjects() +// Returns true if we can attach <n> more animated objects. +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::canAttachMoreAnimatedObjects(U32 n) const +{ +	return (getNumAnimatedObjectAttachments() + n) <= getMaxAnimatedObjectAttachments();  }  //----------------------------------------------------------------------------- @@ -6557,7 +7047,7 @@ void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO )  	LLUUID mesh_id;  	if (getRiggedMeshID(pVO, mesh_id))  	{ -		resetJointsOnDetach(mesh_id); +        // FIXME this seems like an odd place for this code.  		if ( gAgentCamera.cameraCustomizeAvatar() )  		{  			gAgent.unpauseAnimation(); @@ -6582,9 +7072,13 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)  		if (attachment->isObjectAttached(viewer_object))  		{              updateVisualComplexity(); +            bool is_animated_object = viewer_object->isAnimatedObject();  			cleanupAttachedMesh( viewer_object ); -		  			attachment->removeObject(viewer_object); +            if (!is_animated_object) +            { +                updateAttachmentOverrides(); +            }  			LL_DEBUGS() << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << LL_ENDL;  			return TRUE;  		} @@ -6718,7 +7212,10 @@ void LLVOAvatar::getOffObject()  	mRoot->setRotation(cur_rotation_world);  	mRoot->getXform()->update(); -	startMotion(ANIM_AGENT_BODY_NOISE); +    if (mEnableDefaultMotions) +    { +        startMotion(ANIM_AGENT_BODY_NOISE); +    }  	if (isSelf())  	{ @@ -6876,6 +7373,12 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color)  	updateMeshTextures();  } +// FIXME: We have an mVisible member, set in updateVisibility(), but this +// function doesn't return it! isVisible() and mVisible are used +// different places for different purposes. mVisible seems to be more +// related to whether the actual avatar mesh is shown, and isVisible() +// to whether anything about the avatar is displayed in the scene. +// Maybe better naming could make this clearer?  BOOL LLVOAvatar::isVisible() const  {  	return mDrawable.notNull() @@ -6886,6 +7389,11 @@ BOOL LLVOAvatar::isVisible() const  // Determine if we have enough avatar data to render  bool LLVOAvatar::getIsCloud() const  { +	if (mIsDummy) +	{ +		return false; +	} +  	return (   ((const_cast<LLVOAvatar*>(this))->visualParamWeightsAreDefault())// Do we have a shape?  			|| (   !isTextureDefined(TEX_LOWER_BAKED)  				|| !isTextureDefined(TEX_UPPER_BAKED) @@ -7165,9 +7673,9 @@ bool LLVOAvatar::isTooComplex() const          // so that unlimited will completely disable the overly complex impostor rendering          // yes, this leaves them vulnerable to griefing objects... their choice          too_complex = (   max_render_cost > 0 -                       && (   mVisualComplexity > max_render_cost -                           || (max_attachment_area > 0.0f && mAttachmentSurfaceArea > max_attachment_area) -                           )); +                          && (mVisualComplexity > max_render_cost +                                 || (max_attachment_area > 0.0f && mAttachmentSurfaceArea > max_attachment_area) +                              ));  	}  	return too_complex; @@ -8804,6 +9312,7 @@ void LLVOAvatar::updateRegion(LLViewerRegion *regionp)  	LLViewerObject::updateRegion(regionp);  } +// virtual  std::string LLVOAvatar::getFullname() const  {  	std::string name; @@ -8850,6 +9359,11 @@ void LLVOAvatar::updateFreezeCounter(S32 counter)  BOOL LLVOAvatar::updateLOD()  { +    if (mDrawable.isNull()) +    { +        return FALSE; +    } +      	if (isImpostor() && 0 != mDrawable->getNumFaces() && mDrawable->getFace(0)->hasGeometry())  	{  		return TRUE; @@ -8890,10 +9404,10 @@ U32 LLVOAvatar::getPartitionType() const  void LLVOAvatar::updateImpostors()  {  	LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; -	LLCharacter::sAllowInstancesChange = FALSE; -	for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin(); -		iter != LLCharacter::sInstances.end(); ++iter) +    std::vector<LLCharacter*> instances_copy = LLCharacter::sInstances; +	for (std::vector<LLCharacter*>::iterator iter = instances_copy.begin(); +		iter != instances_copy.end(); ++iter)  	{  		LLVOAvatar* avatar = (LLVOAvatar*) *iter;  		if (!avatar->isDead() && avatar->isVisible() @@ -8990,6 +9504,17 @@ void LLVOAvatar::updateImpostorRendering(U32 newMaxNonImpostorsValue)  void LLVOAvatar::idleUpdateRenderComplexity()  { +    if (isControlAvatar()) +    { +        LLControlAvatar *cav = dynamic_cast<LLControlAvatar*>(this); +        bool is_attachment = cav && cav->mRootVolp && cav->mRootVolp->isAttachment(); // For attached animated objects +        if (is_attachment) +        { +            // ARC for animated object attachments is accounted with the avatar they're attached to. +            return; +        } +    } +      // Render Complexity      calculateUpdateRenderComplexity(); // Update mVisualComplexity if needed	 @@ -9037,10 +9562,16 @@ void LLVOAvatar::idleUpdateRenderComplexity()  		// Visual rank  		info_line = llformat("%d rank", mVisibilityRank);  		// Use grey for imposters, white for normal rendering or no impostors -		info_color.set(isImpostor() ? LLColor4::grey : LLColor4::white); +		info_color.set(isImpostor() ? LLColor4::grey : (isControlAvatar() ? LLColor4::yellow : LLColor4::white));  		info_style = LLFontGL::NORMAL;  		mText->addLine(info_line, info_color, info_style); +        // Triangle count +        mText->addLine(std::string("VisTris ") + LLStringOps::getReadableNumber(mAttachmentVisibleTriangleCount),  +                       info_color, info_style); +        mText->addLine(std::string("EstMaxTris ") + LLStringOps::getReadableNumber(mAttachmentEstTriangleCount),  +                       info_color, info_style); +  		// Attachment Surface Area  		static LLCachedControl<F32> max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit", 1000.0f);  		info_line = llformat("%.0f m^2", mAttachmentSurfaceArea); @@ -9059,22 +9590,13 @@ void LLVOAvatar::idleUpdateRenderComplexity()  			info_color.set(LLColor4::grey);  			info_style = LLFontGL::NORMAL;  		} +  		mText->addLine(info_line, info_color, info_style);  		updateText(); // corrects position  	}  } -void LLVOAvatar::addAttachmentArea(F32 delta_area) -{ -    mAttachmentSurfaceArea   += delta_area; -} - -void LLVOAvatar::subtractAttachmentArea(F32 delta_area) -{ -    mAttachmentSurfaceArea   = delta_area > mAttachmentSurfaceArea ? 0.0 : mAttachmentSurfaceArea - delta_area; -} -  void LLVOAvatar::updateVisualComplexity()  {  	LL_DEBUGS("AvatarRender") << "avatar " << getID() << " appearance changed" << LL_ENDL; @@ -9082,6 +9604,135 @@ void LLVOAvatar::updateVisualComplexity()  	mVisualComplexityStale = true;  } +// Account for the complexity of a single top-level object associated +// with an avatar. This will be either an attached object or an animated +// object. +void LLVOAvatar::accountRenderComplexityForObject( +    const LLViewerObject *attached_object, +    const F32 max_attachment_complexity, +    LLVOVolume::texture_cost_t& textures, +    U32& cost, +    hud_complexity_list_t& hud_complexity_list) +{ +    if (attached_object && !attached_object->isHUDAttachment()) +    { +        mAttachmentVisibleTriangleCount += attached_object->recursiveGetTriangleCount(); +        mAttachmentEstTriangleCount += attached_object->recursiveGetEstTrianglesMax(); +        mAttachmentSurfaceArea += attached_object->recursiveGetScaledSurfaceArea(); + +        textures.clear(); +        const LLDrawable* drawable = attached_object->mDrawable; +        if (drawable) +        { +            const LLVOVolume* volume = drawable->getVOVolume(); +            if (volume) +            { +                F32 attachment_total_cost = 0; +                F32 attachment_volume_cost = 0; +                F32 attachment_texture_cost = 0; +                F32 attachment_children_cost = 0; +                const F32 animated_object_attachment_surcharge = 1000; + +                if (attached_object->isAnimatedObject()) +                { +                    attachment_volume_cost += animated_object_attachment_surcharge; +                } +                attachment_volume_cost += volume->getRenderCost(textures); + +                const_child_list_t children = volume->getChildren(); +                for (const_child_list_t::const_iterator child_iter = children.begin(); +                     child_iter != children.end(); +                     ++child_iter) +                { +                    LLViewerObject* child_obj = *child_iter; +                    LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj ); +                    if (child) +                    { +                        attachment_children_cost += child->getRenderCost(textures); +                    } +                } + +                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 +                    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; +                // Limit attachment complexity to avoid signed integer flipping of the wearer's ACI +                cost += (U32)llclamp(attachment_total_cost, MIN_ATTACHMENT_COMPLEXITY, max_attachment_complexity); +            } +        } +    } +    if (isSelf() +        && attached_object +        && attached_object->isHUDAttachment() +        && !attached_object->isTempAttachment() +        && attached_object->mDrawable) +    { +        textures.clear(); + +        mAttachmentSurfaceArea += attached_object->recursiveGetScaledSurfaceArea(); + +        const LLVOVolume* volume = attached_object->mDrawable->getVOVolume(); +        if (volume) +        { +            LLHUDComplexity hud_object_complexity; +            hud_object_complexity.objectName = attached_object->getAttachmentItemName(); +            hud_object_complexity.objectId = attached_object->getAttachmentItemID(); +            std::string joint_name; +            gAgentAvatarp->getAttachedPointName(attached_object->getAttachmentItemID(), joint_name); +            hud_object_complexity.jointName = joint_name; +            // get cost and individual textures +            hud_object_complexity.objectsCost += volume->getRenderCost(textures); +            hud_object_complexity.objectsCount++; + +            LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); +            for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); +                 iter != child_list.end(); ++iter) +            { +                LLViewerObject* childp = *iter; +                const LLVOVolume* chld_volume = dynamic_cast<LLVOVolume*>(childp); +                if (chld_volume) +                { +                    // get cost and individual textures +                    hud_object_complexity.objectsCost += chld_volume->getRenderCost(textures); +                    hud_object_complexity.objectsCount++; +                } +            } + +            hud_object_complexity.texturesCount += textures.size(); + +            for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin(); +                 volume_texture != textures.end(); +                 ++volume_texture) +            { +                // add the cost of each individual texture (ignores duplicates) +                hud_object_complexity.texturesCost += volume_texture->second; +                LLViewerFetchedTexture *tex = LLViewerTextureManager::getFetchedTexture(volume_texture->first); +                if (tex) +                { +                    // Note: Texture memory might be incorect since texture might be still loading. +                    hud_object_complexity.texturesMemoryTotal += tex->getTextureMemory(); +                    if (tex->getOriginalHeight() * tex->getOriginalWidth() >= HUD_OVERSIZED_TEXTURE_DATA_SIZE) +                    { +                        hud_object_complexity.largeTexturesCount++; +                    } +                } +            } +            hud_complexity_list.push_back(hud_object_complexity); +        } +    } +} +  // Calculations for mVisualComplexity value  void LLVOAvatar::calculateUpdateRenderComplexity()  { @@ -9120,7 +9771,25 @@ void LLVOAvatar::calculateUpdateRenderComplexity()  		}          LL_DEBUGS("ARCdetail") << "Avatar body parts complexity: " << cost << LL_ENDL; +        mAttachmentVisibleTriangleCount = 0; +        mAttachmentEstTriangleCount = 0.f; +        mAttachmentSurfaceArea = 0.f; +         +        // A standalone animated object needs to be accounted for +        // using its associated volume. Attached animated objects +        // will be covered by the subsequent loop over attachments. +        LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this); +        if (control_av) +        { +            LLVOVolume *volp = control_av->mRootVolp; +            if (volp && !volp->isAttachment()) +            { +                accountRenderComplexityForObject(volp, max_attachment_complexity, +                                                 textures, cost, hud_complexity_list); +            } +        } +        // Account for complexity of all attachments.  		for (attachment_map_t::const_iterator attachment_point = mAttachmentPoints.begin();   			 attachment_point != mAttachmentPoints.end();  			 ++attachment_point) @@ -9131,112 +9800,8 @@ void LLVOAvatar::calculateUpdateRenderComplexity()  				 ++attachment_iter)  			{  				const LLViewerObject* attached_object = (*attachment_iter); -				if (attached_object && !attached_object->isHUDAttachment()) -				{ -					textures.clear(); -					const LLDrawable* drawable = attached_object->mDrawable; -					if (drawable) -					{ -						const LLVOVolume* volume = drawable->getVOVolume(); -						if (volume) -						{ -                            F32 attachment_total_cost = 0; -                            F32 attachment_volume_cost = 0; -                            F32 attachment_texture_cost = 0; -                            F32 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(); -								  child_iter != children.end(); -								  ++child_iter) -							{ -								LLViewerObject* child_obj = *child_iter; -								LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj ); -								if (child) -								{ -									attachment_children_cost += child->getRenderCost(textures); -								} -							} - -							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 -								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; -                            // Limit attachment complexity to avoid signed integer flipping of the wearer's ACI -                            cost += (U32)llclamp(attachment_total_cost, MIN_ATTACHMENT_COMPLEXITY, max_attachment_complexity); -						} -					} -				} -                if (isSelf() -                    && attached_object -                    && attached_object->isHUDAttachment() -                    && !attached_object->isTempAttachment() -                    && attached_object->mDrawable) -                { -                    textures.clear(); - -                    const LLVOVolume* volume = attached_object->mDrawable->getVOVolume(); -                    if (volume) -                    { -                        LLHUDComplexity hud_object_complexity; -                        hud_object_complexity.objectName = attached_object->getAttachmentItemName(); -                        hud_object_complexity.objectId = attached_object->getAttachmentItemID(); -                        std::string joint_name; -                        gAgentAvatarp->getAttachedPointName(attached_object->getAttachmentItemID(), joint_name); -                        hud_object_complexity.jointName = joint_name; -                        // get cost and individual textures -                        hud_object_complexity.objectsCost += volume->getRenderCost(textures); -                        hud_object_complexity.objectsCount++; - -                        LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); -                        for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); -                            iter != child_list.end(); ++iter) -                        { -                            LLViewerObject* childp = *iter; -                            const LLVOVolume* chld_volume = dynamic_cast<LLVOVolume*>(childp); -                            if (chld_volume) -                            { -                                // get cost and individual textures -                                hud_object_complexity.objectsCost += chld_volume->getRenderCost(textures); -                                hud_object_complexity.objectsCount++; -                            } -                        } - -                        hud_object_complexity.texturesCount += textures.size(); - -                        for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin(); -                            volume_texture != textures.end(); -                            ++volume_texture) -                        { -                            // add the cost of each individual texture (ignores duplicates) -                            hud_object_complexity.texturesCost += volume_texture->second; -                            LLViewerFetchedTexture *tex = LLViewerTextureManager::getFetchedTexture(volume_texture->first); -                            if (tex) -                            { -                                // Note: Texture memory might be incorect since texture might be still loading. -                                hud_object_complexity.texturesMemoryTotal += tex->getTextureMemory(); -                                if (tex->getOriginalHeight() * tex->getOriginalWidth() >= HUD_OVERSIZED_TEXTURE_DATA_SIZE) -                                { -                                    hud_object_complexity.largeTexturesCount++; -                                } -                            } -                        } -                        hud_complexity_list.push_back(hud_object_complexity); -                    } -                } +                accountRenderComplexityForObject(attached_object, max_attachment_complexity, +                                                 textures, cost, hud_complexity_list);  			}  		} diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index bd89d4ef23..cccf857eba 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -50,6 +50,8 @@  #include "llviewertexlayer.h"  #include "material_codes.h"		// LL_MCODE_END  #include "llviewerstats.h" +#include "llvovolume.h" +#include "llavatarrendernotifier.h"  extern const LLUUID ANIM_AGENT_BODY_NOISE;  extern const LLUUID ANIM_AGENT_BREATHE_ROT; @@ -169,7 +171,8 @@ public:  												 LLVector2* tex_coord = NULL,      // return the texture coordinates of the intersection point  												 LLVector4a* normal = NULL,         // return the surface normal at the intersection point  												 LLVector4a* tangent = NULL);     // return the surface tangent at the intersection point -	LLViewerObject*	lineSegmentIntersectRiggedAttachments(const LLVector4a& start, const LLVector4a& end, +	virtual LLViewerObject*	lineSegmentIntersectRiggedAttachments( +                                                 const LLVector4a& start, const LLVector4a& end,  												 S32 face = -1,                    // which face to check, -1 = ALL_SIDES  												 BOOL pick_transparent = FALSE,  												 BOOL pick_rigged = FALSE, @@ -200,18 +203,21 @@ public:  	virtual LLJoint*		getJoint(const std::string &name);  	LLJoint*		        getJoint(S32 num); -	 -	void 					addAttachmentOverridesForObject(LLViewerObject *vo); -	void					resetJointsOnDetach(const LLUUID& mesh_id); -	void					resetJointsOnDetach(LLViewerObject *vo); + +	void 					addAttachmentOverridesForObject(LLViewerObject *vo, std::set<LLUUID>* meshes_seen = NULL, bool recursive = true); +	void					removeAttachmentOverridesForObject(const LLUUID& mesh_id); +	void					removeAttachmentOverridesForObject(LLViewerObject *vo);      bool					jointIsRiggedTo(const std::string& joint_name);      bool					jointIsRiggedTo(const std::string& joint_name, const LLViewerObject *vo);  	void					clearAttachmentOverrides();  	void					rebuildAttachmentOverrides(); +    void					updateAttachmentOverrides();      void                    showAttachmentOverrides(bool verbose = false) const;      void                    getAttachmentOverrideNames(std::set<std::string>& pos_names,                                                          std::set<std::string>& scale_names) const; -	 + +    std::set<LLUUID>		mActiveOverrideMeshes; +      	/*virtual*/ const LLUUID&	getID() const;  	/*virtual*/ void			addDebugText(const std::string& text);  	/*virtual*/ F32				getTimeDilation(); @@ -233,6 +239,9 @@ public:  public:  	virtual bool 	isSelf() const { return false; } // True if this avatar is for this viewer's agent +	virtual bool 	isControlAvatar() const { return mIsControlAvatar; } // True if this avatar is a control av (no associated user) +	virtual bool 	isUIAvatar() const { return mIsUIAvatar; } // True if this avatar is a supplemental av used in some UI views (no associated user) +  private: //aligned members  	LL_ALIGN_16(LLVector4a	mImpostorExtents[2]); @@ -240,8 +249,16 @@ private: //aligned members  	// Updates  	//--------------------------------------------------------------------  public: -	void			updateDebugText(); +    void			updateAppearanceMessageDebugText(); +	void 			updateAnimationDebugText(); +	virtual void	updateDebugText();  	virtual BOOL 	updateCharacter(LLAgent &agent); +    void			updateFootstepSounds(); +    void			computeUpdatePeriod(); +    void			updateOrientation(LLAgent &agent, F32 speed, F32 delta_time); +    void			updateTimeStep(); +    void			updateRootPositionAndRotation(LLAgent &agent, F32 speed, bool was_sit_ground_constrained); +      	void 			idleUpdateVoiceVisualizer(bool voice_enabled);  	void 			idleUpdateMisc(bool detailed_update);  	virtual void	idleUpdateAppearanceAnimation(); @@ -259,14 +276,17 @@ public:  	static void		invalidateNameTags();  	void			addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font);  	void 			idleUpdateRenderComplexity(); +    void 			accountRenderComplexityForObject(const LLViewerObject *attached_object, +                                                     const F32 max_attachment_complexity, +                                                     LLVOVolume::texture_cost_t& textures, +                                                     U32& cost, +                                                     hud_complexity_list_t& hud_complexity_list);  	void			calculateUpdateRenderComplexity();  	static const U32 VISUAL_COMPLEXITY_UNKNOWN;  	void			updateVisualComplexity();  	U32				getVisualComplexity()			{ return mVisualComplexity;				};		// Numbers calculated here by rendering AV  	F32				getAttachmentSurfaceArea()		{ return mAttachmentSurfaceArea;		};		// estimated surface area of attachments -    void            addAttachmentArea(F32 delta_area); -    void            subtractAttachmentArea(F32 delta_area);  	U32				getReportedVisualComplexity()					{ return mReportedVisualComplexity;				};	// Numbers as reported by the SL server  	void			setReportedVisualComplexity(U32 value)			{ mReportedVisualComplexity = value;			}; @@ -422,6 +442,8 @@ public:    private:  	F32			mAttachmentSurfaceArea; //estimated surface area of attachments +    U32			mAttachmentVisibleTriangleCount; +    F32			mAttachmentEstTriangleCount;  	bool		shouldAlphaMask();  	BOOL 		mNeedsSkin; // avatar has been animated and verts have not been updated @@ -441,6 +463,14 @@ public:  	VisualMuteSettings		mVisuallyMuteSetting;			// Always or never visually mute this AV  	//-------------------------------------------------------------------- +	// animated object status +	//-------------------------------------------------------------------- +public: +    bool mIsControlAvatar; +    bool mIsUIAvatar; +    bool mEnableDefaultMotions; + +	//--------------------------------------------------------------------  	// Morph masks  	//--------------------------------------------------------------------  public: @@ -717,6 +747,7 @@ private:  public:  	BOOL			isVisible() const;  	void			setVisibilityRank(U32 rank); +    U32				getVisibilityRank() const { return mVisibilityRank; }  	static S32 		sNumVisibleAvatars; // Number of instances of this class  /**                    Appearance   **                                                                            ** @@ -739,9 +770,9 @@ public:  	static LLVOAvatar*  findAvatarFromAttachment(LLViewerObject* obj);  	/*virtual*/ BOOL	isWearingWearableType(LLWearableType::EType type ) const;  	LLViewerObject *	findAttachmentByID( const LLUUID & target_id ) const; +	LLViewerJointAttachment* getTargetAttachmentPoint(LLViewerObject* viewer_object);  protected: -	LLViewerJointAttachment* getTargetAttachmentPoint(LLViewerObject* viewer_object);  	void 				lazyAttach();  	void				rebuildRiggedAttachments( void ); @@ -761,10 +792,12 @@ public:  	BOOL 				hasHUDAttachment() const;  	LLBBox 				getHUDBBox() const;  	void 				resetHUDAttachments(); -	BOOL				canAttachMoreObjects() const; -	BOOL				canAttachMoreObjects(U32 n) const; +	BOOL				canAttachMoreObjects(U32 n=1) const; +    S32					getMaxAnimatedObjectAttachments() const; +    BOOL				canAttachMoreAnimatedObjects(U32 n=1) const;  protected:  	U32					getNumAttachments() const; // O(N), not O(1) +	U32					getNumAnimatedObjectAttachments() const; // O(N), not O(1)  /**                    Wearables   **                                                                            ** @@ -897,7 +930,7 @@ private:   **/  public: -	std::string		getFullname() const; // Returns "FirstName LastName" +	virtual std::string	getFullname() const; // Returns "FirstName LastName"  	std::string		avString() const; // Frequently used string in log messages "Avatar '<full name'"  protected:  	static void		getAnimLabels(std::vector<std::string>* labels); diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 10af524ee7..a2144d6466 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -2791,7 +2791,7 @@ BOOL LLVOAvatarSelf::needsRenderBeam()  		// don't render selection beam on hud objects  		is_touching_or_grabbing = FALSE;  	} -	return is_touching_or_grabbing || (mState & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection()); +	return is_touching_or_grabbing || (getAttachmentState() & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection());  }  // static diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index de63a3963c..5def0f0c0f 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -92,7 +92,7 @@ LLVOGrass::~LLVOGrass()  void LLVOGrass::updateSpecies()  { -	mSpecies = mState; +	mSpecies = getAttachmentState();  	if (!sSpeciesTable.count(mSpecies))  	{ diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index c1ecfd07c1..b60ff6d280 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -76,8 +76,14 @@  #include "lldatapacker.h"  #include "llviewershadermgr.h"  #include "llvoavatar.h" +#include "llcontrolavatar.h" +#include "llvoavatarself.h"  #include "llvocache.h"  #include "llmaterialmgr.h" +#include "llanimationstates.h" +#include "llinventorytype.h" +#include "llviewerinventory.h" +#include "llcallstack.h"  const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;  const F32 FORCE_CULL_AREA = 8.f; @@ -307,6 +313,7 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,  										  U32 block_num, EObjectUpdateType update_type,  										  LLDataPacker *dp)  { +	 	  	LLColor4U color;  	const S32 teDirtyBits = (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR|TEM_CHANGE_MEDIA); @@ -320,6 +327,9 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,  		LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);  		sculpt_id = sculpt_params->getSculptTexture();  		sculpt_type = sculpt_params->getSculptType(); + +        LL_DEBUGS("ObjectUpdate") << "uuid " << mID << " set sculpt_id " << sculpt_id << LL_ENDL; +        dumpStack("ObjectUpdateStack");  	}  	if (!dp) @@ -1101,16 +1111,34 @@ void LLVOVolume::updateSculptTexture()  } +void LLVOVolume::updateVisualComplexity() +{ +    LLVOAvatar* avatar = getAvatarAncestor(); +    if (avatar) +    { +        avatar->updateVisualComplexity(); +    } +    LLVOAvatar* rigged_avatar = getAvatar(); +    if(rigged_avatar && (rigged_avatar != avatar)) +    { +        rigged_avatar->updateVisualComplexity(); +    } +} +  void LLVOVolume::notifyMeshLoaded()  {   	mSculptChanged = TRUE;  	gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); -	LLVOAvatar* avatar = getAvatar(); -	if (avatar) -	{ -		avatar->updateVisualComplexity(); -	} +    if (getAvatar() && !isAnimatedObject()) +    { +        getAvatar()->addAttachmentOverridesForObject(this); +    } +    if (getControlAvatar() && isAnimatedObject()) +    { +        getControlAvatar()->addAttachmentOverridesForObject(this); +    } +    updateVisualComplexity();  }  // sculpt replaces generate() for sculpted surfaces @@ -1222,16 +1250,16 @@ void LLVOVolume::sculpt()  S32	LLVOVolume::computeLODDetail(F32 distance, F32 radius)  {  	S32	cur_detail; -	if (LLPipeline::sDynamicLOD) -	{ -		// We've got LOD in the profile, and in the twist.  Use radius. -		F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance; -		cur_detail = LLVolumeLODGroup::getDetailFromTan(ll_round(tan_angle, 0.01f)); -	} -	else -	{ -		cur_detail = llclamp((S32) (sqrtf(radius)*LLVOVolume::sLODFactor*4.f), 0, 3);		 -	} +    if (LLPipeline::sDynamicLOD) +    { +        // We've got LOD in the profile, and in the twist.  Use radius. +        F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance; +        cur_detail = LLVolumeLODGroup::getDetailFromTan(ll_round(tan_angle, 0.01f)); +    } +    else +    { +        cur_detail = llclamp((S32) (sqrtf(radius)*LLVOVolume::sLODFactor*4.f), 0, 3);		 +    }  	return cur_detail;  } @@ -1259,11 +1287,21 @@ BOOL LLVOVolume::calcLOD()  		distance = avatar->mDrawable->mDistanceWRTCamera;  		radius = avatar->getBinRadius(); +        if (distance <= 0.f || radius <= 0.f) +        { +            LL_DEBUGS("CalcLOD") << "avatar distance/radius uninitialized, skipping" << LL_ENDL; +            return FALSE; +        }  	}  	else  	{  		distance = mDrawable->mDistanceWRTCamera;  		radius = getVolume() ? getVolume()->mLODScaleBias.scaledVec(getScale()).length() : getScale().length(); +        if (distance <= 0.f || radius <= 0.f) +        { +            LL_DEBUGS("CalcLOD") << "non-avatar distance/radius uninitialized, skipping" << LL_ENDL; +            return FALSE; +        }  	}  	//hold onto unmodified distance for debugging @@ -1285,22 +1323,37 @@ BOOL LLVOVolume::calcLOD()  	distance *= F_PI/3.f;  	cur_detail = computeLODDetail(ll_round(distance, 0.01f),  -									ll_round(radius, 0.01f)); - +                                  ll_round(radius, 0.01f)); +    if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TRIANGLE_COUNT) && mDrawable->getFace(0)) +    { +        if (isRootEdit()) +        { +            S32 total_tris = recursiveGetTriangleCount(); +            S32 est_max_tris = recursiveGetEstTrianglesMax(); +            setDebugText(llformat("TRIS SHOWN %d EST %d", total_tris, est_max_tris)); +        } +    }  	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO) &&  		mDrawable->getFace(0))  	{ -		//setDebugText(llformat("%.2f:%.2f, %d", mDrawable->mDistanceWRTCamera, radius, cur_detail)); - -		setDebugText(llformat("%d", mDrawable->getFace(0)->getTextureIndex())); +        // This is a debug display for LODs. Please don't put the texture index here. +        setDebugText(llformat("%d", cur_detail));  	}  	if (cur_detail != mLOD)  	{ +        LL_DEBUGS("CalcLOD") << "new LOD " << cur_detail << " change from " << mLOD  +                             << " distance " << distance << " radius " << radius << " rampDist " << rampDist +                             << " drawable rigged? " << (mDrawable ? (S32) mDrawable->isState(LLDrawable::RIGGED) : (S32) -1) +							 << " mRiggedVolume " << (void*)getRiggedVolume() +                             << " distanceWRTCamera " << (mDrawable ? mDrawable->mDistanceWRTCamera : -1.f) +                             << LL_ENDL; +          		mAppAngle = ll_round((F32) atan2( mDrawable->getRadius(), mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f);  		mLOD = cur_detail;		 -		return TRUE; + +        return TRUE;  	}  	return FALSE; @@ -1317,6 +1370,16 @@ BOOL LLVOVolume::updateLOD()  	if (lod_changed)  	{ +        if (debugLoggingEnabled("AnimatedObjectsLinkset")) +        { +            if (isAnimatedObject() && isRiggedMesh()) +            { +                std::string vobj_name = llformat("Vol%p", this); +                F32 est_tris = getEstTrianglesMax(); +                LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " updateLOD to " << getLOD() << ", tris " << est_tris << LL_ENDL;  +            } +        } +  		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);  		mLODChanged = TRUE;  	} @@ -1391,7 +1454,8 @@ void LLVOVolume::updateFaceFlags()  BOOL LLVOVolume::setParent(LLViewerObject* parent)  {  	BOOL ret = FALSE ; -	if (parent != getParent()) +    LLViewerObject *old_parent = (LLViewerObject*) getParent(); +	if (parent != old_parent)  	{  		ret = LLViewerObject::setParent(parent);  		if (ret && mDrawable) @@ -1399,6 +1463,7 @@ BOOL LLVOVolume::setParent(LLViewerObject* parent)  			gPipeline.markMoved(mDrawable);  			gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);  		} +        onReparent(old_parent, parent);  	}  	return ret ; @@ -1463,14 +1528,29 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)  	BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED); -	//	bool rigged = false; +    if (getRiggedVolume()) +    { +        // MAINT-8264 - better to use the existing call in calling +        // func LLVOVolume::updateGeometry() if we can detect when +        // updates needed, set REBUILD_RIGGED accordingly. + +        // Without the flag, this will remove unused rigged volumes, which we are not currently very aggressive about. +        updateRiggedVolume(); +    } +      	LLVolume* volume = mRiggedVolume;  	if (!volume)  	{  		volume = getVolume();  	} -	// There's no guarantee that getVolume()->getNumFaces() == mDrawable->getNumFaces() +    bool any_valid_boxes = false; +     +    if (getRiggedVolume()) +    { +        LL_DEBUGS("RiggedBox") << "rebuilding box, volume face count " << getVolume()->getNumVolumeFaces() << " drawable face count " << mDrawable->getNumFaces() << LL_ENDL; +    } +    // There's no guarantee that getVolume()->getNumFaces() == mDrawable->getNumFaces()  	for (S32 i = 0;  		 i < getVolume()->getNumVolumeFaces() && i < mDrawable->getNumFaces() && i < getNumTEs();  		 i++) @@ -1480,16 +1560,28 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)  		{  			continue;  		} -		res &= face->genVolumeBBoxes(*volume, i, -										mRelativeXform,  -										(mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global); + +        BOOL face_res = face->genVolumeBBoxes(*volume, i, +                                              mRelativeXform,  +                                              (mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global); +        res &= face_res; // note that this result is never used +        // MAINT-8264 - ignore bboxes of ill-formed faces. +        if (!face_res) +        { +            continue; +        }  		if (rebuild)  		{ -			if (i == 0) +            if (getRiggedVolume()) +            { +                LL_DEBUGS("RiggedBox") << "rebuilding box, face " << i << " extents " << face->mExtents[0] << ", " << face->mExtents[1] << LL_ENDL; +            } +			if (!any_valid_boxes)  			{  				min = face->mExtents[0];  				max = face->mExtents[1]; +                any_valid_boxes = true;  			}  			else  			{ @@ -1498,17 +1590,28 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)  			}  		}  	} -	 -	if (rebuild) -	{ -		mDrawable->setSpatialExtents(min,max); -		min.add(max); -		min.mul(0.5f); -		mDrawable->setPositionGroup(min);	 -	} -	updateRadius(); -	mDrawable->movePartition(); +    if (any_valid_boxes) +    { +        if (rebuild) +        { +            if (getRiggedVolume()) +            { +                LL_DEBUGS("RiggedBox") << "rebuilding got extents " << min << ", " << max << LL_ENDL; +            } +            mDrawable->setSpatialExtents(min,max); +            min.add(max); +            min.mul(0.5f); +            mDrawable->setPositionGroup(min);	 +        } + +        updateRadius(); +        mDrawable->movePartition(); +    } +    else +    { +        LL_DEBUGS("RiggedBox") << "genBBoxes failed to find any valid face boxes" << LL_ENDL; +    }  	return res;  } @@ -1656,6 +1759,11 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)  	if ((new_lod != old_lod) || mSculptChanged)  	{ +        if (mDrawable->isState(LLDrawable::RIGGED)) +        { +            updateVisualComplexity(); +        } +  		compiled = TRUE;  		sNumLODChanges += new_num_faces; @@ -3291,6 +3399,171 @@ BOOL LLVOVolume::setIsFlexible(BOOL is_flexible)  	return res;  } +const LLMeshSkinInfo* LLVOVolume::getSkinInfo() const +{ +    if (getVolume()) +    { +        return gMeshRepo.getSkinInfo(getVolume()->getParams().getSculptID(), this); +    } +    else +    { +        return NULL; +    } +} + +// virtual +BOOL LLVOVolume::isRiggedMesh() const +{ +    return isMesh() && getSkinInfo(); +} + +//---------------------------------------------------------------------------- +U32 LLVOVolume::getExtendedMeshFlags() const +{ +	const LLExtendedMeshParams *param_block =  +        (const LLExtendedMeshParams *)getParameterEntry(LLNetworkData::PARAMS_EXTENDED_MESH); +	if (param_block) +	{ +		return param_block->getFlags(); +	} +	else +	{ +		return 0; +	} +} + +void LLVOVolume::onSetExtendedMeshFlags(U32 flags) +{ + +    // The isAnySelected() check was needed at one point to prevent +    // graphics problems. These are now believed to be fixed so the +    // check has been disabled. +	if (/*!getRootEdit()->isAnySelected() &&*/ mDrawable.notNull()) +    { +        // Need to trigger rebuildGeom(), which is where control avatars get created/removed +        getRootEdit()->recursiveMarkForUpdate(TRUE); +    } +    if (isAttachment() && getAvatarAncestor()) +    { +        updateVisualComplexity(); +        if (flags & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG) +        { +            // Making a rigged mesh into an animated object +            getAvatarAncestor()->updateAttachmentOverrides(); +        } +        else +        { +            // Making an animated object into a rigged mesh +            getAvatarAncestor()->updateAttachmentOverrides(); +        } +    } +} + +void LLVOVolume::setExtendedMeshFlags(U32 flags) +{ +    U32 curr_flags = getExtendedMeshFlags(); +    if (curr_flags != flags) +    { +        bool in_use = true; +        setParameterEntryInUse(LLNetworkData::PARAMS_EXTENDED_MESH, in_use, true); +        LLExtendedMeshParams *param_block =  +            (LLExtendedMeshParams *)getParameterEntry(LLNetworkData::PARAMS_EXTENDED_MESH); +        if (param_block) +        { +            param_block->setFlags(flags); +        } +        parameterChanged(LLNetworkData::PARAMS_EXTENDED_MESH, true); +        LL_DEBUGS("AnimatedObjects") << this +                                     << " new flags " << flags << " curr_flags " << curr_flags +                                     << ", calling onSetExtendedMeshFlags()" +                                     << LL_ENDL; +        onSetExtendedMeshFlags(flags); +    } +} + +bool LLVOVolume::canBeAnimatedObject() const +{ +    F32 est_tris = recursiveGetEstTrianglesMax(); +    if (est_tris < 0 || est_tris > getAnimatedObjectMaxTris()) +    { +        return false; +    } +    return true; +} + +bool LLVOVolume::isAnimatedObject() const +{ +    LLVOVolume *root_vol = (LLVOVolume*)getRootEdit(); +    bool root_is_animated_flag = root_vol->getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; +    return root_is_animated_flag; +} + +// Called any time parenting changes for a volume. Update flags and +// control av accordingly.  This is called after parent has been +// changed to new_parent, but before new_parent's mChildList has changed. + +// virtual +void LLVOVolume::onReparent(LLViewerObject *old_parent, LLViewerObject *new_parent) +{ +    LLVOVolume *old_volp = dynamic_cast<LLVOVolume*>(old_parent); + +    if (new_parent && !new_parent->isAvatar()) +    { +        if (mControlAvatar.notNull()) +        { +            // Here an animated object is being made the child of some +            // other prim. Should remove the control av from the child. +            LLControlAvatar *av = mControlAvatar; +            mControlAvatar = NULL; +            av->markForDeath(); +        } +    } +    if (old_volp && old_volp->isAnimatedObject()) +    { +        if (old_volp->getControlAvatar()) +        { +            // We have been removed from an animated object, need to do cleanup. +            old_volp->getControlAvatar()->updateAttachmentOverrides(); +            old_volp->getControlAvatar()->updateAnimations(); +        } +    } +} + +// This needs to be called after onReparent(), because mChildList is +// not updated until the end of LLViewerObject::addChild() + +// virtual +void LLVOVolume::afterReparent() +{ +    { +        LL_DEBUGS("AnimatedObjects") << "new child added for parent "  +            << ((LLViewerObject*)getParent())->getID() << LL_ENDL; +    } +                                                                                              +    if (isAnimatedObject() && getControlAvatar()) +    { +        LL_DEBUGS("AnimatedObjects") << "adding attachment overrides, parent is animated object "  +            << ((LLViewerObject*)getParent())->getID() << LL_ENDL; + +        // MAINT-8239 - doing a full rebuild whenever parent is set +        // makes the joint overrides load more robustly. In theory, +        // addAttachmentOverrides should be sufficient, but in +        // practice doing a full rebuild helps compensate for +        // notifyMeshLoaded() not being called reliably enough. +         +        // was: getControlAvatar()->addAttachmentOverridesForObject(this); +        //getControlAvatar()->rebuildAttachmentOverrides(); +        getControlAvatar()->updateAnimations(); +    } +    else +    { +        LL_DEBUGS("AnimatedObjects") << "not adding overrides, parent: "  +                                     << ((LLViewerObject*)getParent())->getID()  +                                     << " isAnimated: "  << isAnimatedObject() << " cav " +                                     << getControlAvatar() << LL_ENDL; +    } +} +  //----------------------------------------------------------------------------  void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point) @@ -3352,7 +3625,7 @@ void LLVOVolume::updateRadius()  BOOL LLVOVolume::isAttachment() const  { -	return mState != 0 ; +	return mAttachmentState != 0 ;  }  BOOL LLVOVolume::isHUDAttachment() const @@ -3360,7 +3633,7 @@ BOOL LLVOVolume::isHUDAttachment() const  	// *NOTE: we assume hud attachment points are in defined range  	// since this range is constant for backwards compatibility  	// reasons this is probably a reasonable assumption to make -	S32 attachment_id = ATTACHMENT_ID_FROM_STATE(mState); +	S32 attachment_id = ATTACHMENT_ID_FROM_STATE(mAttachmentState);  	return ( attachment_id >= 31 && attachment_id <= 38 );  } @@ -3440,16 +3713,25 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const  		path_params = volume_params.getPathParams();  		profile_params = volume_params.getProfileParams(); -		F32 weighted_triangles = -1.0; -		getStreamingCost(NULL, NULL, &weighted_triangles); - -		if (weighted_triangles > 0.0) +        LLMeshCostData costs; +		if (getCostData(costs))  		{ -			num_triangles = (U32)(weighted_triangles);  +            if (isAnimatedObject() && isRiggedMesh()) +            { +                // Scaling here is to make animated object vs +                // non-animated object ARC proportional to the +                // corresponding calculations for streaming cost. +                num_triangles = (ANIMATED_OBJECT_COST_PER_KTRI * 0.001 * costs.getEstTrisForStreamingCost())/0.06; +            } +            else +            { +                F32 radius = getScale().length()*0.5f; +                num_triangles = costs.getRadiusWeightedTris(radius); +            }  		}  	} -	if (num_triangles == 0) +	if (num_triangles <= 0)  	{  		num_triangles = 4;  	} @@ -3463,12 +3745,11 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const  			S32 size = gMeshRepo.getMeshSize(volume_params.getSculptID(), getLOD());  			if ( size > 0)  			{ -				if (gMeshRepo.getSkinInfo(volume_params.getSculptID(), this)) +				if (isRiggedMesh())  				{  					// weighted attachment - 1 point for every 3 bytes  					weighted_mesh = 1;  				} -  			}  			else  			{ @@ -3637,6 +3918,14 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const  		shame += media_faces * ARC_MEDIA_FACE_COST;  	} +    // Streaming cost for animated objects includes a fixed cost +    // per linkset. Add a corresponding charge here translated into +    // triangles, but not weighted by any graphics properties. +    if (isAnimatedObject() && isRootEdit()) +    { +        shame += (ANIMATED_OBJECT_BASE_COST/0.06) * 5.0f; +    } +  	if (shame > mRenderComplexity_current)  	{  		mRenderComplexity_current = (S32)shame; @@ -3645,16 +3934,68 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const  	return (U32)shame;  } -F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const +F32 LLVOVolume::getEstTrianglesMax() const  { -	F32 radius = getScale().length()*0.5f; - -	if (isMesh()) +	if (isMesh() && getVolume())  	{ -		return gMeshRepo.getStreamingCost(getVolume()->getParams().getSculptID(), radius, bytes, visible_bytes, mLOD, unscaled_value); +		return gMeshRepo.getEstTrianglesMax(getVolume()->getParams().getSculptID());  	} -	else +    return 0.f; +} + +F32 LLVOVolume::getEstTrianglesStreamingCost() const +{ +	if (isMesh() && getVolume())  	{ +		return gMeshRepo.getEstTrianglesStreamingCost(getVolume()->getParams().getSculptID()); +	} +    return 0.f; +} + +F32 LLVOVolume::getStreamingCost() const +{ +	F32 radius = getScale().length()*0.5f; +    F32 linkset_base_cost = 0.f; + +    LLMeshCostData costs; +    if (getCostData(costs)) +    { +        if (isAnimatedObject() && isRootEdit()) +        { +            // Root object of an animated object has this to account for skeleton overhead. +            linkset_base_cost = ANIMATED_OBJECT_BASE_COST; +        } +        if (isMesh()) +        { +            if (isAnimatedObject() && isRiggedMesh()) +            { +                return linkset_base_cost + costs.getTriangleBasedStreamingCost(); +            } +            else +            { +                return linkset_base_cost + costs.getRadiusBasedStreamingCost(radius); +            } +        } +        else +        { +            return linkset_base_cost + costs.getRadiusBasedStreamingCost(radius); +        } +    } +    else +    { +        return 0.f; +    } +} + +// virtual +bool LLVOVolume::getCostData(LLMeshCostData& costs) const +{ +    if (isMesh()) +    { +        return gMeshRepo.getCostData(getVolume()->getParams().getSculptID(), costs); +    } +    else +    {  		LLVolume* volume = getVolume();  		S32 counts[4];  		LLVolume::getLoDTriangleCounts(volume->getParams(), counts); @@ -3665,8 +4006,8 @@ F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_v  		header["medium_lod"]["size"] = counts[2] * 10;  		header["high_lod"]["size"] = counts[3] * 10; -		return LLMeshRepository::getStreamingCost(header, radius, NULL, NULL, -1, unscaled_value); -	}	 +		return gMeshRepo.getCostData(header, costs); +    }  }  //static  @@ -3736,6 +4077,21 @@ void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_u  	{  		mVolumeImpl->onParameterChanged(param_type, data, in_use, local_origin);  	} +    if (!local_origin && param_type == LLNetworkData::PARAMS_EXTENDED_MESH) +    { +        U32 extended_mesh_flags = getExtendedMeshFlags(); +        bool enabled =  (extended_mesh_flags & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG); +        bool was_enabled = (getControlAvatar() != NULL); +        if (enabled != was_enabled) +        { +            LL_DEBUGS("AnimatedObjects") << this +                                         << " calling onSetExtendedMeshFlags, enabled " << (U32) enabled +                                         << " was_enabled " << (U32) was_enabled +                                         << " local_origin " << (U32) local_origin +                                         << LL_ENDL; +            onSetExtendedMeshFlags(extended_mesh_flags); +        } +    }  	if (mDrawable.notNull())  	{  		BOOL is_light = getIsLight(); @@ -3749,10 +4105,17 @@ void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_u  void LLVOVolume::setSelected(BOOL sel)  {  	LLViewerObject::setSelected(sel); -	if (mDrawable.notNull()) -	{ -		markForUpdate(TRUE); -	} +    if (isAnimatedObject()) +    { +        getRootEdit()->recursiveMarkForUpdate(TRUE); +    } +    else +    { +        if (mDrawable.notNull()) +        { +            markForUpdate(TRUE); +        } +    }  }  void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) @@ -3862,6 +4225,22 @@ const LLMatrix4& LLVOVolume::getWorldMatrix(LLXformMatrix* xform) const  	return xform->getWorldMatrix();  } +void LLVOVolume::markForUpdate(BOOL priority) +{  +    if (debugLoggingEnabled("AnimatedObjectsLinkset")) +    { +        if (isAnimatedObject() && isRiggedMesh()) +        { +            std::string vobj_name = llformat("Vol%p", this); +            F32 est_tris = getEstTrianglesMax(); +            LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " markForUpdate, tris " << est_tris << LL_ENDL;  +        } +    } + +    LLViewerObject::markForUpdate(priority);  +    mVolumeChanged = TRUE;  +} +  LLVector3 LLVOVolume::agentPositionToVolume(const LLVector3& pos) const  {  	LLVector3 ret = pos - getRenderPosition(); @@ -4114,9 +4493,9 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&  bool LLVOVolume::treatAsRigged()  {  	return isSelected() && -			isAttachment() && -			mDrawable.notNull() && -			mDrawable->isState(LLDrawable::RIGGED); +        (isAttachment() || isAnimatedObject()) && +        mDrawable.notNull() && +        mDrawable->isState(LLDrawable::RIGGED);  }  LLRiggedVolume* LLVOVolume::getRiggedVolume() @@ -4146,9 +4525,7 @@ void LLVOVolume::updateRiggedVolume(bool force_update)  	}  	LLVolume* volume = getVolume(); - -	const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(volume->getParams().getSculptID(), this); - +	const LLMeshSkinInfo* skin = getSkinInfo();  	if (!skin)  	{  		clearRiggedVolume(); @@ -4156,7 +4533,6 @@ void LLVOVolume::updateRiggedVolume(bool force_update)  	}  	LLVOAvatar* avatar = getAvatar(); -  	if (!avatar)  	{  		clearRiggedVolume(); @@ -4171,7 +4547,6 @@ void LLVOVolume::updateRiggedVolume(bool force_update)  	}  	mRiggedVolume->update(skin, avatar, volume); -  }  static LLTrace::BlockTimerStatHandle FTM_SKIN_RIGGED("Skin"); @@ -4201,6 +4576,21 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons  	{  		copyVolumeFaces(volume);	  	} +    else +    { +#if 1 +        bool is_paused = avatar && avatar->areAnimationsPaused(); +		if (is_paused) +		{ +            S32 frames_paused = LLFrameTimer::getFrameCount() - avatar->getMotionController().getPausedFrame(); +            if (frames_paused > 2) +            { +                return; +            } +		} +#endif +    } +  	//build matrix palette  	static const size_t kMaxJoints = LL_MAX_JOINTS_PER_MESH_OBJECT; @@ -4209,6 +4599,9 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons  	U32 maxJoints = LLSkinningUtil::getMeshJointCount(skin);      LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, maxJoints, skin, avatar); +    S32 rigged_vert_count = 0; +    S32 rigged_face_count = 0; +    LLVector4a box_min, box_max;  	for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)  	{  		const LLVolumeFace& vol_face = volume->getVolumeFace(i); @@ -4230,6 +4623,8 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons  				LL_RECORD_BLOCK_TIME(FTM_SKIN_RIGGED);                  U32 max_joints = LLSkinningUtil::getMaxJointCount(); +                rigged_vert_count += dst_face.mNumVertices; +                rigged_face_count++;  				for (U32 j = 0; j < dst_face.mNumVertices; ++j)  				{  					LLMatrix4a final_mat; @@ -4244,11 +4639,17 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons  				}  				//update bounding box +				// VFExtents change  				LLVector4a& min = dst_face.mExtents[0];  				LLVector4a& max = dst_face.mExtents[1];  				min = pos[0];  				max = pos[1]; +                if (i==0) +                { +                    box_min = min; +                    box_max = max; +                }  				for (U32 j = 1; j < dst_face.mNumVertices; ++j)  				{ @@ -4256,6 +4657,9 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons  					max.setMax(max, pos[j]);  				} +                box_min.setMin(min,box_min); +                box_max.setMax(max,box_max); +  				dst_face.mCenter->setAdd(dst_face.mExtents[0], dst_face.mExtents[1]);  				dst_face.mCenter->mul(0.5f); @@ -4274,6 +4678,10 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons  			}  		}  	} +    mExtraDebugText = llformat("rigged %d/%d - box (%f %f %f) (%f %f %f)", +                               rigged_face_count, rigged_vert_count, +                               box_min[0], box_min[1], box_min[2], +                               box_max[0], box_max[1], box_max[2]);  }  U32 LLVOVolume::getPartitionType() const @@ -4665,8 +5073,6 @@ static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj)  void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  { -	 -  	if (group->changeLOD())  	{  		group->mLastUpdateDistance = group->mDistance; @@ -4687,27 +5093,19 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  	group->mBuilt = 1.f; -	LLVOAvatar* pAvatarVO = NULL; -  	LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge(); -	if (bridge) -	{ -		if (bridge->mAvatar.isNull()) -		{ -			LLViewerObject* vobj = bridge->mDrawable->getVObj(); -			if (vobj) -			{ -				bridge->mAvatar = vobj->getAvatar(); -			} -		} +    LLViewerObject *vobj = NULL; +    LLVOVolume *vol_obj = NULL; -		pAvatarVO = bridge->mAvatar; -	} - -	if (pAvatarVO) +	if (bridge)  	{ -		pAvatarVO->subtractAttachmentArea( group->mSurfaceArea ); +        vobj = bridge->mDrawable->getVObj(); +        vol_obj = dynamic_cast<LLVOVolume*>(vobj);  	} +    if (vol_obj) +    { +        vol_obj->updateVisualComplexity(); +    }  	group->mGeometryBytes = 0;  	group->mSurfaceArea = 0; @@ -4750,7 +5148,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  		LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_FACE_LIST);  		//get all the faces into a list -		for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) +		for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin();  +             drawable_iter != group->getDataEnd(); ++drawable_iter)  		{  			LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); @@ -4765,12 +5164,14 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  			}  			LLVOVolume* vobj = drawablep->getVOVolume(); - +              			if (!vobj)  			{  				continue;  			} +            std::string vobj_name = llformat("Vol%p", vobj); +  			if (vobj->isMesh() &&  				((vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded()) || !gMeshRepo.meshRezEnabled()))  			{ @@ -4784,29 +5185,46 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  				group->mSurfaceArea += volume->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]);  			} +            bool is_mesh = vobj->isMesh(); +            F32 est_tris = vobj->getEstTrianglesMax(); + +            vobj->updateControlAvatar(); +             +            LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuilding, isAttachment: " << (U32) vobj->isAttachment() +                                                << " is_mesh " << is_mesh +                                                << " est_tris " << est_tris +                                                << " is_animated " << vobj->isAnimatedObject() +                                                << " can_animate " << vobj->canBeAnimatedObject()  +                                                << " cav " << vobj->getControlAvatar()  +                                                << " lod " << vobj->getLOD() +                                                << " drawable rigged " << (drawablep->isState(LLDrawable::RIGGED)) +                                                << " drawable state " << drawablep->getState() +                                                << " playing " << (U32) (vobj->getControlAvatar() ? vobj->getControlAvatar()->mPlaying : false) +                                                << " frame " << LLFrameTimer::getFrameCount() +                                                << LL_ENDL; +  			llassert_always(vobj);  			vobj->updateTextureVirtualSize(true);  			vobj->preRebuild();  			drawablep->clearState(LLDrawable::HAS_ALPHA); -			bool rigged = vobj->isAttachment() &&  -                          vobj->isMesh() &&  -						  gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj); - -			bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic(); - -			bool is_rigged = false; - -            if (rigged && pAvatarVO) +            if (vobj->isRiggedMesh() && +                ((vobj->isAnimatedObject() && vobj->getControlAvatar()) || +                 (!vobj->isAnimatedObject() && vobj->getAvatar())))              { -                pAvatarVO->addAttachmentOverridesForObject(vobj); -				if (!LLApp::isExiting() && pAvatarVO->isSelf() && debugLoggingEnabled("AvatarAttachments")) -                { -                    bool verbose = true; -					pAvatarVO->showAttachmentOverrides(verbose); -				} +                vobj->getAvatar()->addAttachmentOverridesForObject(vobj, NULL, false);              } +             +            // Standard rigged mesh attachments:  +			bool rigged = !vobj->isAnimatedObject() && vobj->isRiggedMesh() && vobj->isAttachment(); +            // Animated objects. Have to check for isRiggedMesh() to +            // exclude static objects in animated object linksets. +			rigged = rigged || (vobj->isAnimatedObject() && vobj->isRiggedMesh() && +                vobj->getControlAvatar() && vobj->getControlAvatar()->mPlaying); + +			bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic(); +			bool any_rigged_face = false;  			//for each face  			for (S32 i = 0; i < drawablep->getNumFaces(); i++) @@ -4824,7 +5242,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  				//sum up face verts and indices  				drawablep->updateFaceSize(i); -				if (rigged)  +				if (rigged)  				{  					if (!facep->isState(LLFace::RIGGED))  					{ //completely reset vertex buffer @@ -4832,7 +5250,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  					}  					facep->setState(LLFace::RIGGED); -					is_rigged = true; +					any_rigged_face = true;  					//get drawpool of avatar with rigged face  					LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);				 @@ -5176,7 +5594,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  				}		  			} -			if (is_rigged) +			if (any_rigged_face)  			{  				if (!drawablep->isState(LLDrawable::RIGGED))  				{ @@ -5190,6 +5608,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  			else  			{  				drawablep->clearState(LLDrawable::RIGGED); +                vobj->updateRiggedVolume();  			}  		}  	} @@ -5243,9 +5662,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  			LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();  			if(drawablep)  			{ -			drawablep->clearState(LLDrawable::REBUILD_ALL); -		} -	} +                drawablep->clearState(LLDrawable::REBUILD_ALL); +            } +        }  	}  	group->mLastUpdateTime = gFrameTimeSeconds; @@ -5258,11 +5677,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  	}  	mFaceList.clear(); - -	if (pAvatarVO) -	{ -        pAvatarVO->addAttachmentArea( group->mSurfaceArea ); -	}  }  static LLTrace::BlockTimerStatHandle FTM_REBUILD_MESH_FLUSH("Flush Mesh"); @@ -5291,6 +5705,17 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)  			if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) )  			{  				LLVOVolume* vobj = drawablep->getVOVolume(); + +                if (debugLoggingEnabled("AnimatedObjectsLinkset")) +                { +                    if (vobj->isAnimatedObject() && vobj->isRiggedMesh()) +                    { +                        std::string vobj_name = llformat("Vol%p", vobj); +                        F32 est_tris = vobj->getEstTrianglesMax(); +                        LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuildMesh, tris " << est_tris << LL_ENDL;  +                    } +                } +  				vobj->preRebuild();  				if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 1a7e49d198..ebf92acc4f 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -62,6 +62,8 @@ public:  	}  	void update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* src_volume); + +    std::string mExtraDebugText;  };  // Base class for implementations of the volume - Primitive, Flexible Object, etc. @@ -132,8 +134,10 @@ public:  	/*virtual*/	const LLMatrix4	getRenderMatrix() const;  				typedef std::map<LLUUID, S32> texture_cost_t;  				U32 	getRenderCost(texture_cost_t &textures) const; -				F32		getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const; -	/*virtual*/	F32		getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL) { return getStreamingCost(bytes, visible_bytes, NULL); } +    /*virtual*/	F32		getEstTrianglesMax() const; +    /*virtual*/	F32		getEstTrianglesStreamingCost() const; +    /* virtual*/ F32	getStreamingCost() const; +    /*virtual*/ bool getCostData(LLMeshCostData& costs) const;  	/*virtual*/ U32		getTriangleCount(S32* vcount = NULL) const;  	/*virtual*/ U32		getHighLODTriangleCount(); @@ -159,7 +163,7 @@ public:  	/*virtual*/ F32  	getRadius() const						{ return mVObjRadius; };  				const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const; -				void	markForUpdate(BOOL priority)			{ LLViewerObject::markForUpdate(priority); mVolumeChanged = TRUE; } +				void	markForUpdate(BOOL priority);  				void    faceMappingChanged()                    { mFaceMappingChanged=TRUE; };  	/*virtual*/ void	onShift(const LLVector4a &shift_vector); // Called when the drawable shifts @@ -259,12 +263,25 @@ public:  	virtual BOOL isFlexible() const;  	virtual BOOL isSculpted() const;  	virtual BOOL isMesh() const; +	virtual BOOL isRiggedMesh() const;  	virtual BOOL hasLightTexture() const; +      	BOOL isVolumeGlobal() const;  	BOOL canBeFlexible() const;  	BOOL setIsFlexible(BOOL is_flexible); +    const LLMeshSkinInfo* getSkinInfo() const; +     +    // Extended Mesh Properties +    U32 getExtendedMeshFlags() const; +    void onSetExtendedMeshFlags(U32 flags); +    void setExtendedMeshFlags(U32 flags); +    bool canBeAnimatedObject() const; +    bool isAnimatedObject() const; +    virtual void onReparent(LLViewerObject *old_parent, LLViewerObject *new_parent); +    virtual void afterReparent(); +      // Functions that deal with media, or media navigation      // Update this object's media data with the given media data array @@ -298,7 +315,10 @@ public:  	bool hasMedia() const;  	LLVector3 getApproximateFaceNormal(U8 face_id); -	 + +    // Flag any corresponding avatars as needing update. +    void updateVisualComplexity(); +      	void notifyMeshLoaded();  	// Returns 'true' iff the media data for this object is in flight diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 1d083bb2fd..740da863af 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -3350,6 +3350,18 @@ void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags f  {  	if (drawablep && !drawablep->isDead() && assertInitialized())  	{ +        if (debugLoggingEnabled("AnimatedObjectsLinkset")) +        { +            LLVOVolume *vol_obj = drawablep->getVOVolume(); +            if (vol_obj && vol_obj->isAnimatedObject() && vol_obj->isRiggedMesh()) +            { +                std::string vobj_name = llformat("Vol%p", vol_obj); +                F32 est_tris = vol_obj->getEstTrianglesMax(); +                LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " markRebuild, tris " << est_tris  +                                                    << " priority " << (S32) priority << " flag " << std::hex << flag << LL_ENDL;  +            } +        } +      		if (!drawablep->isState(LLDrawable::BUILT))  		{  			priority = true; diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index c9670a60f2..d7fbbdafb6 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -513,11 +513,11 @@ public:  		RENDER_DEBUG_TEXTURE_AREA		= 0x00000100,  		RENDER_DEBUG_FACE_AREA			= 0x00000200,  		RENDER_DEBUG_PARTICLES			= 0x00000400, -		RENDER_DEBUG_GLOW				= 0x00000800, +		RENDER_DEBUG_GLOW				= 0x00000800, // not used  		RENDER_DEBUG_TEXTURE_ANIM		= 0x00001000,  		RENDER_DEBUG_LIGHTS				= 0x00002000,  		RENDER_DEBUG_BATCH_SIZE			= 0x00004000, -		RENDER_DEBUG_ALPHA_BINS			= 0x00008000, +		RENDER_DEBUG_ALPHA_BINS			= 0x00008000, // not used  		RENDER_DEBUG_RAYCAST            = 0x00010000,  		RENDER_DEBUG_AVATAR_DRAW_INFO	= 0x00020000,  		RENDER_DEBUG_SHADOW_FRUSTA		= 0x00040000, @@ -531,8 +531,9 @@ public:  		RENDER_DEBUG_NORMALS	        = 0x04000000,  		RENDER_DEBUG_LOD_INFO	        = 0x08000000,  		RENDER_DEBUG_RENDER_COMPLEXITY  = 0x10000000, -		RENDER_DEBUG_ATTACHMENT_BYTES	= 0x20000000, -		RENDER_DEBUG_TEXEL_DENSITY		= 0x40000000 +		RENDER_DEBUG_ATTACHMENT_BYTES	= 0x20000000, // not used +		RENDER_DEBUG_TEXEL_DENSITY		= 0x40000000, +		RENDER_DEBUG_TRIANGLE_COUNT		= 0x80000000   	};  public: diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index ed3cc26851..63e2ed4bb9 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -2,7 +2,7 @@  <floater   positioning="cascading"   legacy_header_height="18" - height="590" + height="600"   layout="topleft"   bg_opaque_image="Window_NoTitle_Foreground"   bg_alpha_image="Window_NoTitle_Background" @@ -2131,7 +2131,7 @@ even though the user gets a free copy.          <panel           border="false"           follows="all" -         height="367" +         height="387"           label="Features"           layout="topleft"           left_delta="0" @@ -2169,13 +2169,23 @@ even though the user gets a free copy.                  Edit object features:              </text>              <check_box -             height="19" +             height="15" +             label="Animated Mesh" +             layout="topleft" +             left="10" +             name="Animated Mesh Checkbox Ctrl" +             tool_tip="Allows rigged mesh objects to be animated independently" +             top_pad="10" +             width="121" /> +            <check_box +             height="10"               label="Flexible Path" +             follows="left|top"               layout="topleft"               left="10"               name="Flexible1D Checkbox Ctrl"               tool_tip="Allows object to flex about the Z axis (Client-side only)" -             top_pad="20" +             top_pad="15"               width="121" />              <spinner               follows="left|top" diff --git a/indra/newview/skins/default/xui/en/menu_object.xml b/indra/newview/skins/default/xui/en/menu_object.xml index dc9622a27d..ce34508303 100644 --- a/indra/newview/skins/default/xui/en/menu_object.xml +++ b/indra/newview/skins/default/xui/en/menu_object.xml @@ -214,4 +214,20 @@      <menu_item_call.on_enable       function="EnableMuteParticle" />    </menu_item_call> +    <menu_item_call +		 label="Dump XML" +         name="Dump XML"> +            <menu_item_call.on_click +             function="Advanced.AppearanceToXML" /> +            <menu_item_call.on_visible +             function="Advanced.EnableAppearanceToXML"/> +    </menu_item_call> +    <menu_item_call +		 label="Reset Skeleton" +         name="Reset Skeleton"> +            <menu_item_call.on_click +                function="Avatar.ResetSkeleton" /> +            <menu_item_call.on_visible +             function="Avatar.EnableResetSkeleton"/> +    </menu_item_call>  </context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index dcd8f0b495..9051cbf2be 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2638,6 +2638,16 @@             parameter="lod info" />          </menu_item_check>          <menu_item_check +         label="Triangle Count" +         name="Triangle Count"> +          <menu_item_check.on_check +           function="Advanced.CheckInfoDisplay" +           parameter="triangle count" /> +          <menu_item_check.on_click +           function="Advanced.ToggleInfoDisplay" +           parameter="triangle count" /> +        </menu_item_check> +        <menu_item_check           label="Build Queue"           name="Build Queue">            <menu_item_check.on_check diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 6aa6653f42..671a185fe2 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -10197,6 +10197,14 @@ You have been teleported by the object '[OBJECT_NAME]' owned by an unknown user.  Unable to create requested object. The region is full.    </notification> +   <notification +    icon="alertmodal.tga" +   name="CantCreateAnimatedObjectTooLarge" +   type="notify"> +   <tag>fail</tag> +Unable to create requested animated object because it exceeds the rigged triangle limit. +  </notification> +    <notification     icon="alertmodal.tga"     name="CantAttackMultipleObjOneSpot" @@ -10327,6 +10335,46 @@ You are not allowed to change this shape.    <notification     icon="alertmodal.tga" +   name="NoPermsTooManyAttachedAnimatedObjects" +   type="notify"> +   <tag>fail</tag> +Operation would cause the number of attached animated objects to exceed the limit. +  </notification> + +  <notification +   icon="alertmodal.tga" +   name="NoPermsLinkAnimatedObjectTooLarge" +   type="notify"> +   <tag>fail</tag> +Can't link these objects because the resulting animated object would exceed the rigged triangle limit. +  </notification> + +  <notification +   icon="alertmodal.tga" +   name="NoPermsSetFlagAnimatedObjectTooLarge" +   type="notify"> +   <tag>fail</tag> +Can't make this object into an animated object because it would exceed the rigged triangle limit. +  </notification> + +  <notification +   icon="alertmodal.tga" +   name="CantChangeAnimatedObjectStateInsufficientLand" +   type="notify"> +   <tag>fail</tag> +Can't change animated object state for this object because it would cause parcel limit to be exceeded. +  </notification> + +  <notification +   icon="alertmodal.tga" +   name="ErrorNoMeshData" +   type="notify"> +   <tag>fail</tag> +Server error: cannot complete this operation because mesh data is not loaded. +  </notification> + +  <notification +   icon="alertmodal.tga"     name="NoAccessToClaimObjects"     type="notify">     <tag>fail</tag> diff --git a/indra/test/test.cpp b/indra/test/test.cpp index 80c84d9bea..bdeaeec970 100644 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -34,7 +34,6 @@   *   */ -  #include "linden_common.h"  #include "llerrorcontrol.h"  #include "lltut.h" @@ -685,5 +684,4 @@ int main(int argc, char **argv)  	return retval;  	//delete mycallback; -  } | 
