diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 86301b7601e6e25d12d208264cc8116a4583c4ef..84c30506fda9afd8afa4ec2f96862ba4f02797e9 100755 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -491,6 +491,7 @@ void LLAvatarAppearance::computeBodySize() if (new_body_size != mBodySize || old_offset != mAvatarOffset.mV[VZ]) { mBodySize = new_body_size; + bodySizeChanged(); } } @@ -1394,14 +1395,14 @@ BOOL LLAvatarAppearance::teToColorParams( ETextureIndex te, U32 *param_name ) return TRUE; } -void LLAvatarAppearance::setClothesColor( ETextureIndex te, const LLColor4& new_color) +void LLAvatarAppearance::setClothesColor( ETextureIndex te, const LLColor4& new_color, BOOL upload_bake ) { U32 param_name[3]; if( teToColorParams( te, param_name ) ) { - setVisualParamWeight( param_name[0], new_color.mV[VX]); - setVisualParamWeight( param_name[1], new_color.mV[VY]); - setVisualParamWeight( param_name[2], new_color.mV[VZ]); + setVisualParamWeight( param_name[0], new_color.mV[VX], upload_bake ); + setVisualParamWeight( param_name[1], new_color.mV[VY], upload_bake ); + setVisualParamWeight( param_name[2], new_color.mV[VZ], upload_bake ); } } diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index 9c827f85ef98605148ea54e66346d259733117f1..7926648f0ea4ff21be7b47132321b99fd21a02c7 100755 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -109,6 +109,7 @@ public: public: virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent virtual BOOL isValid() const; + virtual BOOL isUsingServerBakes() const = 0; virtual BOOL isUsingLocalAppearance() const = 0; virtual BOOL isEditingAppearance() const = 0; @@ -145,6 +146,7 @@ protected: static BOOL parseSkeletonFile(const std::string& filename); virtual void buildCharacter(); virtual BOOL loadAvatar(); + virtual void bodySizeChanged() = 0; BOOL setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 ¤t_volume_num, S32 ¤t_joint_num); BOOL allocateCharacterJoints(U32 num); @@ -231,7 +233,7 @@ public: // Composites //-------------------------------------------------------------------- public: - virtual void invalidateComposite(LLTexLayerSet* layerset) = 0; + virtual void invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result) = 0; /******************************************************************************** ** ** @@ -262,7 +264,7 @@ protected: // Clothing colors (convenience functions to access visual parameters) //-------------------------------------------------------------------- public: - void setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color); + void setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color, BOOL upload_bake); LLColor4 getClothesColor(LLAvatarAppearanceDefines::ETextureIndex te); static BOOL teToColorParams(LLAvatarAppearanceDefines::ETextureIndex te, U32 *param_name); @@ -271,7 +273,7 @@ public: //-------------------------------------------------------------------- public: LLColor4 getGlobalColor(const std::string& color_name ) const; - virtual void onGlobalColorChanged(const LLTexGlobalColor* global_color) = 0; + virtual void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake) = 0; protected: LLTexGlobalColor* mTexSkinColor; LLTexGlobalColor* mTexHairColor; diff --git a/indra/llappearance/lldriverparam.cpp b/indra/llappearance/lldriverparam.cpp index e630c1118bc859c71c8c0911e3ceb6ec0d0a144b..bdabd0716a6e73fbf3f573103a8ce0a4ec7e82dd 100755 --- a/indra/llappearance/lldriverparam.cpp +++ b/indra/llappearance/lldriverparam.cpp @@ -190,7 +190,7 @@ BOOL LLDriverParam::setInfo(LLDriverParamInfo *info) mID = info->mID; info->mDriverParam = this; - setWeight(getDefaultWeight()); + setWeight(getDefaultWeight(), FALSE ); return TRUE; } @@ -201,7 +201,7 @@ BOOL LLDriverParam::setInfo(LLDriverParamInfo *info) return new LLDriverParam(*this); } -void LLDriverParam::setWeight(F32 weight) +void LLDriverParam::setWeight(F32 weight, BOOL upload_bake) { F32 min_weight = getMinWeight(); F32 max_weight = getMaxWeight(); @@ -260,7 +260,7 @@ void LLDriverParam::setWeight(F32 weight) driven_weight = driven_min; } - setDrivenWeight(driven,driven_weight); + setDrivenWeight(driven,driven_weight,upload_bake); continue; } else @@ -284,13 +284,13 @@ void LLDriverParam::setWeight(F32 weight) driven_weight = driven_min; } - setDrivenWeight(driven,driven_weight); + setDrivenWeight(driven,driven_weight,upload_bake); continue; } } driven_weight = getDrivenWeight(driven, mCurWeight); - setDrivenWeight(driven,driven_weight); + setDrivenWeight(driven,driven_weight, upload_bake); } } @@ -436,9 +436,9 @@ const LLViewerVisualParam* LLDriverParam::getDrivenParam(S32 index) const //----------------------------------------------------------------------------- // setAnimationTarget() //----------------------------------------------------------------------------- -void LLDriverParam::setAnimationTarget( F32 target_value) +void LLDriverParam::setAnimationTarget( F32 target_value, BOOL upload_bake ) { - LLVisualParam::setAnimationTarget(target_value); + LLVisualParam::setAnimationTarget(target_value, upload_bake); for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) { @@ -447,16 +447,16 @@ void LLDriverParam::setAnimationTarget( F32 target_value) // this isn't normally necessary, as driver params handle interpolation of their driven params // but texture params need to know to assume their final value at beginning of interpolation - driven->mParam->setAnimationTarget(driven_weight); + driven->mParam->setAnimationTarget(driven_weight, upload_bake); } } //----------------------------------------------------------------------------- // stopAnimating() //----------------------------------------------------------------------------- -void LLDriverParam::stopAnimating() +void LLDriverParam::stopAnimating(BOOL upload_bake) { - LLVisualParam::stopAnimating(); + LLVisualParam::stopAnimating(upload_bake); for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) { @@ -536,7 +536,7 @@ void LLDriverParam::updateCrossDrivenParams(LLWearableType::EType driven_type) LLWearable *wearable = mAvatarAppearance->getWearableData()->getTopWearable(driver_type); if (wearable) { - wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID)); + wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID), false); } } } @@ -599,7 +599,7 @@ F32 LLDriverParam::getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight return driven_weight; } -void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight) +void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake) { bool use_self = false; if(mWearablep && @@ -616,10 +616,10 @@ void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight) if (use_self) { // call setWeight through LLVOAvatarSelf so other wearables can be updated with the correct values - mAvatarAppearance->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight); + mAvatarAppearance->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight, upload_bake); } else { - driven->mParam->setWeight( driven_weight); + driven->mParam->setWeight( driven_weight, upload_bake); } } diff --git a/indra/llappearance/lldriverparam.h b/indra/llappearance/lldriverparam.h index f71c930e5e3716fbf67683690f9f372fd5f02142..ab28f41590d8334d5c0884ec7d87af439405a846 100755 --- a/indra/llappearance/lldriverparam.h +++ b/indra/llappearance/lldriverparam.h @@ -111,9 +111,9 @@ public: // LLVisualParam Virtual functions /*virtual*/ void apply( ESex sex ) {} // apply is called separately for each driven param. - /*virtual*/ void setWeight(F32 weight); - /*virtual*/ void setAnimationTarget( F32 target_value); - /*virtual*/ void stopAnimating(); + /*virtual*/ void setWeight(F32 weight, BOOL upload_bake) override; + /*virtual*/ void setAnimationTarget( F32 target_value, BOOL upload_bake) override; + /*virtual*/ void stopAnimating(BOOL upload_bake) override; /*virtual*/ BOOL linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params); /*virtual*/ void resetDrivenParams(); @@ -131,7 +131,7 @@ public: protected: LLDriverParam(const LLDriverParam& pOther); F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight); - void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight); + void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake); LL_ALIGN_16(LLVector4a mDefaultVec); // temp holder diff --git a/indra/llappearance/llpolymorph.cpp b/indra/llappearance/llpolymorph.cpp index 907f8823c0aa02b23f42c6de49c9d22f9bd72807..bbd2ea69c544379ec7046d88f38a7c306902970c 100644 --- a/indra/llappearance/llpolymorph.cpp +++ b/indra/llappearance/llpolymorph.cpp @@ -358,7 +358,7 @@ BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info) return FALSE; mInfo = info; mID = info->mID; - setWeight(getDefaultWeight()); + setWeight(getDefaultWeight(), FALSE); LLAvatarAppearance* avatarp = mMesh->getAvatar(); LLPolyMorphTargetInfo::volume_info_list_t::iterator iter; diff --git a/indra/llappearance/llpolyskeletaldistortion.cpp b/indra/llappearance/llpolyskeletaldistortion.cpp index 3dd83f675cd9ea55080fb0c5a12b1b268f6f550f..bb0f526cd874395e638319459c56d3fbe7fe81aa 100644 --- a/indra/llappearance/llpolyskeletaldistortion.cpp +++ b/indra/llappearance/llpolyskeletaldistortion.cpp @@ -139,7 +139,7 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info) return FALSE; mInfo = info; mID = info->mID; - setWeight(getDefaultWeight()); + setWeight(getDefaultWeight(), FALSE); LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter; for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++) diff --git a/indra/llappearance/lltexglobalcolor.cpp b/indra/llappearance/lltexglobalcolor.cpp index 3df2254b1423ec8477b270050b38dfe320b6e12a..a8283ea2e632dfe8e95e39a7166c58388008b563 100755 --- a/indra/llappearance/lltexglobalcolor.cpp +++ b/indra/llappearance/lltexglobalcolor.cpp @@ -117,9 +117,9 @@ LLTexParamGlobalColor::~LLTexParamGlobalColor() return new LLTexParamGlobalColor(*this); } -void LLTexParamGlobalColor::onGlobalColorChanged() +void LLTexParamGlobalColor::onGlobalColorChanged(bool upload_bake) { - mAvatarAppearance->onGlobalColorChanged(mTexGlobalColor); + mAvatarAppearance->onGlobalColorChanged(mTexGlobalColor, upload_bake); } //----------------------------------------------------------------------------- diff --git a/indra/llappearance/lltexglobalcolor.h b/indra/llappearance/lltexglobalcolor.h index 3b426053dee2556bb06ef9ee24ba85624b9349fe..5e312bf3d7f7032a4fffff9ab21902bbaa5e5c55 100755 --- a/indra/llappearance/lltexglobalcolor.h +++ b/indra/llappearance/lltexglobalcolor.h @@ -77,7 +77,7 @@ public: /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const; protected: LLTexParamGlobalColor(const LLTexParamGlobalColor& pOther); - /*virtual*/ void onGlobalColorChanged(); + /*virtual*/ void onGlobalColorChanged(bool upload_bake) override; private: LLTexGlobalColor* mTexGlobalColor; }; diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp index ff682d69069ad15696e65852734dd488e227c39c..b556f66a43b969bc7a1a95c1017bc5464f87da8e 100755 --- a/indra/llappearance/lltexlayerparams.cpp +++ b/indra/llappearance/lltexlayerparams.cpp @@ -183,7 +183,7 @@ BOOL LLTexLayerParamAlpha::getMultiplyBlend() const return ((LLTexLayerParamAlphaInfo *)getInfo())->mMultiplyBlend; } -void LLTexLayerParamAlpha::setWeight(F32 weight) +void LLTexLayerParamAlpha::setWeight(F32 weight, BOOL upload_bake) { if (mIsAnimating || mTexLayer == NULL) { @@ -201,35 +201,36 @@ void LLTexLayerParamAlpha::setWeight(F32 weight) if ((mAvatarAppearance->getSex() & getSex()) && (mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param. { - mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet()); + mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake); mTexLayer->invalidateMorphMasks(); } } } -void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value) +void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value, BOOL upload_bake) { // do not animate dummy parameters if (mIsDummy) { - setWeight(target_value); + setWeight(target_value, upload_bake); return; } mTargetWeight = target_value; - setWeight(target_value); + setWeight(target_value, upload_bake); mIsAnimating = TRUE; if (mNext) { - mNext->setAnimationTarget(target_value); + mNext->setAnimationTarget(target_value, upload_bake); } } -void LLTexLayerParamAlpha::animate(F32 delta) +void LLTexLayerParamAlpha::animate(F32 delta, BOOL upload_bake) { if (mNext) { - mNext->animate(delta); + mNext->animate(delta, upload_bake); + } } @@ -477,7 +478,7 @@ LLColor4 LLTexLayerParamColor::getNetColor() const } -void LLTexLayerParamColor::setWeight(F32 weight) +void LLTexLayerParamColor::setWeight(F32 weight, BOOL upload_bake) { if (mIsAnimating) { @@ -503,10 +504,10 @@ void LLTexLayerParamColor::setWeight(F32 weight) if ((mAvatarAppearance->getSex() & getSex()) && (mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param. { - onGlobalColorChanged(); + onGlobalColorChanged(upload_bake); if (mTexLayer) { - mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet()); + mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake); } } @@ -514,23 +515,23 @@ void LLTexLayerParamColor::setWeight(F32 weight) } } -void LLTexLayerParamColor::setAnimationTarget(F32 target_value) +void LLTexLayerParamColor::setAnimationTarget(F32 target_value, BOOL upload_bake) { // set value first then set interpolating flag to ignore further updates mTargetWeight = target_value; - setWeight(target_value); + setWeight(target_value, upload_bake); mIsAnimating = TRUE; if (mNext) { - mNext->setAnimationTarget(target_value); + mNext->setAnimationTarget(target_value, upload_bake); } } -void LLTexLayerParamColor::animate(F32 delta) +void LLTexLayerParamColor::animate(F32 delta, BOOL upload_bake) { if (mNext) { - mNext->animate(delta); + mNext->animate(delta, upload_bake); } } diff --git a/indra/llappearance/lltexlayerparams.h b/indra/llappearance/lltexlayerparams.h index 0cb2dedbff869d21e70f45f16ecf166c173a799a..900dd5c205c32da507c87fb64fbef597d7a527a2 100755 --- a/indra/llappearance/lltexlayerparams.h +++ b/indra/llappearance/lltexlayerparams.h @@ -85,10 +85,9 @@ public: // LLVisualParam Virtual functions ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); /*virtual*/ void apply( ESex avatar_sex ) {} - /*virtual*/ void setWeight(F32 weight); - /*virtual*/ void setAnimationTarget(F32 target_value); - /*virtual*/ void animate(F32 delta); - + /*virtual*/ void setWeight(F32 weight, BOOL upload_bake) override; + /*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake) override; + /*virtual*/ void animate(F32 delta, BOOL upload_bake) override; // LLViewerVisualParam Virtual functions /*virtual*/ F32 getTotalDistortion() { return 1.f; } /*virtual*/ const LLVector4a& getAvgDistortion() { return mAvgDistortionVec; } @@ -178,9 +177,9 @@ public: // LLVisualParam Virtual functions ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); /*virtual*/ void apply( ESex avatar_sex ) {} - /*virtual*/ void setWeight(F32 weight); - /*virtual*/ void setAnimationTarget(F32 target_value); - /*virtual*/ void animate(F32 delta); + /*virtual*/ void setWeight(F32 weight, BOOL upload_bake) override; + /*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake) override; + /*virtual*/ void animate(F32 delta, BOOL upload_bake) override; // LLViewerVisualParam Virtual functions @@ -196,7 +195,7 @@ public: protected: LLTexLayerParamColor(const LLTexLayerParamColor& pOther); - virtual void onGlobalColorChanged() {} + virtual void onGlobalColorChanged(bool upload_bake) {} private: LL_ALIGN_16(LLVector4a mAvgDistortionVec); } LL_ALIGN_POSTFIX(16); diff --git a/indra/llappearance/llviewervisualparam.cpp b/indra/llappearance/llviewervisualparam.cpp index af8394b60ce9209fe92bde53ec38a2e55c18fbe7..52e204205d254f64ec9e335bf15d4e9c760a20f0 100644 --- a/indra/llappearance/llviewervisualparam.cpp +++ b/indra/llappearance/llviewervisualparam.cpp @@ -153,7 +153,7 @@ BOOL LLViewerVisualParam::setInfo(LLViewerVisualParamInfo *info) return FALSE; mInfo = info; mID = info->mID; - setWeight(getDefaultWeight()); + setWeight(getDefaultWeight(), FALSE); return TRUE; } diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp index dd94afeb9ee32174f6df3d4fe146d5f769b7b322..6a94f7015b1e13f06f05bc5ee80a7b3b16ea555c 100755 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -549,7 +549,7 @@ void LLWearable::revertValues() LLVisualParam *param = getVisualParam(id); if(param && !dynamic_cast<LLDriverParam*>(param) ) { - setVisualParamWeight(id, value); + setVisualParamWeight(id, value, TRUE); } } @@ -561,7 +561,7 @@ void LLWearable::revertValues() LLVisualParam *param = getVisualParam(id); if(param && dynamic_cast<LLDriverParam*>(param) ) { - setVisualParamWeight(id, value); + setVisualParamWeight(id, value, TRUE); } } @@ -664,12 +664,12 @@ void LLWearable::addVisualParam(LLVisualParam *param) } -void LLWearable::setVisualParamWeight(S32 param_index, F32 value) +void LLWearable::setVisualParamWeight(S32 param_index, F32 value, BOOL upload_bake) { if( is_in_map(mVisualParamIndexMap, param_index ) ) { LLVisualParam *wearable_param = mVisualParamIndexMap[param_index]; - wearable_param->setWeight(value); + wearable_param->setWeight(value, upload_bake); } else { @@ -713,14 +713,14 @@ void LLWearable::getVisualParams(visual_param_vec_t &list) } } -void LLWearable::animateParams(F32 delta) +void LLWearable::animateParams(F32 delta, BOOL upload_bake) { for(visual_param_index_map_t::iterator iter = mVisualParamIndexMap.begin(); iter != mVisualParamIndexMap.end(); ++iter) { LLVisualParam *param = (LLVisualParam*) iter->second; - param->animate(delta); + param->animate(delta, upload_bake); } } @@ -738,14 +738,14 @@ LLColor4 LLWearable::getClothesColor(S32 te) const return color; } -void LLWearable::setClothesColor( S32 te, const LLColor4& new_color) +void LLWearable::setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake) { U32 param_name[3]; if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) ) { for( U8 index = 0; index < 3; index++ ) { - setVisualParamWeight(param_name[index], new_color.mV[index]); + setVisualParamWeight(param_name[index], new_color.mV[index], upload_bake); } } } @@ -764,7 +764,7 @@ void LLWearable::writeToAvatar(LLAvatarAppearance* avatarp) S32 param_id = param->getID(); F32 weight = getVisualParamWeight(param_id); - avatarp->setVisualParamWeight( param_id, weight); + avatarp->setVisualParamWeight( param_id, weight, FALSE); } } #else @@ -772,7 +772,7 @@ void LLWearable::writeToAvatar(LLAvatarAppearance* avatarp) { LLVisualParam* param = it->second; if(!((LLViewerVisualParam*)param)->getCrossWearable()) - avatarp->setVisualParamWeight( param->getID(), param->getWeight() ); + avatarp->setVisualParamWeight( param->getID(), param->getWeight(), FALSE ); } #endif } diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h index f50119418f554188950e3e165b190e848659de2d..eb668ac07d7b85af32878d2d1565468e8c87eb18 100755 --- a/indra/llappearance/llwearable.h +++ b/indra/llappearance/llwearable.h @@ -96,14 +96,13 @@ public: void setLocalTextureObject(S32 index, LLLocalTextureObject <o); void addVisualParam(LLVisualParam *param); - void setVisualParamWeight(S32 index, F32 value); + void setVisualParamWeight(S32 index, F32 value, BOOL upload_bake); F32 getVisualParamWeight(S32 index) const; LLVisualParam* getVisualParam(S32 index) const; void getVisualParams(visual_param_vec_t &list); - void animateParams(F32 delta); - + void animateParams(F32 delta, BOOL upload_bake); LLColor4 getClothesColor(S32 te) const; - void setClothesColor( S32 te, const LLColor4& new_color); + void setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake); virtual void revertValues(); virtual void saveValues(); diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp index 5416304c93d52ab53ba50398928e8e1f4af0cb73..b6e3fb26a3f14935fe4b9e85ede5d830c4411650 100755 --- a/indra/llcharacter/llcharacter.cpp +++ b/indra/llcharacter/llcharacter.cpp @@ -287,13 +287,13 @@ void LLCharacter::removeAnimationData(std::string name) //----------------------------------------------------------------------------- // setVisualParamWeight() //----------------------------------------------------------------------------- -BOOL LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 weight) +BOOL LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 weight, BOOL upload_bake) { S32 index = which_param->getID(); visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index); if (index_iter != mVisualParamIndexMap.end()) { - index_iter->second->setWeight(weight); + index_iter->second->setWeight(weight, upload_bake); return TRUE; } return FALSE; @@ -302,7 +302,7 @@ BOOL LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 wei //----------------------------------------------------------------------------- // setVisualParamWeight() //----------------------------------------------------------------------------- -BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight) +BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake) { std::string tname(param_name); LLStringUtil::toLower(tname); @@ -310,7 +310,7 @@ BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight) visual_param_name_map_t::iterator name_iter = mVisualParamNameMap.find(tableptr); if (name_iter != mVisualParamNameMap.end()) { - name_iter->second->setWeight(weight); + name_iter->second->setWeight(weight, upload_bake); return TRUE; } LL_WARNS() << "LLCharacter::setVisualParamWeight() Invalid visual parameter: " << param_name << LL_ENDL; @@ -320,12 +320,12 @@ BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight) //----------------------------------------------------------------------------- // setVisualParamWeight() //----------------------------------------------------------------------------- -BOOL LLCharacter::setVisualParamWeight(S32 index, F32 weight) +BOOL LLCharacter::setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake) { visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index); if (index_iter != mVisualParamIndexMap.end()) { - index_iter->second->setWeight(weight); + index_iter->second->setWeight(weight, upload_bake); return TRUE; } LL_WARNS() << "LLCharacter::setVisualParamWeight() Invalid visual parameter index: " << index << LL_ENDL; @@ -395,7 +395,7 @@ void LLCharacter::clearVisualParamWeights() { if (param->isTweakable()) { - param->setWeight( param->getDefaultWeight()); + param->setWeight( param->getDefaultWeight(), FALSE); } } } diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h index 174899d7b5845eec1354cd600c107184f0fd2bcb..4840b44dc41ac55b17076e24670fe4a0542eb15c 100755 --- a/indra/llcharacter/llcharacter.h +++ b/indra/llcharacter/llcharacter.h @@ -194,9 +194,10 @@ public: void addVisualParam(LLVisualParam *param); void addSharedVisualParam(LLVisualParam *param); - virtual BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight); - virtual BOOL setVisualParamWeight(const char* param_name, F32 weight); - virtual BOOL setVisualParamWeight(S32 index, F32 weight); + virtual BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight, BOOL upload_bake = FALSE ); + virtual BOOL setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake = FALSE ); + virtual BOOL setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake = FALSE ); + // get visual param weight by param or name F32 getVisualParamWeight(LLVisualParam *distortion); diff --git a/indra/llcharacter/llvisualparam.cpp b/indra/llcharacter/llvisualparam.cpp index 2235496ac5f411882df6cf387887ea9755447eb2..aae176b4e82cc8a8556857564f75aa92cd5c74c6 100755 --- a/indra/llcharacter/llvisualparam.cpp +++ b/indra/llcharacter/llvisualparam.cpp @@ -236,7 +236,7 @@ BOOL LLVisualParam::parseData(LLXmlTreeNode *node) //----------------------------------------------------------------------------- // setWeight() //----------------------------------------------------------------------------- -void LLVisualParam::setWeight(F32 weight) +void LLVisualParam::setWeight(F32 weight, BOOL upload_bake) { if (mIsAnimating) { @@ -254,19 +254,19 @@ void LLVisualParam::setWeight(F32 weight) if (mNext) { - mNext->setWeight(weight); + mNext->setWeight(weight, upload_bake); } } //----------------------------------------------------------------------------- // setAnimationTarget() //----------------------------------------------------------------------------- -void LLVisualParam::setAnimationTarget(F32 target_value) +void LLVisualParam::setAnimationTarget(F32 target_value, BOOL upload_bake) { // don't animate dummy parameters if (mIsDummy) { - setWeight(target_value); + setWeight(target_value, upload_bake); mTargetWeight = mCurWeight; return; } @@ -286,7 +286,7 @@ void LLVisualParam::setAnimationTarget(F32 target_value) if (mNext) { - mNext->setAnimationTarget(target_value); + mNext->setAnimationTarget(target_value, upload_bake); } } @@ -311,24 +311,24 @@ void LLVisualParam::clearNextParam() //----------------------------------------------------------------------------- // animate() //----------------------------------------------------------------------------- -void LLVisualParam::animate( F32 delta) +void LLVisualParam::animate( F32 delta, BOOL upload_bake) { if (mIsAnimating) { F32 new_weight = ((mTargetWeight - mCurWeight) * delta) + mCurWeight; - setWeight(new_weight); + setWeight(new_weight, upload_bake); } } //----------------------------------------------------------------------------- // stopAnimating() //----------------------------------------------------------------------------- -void LLVisualParam::stopAnimating() +void LLVisualParam::stopAnimating(BOOL upload_bake) { if (mIsAnimating && isTweakable()) { mIsAnimating = FALSE; - setWeight(mTargetWeight); + setWeight(mTargetWeight, upload_bake); } } diff --git a/indra/llcharacter/llvisualparam.h b/indra/llcharacter/llvisualparam.h index b1269a20736190f66e188a2dd3b17868f9ee9083..6592f4ece436235bc8f52aca5ea7a4b7ff7a4bf2 100755 --- a/indra/llcharacter/llvisualparam.h +++ b/indra/llcharacter/llvisualparam.h @@ -132,10 +132,10 @@ public: //virtual BOOL parseData( LLXmlTreeNode *node ) = 0; virtual void apply( ESex avatar_sex ) = 0; // Default functions - virtual void setWeight(F32 weight); - virtual void setAnimationTarget( F32 target_value); - virtual void animate(F32 delta); - virtual void stopAnimating(); + virtual void setWeight(F32 weight, BOOL upload_bake); + virtual void setAnimationTarget( F32 target_value, BOOL upload_bake); + virtual void animate(F32 delta, BOOL upload_bake); + virtual void stopAnimating(BOOL upload_bake); virtual BOOL linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params); virtual void resetDrivenParams(); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index ded47875ad62de2c81e7cd4bf18fa53a7282fc71..290b30f4dd3f04dbd278aede7502a4a02e76cc03 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -133,6 +133,7 @@ set(viewer_SOURCE_FILES llagentpilot.cpp llagentui.cpp llagentwearables.cpp + llagentwearablesfetch.cpp llaisapi.cpp llanimstatelabels.cpp llappcorehttp.cpp @@ -772,6 +773,7 @@ set(viewer_HEADER_FILES llagentpilot.h llagentui.h llagentwearables.h + llagentwearablesfetch.h llaisapi.h llanimstatelabels.h llappcorehttp.h diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index c343a30144eecaea08f4696e20ae4daee050bc61..67c0fc8a6b0965a1296b93984982c2101a44b96f 100755 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -429,6 +429,7 @@ LLAgent::LLAgent() : mVoiceConnected(false), + mAppearanceSerialNum(0), mMouselookModeInSignal(NULL), mMouselookModeOutSignal(NULL) { @@ -834,6 +835,29 @@ void LLAgent::standUp() setControlFlags(AGENT_CONTROL_STAND_UP); } +void LLAgent::handleServerBakeRegionTransition(const LLUUID& region_id) +{ + LL_INFOS() << "called" << LL_ENDL; + + + // Old-style appearance entering a server-bake region. + if (isAgentAvatarValid() && + !gAgentAvatarp->isUsingServerBakes() && + (mRegionp->getCentralBakeVersion()>0)) + { + LL_INFOS() << "update requested due to region transition" << LL_ENDL; + LLAppearanceMgr::instance().requestServerAppearanceUpdate(); + } + // new-style appearance entering a non-bake region, + // need to check for existence of the baking service. + else if (isAgentAvatarValid() && + gAgentAvatarp->isUsingServerBakes() && + mRegionp->getCentralBakeVersion()==0) + { + gAgentAvatarp->checkForUnsupportedServerBakeAppearance(); + } +} + void LLAgent::changeParcels() { LL_DEBUGS("AgentLocation") << "Calling ParcelChanged callbacks" << LL_ENDL; @@ -929,6 +953,19 @@ void LLAgent::setRegion(LLViewerRegion *regionp) LLFloaterMove::sUpdateFlyingStatus(); + // If the newly entered region is using server bakes, and our + // current appearance is non-baked, request appearance update from + // server. + if (mRegionp->capabilitiesReceived()) + { + handleServerBakeRegionTransition(mRegionp->getRegionID()); + } + else + { + // Need to handle via callback after caps arrive. + mRegionp->setCapabilitiesReceivedCallback(boost::bind(&LLAgent::handleServerBakeRegionTransition,this,_1)); + } + LL_DEBUGS("AgentLocation") << "Calling RegionChanged callbacks" << LL_ENDL; mRegionChangedSignal(); } @@ -3707,6 +3744,82 @@ void LLAgent::processControlRelease(LLMessageSystem *msg, void **) } */ +//static +void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void **user_data) +{ + gAgentQueryManager.mNumPendingQueries--; + if (gAgentQueryManager.mNumPendingQueries == 0) + { + selfStopPhase("fetch_texture_cache_entries"); + } + + if (!isAgentAvatarValid() || gAgentAvatarp->isDead()) + { + LL_WARNS() << "No avatar for user in cached texture update!" << LL_ENDL; + return; + } + + if (isAgentAvatarValid() && gAgentAvatarp->isEditingAppearance()) + { + // ignore baked textures when in customize mode + return; + } + + S32 query_id; + mesgsys->getS32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, query_id); + + S32 num_texture_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_WearableData); + + + S32 num_results = 0; + for (S32 texture_block = 0; texture_block < num_texture_blocks; texture_block++) + { + LLUUID texture_id; + U8 texture_index; + + mesgsys->getUUIDFast(_PREHASH_WearableData, _PREHASH_TextureID, texture_id, texture_block); + mesgsys->getU8Fast(_PREHASH_WearableData, _PREHASH_TextureIndex, texture_index, texture_block); + + + if ((S32)texture_index < TEX_NUM_INDICES ) + { + const LLAvatarAppearanceDictionary::TextureEntry *texture_entry = LLAvatarAppearanceDictionary::instance().getTexture((ETextureIndex)texture_index); + if (texture_entry) + { + EBakedTextureIndex baked_index = texture_entry->mBakedTextureIndex; + + if (gAgentQueryManager.mActiveCacheQueries[baked_index] == query_id) + { + if (texture_id.notNull()) + { + //LL_INFOS() << "Received cached texture " << (U32)texture_index << ": " << texture_id << LL_ENDL; + gAgentAvatarp->setCachedBakedTexture((ETextureIndex)texture_index, texture_id); + //gAgentAvatarp->setTETexture( LLVOAvatar::sBakedTextureIndices[texture_index], texture_id ); + gAgentQueryManager.mActiveCacheQueries[baked_index] = 0; + num_results++; + } + else + { + // no cache of this bake. request upload. + gAgentAvatarp->invalidateComposite(gAgentAvatarp->getLayerSet(baked_index),TRUE); + } + } + } + } + } + LL_INFOS() << "Received cached texture response for " << num_results << " textures." << LL_ENDL; + gAgentAvatarp->outputRezTiming("Fetched agent wearables textures from cache. Will now load them"); + + gAgentAvatarp->updateMeshTextures(); + + if (gAgentQueryManager.mNumPendingQueries == 0) + { + // RN: not sure why composites are disabled at this point + gAgentAvatarp->setCompositeUpdatesEnabled(TRUE); + gAgent.sendAgentSetAppearance(); + } +} + BOOL LLAgent::anyControlGrabbed() const { for (U32 i = 0; i < TOTAL_CONTROLS; i++) @@ -4326,6 +4439,193 @@ void LLAgent::requestLeaveGodMode() sendReliableMessage(); } +// For debugging, trace agent state at times appearance message are sent out. +void LLAgent::dumpSentAppearance(const std::string& dump_prefix) +{ + std::string outfilename = get_sequential_numbered_file_name(dump_prefix,".xml"); + + LLAPRFile outfile; + std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename); + outfile.open(fullpath, LL_APR_WB ); + apr_file_t* file = outfile.getFileHandle(); + if (!file) + { + return; + } + else + { + LL_DEBUGS("Avatar") << "dumping sent appearance message to " << fullpath << LL_ENDL; + } + + LLVisualParam* appearance_version_param = gAgentAvatarp->getVisualParam(11000); + if (appearance_version_param) + { + F32 value = appearance_version_param->getWeight(); + dump_visual_param(file, appearance_version_param, value); + } + for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); + iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); + ++iter) + { + const ETextureIndex index = iter->first; + const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second; + if (texture_dict->mIsBakedTexture) + { + LLTextureEntry* entry = gAgentAvatarp->getTE((U8) index); + const LLUUID& uuid = entry->getID(); + apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", index, uuid.asString().c_str()); + } + } +} + +//----------------------------------------------------------------------------- +// sendAgentSetAppearance() +//----------------------------------------------------------------------------- +void LLAgent::sendAgentSetAppearance() +{ + if (gAgentQueryManager.mNumPendingQueries > 0) + { + return; + } + + if (!isAgentAvatarValid() || gAgentAvatarp->isEditingAppearance() || (getRegion() && getRegion()->getCentralBakeVersion())) return; + + // At this point we have a complete appearance to send and are in a non-baking region. + // DRANO FIXME + //gAgentAvatarp->setIsUsingServerBakes(FALSE); + S32 sb_count, host_count, both_count, neither_count; + gAgentAvatarp->bakedTextureOriginCounts(sb_count, host_count, both_count, neither_count); + if (both_count != 0 || neither_count != 0) + { + LL_WARNS() << "bad bake texture state " << sb_count << "," << host_count << "," << both_count << "," << neither_count << LL_ENDL; + } + if (sb_count != 0 && host_count == 0) + { + gAgentAvatarp->setIsUsingServerBakes(true); + } + else if (sb_count == 0 && host_count != 0) + { + gAgentAvatarp->setIsUsingServerBakes(false); + } + else if (sb_count + host_count > 0) + { + LL_WARNS() << "unclear baked texture state, not sending appearance" << LL_ENDL; + return; + } + + + LL_INFOS("Avatar") << gAgentAvatarp->avString() << "TAT: Sent AgentSetAppearance: " << gAgentAvatarp->getBakedStatusForPrintout() << LL_ENDL; + //dumpAvatarTEs( "sendAgentSetAppearance()" ); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_AgentSetAppearance); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, getID()); + msg->addUUIDFast(_PREHASH_SessionID, getSessionID()); + + // correct for the collision tolerance (to make it look like the + // agent is actually walking on the ground/object) + // NOTE -- when we start correcting all of the other Havok geometry + // to compensate for the COLLISION_TOLERANCE ugliness we will have + // to tweak this number again + const LLVector3 body_size = gAgentAvatarp->mBodySize + gAgentAvatarp->mAvatarOffset; + msg->addVector3Fast(_PREHASH_Size, body_size); + + // To guard against out of order packets + // Note: always start by sending 1. This resets the server's count. 0 on the server means "uninitialized" + mAppearanceSerialNum++; + msg->addU32Fast(_PREHASH_SerialNum, mAppearanceSerialNum ); + + // is texture data current relative to wearables? + // KLW - TAT this will probably need to check the local queue. + BOOL textures_current = gAgentAvatarp->areTexturesCurrent(); + + for(U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++ ) + { + const ETextureIndex texture_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)baked_index); + + // if we're not wearing a skirt, we don't need the texture to be baked + if (texture_index == TEX_SKIRT_BAKED && !gAgentAvatarp->isWearingWearableType(LLWearableType::WT_SKIRT)) + { + continue; + } + + // IMG_DEFAULT_AVATAR means not baked. 0 index should be ignored for baked textures + if (!gAgentAvatarp->isTextureDefined(texture_index, 0)) + { + LL_DEBUGS("Avatar") << "texture not current for baked " << (S32)baked_index << " local " << (S32)texture_index << LL_ENDL; + textures_current = FALSE; + break; + } + } + + // only update cache entries if we have all our baked textures + + // FIXME DRANO need additional check for not in appearance editing + // mode, if still using local composites need to set using local + // composites to false, and update mesh textures. + if (textures_current) + { + bool enable_verbose_dumps = gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"); + std::string dump_prefix = gAgentAvatarp->getFullname() + "_sent_appearance"; + if (enable_verbose_dumps) + { + dumpSentAppearance(dump_prefix); + } + LL_INFOS("Avatar") << gAgentAvatarp->avString() << "TAT: Sending cached texture data" << LL_ENDL; + for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) + { + BOOL generate_valid_hash = TRUE; + if (isAgentAvatarValid() && !gAgentAvatarp->isBakedTextureFinal((LLAvatarAppearanceDefines::EBakedTextureIndex)baked_index)) + { + generate_valid_hash = FALSE; + LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "Not caching baked texture upload for " << (U32)baked_index << " due to being uploaded at low resolution." << LL_ENDL; + } + + const LLUUID hash = gAgentWearables.computeBakedTextureHash((EBakedTextureIndex) baked_index, generate_valid_hash); + if (hash.notNull()) + { + ETextureIndex texture_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((EBakedTextureIndex) baked_index); + msg->nextBlockFast(_PREHASH_WearableData); + msg->addUUIDFast(_PREHASH_CacheID, hash); + msg->addU8Fast(_PREHASH_TextureIndex, (U8)texture_index); + } + } + msg->nextBlockFast(_PREHASH_ObjectData); + gAgentAvatarp->sendAppearanceMessage( gMessageSystem ); + } + else + { + // If the textures aren't baked, send NULL for texture IDs + // This means the baked texture IDs on the server will be untouched. + // Once all textures are baked, another AvatarAppearance message will be sent to update the TEs + msg->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addBinaryDataFast(_PREHASH_TextureEntry, NULL, 0); + } + + + S32 transmitted_params = 0; + for (LLViewerVisualParam* param = (LLViewerVisualParam*)gAgentAvatarp->getFirstVisualParam(); + param; + param = (LLViewerVisualParam*)gAgentAvatarp->getNextVisualParam()) + { + if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE || + param->getGroup() == VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE) // do not transmit params of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT + { + msg->nextBlockFast(_PREHASH_VisualParam ); + + // We don't send the param ids. Instead, we assume that the receiver has the same params in the same sequence. + const F32 param_value = param->getWeight(); + const U8 new_weight = F32_to_U8(param_value, param->getMinWeight(), param->getMaxWeight()); + msg->addU8Fast(_PREHASH_ParamValue, new_weight ); + transmitted_params++; + } + } + + LL_INFOS() << "Avatar XML num VisualParams transmitted = " << transmitted_params << LL_ENDL; + sendReliableMessage(); +} + void LLAgent::sendAgentDataUpdateRequest() { gMessageSystem->newMessageFast(_PREHASH_AgentDataUpdateRequest); @@ -4468,6 +4768,23 @@ void LLAgent::renderAutoPilotTarget() /********************************************************************************/ +LLAgentQueryManager gAgentQueryManager; + +LLAgentQueryManager::LLAgentQueryManager() : + mWearablesCacheQueryID(0), + mNumPendingQueries(0), + mUpdateSerialNum(0) +{ + for (U32 i = 0; i < BAKED_NUM_INDICES; i++) + { + mActiveCacheQueries[i] = 0; + } +} + +LLAgentQueryManager::~LLAgentQueryManager() +{ +} + //----------------------------------------------------------------------------- // LLTeleportRequest //----------------------------------------------------------------------------- diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 3a8920fa7e2021439f1425f344aab79ac9bbeb83..c27ed8ea5d6a412e546ca9b37d5360afd4a45cb5 100755 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -672,6 +672,7 @@ private: void handleTeleportFinished(); void handleTeleportFailed(); + void handleServerBakeRegionTransition(const LLUUID& region_id); //-------------------------------------------------------------------- // Teleport State @@ -806,6 +807,7 @@ public: private: BOOL mShowAvatar; // Should we render the avatar? + U32 mAppearanceSerialNum; //-------------------------------------------------------------------- // Rendering state bitmap helpers @@ -906,6 +908,8 @@ private: public: void sendMessage(); // Send message to this agent's region void sendReliableMessage(); + void dumpSentAppearance(const std::string& dump_prefix); + void sendAgentSetAppearance(); void sendAgentDataUpdateRequest(); void sendAgentUserInfoRequest(); // IM to Email and Online visibility @@ -919,6 +923,7 @@ public: static void processAgentGroupDataUpdate(LLMessageSystem *msg, void **); static void processAgentDropGroup(LLMessageSystem *msg, void **); static void processScriptControlChange(LLMessageSystem *msg, void **); + static void processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void **user_data); /** Messaging ** ** @@ -947,4 +952,24 @@ inline bool operator==(const LLGroupData &a, const LLGroupData &b) return (a.mID == b.mID); } +class LLAgentQueryManager +{ + friend class LLAgent; + friend class LLAgentWearables; + +public: + LLAgentQueryManager(); + virtual ~LLAgentQueryManager(); + + BOOL hasNoPendingQueries() const { return getNumPendingQueries() == 0; } + S32 getNumPendingQueries() const { return mNumPendingQueries; } +private: + S32 mNumPendingQueries; + S32 mWearablesCacheQueryID; + U32 mUpdateSerialNum; + S32 mActiveCacheQueries[LLAvatarAppearanceDefines::BAKED_NUM_INDICES]; +}; + +extern LLAgentQueryManager gAgentQueryManager; + #endif diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 06b86e311a0233a2ad976bac1545930a335e1cdd..9470207342b3341c0fdfe7e12231035967894d01 100755 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -54,6 +54,8 @@ #include <boost/scoped_ptr.hpp> +#include "llagentwearablesfetch.h" +#include "llviewernetwork.h" LLAgentWearables gAgentWearables; BOOL LLAgentWearables::mInitialWearablesUpdateReceived = FALSE; @@ -210,6 +212,11 @@ void LLAgentWearables::initClass() void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar) { llassert(avatar); + if (!LLGridManager::getInstance()->isInSecondlife()) + { + avatar->outputRezTiming("Sending wearables request"); + sendAgentWearablesRequest(); + } setAvatarAppearance(avatar); } @@ -242,9 +249,24 @@ void LLAgentWearables::AddWearableToAgentInventoryCallback::fire(const LLUUID& i gAgentWearables.addWearabletoAgentInventoryDone(mType, mIndex, inv_item, mWearable); + if (mTodo & CALL_UPDATE) + { + gAgentWearables.sendAgentWearablesUpdate(); + } + if (mTodo & CALL_RECOVERDONE) + { + LLAppearanceMgr::instance().addCOFItemLink(inv_item); + gAgentWearables.recoverMissingWearableDone(); + } + /* * Do this for every one in the loop */ + if (mTodo & CALL_CREATESTANDARDDONE) + { + LLAppearanceMgr::instance().addCOFItemLink(inv_item); + gAgentWearables.createStandardWearablesDone(mType, mIndex); + } if (mTodo & CALL_MAKENEWOUTFITDONE) { gAgentWearables.makeNewOutfitDone(mType, mIndex); @@ -299,7 +321,81 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::ETy gInventory.notifyObservers(); } -void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index, +void LLAgentWearables::sendAgentWearablesUpdate() +{ + // First make sure that we have inventory items for each wearable + for (S32 type=0; type < LLWearableType::WT_COUNT; ++type) + { + for (U32 index=0; index < getWearableCount((LLWearableType::EType)type); ++index) + { + LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)type,index); + if (wearable) + { + if (wearable->getItemID().isNull()) + { + LLPointer<LLInventoryCallback> cb = + new AddWearableToAgentInventoryCallback( + LLPointer<LLRefCount>(NULL), + (LLWearableType::EType)type, + index, + wearable, + AddWearableToAgentInventoryCallback::CALL_NONE); + addWearableToAgentInventory(cb, wearable); + } + else + { + gInventory.addChangedMask(LLInventoryObserver::LABEL, + wearable->getItemID()); + } + } + } + } + + // Then make sure the inventory is in sync with the avatar. + gInventory.notifyObservers(); + + // Send the AgentIsNowWearing + gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing); + + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + + LL_DEBUGS() << "sendAgentWearablesUpdate()" << LL_ENDL; + // MULTI-WEARABLE: DEPRECATED: HACK: index to 0- server database tables don't support concept of multiwearables. + for (S32 type=0; type < LLWearableType::WT_COUNT; ++type) + { + gMessageSystem->nextBlockFast(_PREHASH_WearableData); + + U8 type_u8 = (U8)type; + gMessageSystem->addU8Fast(_PREHASH_WearableType, type_u8); + + LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)type, 0); + if (wearable) + { + //LL_INFOS() << "Sending wearable " << wearable->getName() << LL_ENDL; + LLUUID item_id = wearable->getItemID(); + const LLViewerInventoryItem *item = gInventory.getItem(item_id); + if (item && item->getIsLinkType()) + { + // Get the itemID that this item points to. i.e. make sure + // we are storing baseitems, not their links, in the database. + item_id = item->getLinkedUUID(); + } + gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_id); + } + else + { + //LL_INFOS() << "Not wearing wearable type " << LLWearableType::getTypeName((LLWearableType::EType)i) << LL_ENDL; + gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null); + } + + LL_DEBUGS() << " " << LLWearableType::getTypeLabel((LLWearableType::EType)type) << ": " << (wearable ? wearable->getAssetID() : LLUUID::null) << LL_ENDL; + } + gAgent.sendReliableMessage(); +} + +void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update, const std::string new_name) { LLViewerWearable* old_wearable = getViewerWearable(type, index); @@ -346,6 +442,10 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 { // Add a new inventory item (shouldn't ever happen here) U32 todo = AddWearableToAgentInventoryCallback::CALL_NONE; + if (send_update) + { + todo |= AddWearableToAgentInventoryCallback::CALL_UPDATE; + } LLPointer<LLInventoryCallback> cb = new AddWearableToAgentInventoryCallback( LLPointer<LLRefCount>(NULL), @@ -357,7 +457,12 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 return; } - gAgentAvatarp->wearableUpdated(type); + gAgentAvatarp->wearableUpdated(type, TRUE); + + if (send_update) + { + sendAgentWearablesUpdate(); + } } } @@ -434,6 +539,8 @@ void LLAgentWearables::revertWearable(const LLWearableType::EType type, const U3 { wearable->revertValues(); } + + gAgent.sendAgentSetAppearance(); } void LLAgentWearables::saveAllWearables() @@ -446,8 +553,10 @@ void LLAgentWearables::saveAllWearables() for (S32 i=0; i < LLWearableType::WT_COUNT; i++) { for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++) - saveWearable((LLWearableType::EType)i, j); + saveWearable((LLWearableType::EType)i, j, FALSE); } + //sendAgentWearablesUpdate(); + gAgent.sendAgentSetAppearance(); } // Called when the user changes the name of a wearable inventory item that is currently being worn. @@ -476,6 +585,7 @@ void LLAgentWearables::setWearableName(const LLUUID& item_id, const std::string& old_wearable->setName(old_name); setWearable((LLWearableType::EType)i,j,new_wearable); + sendAgentWearablesUpdate(); break; } } @@ -596,6 +706,15 @@ LLViewerWearable* LLAgentWearables::getWearableFromAssetID(const LLUUID& asset_i return NULL; } +void LLAgentWearables::sendAgentWearablesRequest() +{ + gMessageSystem->newMessageFast(_PREHASH_AgentWearablesRequest); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gAgent.sendReliableMessage(); +} + LLViewerWearable* LLAgentWearables::getViewerWearable(const LLWearableType::EType type, U32 index /*= 0*/) { return dynamic_cast<LLViewerWearable*> (getWearable(type, index)); @@ -617,7 +736,8 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed) { if (isAgentAvatarValid()) { - gAgentAvatarp->wearableUpdated(wearable->getType()); + const BOOL upload_result = removed; + gAgentAvatarp->wearableUpdated(wearable->getType(), upload_result); } LLWearableData::wearableUpdated(wearable, removed); @@ -639,7 +759,7 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed) { LL_INFOS() << "forcing wearable type " << wearable->getType() << " to version 22 from 24" << LL_ENDL; wearable->setDefinitionVersion(22); - saveWearable(wearable->getType(),index); + saveWearable(wearable->getType(),index, TRUE); } } @@ -647,6 +767,18 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed) } } + + +BOOL LLAgentWearables::itemUpdatePending(const LLUUID& item_id) const +{ + return mItemsAwaitingWearableUpdate.find(item_id) != mItemsAwaitingWearableUpdate.end(); +} + +U32 LLAgentWearables::itemUpdatePendingCount() const +{ + return mItemsAwaitingWearableUpdate.size(); +} + const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type, U32 index) const { const LLViewerWearable *wearable = getViewerWearable(type,index); @@ -670,6 +802,157 @@ BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id) const return getWearableFromItemID(item_id) != NULL; } +// MULTI-WEARABLE: DEPRECATED (see backwards compatibility) +// static +// ! BACKWARDS COMPATIBILITY ! When we stop supporting viewer1.23, we can assume +// that viewers have a Current Outfit Folder and won't need this message, and thus +// we can remove/ignore this whole function. EXCEPT gAgentWearables.notifyLoadingStarted +void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data) +{ + // We should only receive this message a single time. Ignore subsequent AgentWearablesUpdates + // that may result from AgentWearablesRequest having been sent more than once. + if (mInitialWearablesUpdateReceived) + return; + + if (isAgentAvatarValid()) + { + gAgentAvatarp->startPhase("process_initial_wearables_update"); + gAgentAvatarp->outputRezTiming("Received initial wearables update"); + } + + // notify subscribers that wearables started loading. See EXT-7777 + // *TODO: find more proper place to not be called from deprecated method. + // Seems such place is found: LLInitialWearablesFetch::processContents() + gAgentWearables.notifyLoadingStarted(); + + mInitialWearablesUpdateReceived = true; + + LLUUID agent_id; + gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + + if (isAgentAvatarValid() && (agent_id == gAgentAvatarp->getID())) + { + gMessageSystem->getU32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, gAgentQueryManager.mUpdateSerialNum); + + const S32 NUM_BODY_PARTS = 4; + S32 num_wearables = gMessageSystem->getNumberOfBlocksFast(_PREHASH_WearableData); + if (num_wearables < NUM_BODY_PARTS) + { + // Transitional state. Avatars should always have at least their body parts (hair, eyes, shape and skin). + // The fact that they don't have any here (only a dummy is sent) implies that either: + // 1. This account existed before we had wearables + // 2. The database has gotten messed up + // 3. This is the account's first login (i.e. the wearables haven't been generated yet). + return; + } + + // Get the UUID of the current outfit folder (will be created if it doesn't exist) + const LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + LLInitialWearablesFetch* outfit = new LLInitialWearablesFetch(current_outfit_id); + + //LL_DEBUGS() << "processAgentInitialWearablesUpdate()" << LL_ENDL; + // Add wearables + // MULTI-WEARABLE: DEPRECATED: Message only supports one wearable per type, will be ignored in future. + gAgentWearables.mItemsAwaitingWearableUpdate.clear(); + for (S32 i = 0; i < num_wearables; i++) + { + // Parse initial wearables data from message system + U8 type_u8 = 0; + gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i); + if (type_u8 >= LLWearableType::WT_COUNT) + { + continue; + } + const LLWearableType::EType type = (LLWearableType::EType) type_u8; + + LLUUID item_id; + gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_ItemID, item_id, i); + + LLUUID asset_id; + gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_AssetID, asset_id, i); + if (asset_id.isNull()) + { + LLViewerWearable::removeFromAvatar(type, FALSE); + } + else + { + LLAssetType::EType asset_type = LLWearableType::getAssetType(type); + if (asset_type == LLAssetType::AT_NONE) + { + continue; + } + + // MULTI-WEARABLE: DEPRECATED: this message only supports one wearable per type. Should be ignored in future versions + + // Store initial wearables data until we know whether we have the current outfit folder or need to use the data. + LLInitialWearablesFetch::InitialWearableData wearable_data(type, item_id, asset_id); + outfit->add(wearable_data); + } + + LL_DEBUGS() << " " << LLWearableType::getTypeLabel(type) << LL_ENDL; + } + + // Get the complete information on the items in the inventory and set up an observer + // that will trigger when the complete information is fetched. + outfit->startFetch(); + if (outfit->isFinished()) + { + // everything is already here - call done. + outfit->done(); + } + else + { + // it's all on it's way - add an observer, and the inventory + // will call done for us when everything is here. + gInventory.addObserver(outfit); + } + + } +} + +// Normally, all wearables referred to "AgentWearablesUpdate" will correspond to actual assets in the +// database. If for some reason, we can't load one of those assets, we can try to reconstruct it so that +// the user isn't left without a shape, for example. (We can do that only after the inventory has loaded.) +void LLAgentWearables::recoverMissingWearable(const LLWearableType::EType type, U32 index) +{ + // Try to recover by replacing missing wearable with a new one. + LLNotificationsUtil::add("ReplacedMissingWearable"); + LL_DEBUGS() << "Wearable " << LLWearableType::getTypeLabel(type) << " could not be downloaded. Replaced inventory item with default wearable." << LL_ENDL; + LLViewerWearable* new_wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp); + + setWearable(type,index,new_wearable); + //new_wearable->writeToAvatar(TRUE); + + // Add a new one in the lost and found folder. + // (We used to overwrite the "not found" one, but that could potentially + // destory content.) JC + const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + LLPointer<LLInventoryCallback> cb = + new AddWearableToAgentInventoryCallback( + LLPointer<LLRefCount>(NULL), + type, + index, + new_wearable, + AddWearableToAgentInventoryCallback::CALL_RECOVERDONE); + addWearableToAgentInventory(cb, new_wearable, lost_and_found_id, TRUE); +} + +void LLAgentWearables::recoverMissingWearableDone() +{ + // Have all the wearables that the avatar was wearing at log-in arrived or been fabricated? + updateWearablesLoaded(); + if (areWearablesLoaded()) + { + // Make sure that the server's idea of the avatar's wearables actually match the wearables. + gAgent.sendAgentSetAppearance(); + } + else + { + gInventory.addChangedMask(LLInventoryObserver::LABEL, LLUUID::null); + gInventory.notifyObservers(); + } +} + void LLAgentWearables::addLocalTextureObject(const LLWearableType::EType wearable_type, const LLAvatarAppearanceDefines::ETextureIndex texture_type, U32 wearable_index) { LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)wearable_type, wearable_index); @@ -837,6 +1120,29 @@ void LLAgentWearables::sendDummyAgentWearablesUpdate() gAgent.sendReliableMessage(); } +void LLAgentWearables::createStandardWearablesDone(S32 type, U32 index) +{ + LL_INFOS() << "type " << type << " index " << index << LL_ENDL; + + if (!isAgentAvatarValid()) return; + gAgentAvatarp->updateVisualParams(); +} + +void LLAgentWearables::createStandardWearablesAllDone() +{ + // ... because sendAgentWearablesUpdate will notify inventory + // observers. + LL_INFOS() << "all done?" << LL_ENDL; + + mWearablesLoaded = TRUE; + checkWearablesLoaded(); + notifyLoadingFinished(); + + updateServer(); + + // Treat this as the first texture entry message, if none received yet + gAgentAvatarp->onFirstTEMessageReceived(); +} void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index) { @@ -954,7 +1260,7 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo if (old_wearable) { eraseWearable(old_wearable); - old_wearable->removeFromAvatar(); + old_wearable->removeFromAvatar(TRUE); } } clearWearableType(type); @@ -966,10 +1272,13 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo if (old_wearable) { eraseWearable(old_wearable); - old_wearable->removeFromAvatar(); + old_wearable->removeFromAvatar(TRUE); } } + queryWearableCache(); + updateServer(); + gInventory.notifyObservers(); } @@ -1107,6 +1416,7 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it // Start rendering & update the server mWearablesLoaded = TRUE; + checkWearablesLoaded(); notifyLoadingFinished(); // Copy wearable params to avatar. @@ -1115,6 +1425,9 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it // Then update the avatar based on the copied params. gAgentAvatarp->updateVisualParams(); + queryWearableCache(); + updateServer(); + gAgentAvatarp->dumpAvatarTEs("setWearableOutfit"); LL_DEBUGS("Avatar") << "setWearableOutfit() end" << LL_ENDL; @@ -1241,6 +1554,72 @@ void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLViewerWeara << " size is now " << getWearableCount(type) << LL_ENDL; } } +void LLAgentWearables::queryWearableCache() +{ + if (!areWearablesLoaded() || (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion())) + { + return; + } + + // Look up affected baked textures. + // If they exist: + // disallow updates for affected layersets (until dataserver responds with cache request.) + // If cache miss, turn updates back on and invalidate composite. + // If cache hit, modify baked texture entries. + // + // Cache requests contain list of hashes for each baked texture entry. + // Response is list of valid baked texture assets. (same message) + + gMessageSystem->newMessageFast(_PREHASH_AgentCachedTexture); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->addS32Fast(_PREHASH_SerialNum, gAgentQueryManager.mWearablesCacheQueryID); + + S32 num_queries = 0; + for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) + { + LLUUID hash_id = computeBakedTextureHash((EBakedTextureIndex) baked_index); + if (hash_id.notNull()) + { + num_queries++; + // *NOTE: make sure at least one request gets packed + + ETextureIndex te_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)baked_index); + + //LL_INFOS() << "Requesting texture for hash " << hash << " in baked texture slot " << baked_index << LL_ENDL; + gMessageSystem->nextBlockFast(_PREHASH_WearableData); + gMessageSystem->addUUIDFast(_PREHASH_ID, hash_id); + gMessageSystem->addU8Fast(_PREHASH_TextureIndex, (U8)te_index); + } + + gAgentQueryManager.mActiveCacheQueries[baked_index] = gAgentQueryManager.mWearablesCacheQueryID; + } + //VWR-22113: gAgent.getRegion() can return null if invalid, seen here on logout + if(gAgent.getRegion()) + { + if (isAgentAvatarValid()) + { + selfStartPhase("fetch_texture_cache_entries"); + gAgentAvatarp->outputRezTiming("Fetching textures from cache"); + } + + LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "Requesting texture cache entry for " << num_queries << " baked textures" << LL_ENDL; + gMessageSystem->sendReliable(gAgent.getRegion()->getHost()); + gAgentQueryManager.mNumPendingQueries++; + gAgentQueryManager.mWearablesCacheQueryID++; + } +} + +// virtual +void LLAgentWearables::invalidateBakedTextureHash(LLMD5& hash) const +{ + // Add some garbage into the hash so that it becomes invalid. + if (isAgentAvatarValid()) + { + hash.update((const unsigned char*)gAgentAvatarp->getID().mData, UUID_BYTES); + } +} // User has picked "remove from avatar" from a menu. // static @@ -1263,6 +1642,8 @@ void LLAgentWearables::userRemoveWearablesOfType(const LLWearableType::EType &ty } } + + // Given a desired set of attachments, find what objects need to be // removed, and what additional inventory items need to be added. void LLAgentWearables::findAttachmentsAddRemoveInfo(LLInventoryModel::item_array_t& obj_item_array, @@ -1394,6 +1775,17 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra } } +void LLAgentWearables::checkWearablesLoaded() const +{ +#ifdef SHOW_ASSERT + U32 item_pend_count = itemUpdatePendingCount(); + if (mWearablesLoaded) + { + llassert(item_pend_count==0); + } +#endif +} + // Returns false if the given wearable is already topmost/bottommost // (depending on closer_to_body parameter). bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_body) const @@ -1410,9 +1802,20 @@ bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_bod BOOL LLAgentWearables::areWearablesLoaded() const { + checkWearablesLoaded(); return mWearablesLoaded; } +// MULTI-WEARABLE: DEPRECATED: item pending count relies on old messages that don't support multi-wearables. do not trust to be accurate +void LLAgentWearables::updateWearablesLoaded() +{ + mWearablesLoaded = (itemUpdatePendingCount()==0); + if (mWearablesLoaded) + { + notifyLoadingFinished(); + } +} + bool LLAgentWearables::canWearableBeRemoved(const LLViewerWearable* wearable) const { if (!wearable) return false; @@ -1422,7 +1825,7 @@ bool LLAgentWearables::canWearableBeRemoved(const LLViewerWearable* wearable) co return !(((type == LLWearableType::WT_SHAPE) || (type == LLWearableType::WT_SKIN) || (type == LLWearableType::WT_HAIR) || (type == LLWearableType::WT_EYES)) && (getWearableCount(type) <= 1) ); } -void LLAgentWearables::animateAllWearableParams(F32 delta) +void LLAgentWearables::animateAllWearableParams(F32 delta, BOOL upload_bake) { for( S32 type = 0; type < LLWearableType::WT_COUNT; ++type ) { @@ -1432,7 +1835,7 @@ void LLAgentWearables::animateAllWearableParams(F32 delta) llassert(wearable); if (wearable) { - wearable->animateParams(delta); + wearable->animateParams(delta, upload_bake); } } } @@ -1569,6 +1972,12 @@ void LLAgentWearables::editWearableIfRequested(const LLUUID& item_id) } } +void LLAgentWearables::updateServer() +{ + sendAgentWearablesUpdate(); + gAgent.sendAgentSetAppearance(); +} + boost::signals2::connection LLAgentWearables::addLoadingStartedCallback(loading_started_callback_t cb) { return mLoadingStartedSignal.connect(cb); diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 100448202080c8a2f6ecdfae5dd086e01dc4a5b5..566478c8eeae3c4f1c7ab7bb13fa0dabc7ba73c8 100755 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -42,6 +42,7 @@ class LLInventoryItem; class LLVOAvatarSelf; class LLViewerWearable; +class LLInitialWearablesFetch; class LLViewerObject; class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearableData @@ -50,6 +51,7 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable // Constructors / destructors / Initializers //-------------------------------------------------------------------- public: + friend class LLInitialWearablesFetch; LLAgentWearables(); virtual ~LLAgentWearables(); @@ -60,6 +62,9 @@ public: // LLInitClass interface static void initClass(); +protected: + void createStandardWearablesDone(S32 type, U32 index/* = 0*/); + void createStandardWearablesAllDone(); //-------------------------------------------------------------------- // Queries @@ -80,7 +85,7 @@ public: // Note: False for shape, skin, eyes, and hair, unless you have MORE than 1. bool canWearableBeRemoved(const LLViewerWearable* wearable) const; - void animateAllWearableParams(F32 delta); + void animateAllWearableParams(F32 delta, BOOL upload_bake); //-------------------------------------------------------------------- // Accessors @@ -147,10 +152,28 @@ private: void removeWearableFinal(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); protected: static bool onRemoveWearableDialog(const LLSD& notification, const LLSD& response); + + //-------------------------------------------------------------------- + // Server Communication + //-------------------------------------------------------------------- +public: + // Processes the initial wearables update message (if necessary, since the outfit folder makes it redundant) + static void processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data); + +protected: + + /*virtual*/ void invalidateBakedTextureHash(LLMD5& hash) const; + void sendAgentWearablesUpdate(); + void sendAgentWearablesRequest(); + void queryWearableCache(); + void updateServer(); + static void onInitialWearableAssetArrived(LLViewerWearable* wearable, void* userdata); //-------------------------------------------------------------------- // Outfits //-------------------------------------------------------------------- + + private: void makeNewOutfitDone(S32 type, U32 index); @@ -159,7 +182,7 @@ private: //-------------------------------------------------------------------- public: void saveWearableAs(const LLWearableType::EType type, const U32 index, const std::string& new_name, const std::string& description, BOOL save_in_lost_and_found); - void saveWearable(const LLWearableType::EType type, const U32 index, + void saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update = TRUE, const std::string new_name = ""); void saveAllWearables(); void revertWearable(const LLWearableType::EType type, const U32 index); @@ -185,6 +208,9 @@ public: static void userRemoveMultipleAttachments(llvo_vec_t& llvo_array); static void userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array); + BOOL itemUpdatePending(const LLUUID& item_id) const; + U32 itemUpdatePendingCount() const; + //-------------------------------------------------------------------- // Signals //-------------------------------------------------------------------- @@ -211,6 +237,7 @@ private: private: static BOOL mInitialWearablesUpdateReceived; BOOL mWearablesLoaded; + std::set<LLUUID> mItemsAwaitingWearableUpdate; /** * True if agent's outfit is being changed now. @@ -222,6 +249,18 @@ private: // Support classes //-------------------------------------------------------------------------------- private: + + class createStandardWearablesAllDoneCallback : public LLRefCount + { + protected: + ~createStandardWearablesAllDoneCallback(); + }; + class sendAgentWearablesUpdateCallback : public LLRefCount + { + protected: + ~sendAgentWearablesUpdateCallback(); + }; + class AddWearableToAgentInventoryCallback : public LLInventoryCallback { public: diff --git a/indra/newview/llagentwearablesfetch.cpp b/indra/newview/llagentwearablesfetch.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c56ac6d82291a07f9fe14f49ee82c8bb7b80211a --- /dev/null +++ b/indra/newview/llagentwearablesfetch.cpp @@ -0,0 +1,202 @@ +/** + * @file llagentwearablesfetch.cpp + * @brief LLAgentWearblesFetch class implementation + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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 "llagentwearablesfetch.h" + +#include "llagent.h" +#include "llagentwearables.h" +#include "llappearancemgr.h" +#include "llinventoryfunctions.h" +#include "llstartup.h" +#include "llvoavatarself.h" + + +LLInitialWearablesFetch::LLInitialWearablesFetch(const LLUUID& cof_id) : + LLInventoryFetchDescendentsObserver(cof_id) +{ + if (isAgentAvatarValid()) + { + gAgentAvatarp->startPhase("initial_wearables_fetch"); + gAgentAvatarp->outputRezTiming("Initial wearables fetch started"); + } +} + +LLInitialWearablesFetch::~LLInitialWearablesFetch() +{ +} + +// virtual +void LLInitialWearablesFetch::done() +{ + // Delay processing the actual results of this so it's not handled within + // gInventory.notifyObservers. The results will be handled in the next + // idle tick instead. + gInventory.removeObserver(this); + doOnIdleOneTime(boost::bind(&LLInitialWearablesFetch::processContents,this)); + if (isAgentAvatarValid()) + { + gAgentAvatarp->stopPhase("initial_wearables_fetch"); + gAgentAvatarp->outputRezTiming("Initial wearables fetch done"); + } +} + +void LLInitialWearablesFetch::add(InitialWearableData &data) + +{ + mAgentInitialWearables.push_back(data); +} + +void LLInitialWearablesFetch::processContents() +{ + if(!gAgentAvatarp) //no need to process wearables if the agent avatar is deleted. + { + delete this; + return ; + } + + // Fetch the wearable items from the Current Outfit Folder + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t wearable_array; + LLFindWearables is_wearable; + llassert_always(mComplete.size() != 0); + gInventory.collectDescendentsIf(mComplete.front(), cat_array, wearable_array, + LLInventoryModel::EXCLUDE_TRASH, is_wearable); + + LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); + if (!wearable_array.empty()) + { + gAgentWearables.notifyLoadingStarted(); + LLAppearanceMgr::instance().updateAppearanceFromCOF(); + } + else + { + // if we're constructing the COF from the wearables message, we don't have a proper outfit link + LLAppearanceMgr::instance().setOutfitDirty(true); + processWearablesMessage(); + } + delete this; +} + +class LLFetchAndLinkObserver: public LLInventoryFetchItemsObserver +{ +public: + LLFetchAndLinkObserver(uuid_vec_t& ids): + LLInventoryFetchItemsObserver(ids) + { + } + ~LLFetchAndLinkObserver() + { + } + virtual void done() + { + gInventory.removeObserver(this); + + // Link to all fetched items in COF. + LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy; + LLInventoryObject::const_object_list_t item_array; + for (uuid_vec_t::iterator it = mIDs.begin(); + it != mIDs.end(); + ++it) + { + LLUUID id = *it; + LLConstPointer<LLInventoryObject> item = gInventory.getItem(*it); + if (!item) + { + LL_WARNS() << "fetch failed for item " << (*it) << "!" << LL_ENDL; + continue; + } + + item_array.push_back(item); + } + link_inventory_array(LLAppearanceMgr::instance().getCOF(), item_array, link_waiter); + } +}; + +void LLInitialWearablesFetch::processWearablesMessage() +{ + if (!mAgentInitialWearables.empty()) // We have an empty current outfit folder, use the message data instead. + { + const LLUUID current_outfit_id = LLAppearanceMgr::instance().getCOF(); + uuid_vec_t ids; + for (U8 i = 0; i < mAgentInitialWearables.size(); ++i) + { + // Populate the current outfit folder with links to the wearables passed in the message + InitialWearableData *wearable_data = new InitialWearableData(mAgentInitialWearables[i]); // This will be deleted in the callback. + + if (wearable_data->mAssetID.notNull()) + { + ids.push_back(wearable_data->mItemID); + } + else + { + LL_INFOS() << "Invalid wearable, type " << wearable_data->mType << " itemID " + << wearable_data->mItemID << " assetID " << wearable_data->mAssetID << LL_ENDL; + delete wearable_data; + } + } + + // Add all current attachments to the requested items as well. + if (isAgentAvatarValid()) + { + for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); + iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + if (!attachment) continue; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject* attached_object = (*attachment_iter); + if (!attached_object) continue; + const LLUUID& item_id = attached_object->getAttachmentItemID(); + if (item_id.isNull()) continue; + ids.push_back(item_id); + } + } + } + + // Need to fetch the inventory items for ids, then create links to them after they arrive. + LLFetchAndLinkObserver *fetcher = new LLFetchAndLinkObserver(ids); + fetcher->startFetch(); + // If no items to be fetched, done will never be triggered. + // TODO: Change LLInventoryFetchItemsObserver::fetchItems to trigger done() on this condition. + if (fetcher->isFinished()) + { + fetcher->done(); + } + else + { + gInventory.addObserver(fetcher); + } + } + else + { + LL_WARNS("Wearables") << "No current outfit folder items found and no initial wearables fallback message received." << LL_ENDL; + } +} + diff --git a/indra/newview/llagentwearablesfetch.h b/indra/newview/llagentwearablesfetch.h new file mode 100644 index 0000000000000000000000000000000000000000..81b03110ae34ec487c321300a94a95021f2b2ca8 --- /dev/null +++ b/indra/newview/llagentwearablesfetch.h @@ -0,0 +1,73 @@ +/** + * @file llagentwearablesinitialfetch.h + * @brief LLAgentWearablesInitialFetch class header file + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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_LLAGENTWEARABLESINITIALFETCH_H +#define LL_LLAGENTWEARABLESINITIALFETCH_H + +#include "llinventoryobserver.h" +#include "llwearabletype.h" +#include "lluuid.h" + +//-------------------------------------------------------------------- +// InitialWearablesFetch +// +// This grabs contents from the COF and processes them. +// The processing is handled in idle(), i.e. outside of done(), +// to avoid gInventory.notifyObservers recursion. +//-------------------------------------------------------------------- +class LLInitialWearablesFetch : public LLInventoryFetchDescendentsObserver +{ + LOG_CLASS(LLInitialWearablesFetch); + +public: + LLInitialWearablesFetch(const LLUUID& cof_id); + ~LLInitialWearablesFetch(); + virtual void done(); + + struct InitialWearableData + { + LLWearableType::EType mType; + LLUUID mItemID; + LLUUID mAssetID; + InitialWearableData(LLWearableType::EType type, LLUUID& itemID, LLUUID& assetID) : + mType(type), + mItemID(itemID), + mAssetID(assetID) + {} + }; + + void add(InitialWearableData &data); + +protected: + void processWearablesMessage(); + void processContents(); + +private: + typedef std::vector<InitialWearableData> initial_wearable_data_vec_t; + initial_wearable_data_vec_t mAgentInitialWearables; // Wearables from the old agent wearables msg +}; + +#endif // LL_AGENTWEARABLESINITIALFETCH_H diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 10a6630917bfe910177fb933e7c2586c94d731a7..24a4f6cdcec12555a4b7db5359be0878348f02ed 100755 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -3900,7 +3900,7 @@ bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_b bool result = false; if ((result = gAgentWearables.moveWearable(item, closer_to_body))) { - gAgentAvatarp->wearableUpdated(item->getWearableType()); + gAgentAvatarp->wearableUpdated(item->getWearableType(), FALSE); } setOutfitDirty(true); diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index d2b1dcbf359d3365263d8720934067be261d95c4..0f9d357f8eebdbdccb97183946585dea1da4c60c 100755 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -474,6 +474,57 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) //LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], TRUE); } +LLSendTexLayerResponder::LLSendTexLayerResponder(const LLSD& post_data, + const LLUUID& vfile_id, + LLAssetType::EType asset_type, + LLBakedUploadData * baked_upload_data) : + LLAssetUploadResponder(post_data, vfile_id, asset_type), + mBakedUploadData(baked_upload_data) +{ +} + +LLSendTexLayerResponder::~LLSendTexLayerResponder() +{ + // mBakedUploadData is normally deleted by calls to LLViewerTexLayerSetBuffer::onTextureUploadComplete() below + if (mBakedUploadData) + { // ...but delete it in the case where uploadComplete() is never called + delete mBakedUploadData; + mBakedUploadData = NULL; + } +} + + +// Baked texture upload completed +void LLSendTexLayerResponder::uploadComplete(const LLSD& content) +{ + LLUUID item_id = mPostData["item_id"]; + + std::string result = content["state"]; + LLUUID new_id = content["new_asset"]; + + llinfos << "result: " << result << " new_id: " << new_id << llendl; + if (result == "complete" + && mBakedUploadData != NULL) + { // Invoke + LLViewerTexLayerSetBuffer::onTextureUploadComplete(new_id, (void*) mBakedUploadData, 0, LL_EXSTAT_NONE); + mBakedUploadData = NULL; // deleted in onTextureUploadComplete() + } + else + { // Invoke the original callback with an error result + LLViewerTexLayerSetBuffer::onTextureUploadComplete(new_id, (void*) mBakedUploadData, -1, LL_EXSTAT_NONE); + mBakedUploadData = NULL; // deleted in onTextureUploadComplete() + } +} + +void LLSendTexLayerResponder::httpFailure() +{ + llwarns << dumpResponse() << llendl; + + // Invoke the original callback with an error result + LLViewerTexLayerSetBuffer::onTextureUploadComplete(LLUUID(), (void*) mBakedUploadData, -1, LL_EXSTAT_NONE); + mBakedUploadData = NULL; // deleted in onTextureUploadComplete() +} + LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder( const LLSD& post_data, const LLUUID& vfile_id, diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h index 7fbebc7481c1f585dacf23f1c13be02276da9aee..abfdc4ca7712e84a2555d48dd78032d7f3a9aab3 100755 --- a/indra/newview/llassetuploadresponders.h +++ b/indra/newview/llassetuploadresponders.h @@ -116,6 +116,27 @@ private: Impl* mImpl; }; +struct LLBakedUploadData; +class LLSendTexLayerResponder : public LLAssetUploadResponder +{ + LOG_CLASS(LLSendTexLayerResponder); +public: + LLSendTexLayerResponder(const LLSD& post_data, + const LLUUID& vfile_id, + LLAssetType::EType asset_type, + LLBakedUploadData * baked_upload_data); + + ~LLSendTexLayerResponder(); + + virtual void uploadComplete(const LLSD& content); + +protected: + virtual void httpFailure(); + +private: + LLBakedUploadData * mBakedUploadData; +}; + class LLUpdateAgentInventoryResponder : public LLAssetUploadResponder { public: diff --git a/indra/newview/llbreastmotion.cpp b/indra/newview/llbreastmotion.cpp index 3a88bab3b3621ac8b9ad9f90b26c8fe2a4ceb30a..d8d3ec1fab6edc29053ec74ce630eaebc35e2e02 100755 --- a/indra/newview/llbreastmotion.cpp +++ b/indra/newview/llbreastmotion.cpp @@ -340,7 +340,7 @@ BOOL LLBreastMotion::onUpdate(F32 time, U8* joint_mask) if (mBreastParamsDriven[i]) { mCharacter->setVisualParamWeight(mBreastParamsDriven[i], - new_local_pt[i]); + new_local_pt[i], FALSE); } } diff --git a/indra/newview/llemote.cpp b/indra/newview/llemote.cpp index 5c3bee24f8fc81fd0804f94042fc27c779a7de95..9033144a614a1e88166196b0e03b6c3db078dfd0 100755 --- a/indra/newview/llemote.cpp +++ b/indra/newview/llemote.cpp @@ -80,13 +80,13 @@ BOOL LLEmote::onActivate() LLVisualParam* default_param = mCharacter->getVisualParam( "Express_Closed_Mouth" ); if( default_param ) { - default_param->setWeight( default_param->getMaxWeight()); + default_param->setWeight( default_param->getMaxWeight(), FALSE); } mParam = mCharacter->getVisualParam(mName.c_str()); if (mParam) { - mParam->setWeight(0.f); + mParam->setWeight(0.f, FALSE); mCharacter->updateVisualParams(); } @@ -102,7 +102,7 @@ BOOL LLEmote::onUpdate(F32 time, U8* joint_mask) if( mParam ) { F32 weight = mParam->getMinWeight() + mPose.getWeight() * (mParam->getMaxWeight() - mParam->getMinWeight()); - mParam->setWeight(weight); + mParam->setWeight(weight, FALSE); // Cross fade against the default parameter LLVisualParam* default_param = mCharacter->getVisualParam( "Express_Closed_Mouth" ); @@ -111,7 +111,7 @@ BOOL LLEmote::onUpdate(F32 time, U8* joint_mask) F32 default_param_weight = default_param->getMinWeight() + (1.f - mPose.getWeight()) * ( default_param->getMaxWeight() - default_param->getMinWeight() ); - default_param->setWeight( default_param_weight); + default_param->setWeight( default_param_weight, FALSE); } mCharacter->updateVisualParams(); @@ -128,13 +128,13 @@ void LLEmote::onDeactivate() { if( mParam ) { - mParam->setWeight( mParam->getDefaultWeight()); + mParam->setWeight( mParam->getDefaultWeight(), FALSE); } LLVisualParam* default_param = mCharacter->getVisualParam( "Express_Closed_Mouth" ); if( default_param ) { - default_param->setWeight( default_param->getMaxWeight()); + default_param->setWeight( default_param->getMaxWeight(), FALSE); } mCharacter->updateVisualParams(); diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index c6dedda38c229d1cc6b0f1d2b39f253244acb3bd..0086e5c8a2777a3cb9462b6bac4fe193e06fc47d 100755 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -554,7 +554,7 @@ void LLLocalBitmap::updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableTyp if (gAgentWearables.getWearableIndex(wearable,index)) { gAgentAvatarp->setLocalTexture(reg_texind, gTextureList.getImage(new_id), FALSE, index); - gAgentAvatarp->wearableUpdated(type); + gAgentAvatarp->wearableUpdated(type, FALSE); /* telling the manager to rebake once update cycle is fully done */ LLLocalBitmapMgr::setNeedsRebake(); } diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 95e11472c2b2e38a89c7e673e3752b21f98d5011..e8299beceafc85268128c4079995bfa69498c23a 100755 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -946,11 +946,11 @@ void LLPanelEditWearable::onCommitSexChange() LLViewerWearable* wearable = gAgentWearables.getViewerWearable(type, index); if (wearable) { - wearable->setVisualParamWeight(param->getID(), is_new_sex_male); + wearable->setVisualParamWeight(param->getID(), is_new_sex_male, FALSE); } - param->setWeight( is_new_sex_male); + param->setWeight( is_new_sex_male, FALSE); - gAgentAvatarp->updateSexDependentLayerSets(); + gAgentAvatarp->updateSexDependentLayerSets(FALSE); gAgentAvatarp->updateVisualParams(); showWearable(mWearablePtr, TRUE, TRUE); @@ -987,7 +987,7 @@ void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl) { gAgentAvatarp->setLocalTexture(entry->mTextureIndex, image, FALSE, index); LLVisualParamHint::requestHintUpdates(); - gAgentAvatarp->wearableUpdated(type); + gAgentAvatarp->wearableUpdated(type, FALSE); } else { @@ -1016,9 +1016,9 @@ void LLPanelEditWearable::onColorSwatchCommit(const LLUICtrl* ctrl) const LLColor4& new_color = LLColor4(ctrl->getValue()); if( old_color != new_color ) { - getWearable()->setClothesColor(entry->mTextureIndex, new_color); + getWearable()->setClothesColor(entry->mTextureIndex, new_color, TRUE); LLVisualParamHint::requestHintUpdates(); - gAgentAvatarp->wearableUpdated(getWearable()->getType()); + gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); } } else @@ -1119,7 +1119,7 @@ void LLPanelEditWearable::saveChanges(bool force_save_as) // Remove old link remove_inventory_item(link_item->getUUID(), gAgentAvatarp->mEndCustomizeCallback); } - gAgentWearables.saveWearable(mWearablePtr->getType(), index, new_name); + gAgentWearables.saveWearable(mWearablePtr->getType(), index, TRUE, new_name); } @@ -1137,7 +1137,7 @@ void LLPanelEditWearable::revertChanges() mNameEditor->setText(mWearableItem->getName()); updatePanelPickerControls(mWearablePtr->getType()); updateTypeSpecificControls(mWearablePtr->getType()); - gAgentAvatarp->wearableUpdated(mWearablePtr->getType()); + gAgentAvatarp->wearableUpdated(mWearablePtr->getType(), FALSE); } void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BOOL disable_camera_switch) @@ -1604,7 +1604,7 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( IMG_INVISIBLE ); gAgentAvatarp->setLocalTexture(te, image, FALSE, index); - gAgentAvatarp->wearableUpdated(getWearable()->getType()); + gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); } else { @@ -1620,7 +1620,7 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL if (!image) return; gAgentAvatarp->setLocalTexture(te, image, FALSE, index); - gAgentAvatarp->wearableUpdated(getWearable()->getType()); + gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); } updatePanelPickerControls(getWearable()->getType()); @@ -1708,7 +1708,7 @@ void LLPanelEditWearable::onClickedImportBtn() { LLVisualParam* visual_param = getWearable()->getVisualParam(id); if (visual_param) - visual_param->setWeight(value); + visual_param->setWeight(value, FALSE); } else { diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp index 5ea2267f3f18cc80fc7ced963bb6a87c084d17e9..873b85ae2232033be647f55582671aac2131a00a 100755 --- a/indra/newview/llphysicsmotion.cpp +++ b/indra/newview/llphysicsmotion.cpp @@ -669,7 +669,7 @@ BOOL LLPhysicsMotion::onUpdate(F32 time) if ((driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) && (driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT)) { - mCharacter->setVisualParamWeight(driver_param, 0); + mCharacter->setVisualParamWeight(driver_param, 0, FALSE); } S32 num_driven = driver_param->getDrivenParamsCount(); for (S32 i = 0; i < num_driven; ++i) @@ -769,5 +769,5 @@ void LLPhysicsMotion::setParamValue(const LLViewerVisualParam *param, // Scale from [0,1] to [value_min_local,value_max_local] const F32 new_value_local = value_min_local + (value_max_local-value_min_local) * new_value_rescaled; - mCharacter->setVisualParamWeight(param, new_value_local); + mCharacter->setVisualParamWeight(param, new_value_local, FALSE); } diff --git a/indra/newview/llscrollingpanelparam.cpp b/indra/newview/llscrollingpanelparam.cpp index bfa453a0ae1862f72286ef4be3453f13e7e2a734..797ed261de30e2cff2d4df5889b1ac8ca4ad3eb5 100755 --- a/indra/newview/llscrollingpanelparam.cpp +++ b/indra/newview/llscrollingpanelparam.cpp @@ -266,8 +266,7 @@ void LLScrollingPanelParam::onHintHeldDown( LLVisualParamHint* hint ) if (slider->getMinValue() < new_percent && new_percent < slider->getMaxValue()) { - mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight); - mWearable->writeToAvatar(gAgentAvatarp); + mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight, FALSE); mWearable->writeToAvatar(gAgentAvatarp); gAgentAvatarp->updateVisualParams(); slider->setValue( weightToPercent( new_weight ) ); @@ -299,7 +298,7 @@ void LLScrollingPanelParam::onHintMinMouseUp( void* userdata ) if (slider->getMinValue() < new_percent && new_percent < slider->getMaxValue()) { - self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight); + self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE); self->mWearable->writeToAvatar(gAgentAvatarp); slider->setValue( self->weightToPercent( new_weight ) ); } @@ -333,7 +332,7 @@ void LLScrollingPanelParam::onHintMaxMouseUp( void* userdata ) if (slider->getMinValue() < new_percent && new_percent < slider->getMaxValue()) { - self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight); + self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE); self->mWearable->writeToAvatar(gAgentAvatarp); slider->setValue( self->weightToPercent( new_weight ) ); } diff --git a/indra/newview/llscrollingpanelparambase.cpp b/indra/newview/llscrollingpanelparambase.cpp index fe7a3627235560c7cd38b126d7417477c928aece..b1ac39bfff7707a892e42702ae7e26634f14b31b 100755 --- a/indra/newview/llscrollingpanelparambase.cpp +++ b/indra/newview/llscrollingpanelparambase.cpp @@ -93,7 +93,7 @@ void LLScrollingPanelParamBase::onSliderMoved(LLUICtrl* ctrl, void* userdata) F32 new_weight = self->percentToWeight( (F32)slider->getValue().asReal() ); if (current_weight != new_weight ) { - self->mWearable->setVisualParamWeight( param->getID(), new_weight); + self->mWearable->setVisualParamWeight( param->getID(), new_weight, FALSE); self->mWearable->writeToAvatar(gAgentAvatarp); gAgentAvatarp->updateVisualParams(); } diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 95500d72fff263c4cb694c7a015b5f8031cb2c2b..45d7d40d1bab6b109a74de821a7f853fae193fab 100755 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2078,7 +2078,8 @@ bool idle_startup() { gAgentWearables.notifyLoadingStarted(); gAgent.setOutfitChosen(TRUE); - gAgentWearables.sendDummyAgentWearablesUpdate(); + if (LLGridManager::getInstance()->isInSecondlife()) + gAgentWearables.sendDummyAgentWearablesUpdate(); callAfterCategoryFetch(LLAppearanceMgr::instance().getCOF(), set_flags_and_update_appearance); } @@ -2137,7 +2138,8 @@ bool idle_startup() display_startup(); - if (gAgent.isOutfitChosen() && (wearables_time > max_wearables_time)) + if ((LLGridManager::getInstance()->isInSecondlife() && gAgent.isOutfitChosen() && (wearables_time > max_wearables_time)) || + (!LLGridManager::getInstance()->isInSecondlife() && (wearables_time > max_wearables_time))) { LLNotificationsUtil::add("ClothingLoading"); record(LLStatViewer::LOADING_WEARABLES_LONG_DELAY, wearables_time); @@ -2413,6 +2415,8 @@ void register_viewer_callbacks(LLMessageSystem* msg) msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value); msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation); msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance); + msg->setHandlerFunc("AgentCachedTextureResponse", LLAgent::processAgentCachedTextureResponse); + msg->setHandlerFunc("RebakeAvatarTextures", LLVOAvatarSelf::processRebakeAvatarTextures); msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint); msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response); msg->setHandlerFunc("SetFollowCamProperties", process_set_follow_cam_properties); @@ -2486,6 +2490,8 @@ void register_viewer_callbacks(LLMessageSystem* msg) // msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply, // LLFloaterRate::processReputationIndividualReply); + msg->setHandlerFuncFast(_PREHASH_AgentWearablesUpdate, LLAgentWearables::processAgentInitialWearablesUpdate ); + msg->setHandlerFunc("ScriptControlChange", LLAgent::processScriptControlChange ); @@ -2650,7 +2656,8 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, } gAgent.setOutfitChosen(TRUE); - gAgentWearables.sendDummyAgentWearablesUpdate(); + if (LLGridManager::getInstance()->isInSecondlife()) + gAgentWearables.sendDummyAgentWearablesUpdate(); } //static diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index edc0271451e6d5b02f505d992e428990e904427f..bd456413ae0eccf951aa68609ad39f41842a1744 100755 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -435,6 +435,15 @@ void LLAvatarTexBar::draw() LLColor4 text_color = LLColor4::white; + if (layerset_buffer->uploadNeeded()) + { + text_color = LLColor4::red; + } + if (layerset_buffer->uploadInProgress()) + { + text_color = LLColor4::magenta; + } + std::string text = layerset_buffer->dumpTextureInfo(); LLFontGL::getFontMonospace()->renderUTF8(text, 0, l_offset, v_offset + line_height*line_num, text_color, LLFontGL::LEFT, LLFontGL::TOP); //, LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT); diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp index 2d458db36bb782d86be08b836c4e65380c2b6a1d..71e0509d03795d01b77d781e1a243399e8bfbbb7 100755 --- a/indra/newview/lltoolmorph.cpp +++ b/indra/newview/lltoolmorph.cpp @@ -154,8 +154,8 @@ void LLVisualParamHint::preRender(BOOL clear_depth) wearable->setVolatile(TRUE); } mLastParamWeight = mVisualParam->getWeight(); - mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight); - gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight); + mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); + gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); gAgentAvatarp->setVisualParamWeight("Blink_Left", 0.f); gAgentAvatarp->setVisualParamWeight("Blink_Right", 0.f); gAgentAvatarp->updateComposites(); @@ -246,7 +246,7 @@ BOOL LLVisualParamHint::render() gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); } gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight); - mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight); + mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight, FALSE); LLViewerWearable* wearable = (LLViewerWearable*)mWearablePtr; if (wearable) { diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 2387b4b53f2b99101e8373f7b82587bfd9e09231..531d0b55800224c1bb9ccfbfe3890e3c269f2f7b 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -4325,6 +4325,10 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) gAgent.setTeleportState( LLAgent::TELEPORT_START_ARRIVAL ); + // set the appearance on teleport since the new sim does not + // know what you look like. + gAgent.sendAgentSetAppearance(); + if (isAgentAvatarValid()) { // Set the new position diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index e13633def49f537190edde7fe7a1704b8dd830c5..9c54272bd952be30d587a2781bd5a92cb68382f8 100755 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -102,6 +102,7 @@ #include "llmediaentry.h" #include "llfloaterperms.h" #include "llvocache.h" +#include "llviewernetwork.h" //#define DEBUG_UPDATE_TYPE @@ -154,7 +155,11 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco { gAgentAvatarp = new LLVOAvatarSelf(id, pcode, regionp); gAgentAvatarp->initInstance(); - gAgentWearables.setAvatarObject(gAgentAvatarp); + if (LLGridManager::getInstance()->isInSecondlife()) + { + gAgentWearables.setAvatarObject(gAgentAvatarp); + + } } else { @@ -5631,7 +5636,7 @@ BOOL LLViewerObject::permOwnerModify() const return TRUE; #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER - if (!LLGridManager::getInstance()->isInProductionGrid() + if (!LLGridManager::getInstance()->isInSLMain() && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) { return TRUE; @@ -5655,7 +5660,7 @@ BOOL LLViewerObject::permModify() const return TRUE; #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER - if (!LLGridManager::getInstance()->isInProductionGrid() + if (!LLGridManager::getInstance()->isInSLMain() && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) { return TRUE; diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 8e5600006bb4ab415405e4704877e7858e8b3799..f74958b4f03c94c4d9dfad5461524dbf0db7f454 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -416,7 +416,7 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, mSimAccess( SIM_ACCESS_MIN ), mBillableFactor(1.0), mMaxTasks(DEFAULT_MAX_REGION_WIDE_PRIM_COUNT), - mCentralBakeVersion(1), + mCentralBakeVersion(0), mClassID(0), mCPURatio(0), mColoName("unknown"), diff --git a/indra/newview/llviewertexlayer.cpp b/indra/newview/llviewertexlayer.cpp index 66e5742911e85d03128fa23328f2b638d5dc94c0..cadb8d2aa433cc6dff5e831865531bd07ac2489e 100755 --- a/indra/newview/llviewertexlayer.cpp +++ b/indra/newview/llviewertexlayer.cpp @@ -37,11 +37,32 @@ #include "llglslshader.h" #include "llvoavatarself.h" #include "pipeline.h" +#include "llassetuploadresponders.h" #include "llviewercontrol.h" +#include "llviewerstats.h" + +static const S32 BAKE_UPLOAD_ATTEMPTS = 7; +static const F32 BAKE_UPLOAD_RETRY_DELAY = 2.f; // actual delay grows by power of 2 each attempt // runway consolidate extern std::string self_av_string(); + +//----------------------------------------------------------------------------- +// LLBakedUploadData() +//----------------------------------------------------------------------------- +LLBakedUploadData::LLBakedUploadData(const LLVOAvatarSelf* avatar, + LLViewerTexLayerSet* layerset, + const LLUUID& id, + bool highest_res) : + mAvatar(avatar), + mTexLayerSet(layerset), + mID(id), + mStartTime(LLFrameTimer::getTotalTime()), // Record starting time + mIsHighestRes(highest_res) +{ +} + //----------------------------------------------------------------------------- // LLViewerTexLayerSetBuffer // The composite image that a LLViewerTexLayerSet writes to. Each LLViewerTexLayerSet has one. @@ -55,10 +76,15 @@ LLViewerTexLayerSetBuffer::LLViewerTexLayerSetBuffer(LLTexLayerSet* const owner, // ORDER_LAST => must render these after the hints are created. LLTexLayerSetBuffer(owner), LLViewerDynamicTexture( width, height, 4, LLViewerDynamicTexture::ORDER_LAST, TRUE ), + mUploadPending(FALSE), // Not used for any logic here, just to sync sending of updates + mNeedsUpload(FALSE), + mNumLowresUploads(0), + mUploadFailCount(0), mNeedsUpdate(TRUE), mNumLowresUpdates(0) { LLViewerTexLayerSetBuffer::sGLByteCount += getSize(); + mNeedsUploadTimer.start(); mNeedsUpdateTimer.start(); } @@ -101,6 +127,33 @@ void LLViewerTexLayerSetBuffer::requestUpdate() restartUpdateTimer(); mNeedsUpdate = TRUE; mNumLowresUpdates = 0; + // If we're in the middle of uploading a baked texture, we don't care about it any more. + // When it's downloaded, ignore it. + mUploadID.setNull(); +} + +void LLViewerTexLayerSetBuffer::requestUpload() +{ + conditionalRestartUploadTimer(); + mNeedsUpload = TRUE; + mNumLowresUploads = 0; + mUploadPending = TRUE; +} + +void LLViewerTexLayerSetBuffer::conditionalRestartUploadTimer() +{ + // If we requested a new upload but haven't even uploaded + // a low res version of our last upload request, then + // keep the timer ticking instead of resetting it. + if (mNeedsUpload && (mNumLowresUploads == 0)) + { + mNeedsUploadTimer.unpause(); + } + else + { + mNeedsUploadTimer.reset(); + mNeedsUploadTimer.start(); + } } void LLViewerTexLayerSetBuffer::restartUpdateTimer() @@ -109,16 +162,25 @@ void LLViewerTexLayerSetBuffer::restartUpdateTimer() mNeedsUpdateTimer.start(); } +void LLViewerTexLayerSetBuffer::cancelUpload() +{ + mNeedsUpload = FALSE; + mUploadPending = FALSE; + mNeedsUploadTimer.pause(); + mUploadRetryTimer.reset(); +} + // virtual BOOL LLViewerTexLayerSetBuffer::needsRender() { llassert(mTexLayerSet->getAvatarAppearance() == gAgentAvatarp); if (!isAgentAvatarValid()) return FALSE; + const BOOL upload_now = mNeedsUpload && isReadyToUpload(); const BOOL update_now = mNeedsUpdate && isReadyToUpdate(); // Don't render if we don't want to (or aren't ready to) update. - if (!update_now) + if (!(update_now || upload_now)) { return FALSE; } @@ -133,6 +195,7 @@ BOOL LLViewerTexLayerSetBuffer::needsRender() if (gAgentAvatarp->getBakedTE(getViewerTexLayerSet()) == LLAvatarAppearanceDefines::TEX_SKIRT_BAKED && !gAgentAvatarp->isWearingWearableType(LLWearableType::WT_SKIRT)) { + cancelUpload(); return FALSE; } @@ -160,7 +223,36 @@ void LLViewerTexLayerSetBuffer::postRenderTexLayerSet(BOOL success) // virtual void LLViewerTexLayerSetBuffer::midRenderTexLayerSet(BOOL success) { + // do we need to upload, and do we have sufficient data to create an uploadable composite? + // TODO: When do we upload the texture if gAgent.mNumPendingQueries is non-zero? + const BOOL upload_now = mNeedsUpload && isReadyToUpload(); const BOOL update_now = mNeedsUpdate && isReadyToUpdate(); + + if(upload_now) + { + if (!success) + { + LL_INFOS() << "Failed attempt to bake " << mTexLayerSet->getBodyRegionName() << LL_ENDL; + mUploadPending = FALSE; + } + else + { + LLViewerTexLayerSet* layer_set = getViewerTexLayerSet(); + if (layer_set->isVisible()) + { + layer_set->getAvatar()->debugBakedTextureUpload(layer_set->getBakedTexIndex(), FALSE); // FALSE for start of upload, TRUE for finish. + doUpload(); + } + else + { + mUploadPending = FALSE; + mNeedsUpload = FALSE; + mNeedsUploadTimer.pause(); + layer_set->getAvatar()->setNewBakedTexture(layer_set->getBakedTexIndex(),IMG_INVISIBLE); + } + } + } + if (update_now) { doUpdate(); @@ -176,6 +268,60 @@ BOOL LLViewerTexLayerSetBuffer::isInitialized(void) const return mGLTexturep.notNull() && mGLTexturep->isGLTextureCreated(); } +BOOL LLViewerTexLayerSetBuffer::uploadPending() const +{ + return mUploadPending; +} + +BOOL LLViewerTexLayerSetBuffer::uploadNeeded() const +{ + return mNeedsUpload; +} + +BOOL LLViewerTexLayerSetBuffer::uploadInProgress() const +{ + return !mUploadID.isNull(); +} + +BOOL LLViewerTexLayerSetBuffer::isReadyToUpload() const +{ + if (!gAgentQueryManager.hasNoPendingQueries()) return FALSE; // Can't upload if there are pending queries. + if (isAgentAvatarValid() && gAgentAvatarp->isEditingAppearance()) return FALSE; // Don't upload if avatar is being edited. + + BOOL ready = FALSE; + if (getViewerTexLayerSet()->isLocalTextureDataFinal()) + { + // If we requested an upload and have the final LOD ready, upload (or wait a while if this is a retry) + if (mUploadFailCount == 0) + { + ready = TRUE; + } + else + { + ready = mUploadRetryTimer.getElapsedTimeF32() >= BAKE_UPLOAD_RETRY_DELAY * (1 << (mUploadFailCount - 1)); + } + } + else + { + // Upload if we've hit a timeout. Upload is a pretty expensive process so we need to make sure + // we aren't doing uploads too frequently. + const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedTextureUploadTimeout"); + if (texture_timeout != 0) + { + // The timeout period increases exponentially between every lowres upload in order to prevent + // spamming the server with frequent uploads. + const U32 texture_timeout_threshold = texture_timeout*(1 << mNumLowresUploads); + + // If we hit our timeout and have textures available at even lower resolution, then upload. + const BOOL is_upload_textures_timeout = mNeedsUploadTimer.getElapsedTimeF32() >= texture_timeout_threshold; + const BOOL has_lower_lod = getViewerTexLayerSet()->isLocalTextureDataAvailable(); + ready = has_lower_lod && is_upload_textures_timeout; + } + } + + return ready; +} + BOOL LLViewerTexLayerSetBuffer::isReadyToUpdate() const { // If we requested an update and have the final LOD ready, then update. @@ -212,6 +358,158 @@ BOOL LLViewerTexLayerSetBuffer::requestUpdateImmediate() return result; } +// Create the baked texture, send it out to the server, then wait for it to come +// back so we can switch to using it. +void LLViewerTexLayerSetBuffer::doUpload() +{ + LLViewerTexLayerSet* layer_set = getViewerTexLayerSet(); + LL_INFOS() << "Uploading baked " << layer_set->getBodyRegionName() << LL_ENDL; + add(LLStatViewer::TEX_BAKES, 1); + + // Don't need caches since we're baked now. (note: we won't *really* be baked + // until this image is sent to the server and the Avatar Appearance message is received.) + layer_set->deleteCaches(); + + // Get the COLOR information from our texture + U8* baked_color_data = new U8[ mFullWidth * mFullHeight * 4 ]; + glReadPixels(mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, GL_RGBA, GL_UNSIGNED_BYTE, baked_color_data ); + stop_glerror(); + + // Get the MASK information from our texture + LLGLSUIDefault gls_ui; + LLPointer<LLImageRaw> baked_mask_image = new LLImageRaw(mFullWidth, mFullHeight, 1 ); + U8* baked_mask_data = baked_mask_image->getData(); + layer_set->gatherMorphMaskAlpha(baked_mask_data, + mOrigin.mX, mOrigin.mY, + mFullWidth, mFullHeight); + + + // Create the baked image from our color and mask information + const S32 baked_image_components = 5; // red green blue [bump] clothing + LLPointer<LLImageRaw> baked_image = new LLImageRaw( mFullWidth, mFullHeight, baked_image_components ); + U8* baked_image_data = baked_image->getData(); + S32 i = 0; + for (S32 u=0; u < mFullWidth; u++) + { + for (S32 v=0; v < mFullHeight; v++) + { + baked_image_data[5*i + 0] = baked_color_data[4*i + 0]; + baked_image_data[5*i + 1] = baked_color_data[4*i + 1]; + baked_image_data[5*i + 2] = baked_color_data[4*i + 2]; + baked_image_data[5*i + 3] = baked_color_data[4*i + 3]; // alpha should be correct for eyelashes. + baked_image_data[5*i + 4] = baked_mask_data[i]; + i++; + } + } + + LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C; + const char* comment_text = LINDEN_J2C_COMMENT_PREFIX "RGBHM"; // writes into baked_color_data. 5 channels (rgb, heightfield/alpha, mask) + if (compressedImage->encode(baked_image, comment_text)) + { + LLTransactionID tid; + tid.generate(); + const LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); + if (LLVFile::writeFile(compressedImage->getData(), compressedImage->getDataSize(), + gVFS, asset_id, LLAssetType::AT_TEXTURE)) + { + // Read back the file and validate. + BOOL valid = FALSE; + LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C; + S32 file_size = 0; + LLVFile file(gVFS, asset_id, LLAssetType::AT_TEXTURE); + file_size = file.getSize(); + U8* data = integrity_test->allocateData(file_size); + file.read(data, file_size); + if (data) + { + valid = integrity_test->validate(data, file_size); // integrity_test will delete 'data' + } + else + { + integrity_test->setLastError("Unable to read entire file"); + } + + if (valid) + { + const bool highest_lod = layer_set->isLocalTextureDataFinal(); + // Baked_upload_data is owned by the responder and deleted after the request completes. + LLBakedUploadData* baked_upload_data = new LLBakedUploadData(gAgentAvatarp, + layer_set, + asset_id, + highest_lod); + // upload ID is used to avoid overlaps, e.g. when the user rapidly makes two changes outside of Face Edit. + mUploadID = asset_id; + + // Upload the image + const std::string url = gAgent.getRegion()->getCapability("UploadBakedTexture"); + if(!url.empty() + && !LLPipeline::sForceOldBakedUpload // toggle debug setting UploadBakedTexOld to change between the new caps method and old method + && (mUploadFailCount < (BAKE_UPLOAD_ATTEMPTS - 1))) // Try last ditch attempt via asset store if cap upload is failing. + { + LLSD body = LLSD::emptyMap(); + // The responder will call LLViewerTexLayerSetBuffer::onTextureUploadComplete() + LLHTTPClient::post(url, body, new LLSendTexLayerResponder(body, mUploadID, LLAssetType::AT_TEXTURE, baked_upload_data)); + LL_INFOS() << "Baked texture upload via capability of " << mUploadID << " to " << url << LL_ENDL; + } + else + { + gAssetStorage->storeAssetData(tid, + LLAssetType::AT_TEXTURE, + LLViewerTexLayerSetBuffer::onTextureUploadComplete, + baked_upload_data, + TRUE, // temp_file + TRUE, // is_priority + TRUE); // store_local + LL_INFOS() << "Baked texture upload via Asset Store." << LL_ENDL; + } + + if (highest_lod) + { + // Sending the final LOD for the baked texture. All done, pause + // the upload timer so we know how long it took. + mNeedsUpload = FALSE; + mNeedsUploadTimer.pause(); + } + else + { + // Sending a lower level LOD for the baked texture. Restart the upload timer. + mNumLowresUploads++; + mNeedsUploadTimer.unpause(); + mNeedsUploadTimer.reset(); + } + + // Print out notification that we uploaded this texture. + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + const std::string lod_str = highest_lod ? "HighRes" : "LowRes"; + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)layer_set->getAvatar()->debugGetExistenceTimeElapsedF32()); + args["TIME"] = llformat("%d",(U32)mNeedsUploadTimer.getElapsedTimeF32()); + args["BODYREGION"] = layer_set->getBodyRegionName(); + args["RESOLUTION"] = lod_str; + LLNotificationsUtil::add("AvatarRezSelfBakedTextureUploadNotification",args); + LL_DEBUGS("Avatar") << self_av_string() << "Uploading [ name: " << layer_set->getBodyRegionName() << " res:" << lod_str << " time:" << (U32)mNeedsUploadTimer.getElapsedTimeF32() << " ]" << LL_ENDL; + } + } + else + { + // The read back and validate operation failed. Remove the uploaded file. + mUploadPending = FALSE; + LLVFile file(gVFS, asset_id, LLAssetType::AT_TEXTURE, LLVFile::WRITE); + file.remove(); + LL_INFOS() << "Unable to create baked upload file (reason: corrupted)." << LL_ENDL; + } + } + } + else + { + // The VFS write file operation failed. + mUploadPending = FALSE; + LL_INFOS() << "Unable to create baked upload file (reason: failed to write file)" << LL_ENDL; + } + + delete [] baked_color_data; +} // Mostly bookkeeping; don't need to actually "do" anything since // render() will actually do the update. @@ -249,6 +547,82 @@ void LLViewerTexLayerSetBuffer::doUpdate() } } +// static +void LLViewerTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid, + void* userdata, + S32 result, + LLExtStat ext_status) // StoreAssetData callback (not fixed) +{ + LLBakedUploadData* baked_upload_data = (LLBakedUploadData*)userdata; + + if (isAgentAvatarValid() && + !gAgentAvatarp->isDead() && + (baked_upload_data->mAvatar == gAgentAvatarp) && // Sanity check: only the user's avatar should be uploading textures. + (baked_upload_data->mTexLayerSet->hasComposite())) + { + LLViewerTexLayerSetBuffer* layerset_buffer = baked_upload_data->mTexLayerSet->getViewerComposite(); + S32 failures = layerset_buffer->mUploadFailCount; + layerset_buffer->mUploadFailCount = 0; + + if (layerset_buffer->mUploadID.isNull()) + { + // The upload got canceled, we should be in the + // process of baking a new texture so request an + // upload with the new data + + // BAP: does this really belong in this callback, as + // opposed to where the cancellation takes place? + // suspect this does nothing. + layerset_buffer->requestUpload(); + } + else if (baked_upload_data->mID == layerset_buffer->mUploadID) + { + // This is the upload we're currently waiting for. + layerset_buffer->mUploadID.setNull(); + const std::string name(baked_upload_data->mTexLayerSet->getBodyRegionName()); + const std::string resolution = baked_upload_data->mIsHighestRes ? " full res " : " low res "; + if (result >= 0) + { + layerset_buffer->mUploadPending = FALSE; // Allows sending of AgentSetAppearance later + LLAvatarAppearanceDefines::ETextureIndex baked_te = gAgentAvatarp->getBakedTE(layerset_buffer->getViewerTexLayerSet()); + // Update baked texture info with the new UUID + U64 now = LLFrameTimer::getTotalTime(); // Record starting time + LL_INFOS() << "Baked" << resolution << "texture upload for " << name << " took " << (S32)((now - baked_upload_data->mStartTime) / 1000) << " ms" << LL_ENDL; + gAgentAvatarp->setNewBakedTexture(baked_te, uuid); + } + else + { + ++failures; + S32 max_attempts = baked_upload_data->mIsHighestRes ? BAKE_UPLOAD_ATTEMPTS : 1; // only retry final bakes + LL_WARNS() << "Baked" << resolution << "texture upload for " << name << " failed (attempt " << failures << "/" << max_attempts << ")" << LL_ENDL; + if (failures < max_attempts) + { + layerset_buffer->mUploadFailCount = failures; + layerset_buffer->mUploadRetryTimer.start(); + layerset_buffer->requestUpload(); + } + } + } + else + { + LL_INFOS() << "Received baked texture out of date, ignored." << LL_ENDL; + } + + gAgentAvatarp->dirtyMesh(); + } + else + { + // Baked texture failed to upload (in which case since we + // didn't set the new baked texture, it means that they'll try + // and rebake it at some point in the future (after login?)), + // or this response to upload is out of date, in which case a + // current response should be on the way or already processed. + LL_WARNS() << "Baked upload failed" << LL_ENDL; + } + + delete baked_upload_data; +} + //----------------------------------------------------------------------------- // LLViewerTexLayerSet // An ordered set of texture layers that get composited into a single texture. @@ -290,6 +664,20 @@ void LLViewerTexLayerSet::requestUpdate() } } +void LLViewerTexLayerSet::requestUpload() +{ + createComposite(); + getViewerComposite()->requestUpload(); +} + +void LLViewerTexLayerSet::cancelUpload() +{ + if(mComposite) + { + getViewerComposite()->cancelUpload(); + } +} + void LLViewerTexLayerSet::updateComposite() { createComposite(); @@ -342,12 +730,19 @@ const std::string LLViewerTexLayerSetBuffer::dumpTextureInfo() const { if (!isAgentAvatarValid()) return ""; - const BOOL is_high_res = TRUE; - const U32 num_low_res = 0; + const BOOL is_high_res = !mNeedsUpload; + const U32 num_low_res = mNumLowresUploads; + const U32 upload_time = (U32)mNeedsUploadTimer.getElapsedTimeF32(); const std::string local_texture_info = gAgentAvatarp->debugDumpLocalTextureDataInfo(getViewerTexLayerSet()); - std::string text = llformat("[HiRes:%d LoRes:%d] %s", + std::string status = "CREATING "; + if (!uploadNeeded()) status = "DONE "; + if (uploadInProgress()) status = "UPLOADING"; + + std::string text = llformat("[%s] [HiRes:%d LoRes:%d] [Elapsed:%d] %s", + status.c_str(), is_high_res, num_low_res, + upload_time, local_texture_info.c_str()); return text; } diff --git a/indra/newview/llviewertexlayer.h b/indra/newview/llviewertexlayer.h index 027ae255ec3b53fef615dd18eec97b96ee6613d0..0de6bbe389ef769acf2ed308f4bfc9d3e42b2ae6 100755 --- a/indra/newview/llviewertexlayer.h +++ b/indra/newview/llviewertexlayer.h @@ -47,6 +47,8 @@ public: virtual ~LLViewerTexLayerSet(); /*virtual*/void requestUpdate(); + void requestUpload(); + void cancelUpload(); BOOL isLocalTextureDataAvailable() const; BOOL isLocalTextureDataFinal() const; void updateComposite(); @@ -112,7 +114,33 @@ protected: virtual void preRender(BOOL clear_depth) { preRenderTexLayerSet(); } virtual void postRender(BOOL success) { postRenderTexLayerSet(success); } virtual BOOL render() { return renderTexLayerSet(); } - + + + //-------------------------------------------------------------------- + // Uploads + //-------------------------------------------------------------------- +public: + void requestUpload(); + void cancelUpload(); + BOOL uploadNeeded() const; // We need to upload a new texture + BOOL uploadInProgress() const; // We have started uploading a new texture and are awaiting the result + BOOL uploadPending() const; // We are expecting a new texture to be uploaded at some point + static void onTextureUploadComplete(const LLUUID& uuid, + void* userdata, + S32 result, LLExtStat ext_status); +protected: + BOOL isReadyToUpload() const; + void doUpload(); // Does a read back and upload. + void conditionalRestartUploadTimer(); +private: + BOOL mNeedsUpload; // Whether we need to send our baked textures to the server + U32 mNumLowresUploads; // Number of times we've sent a lowres version of our baked textures to the server + BOOL mUploadPending; // Whether we have received back the new baked textures + LLUUID mUploadID; // The current upload process (null if none). + LLFrameTimer mNeedsUploadTimer; // Tracks time since upload was requested and performed. + S32 mUploadFailCount; // Number of consecutive upload failures + LLFrameTimer mUploadRetryTimer; // Tracks time since last upload failure. + //-------------------------------------------------------------------- // Updates //-------------------------------------------------------------------- @@ -129,5 +157,24 @@ private: LLFrameTimer mNeedsUpdateTimer; // Tracks time since update was requested and performed. }; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// LLBakedUploadData +// +// Used by LLTexLayerSetBuffer for a callback. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +struct LLBakedUploadData +{ + LLBakedUploadData(const LLVOAvatarSelf* avatar, + LLViewerTexLayerSet* layerset, + const LLUUID& id, + bool highest_res); + ~LLBakedUploadData() {} + const LLUUID mID; + const LLVOAvatarSelf* mAvatar; // note: backlink only; don't LLPointer + LLViewerTexLayerSet* mTexLayerSet; + const U64 mStartTime; // for measuring baked texture upload time + const bool mIsHighestRes; // whether this is a "final" bake, or intermediate low res +}; #endif // LL_VIEWER_TEXLAYER_H diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 411c46e32daf40c72f496ca9ab16bb47ba28d7b7..6e2681e63bc5fde87c338ff61953af0f9dcae9de 100755 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1018,7 +1018,8 @@ LLViewerFetchedTexture::LLViewerFetchedTexture(const LLUUID& id, FTType f_type, mFTType = f_type; if (mFTType == FTT_HOST_BAKE) { - LL_WARNS() << "Unsupported fetch type " << mFTType << LL_ENDL; + //LL_WARNS() << "Unsupported fetch type " << mFTType << LL_ENDL; + mCanUseHTTP = false; } generateGLTexture(); } diff --git a/indra/newview/llviewerwearable.cpp b/indra/newview/llviewerwearable.cpp index 47d0592ae6aa9a9b0bd4196dd1677ed76f40410b..a2565c7fe8d1f1182d7fd13b0e06e28ce56c8857 100755 --- a/indra/newview/llviewerwearable.cpp +++ b/indra/newview/llviewerwearable.cpp @@ -268,7 +268,7 @@ void LLViewerWearable::setParamsToDefaults() { if( (((LLViewerVisualParam*)param)->getWearableType() == mType ) && (param->isTweakable() ) ) { - setVisualParamWeight(param->getID(),param->getDefaultWeight()); + setVisualParamWeight(param->getID(),param->getDefaultWeight(), FALSE); } } } @@ -353,14 +353,14 @@ void LLViewerWearable::writeToAvatar(LLAvatarAppearance *avatarp) ESex new_sex = avatarp->getSex(); if( old_sex != new_sex ) { - viewer_avatar->updateSexDependentLayerSets(); + viewer_avatar->updateSexDependentLayerSets(FALSE); } } // Updates the user's avatar's appearance, replacing this wearables' parameters and textures with default values. // static -void LLViewerWearable::removeFromAvatar( LLWearableType::EType type) +void LLViewerWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload_bake) { if (!isAgentAvatarValid()) return; @@ -379,7 +379,7 @@ void LLViewerWearable::removeFromAvatar( LLWearableType::EType type) if( (((LLViewerVisualParam*)param)->getWearableType() == type) && (param->isTweakable() ) ) { S32 param_id = param->getID(); - gAgentAvatarp->setVisualParamWeight( param_id, param->getDefaultWeight()); + gAgentAvatarp->setVisualParamWeight( param_id, param->getDefaultWeight(), upload_bake); } } @@ -389,7 +389,7 @@ void LLViewerWearable::removeFromAvatar( LLWearableType::EType type) } gAgentAvatarp->updateVisualParams(); - gAgentAvatarp->wearableUpdated(type); + gAgentAvatarp->wearableUpdated(type, FALSE); } // Does not copy mAssetID. @@ -499,6 +499,12 @@ void LLViewerWearable::refreshName() } } +void LLViewerWearable::addToBakedTextureHash(LLMD5& hash) const +{ + LLUUID asset_id = getAssetID(); + hash.update((const unsigned char*)asset_id.mData, UUID_BYTES); +} + struct LLWearableSaveData { LLWearableType::EType mType; diff --git a/indra/newview/llviewerwearable.h b/indra/newview/llviewerwearable.h index 62cd5e21add899551997d32ba06a1b773e315f4a..869aec3c95761d1f8ff4b54b3d84e81c52a777fd 100755 --- a/indra/newview/llviewerwearable.h +++ b/indra/newview/llviewerwearable.h @@ -62,8 +62,8 @@ public: BOOL isOldVersion() const; /*virtual*/ void writeToAvatar(LLAvatarAppearance *avatarp); - void removeFromAvatar() { LLViewerWearable::removeFromAvatar( mType); } - static void removeFromAvatar( LLWearableType::EType type); + void removeFromAvatar( BOOL upload_bake ) { LLViewerWearable::removeFromAvatar( mType, upload_bake ); } + static void removeFromAvatar( LLWearableType::EType type, BOOL upload_bake ); /*virtual*/ EImportResult importStream( std::istream& input_stream, LLAvatarAppearance* avatarp ); @@ -91,7 +91,7 @@ public: // the wearable was worn. make sure the name of the wearable object matches the LLViewerInventoryItem, // not the wearable asset itself. void refreshName(); - /*virtual*/void addToBakedTextureHash(LLMD5& hash) const {} + /*virtual*/void addToBakedTextureHash(LLMD5& hash) const; protected: LLAssetID mAssetID; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 7f427a2136feba551fe891144a6c4ab4e01a235c..14b1801eab4b13c5a66b2b92b09206bd4d75a8b6 100755 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -725,6 +725,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mLastRezzedStatus(-1), mIsEditingAppearance(FALSE), mUseLocalAppearance(FALSE), + mUseServerBakes(FALSE), mLastUpdateRequestCOFVersion(-1), mLastUpdateReceivedCOFVersion(-1), mCachedMuteListUpdateTime(0), @@ -1102,7 +1103,7 @@ void LLVOAvatar::restoreGL() gAgentAvatarp->setCompositeUpdatesEnabled(TRUE); for (U32 i = 0; i < gAgentAvatarp->mBakedTextureDatas.size(); i++) { - gAgentAvatarp->invalidateComposite(gAgentAvatarp->getTexLayerSet(i)); + gAgentAvatarp->invalidateComposite(gAgentAvatarp->getTexLayerSet(i), FALSE); } gAgentAvatarp->updateMeshTextures(); } @@ -2091,14 +2092,20 @@ LLViewerFetchedTexture *LLVOAvatar::getBakedTextureImage(const U8 te, const LLUU { const std::string url = getImageURL(te,uuid); - if (url.empty()) + if (!url.empty()) { - LL_WARNS() << "unable to determine URL for te " << te << " uuid " << uuid << LL_ENDL; - return NULL; + LL_DEBUGS("Avatar") << avString() << "get server-bake image from URL " << url << LL_ENDL; + result = LLViewerTextureManager::getFetchedTextureFromUrl( + url, FTT_SERVER_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid); } - LL_DEBUGS("Avatar") << avString() << "get server-bake image from URL " << url << LL_ENDL; - result = LLViewerTextureManager::getFetchedTextureFromUrl( - url, FTT_SERVER_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid); + else + { + LL_DEBUGS("Avatar") << avString() << "get old-bake image from host " << uuid << LL_ENDL; + LLHost host = getObjectHost(); + result = LLViewerTextureManager::getFetchedTexture( + uuid, FTT_HOST_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host); + } + if (result->isMissingAsset()) { result->setIsMissingAsset(false); @@ -2332,8 +2339,8 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) if ( mLipSyncActive ) { - if( mOohMorph ) mOohMorph->setWeight(mOohMorph->getMinWeight()); - if( mAahMorph ) mAahMorph->setWeight(mAahMorph->getMinWeight()); + if( mOohMorph ) mOohMorph->setWeight(mOohMorph->getMinWeight(), FALSE); + if( mAahMorph ) mAahMorph->setWeight(mAahMorph->getMinWeight(), FALSE); mLipSyncActive = false; LLCharacter::updateVisualParams(); @@ -2539,10 +2546,14 @@ void LLVOAvatar::idleUpdateAppearanceAnimation() { if (param->isTweakable()) { - param->stopAnimating(); + param->stopAnimating(FALSE); } } updateVisualParams(); + if (isSelf()) + { + gAgent.sendAgentSetAppearance(); + } } else { @@ -2558,7 +2569,7 @@ void LLVOAvatar::idleUpdateAppearanceAnimation() { if (param->isTweakable()) { - param->animate(morph_amt); + param->animate(morph_amt, FALSE); } } } @@ -2611,7 +2622,7 @@ void LLVOAvatar::idleUpdateLipSync(bool voice_enabled) F32 ooh_weight = mOohMorph->getMinWeight() + ooh_morph_amount * (mOohMorph->getMaxWeight() - mOohMorph->getMinWeight()); - mOohMorph->setWeight( ooh_weight); + mOohMorph->setWeight( ooh_weight, FALSE); } if( mAahMorph ) @@ -2619,7 +2630,7 @@ void LLVOAvatar::idleUpdateLipSync(bool voice_enabled) F32 aah_weight = mAahMorph->getMinWeight() + aah_morph_amount * (mAahMorph->getMaxWeight() - mAahMorph->getMinWeight()); - mAahMorph->setWeight( aah_weight); + mAahMorph->setWeight( aah_weight, FALSE); } mLipSyncActive = true; @@ -3363,7 +3374,7 @@ void LLVOAvatar::updateDebugText() isSelf() ? (all_local_downloaded ? "L" : "l") : "-", all_baked_downloaded ? "B" : "b", mUseLocalAppearance, mIsEditingAppearance, - 1, central_bake_version); + mUseServerBakes, central_bake_version); std::string origin_string = bakedTextureOriginInfo(); debug_line += " [" + origin_string + "]"; S32 curr_cof_version = LLAppearanceMgr::instance().getCOFVersion(); @@ -4510,6 +4521,34 @@ bool LLVOAvatar::allBakedTexturesCompletelyDownloaded() const return allTexturesCompletelyDownloaded(baked_ids); } +void LLVOAvatar::bakedTextureOriginCounts(S32 &sb_count, // server-bake, has origin URL. + S32 &host_count, // host-based bake, has host. + S32 &both_count, // error - both host and URL set. + S32 &neither_count) // error - neither set. +{ + sb_count = host_count = both_count = neither_count = 0; + + std::set<LLUUID> baked_ids; + collectBakedTextureUUIDs(baked_ids); + for (std::set<LLUUID>::const_iterator it = baked_ids.begin(); it != baked_ids.end(); ++it) + { + LLViewerFetchedTexture *imagep = gTextureList.findImage(*it); + bool has_url = false, has_host = false; + if (!imagep->getUrl().empty()) + { + has_url = true; + } + if (imagep->getTargetHost().isOk()) + { + has_host = true; + } + if (has_url && !has_host) sb_count++; + else if (has_host && !has_url) host_count++; + else if (has_host && has_url) both_count++; + else if (!has_host && !has_url) neither_count++; + } +} + std::string LLVOAvatar::bakedTextureOriginInfo() { std::string result; @@ -4750,6 +4789,19 @@ void LLVOAvatar::updateTextures() { const S32 boost_level = getAvatarBakedBoostLevel(); imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index,0), TRUE); + // Spam if this is a baked texture, not set to default image, without valid host info + if (isIndexBakedTexture((ETextureIndex)texture_index) + && imagep->getID() != IMG_DEFAULT_AVATAR + && imagep->getID() != IMG_INVISIBLE + && !isUsingServerBakes() + && !imagep->getTargetHost().isOk()) + { + LL_WARNS_ONCE("Texture") << "LLVOAvatar::updateTextures No host for texture " + << imagep->getID() << " for avatar " + << (isSelf() ? "<myself>" : getID().asString()) + << " on host " << getRegion()->getHost() << LL_ENDL; + } + addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level ); } } @@ -4881,19 +4933,22 @@ const std::string LLVOAvatar::getImageURL(const U8 te, const LLUUID &uuid) { llassert(isIndexBakedTexture(ETextureIndex(te))); std::string url = ""; - const std::string& appearance_service_url = LLAppearanceMgr::instance().getAppearanceServiceURL(); - if (appearance_service_url.empty()) + if (isUsingServerBakes()) { - // Probably a server-side issue if we get here: - LL_WARNS() << "AgentAppearanceServiceURL not set - Baked texture requests will fail" << LL_ENDL; - return url; - } + const std::string& appearance_service_url = LLAppearanceMgr::instance().getAppearanceServiceURL(); + if (appearance_service_url.empty()) + { + // Probably a server-side issue if we get here: + LL_WARNS() << "AgentAppearanceServiceURL not set - Baked texture requests will fail" << LL_ENDL; + return url; + } - const LLAvatarAppearanceDictionary::TextureEntry* texture_entry = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)te); - if (texture_entry != NULL) - { - url = appearance_service_url + "texture/" + getID().asString() + "/" + texture_entry->mDefaultImageName + "/" + uuid.asString(); - //LL_INFOS() << "baked texture url: " << url << LL_ENDL; + const LLAvatarAppearanceDictionary::TextureEntry* texture_entry = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)te); + if (texture_entry != NULL) + { + url = appearance_service_url + "texture/" + getID().asString() + "/" + texture_entry->mDefaultImageName + "/" + uuid.asString(); + //LL_INFOS() << "baked texture url: " << url << LL_ENDL; + } } return url; } @@ -5851,11 +5906,11 @@ BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable) //----------------------------------------------------------------------------- // updateSexDependentLayerSets() //----------------------------------------------------------------------------- -void LLVOAvatar::updateSexDependentLayerSets() +void LLVOAvatar::updateSexDependentLayerSets(BOOL upload_bake) { - invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet); - invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet); - invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet); + invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake); + invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake); + invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, upload_bake); } //----------------------------------------------------------------------------- @@ -6443,8 +6498,7 @@ LLViewerObject * LLVOAvatar::findAttachmentByID( const LLUUID & target_id ) cons } // virtual -void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset) -{ +void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result){ } void LLVOAvatar::invalidateAll() @@ -6452,19 +6506,18 @@ void LLVOAvatar::invalidateAll() } // virtual -void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color) +void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake) { if (global_color == mTexSkinColor) { - invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet); - invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet); - invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet); + invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake); + invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake); + invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, upload_bake); } else if (global_color == mTexHairColor) { - invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet); - invalidateComposite( mBakedTextureDatas[BAKED_HAIR].mTexLayerSet); - + invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake); + invalidateComposite( mBakedTextureDatas[BAKED_HAIR].mTexLayerSet, upload_bake); // ! BACKWARDS COMPATIBILITY ! // Fix for dealing with avatars from viewers that don't bake hair. if (!isTextureDefined(mBakedTextureDatas[BAKED_HAIR].mTextureIndex)) @@ -6485,8 +6538,7 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color) else if (global_color == mTexEyeColor) { // LL_INFOS() << "invalidateComposite cause: onGlobalColorChanged( eyecolor )" << LL_ENDL; - invalidateComposite( mBakedTextureDatas[BAKED_EYES].mTexLayerSet); - } + invalidateComposite( mBakedTextureDatas[BAKED_EYES].mTexLayerSet, upload_bake); } updateMeshTextures(); } @@ -6681,7 +6733,7 @@ void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapse } record["grid_x"] = LLSD::Integer(grid_x); record["grid_y"] = LLSD::Integer(grid_y); - record["is_using_server_bakes"] = true; + record["is_using_server_bakes"] = ((bool) isUsingServerBakes()); record["is_self"] = isSelf(); if (isAgentAvatarValid()) @@ -7538,13 +7590,13 @@ bool resolve_appearance_version(const LLAppearanceMessageContents& contents, S32 { appearance_version = contents.mParamAppearanceVersion; } - else if (contents.mAppearanceVersion > 0) + if (contents.mAppearanceVersion >= 0) { appearance_version = contents.mAppearanceVersion; } - else // still not set, go with 1. + if (appearance_version < 0) // still not set, go with 0. { - appearance_version = 1; + appearance_version = 0; } LL_DEBUGS("Avatar") << "appearance version info - field " << contents.mAppearanceVersion << " param: " << contents.mParamAppearanceVersion @@ -7599,6 +7651,14 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) LL_DEBUGS("Avatar") << "this_update_cof_version " << this_update_cof_version << " last_update_request_cof_version " << last_update_request_cof_version << " my_cof_version " << LLAppearanceMgr::instance().getCOFVersion() << LL_ENDL; + if (getRegion() && (getRegion()->getCentralBakeVersion()==0)) + { + LL_WARNS() << avString() << "Received AvatarAppearance message for self in non-server-bake region" << LL_ENDL; + } + if( mFirstTEMessageReceived && (appearance_version == 0)) + { + return; + } } else { @@ -7607,6 +7667,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) // Check for stale update. if (isSelf() + && (appearance_version>0) && (this_update_cof_version < last_update_request_cof_version)) { LL_WARNS() << "Stale appearance update, wanted version " << last_update_request_cof_version @@ -7633,13 +7694,17 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) } // No backsies zone - if we get here, the message should be valid and usable, will be processed. + setIsUsingServerBakes(appearance_version > 0); + if (appearance_version > 0) + { // Note: // RequestAgentUpdateAppearanceResponder::onRequestRequested() // assumes that cof version is only updated with server-bake // appearance messages. mLastUpdateReceivedCOFVersion = this_update_cof_version; + } applyParsedTEMessage(contents.mTEContents); // prevent the overwriting of valid baked textures with invalid baked textures @@ -7649,13 +7714,13 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) && mBakedTextureDatas[baked_index].mLastTextureID != IMG_DEFAULT && baked_index != BAKED_SKIRT) { - LL_DEBUGS("Avatar") << avString() << " baked_index " << (S32) baked_index << " using mLastTextureID " << mBakedTextureDatas[baked_index].mLastTextureID << LL_ENDL; + LL_DEBUGS("Avatar") << avString() << "sb " << (S32) isUsingServerBakes() << " baked_index " << (S32) baked_index << " using mLastTextureID " << mBakedTextureDatas[baked_index].mLastTextureID << LL_ENDL; setTEImage(mBakedTextureDatas[baked_index].mTextureIndex, LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[baked_index].mLastTextureID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)); } else { - LL_DEBUGS("Avatar") << avString() << " baked_index " << (S32) baked_index << " using texture id " + LL_DEBUGS("Avatar") << avString() << "sb " << (S32) isUsingServerBakes() << " baked_index " << (S32) baked_index << " using texture id " << getTE(mBakedTextureDatas[baked_index].mTextureIndex)->getID() << LL_ENDL; } } @@ -7698,12 +7763,12 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) if(is_first_appearance_message) { //LL_DEBUGS("Avatar") << "param slam " << i << " " << newWeight << LL_ENDL; - param->setWeight(newWeight); + param->setWeight(newWeight, FALSE); } else { interp_params = TRUE; - param->setAnimationTarget(newWeight); + param->setAnimationTarget(newWeight, FALSE); } } } @@ -7726,7 +7791,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) ESex new_sex = getSex(); if( old_sex != new_sex ) { - updateSexDependentLayerSets(); + updateSexDependentLayerSets(FALSE); } } @@ -8294,6 +8359,39 @@ void LLVOAvatar::startAppearanceAnimation() } } +// virtual +void LLVOAvatar::bodySizeChanged() +{ + if (isSelf() && !LLAppearanceMgr::instance().isInUpdateAppearanceFromCOF()) + { // notify simulator of change in size + // but not if we are in the middle of updating appearance + gAgent.sendAgentSetAppearance(); + } +} + +BOOL LLVOAvatar::isUsingServerBakes() const +{ + // Sanity check - visual param for appearance version should match mUseServerBakes + LLVisualParam* appearance_version_param = getVisualParam(11000); + llassert(appearance_version_param); + F32 wt = appearance_version_param->getWeight(); + F32 expect_wt = mUseServerBakes ? 1.0 : 0.0; + if (!is_approx_equal(wt, expect_wt)) + { + LL_WARNS() << "wt " << wt << " differs from expected " << expect_wt << LL_ENDL; + } + + return mUseServerBakes; +} + +void LLVOAvatar::setIsUsingServerBakes(BOOL newval) +{ + mUseServerBakes = newval; + LLVisualParam* appearance_version_param = getVisualParam(11000); + llassert(appearance_version_param); + appearance_version_param->setWeight(newval ? 1.0 : 0.0, false); +} + // virtual void LLVOAvatar::removeMissingBakedTextures() { diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index b3bd471960cf901574bd2d145e7d014217ad6ce6..53746b450d97890e6ec0d30a8e2affdaa6e5e36e 100755 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -442,7 +442,7 @@ public: // Global colors //-------------------------------------------------------------------- public: - /*virtual*/void onGlobalColorChanged(const LLTexGlobalColor* global_color); + /*virtual*/void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake) override; //-------------------------------------------------------------------- // Visibility @@ -602,7 +602,7 @@ protected: // Composites //-------------------------------------------------------------------- public: - virtual void invalidateComposite(LLTexLayerSet* layerset); + virtual void invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result); virtual void invalidateAll(); virtual void setCompositeUpdatesEnabled(bool b) {} virtual void setCompositeUpdatesEnabled(U32 index, bool b) {} @@ -639,7 +639,7 @@ private: public: void debugColorizeSubMeshes(U32 i, const LLColor4& color); virtual void updateMeshTextures(); - void updateSexDependentLayerSets(); + void updateSexDependentLayerSets(BOOL upload_bake); virtual void dirtyMesh(); // Dirty the avatar mesh void updateMeshData(); protected: @@ -671,8 +671,9 @@ public: void parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMessageContents& msg); void processAvatarAppearance(LLMessageSystem* mesgsys); void hideSkirt(); - void startAppearanceAnimation(); - + void startAppearanceAnimation(); + /*virtual*/ void bodySizeChanged(); + //-------------------------------------------------------------------- // Appearance morphing //-------------------------------------------------------------------- @@ -684,6 +685,9 @@ public: // editing or when waiting for a subsequent server rebake. /*virtual*/ BOOL isUsingLocalAppearance() const { return mUseLocalAppearance; } + BOOL isUsingServerBakes() const; + void setIsUsingServerBakes(BOOL newval); + // True if we are currently in appearance editing mode. Often but // not always the same as isUsingLocalAppearance(). /*virtual*/ BOOL isEditingAppearance() const { return mIsEditingAppearance; } @@ -696,6 +700,7 @@ private: F32 mLastAppearanceBlendTime; BOOL mIsEditingAppearance; // flag for if we're actively in appearance editing mode BOOL mUseLocalAppearance; // flag for if we're using a local composite + BOOL mUseServerBakes; // flag for if baked textures should be fetched from baking service (false if they're temporary uploads) //-------------------------------------------------------------------- // Visibility diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index dd8838ad4c96be9c1e0eefce98db2c3e6d7f2638..9f3bd97d987b44d8e65d8f5fbf713f710c1b799c 100755 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -59,6 +59,7 @@ #include "llsdutil.h" #include "llstartup.h" #include "llsdserialize.h" +#include "llviewernetwork.h" LLPointer<LLVOAvatarSelf> gAgentAvatarp = NULL; @@ -170,6 +171,10 @@ LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id, // first time through. mLastHoverOffsetSent(LLVector3(0.0f, 0.0f, -999.0f)) { + if (!LLGridManager::getInstance()->isInSecondlife()) + { + gAgentWearables.setAvatarObject(this); + } mMotionController.mIsSelf = TRUE; LL_DEBUGS() << "Marking avatar as self " << id << LL_ENDL; @@ -195,6 +200,16 @@ bool update_avatar_rez_metrics() return false; } +bool check_for_unsupported_baked_appearance() +{ + if (!isAgentAvatarValid()) + return true; + + gAgentAvatarp->checkForUnsupportedServerBakeAppearance(); + return false; + +} + void LLVOAvatarSelf::initInstance() { BOOL status = TRUE; @@ -233,14 +248,16 @@ void LLVOAvatarSelf::initInstance() //doPeriodically(output_self_av_texture_diagnostics, 30.0); doPeriodically(update_avatar_rez_metrics, 5.0); + doPeriodically(check_for_unsupported_baked_appearance, 120.0); doPeriodically(boost::bind(&LLVOAvatarSelf::checkStuckAppearance, this), 30.0); } void LLVOAvatarSelf::setHoverIfRegionEnabled() { - if (getRegion() && getRegion()->simulatorFeaturesReceived()) + LLViewerRegion* region = getRegion(); + if (region && region->simulatorFeaturesReceived()) { - if (getRegion()->avatarHoverHeightEnabled()) + if (region->avatarHoverHeightEnabled()) { F32 hover_z = gSavedPerAccountSettings.getF32("AvatarHoverOffsetZ"); setHoverOffset(LLVector3(0.0, 0.0, llclamp(hover_z,MIN_HOVER_Z,MAX_HOVER_Z))); @@ -255,9 +272,9 @@ void LLVOAvatarSelf::setHoverIfRegionEnabled() else { LL_INFOS("Avatar") << avString() << " region or simulator features not known, no change on hover" << LL_ENDL; - if (getRegion()) + if (region) { - getRegion()->setSimulatorFeaturesReceivedCallback(boost::bind(&LLVOAvatarSelf::onSimulatorFeaturesReceived,this,_1)); + region->setSimulatorFeaturesReceivedCallback(boost::bind(&LLVOAvatarSelf::onSimulatorFeaturesReceived, this, _1)); } } @@ -707,35 +724,35 @@ LLJoint *LLVOAvatarSelf::getJoint(const std::string &name) //return LLVOAvatar::getJoint(name); } // virtual -BOOL LLVOAvatarSelf::setVisualParamWeight(const LLVisualParam *which_param, F32 weight) +BOOL LLVOAvatarSelf::setVisualParamWeight(const LLVisualParam *which_param, F32 weight, BOOL upload_bake) { if (!which_param) { return FALSE; } LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(which_param->getID()); - return setParamWeight(param,weight); + return setParamWeight(param,weight,upload_bake); } // virtual -BOOL LLVOAvatarSelf::setVisualParamWeight(const char* param_name, F32 weight) +BOOL LLVOAvatarSelf::setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake) { if (!param_name) { return FALSE; } LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(param_name); - return setParamWeight(param,weight); + return setParamWeight(param,weight,upload_bake); } // virtual -BOOL LLVOAvatarSelf::setVisualParamWeight(S32 index, F32 weight) +BOOL LLVOAvatarSelf::setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake) { LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(index); - return setParamWeight(param,weight); + return setParamWeight(param,weight,upload_bake); } -BOOL LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight) +BOOL LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight, BOOL upload_bake) { if (!param) { @@ -751,12 +768,12 @@ BOOL LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight LLViewerWearable *wearable = gAgentWearables.getViewerWearable(type,count); if (wearable) { - wearable->setVisualParamWeight(param->getID(), weight); + wearable->setVisualParamWeight(param->getID(), weight, upload_bake); } } } - return LLCharacter::setVisualParamWeight(param,weight); + return LLCharacter::setVisualParamWeight(param,weight,upload_bake); } /*virtual*/ @@ -782,7 +799,7 @@ void LLVOAvatarSelf::writeWearablesToAvatar() void LLVOAvatarSelf::idleUpdateAppearanceAnimation() { // Animate all top-level wearable visual parameters - gAgentWearables.animateAllWearableParams(calcMorphAmount()); + gAgentWearables.animateAllWearableParams(calcMorphAmount(), FALSE); // Apply wearable visual params to avatar writeWearablesToAvatar(); @@ -876,9 +893,13 @@ void LLVOAvatarSelf::removeMissingBakedTextures() { LLViewerTexLayerSet *layerset = getTexLayerSet(i); layerset->setUpdatesEnabled(TRUE); - invalidateComposite(layerset); + invalidateComposite(layerset, FALSE); } updateMeshTextures(); + if (getRegion() && !getRegion()->getCentralBakeVersion()) + { + requestLayerSetUploads(); + } } } @@ -1155,7 +1176,7 @@ void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode) // forces an update to any baked textures relevant to type. // will force an upload of the resulting bake if the second parameter is TRUE //----------------------------------------------------------------------------- -void LLVOAvatarSelf::wearableUpdated(LLWearableType::EType type) +void LLVOAvatarSelf::wearableUpdated(LLWearableType::EType type, BOOL upload_result) { for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin(); baked_iter != LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end(); @@ -1177,13 +1198,20 @@ void LLVOAvatarSelf::wearableUpdated(LLWearableType::EType type) if (layerset) { layerset->setUpdatesEnabled(true); - invalidateComposite(layerset); + invalidateComposite(layerset, upload_result); } break; } } } } + + // Physics type has no associated baked textures, but change of params needs to be sent to + // other avatars. + if (type == LLWearableType::WT_PHYSICS) + { + gAgent.sendAgentSetAppearance(); + } } //----------------------------------------------------------------------------- @@ -1565,6 +1593,15 @@ BOOL LLVOAvatarSelf::isAllLocalTextureDataFinal() const return TRUE; } +BOOL LLVOAvatarSelf::isBakedTextureFinal(const LLAvatarAppearanceDefines::EBakedTextureIndex index) const +{ + const LLViewerTexLayerSet *layerset = getLayerSet(index); + if (!layerset) return FALSE; + const LLViewerTexLayerSetBuffer *layerset_buffer = layerset->getViewerComposite(); + if (!layerset_buffer) return FALSE; + return !layerset_buffer->uploadNeeded(); +} + BOOL LLVOAvatarSelf::isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const { LLUUID id; @@ -1630,12 +1667,48 @@ BOOL LLVOAvatarSelf::isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex t } } +//----------------------------------------------------------------------------- +// requestLayerSetUploads() +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::requestLayerSetUploads() +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + requestLayerSetUpload((EBakedTextureIndex)i); + } +} + +void LLVOAvatarSelf::requestLayerSetUpload(LLAvatarAppearanceDefines::EBakedTextureIndex i) +{ + ETextureIndex tex_index = mBakedTextureDatas[i].mTextureIndex; + const BOOL layer_baked = isTextureDefined(tex_index, gAgentWearables.getWearableCount(tex_index)); + LLViewerTexLayerSet *layerset = getLayerSet(i); + if (!layer_baked && layerset) + { + layerset->requestUpload(); + } +} + bool LLVOAvatarSelf::areTexturesCurrent() const { - return gAgentWearables.areWearablesLoaded(); + return !hasPendingBakedUploads() && gAgentWearables.areWearablesLoaded(); } -void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset) +// virtual +bool LLVOAvatarSelf::hasPendingBakedUploads() const +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + LLViewerTexLayerSet* layerset = getTexLayerSet(i); + if (layerset && layerset->getViewerComposite() && layerset->getViewerComposite()->uploadPending()) + { + return true; + } + } + return false; +} + +void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result) { LLViewerTexLayerSet *layer_set = dynamic_cast<LLViewerTexLayerSet*>(layerset); if( !layer_set || !layer_set->getUpdatesEnabled() ) @@ -1646,6 +1719,16 @@ void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset) layer_set->requestUpdate(); layer_set->invalidateMorphMasks(); + + if( upload_result && (getRegion() && !getRegion()->getCentralBakeVersion())) + { + llassert(isSelf()); + + ETextureIndex baked_te = getBakedTE( layer_set ); + setTEImage( baked_te, LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR) ); + layer_set->requestUpload(); + updateMeshTextures(); + } } void LLVOAvatarSelf::invalidateAll() @@ -1653,7 +1736,7 @@ void LLVOAvatarSelf::invalidateAll() for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { LLViewerTexLayerSet *layerset = getTexLayerSet(i); - invalidateComposite(layerset); + invalidateComposite(layerset, TRUE); } //mDebugSelfLoadTimer.reset(); } @@ -2428,6 +2511,59 @@ void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics() } } +class CheckAgentAppearanceServiceResponder: public LLHTTPClient::Responder +{ +public: + CheckAgentAppearanceServiceResponder() {} + + virtual ~CheckAgentAppearanceServiceResponder() {} + + /* virtual */ void httpSuccess() + { + LL_DEBUGS("Avatar") << "OK" << LL_ENDL; + } + + // Error + /*virtual*/ void httpFailure() + { + if (isAgentAvatarValid()) + { + LL_DEBUGS("Avatar") << "failed, will rebake " + << dumpResponse() << LL_ENDL; + forceAppearanceUpdate(); + } + } + + static void forceAppearanceUpdate() + { + // Trying to rebake immediately after crossing region boundary + // seems to be failure prone; adding a delay factor. Yes, this + // fix is ad-hoc and not guaranteed to work in all cases. + doAfterInterval(boost::bind(&LLVOAvatarSelf::forceBakeAllTextures, + gAgentAvatarp.get(), true), 5.0); + } +}; + +void LLVOAvatarSelf::checkForUnsupportedServerBakeAppearance() +{ + // Need to check only if we have a server baked appearance and are + // in a non-baking region. + if (!gAgentAvatarp->isUsingServerBakes()) + return; + if (!gAgent.getRegion() || gAgent.getRegion()->getCentralBakeVersion()!=0) + return; + + // if baked image service is unknown, need to refresh. + if (LLAppearanceMgr::instance().getAppearanceServiceURL().empty()) + { + CheckAgentAppearanceServiceResponder::forceAppearanceUpdate(); + } + // query baked image service to check status. + std::string image_url = gAgentAvatarp->getImageURL(TEX_HEAD_BAKED, + getTE(TEX_HEAD_BAKED)->getID()); + LLHTTPClient::head(image_url, new CheckAgentAppearanceServiceResponder); +} + const LLUUID& LLVOAvatarSelf::grabBakedTexture(EBakedTextureIndex baked_index) const { if (canGrabBakedTexture(baked_index)) @@ -2584,6 +2720,81 @@ ETextureIndex LLVOAvatarSelf::getBakedTE( const LLViewerTexLayerSet* layerset ) return TEX_HEAD_BAKED; } + +void LLVOAvatarSelf::setNewBakedTexture(LLAvatarAppearanceDefines::EBakedTextureIndex i, const LLUUID &uuid) +{ + ETextureIndex index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex(i); + setNewBakedTexture(index, uuid); +} + + +//----------------------------------------------------------------------------- +// setNewBakedTexture() +// A new baked texture has been successfully uploaded and we can start using it now. +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::setNewBakedTexture( ETextureIndex te, const LLUUID& uuid ) +{ + // Baked textures live on other sims. + LLHost target_host = getObjectHost(); + setTEImage( te, LLViewerTextureManager::getFetchedTextureFromHost( uuid, FTT_HOST_BAKE, target_host ) ); + updateMeshTextures(); + dirtyMesh(); + + LLVOAvatar::cullAvatarsByPixelArea(); + + /* switch(te) + case TEX_HEAD_BAKED: + LL_INFOS() << "New baked texture: HEAD" << LL_ENDL; */ + const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture(te); + if (texture_dict->mIsBakedTexture) + { + debugBakedTextureUpload(texture_dict->mBakedTextureIndex, TRUE); // FALSE for start of upload, TRUE for finish. + LL_INFOS() << "New baked texture: " << texture_dict->mName << " UUID: " << uuid <<LL_ENDL; + } + else + { + LL_WARNS() << "New baked texture: unknown te " << te << LL_ENDL; + } + + // dumpAvatarTEs( "setNewBakedTexture() send" ); + // RN: throttle uploads + if (!hasPendingBakedUploads()) + { + gAgent.sendAgentSetAppearance(); + + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["TIME"] = llformat("%d",(U32)mDebugSelfLoadTimer.getElapsedTimeF32()); + if (isAllLocalTextureDataFinal()) + { + LLNotificationsUtil::add("AvatarRezSelfBakedDoneNotification",args); + LL_DEBUGS("Avatar") << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() + << "sec ]" + << avString() + << "RuthTimer " << (U32)mRuthDebugTimer.getElapsedTimeF32() + << " SelfLoadTimer " << (U32)mDebugSelfLoadTimer.getElapsedTimeF32() + << " Notification " << "AvatarRezSelfBakedDoneNotification" + << LL_ENDL; + } + else + { + args["STATUS"] = debugDumpAllLocalTextureDataInfo(); + LLNotificationsUtil::add("AvatarRezSelfBakedUpdateNotification",args); + LL_DEBUGS("Avatar") << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() + << "sec ]" + << avString() + << "RuthTimer " << (U32)mRuthDebugTimer.getElapsedTimeF32() + << " SelfLoadTimer " << (U32)mDebugSelfLoadTimer.getElapsedTimeF32() + << " Notification " << "AvatarRezSelfBakedUpdateNotification" + << LL_ENDL; + } + } + + outputRezDiagnostics(); + } +} // FIXME: This is not called consistently. Something may be broken. void LLVOAvatarSelf::outputRezDiagnostics() const { @@ -2658,8 +2869,88 @@ void LLVOAvatarSelf::reportAvatarRezTime() const { // TODO: report mDebugSelfLoadTimer.getElapsedTimeF32() somehow. } +//----------------------------------------------------------------------------- +// setCachedBakedTexture() +// A baked texture id was received from a cache query, make it active +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::setCachedBakedTexture( ETextureIndex te, const LLUUID& uuid ) +{ + setTETexture( te, uuid ); + + /* switch(te) + case TEX_HEAD_BAKED: + if( mHeadLayerSet ) + mHeadLayerSet->cancelUpload(); */ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + LLViewerTexLayerSet *layerset = getTexLayerSet(i); + if ( mBakedTextureDatas[i].mTextureIndex == te && layerset) + { + if (mInitialBakeIDs[i] != LLUUID::null) + { + if (mInitialBakeIDs[i] == uuid) + { + LL_INFOS() << "baked texture correctly loaded at login! " << i << LL_ENDL; + } + else + { + LL_WARNS() << "baked texture does not match id loaded at login!" << i << LL_ENDL; + } + mInitialBakeIDs[i] = LLUUID::null; + } + layerset->cancelUpload(); + } + } +} + +// static +void LLVOAvatarSelf::processRebakeAvatarTextures(LLMessageSystem* msg, void**) +{ + LLUUID texture_id; + msg->getUUID("TextureData", "TextureID", texture_id); + if (!isAgentAvatarValid()) return; + + // If this is a texture corresponding to one of our baked entries, + // just rebake that layer set. + BOOL found = FALSE; + + /* ETextureIndex baked_texture_indices[BAKED_NUM_INDICES] = + TEX_HEAD_BAKED, + TEX_UPPER_BAKED, */ + for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); + iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); + ++iter) + { + const ETextureIndex index = iter->first; + const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second; + if (texture_dict->mIsBakedTexture) + { + if (texture_id == gAgentAvatarp->getTEImage(index)->getID()) + { + LLViewerTexLayerSet* layer_set = gAgentAvatarp->getLayerSet(index); + if (layer_set) + { + LL_INFOS() << "TAT: rebake - matched entry " << (S32)index << LL_ENDL; + gAgentAvatarp->invalidateComposite(layer_set, TRUE); + found = TRUE; + add(LLStatViewer::TEX_REBAKES, 1); + } + } + } + } + + // If texture not found, rebake all entries. + if (!found) + { + gAgentAvatarp->forceBakeAllTextures(); + } + else + { + // Not sure if this is necessary, but forceBakeAllTextures() does it. + gAgentAvatarp->updateMeshTextures(); + } +} -// SUNSHINE CLEANUP - not clear we need any of this, may be sufficient to request server appearance in llviewermenu.cpp:handle_rebake_textures() void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug) { LL_INFOS() << "TAT: forced full rebake. " << LL_ENDL; @@ -2673,9 +2964,10 @@ void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug) if (slam_for_debug) { layer_set->setUpdatesEnabled(TRUE); + layer_set->cancelUpload(); } - invalidateComposite(layer_set); + invalidateComposite(layer_set, TRUE); add(LLStatViewer::TEX_REBAKES, 1); } else @@ -2775,6 +3067,12 @@ void LLVOAvatarSelf::onCustomizeEnd(bool disable_camera_switch) if (isAgentAvatarValid()) { gAgentAvatarp->mIsEditingAppearance = false; + if (gAgentAvatarp->getRegion() && !gAgentAvatarp->getRegion()->getCentralBakeVersion()) + { + // FIXME DRANO - move to sendAgentSetAppearance, make conditional on upload complete. + gAgentAvatarp->mUseLocalAppearance = false; + } + gAgentAvatarp->invalidateAll(); if (gAgentCamera.cameraCustomizeAvatar() && !disable_camera_switch) diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index a64fc42132bcba65f8235bdf2d957791289b3f5c..e53f85fdfe61f067e0db4f1f05e1364d6075c26e 100755 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -90,16 +90,16 @@ public: /*virtual*/ void requestStopMotion(LLMotion* motion); /*virtual*/ LLJoint* getJoint(const std::string &name); - /*virtual*/ BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight); - /*virtual*/ BOOL setVisualParamWeight(const char* param_name, F32 weight); - /*virtual*/ BOOL setVisualParamWeight(S32 index, F32 weight); + /*virtual*/ BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight, BOOL upload_bake = FALSE) override; + /*virtual*/ BOOL setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake = FALSE) override; + /*virtual*/ BOOL setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake = FALSE) override; /*virtual*/ void updateVisualParams(); void writeWearablesToAvatar(); /*virtual*/ void idleUpdateAppearanceAnimation(); private: // helper function. Passed in param is assumed to be in avatar's parameter list. - BOOL setParamWeight(const LLViewerVisualParam *param, F32 weight); + BOOL setParamWeight(const LLViewerVisualParam *param, F32 weight, BOOL upload_bake = FALSE); @@ -184,10 +184,12 @@ public: // Loading status //-------------------------------------------------------------------- public: + /*virtual*/ bool hasPendingBakedUploads() const; S32 getLocalDiscardLevel(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const; bool areTexturesCurrent() const; BOOL isLocalTextureDataAvailable(const LLViewerTexLayerSet* layerset) const; BOOL isLocalTextureDataFinal(const LLViewerTexLayerSet* layerset) const; + BOOL isBakedTextureFinal(const LLAvatarAppearanceDefines::EBakedTextureIndex index) const; // If you want to check all textures of a given type, pass gAgentWearables.getWearableCount() for index /*virtual*/ BOOL isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const; /*virtual*/ BOOL isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex type, U32 index = 0) const; @@ -224,6 +226,12 @@ public: LLAvatarAppearanceDefines::ETextureIndex getBakedTE(const LLViewerTexLayerSet* layerset ) const; // SUNSHINE CLEANUP - dead? or update to just call request appearance update? void forceBakeAllTextures(bool slam_for_debug = false); + + void setNewBakedTexture(LLAvatarAppearanceDefines::EBakedTextureIndex i, const LLUUID &uuid); + void setNewBakedTexture(LLAvatarAppearanceDefines::ETextureIndex i, const LLUUID& uuid); + void setCachedBakedTexture(LLAvatarAppearanceDefines::ETextureIndex i, const LLUUID& uuid); + static void processRebakeAvatarTextures(LLMessageSystem* msg, void**); + protected: /*virtual*/ void removeMissingBakedTextures(); @@ -231,6 +239,8 @@ protected: // Layers //-------------------------------------------------------------------- public: + void requestLayerSetUploads(); + void requestLayerSetUpload(LLAvatarAppearanceDefines::EBakedTextureIndex i); void requestLayerSetUpdate(LLAvatarAppearanceDefines::ETextureIndex i); LLViewerTexLayerSet* getLayerSet(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index) const; LLViewerTexLayerSet* getLayerSet(LLAvatarAppearanceDefines::ETextureIndex index) const; @@ -240,7 +250,7 @@ public: // Composites //-------------------------------------------------------------------- public: - /* virtual */ void invalidateComposite(LLTexLayerSet* layerset); + /* virtual */ void invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result); /* virtual */ void invalidateAll(); /* virtual */ void setCompositeUpdatesEnabled(bool b); // only works for self /* virtual */ void setCompositeUpdatesEnabled(U32 index, bool b); @@ -282,7 +292,7 @@ protected: **/ public: - void wearableUpdated(LLWearableType::EType type); + void wearableUpdated(LLWearableType::EType type, BOOL upload_result); protected: U32 getNumWearables(LLAvatarAppearanceDefines::ETextureIndex i) const; @@ -386,6 +396,7 @@ public: const std::string debugDumpLocalTextureDataInfo(const LLViewerTexLayerSet* layerset) const; // Lists out state of this particular baked texture layer const std::string debugDumpAllLocalTextureDataInfo() const; // Lists out which baked textures are at highest LOD void sendViewerAppearanceChangeMetrics(); // send data associated with completing a change. + void checkForUnsupportedServerBakeAppearance(); private: LLFrameTimer mDebugSelfLoadTimer; F32 mDebugTimeWearablesLoaded;