From 45dae5ce43fbfbdf1caa26a22c8af8a76c46be0e Mon Sep 17 00:00:00 2001 From: Rye Mutt <rye@alchemyviewer.org> Date: Sun, 20 Mar 2022 22:00:21 -0400 Subject: [PATCH] Add support for viewer-side baking --- indra/llappearance/llavatarappearance.cpp | 11 +- indra/llappearance/llavatarappearance.h | 24 +- indra/llappearance/lldriverparam.cpp | 28 +- indra/llappearance/lldriverparam.h | 34 +- indra/llappearance/llpolymorph.cpp | 2 +- .../llappearance/llpolyskeletaldistortion.cpp | 2 +- indra/llappearance/lltexglobalcolor.cpp | 4 +- indra/llappearance/lltexglobalcolor.h | 4 +- indra/llappearance/lltexlayer.cpp | 6 +- indra/llappearance/lltexlayer.h | 2 +- indra/llappearance/lltexlayerparams.cpp | 32 +- indra/llappearance/lltexlayerparams.h | 48 +- indra/llappearance/llviewervisualparam.cpp | 2 +- indra/llappearance/llwearable.cpp | 18 +- indra/llappearance/llwearable.h | 6 +- indra/llcharacter/llcharacter.cpp | 14 +- indra/llcharacter/llcharacter.h | 7 +- indra/llcharacter/llvisualparam.cpp | 18 +- indra/llcharacter/llvisualparam.h | 8 +- indra/newview/CMakeLists.txt | 2 + indra/newview/llagent.cpp | 333 +++++++++- indra/newview/llagent.h | 25 + indra/newview/llagentwearables.cpp | 448 +++++++++++++- indra/newview/llagentwearables.h | 45 +- indra/newview/llagentwearablesfetch.cpp | 585 ++++++++++++++++++ indra/newview/llagentwearablesfetch.h | 114 ++++ indra/newview/llappearancemgr.cpp | 2 +- indra/newview/llemote.cpp | 12 +- indra/newview/lllocalbitmaps.cpp | 2 +- indra/newview/llpaneleditwearable.cpp | 20 +- indra/newview/llphysicsmotion.cpp | 4 +- indra/newview/llscrollingpanelparam.cpp | 6 +- indra/newview/llscrollingpanelparambase.cpp | 2 +- indra/newview/llstartup.cpp | 30 +- indra/newview/lltextureview.cpp | 9 + indra/newview/lltoolmorph.cpp | 6 +- indra/newview/llviewermessage.cpp | 4 + indra/newview/llviewerobject.cpp | 2 +- indra/newview/llviewerregion.cpp | 2 +- indra/newview/llviewertexlayer.cpp | 490 ++++++++++++++- indra/newview/llviewertexlayer.h | 81 ++- indra/newview/llviewertexture.cpp | 3 +- indra/newview/llviewerwearable.cpp | 16 +- indra/newview/llviewerwearable.h | 6 +- indra/newview/llvoavatar.cpp | 201 ++++-- indra/newview/llvoavatar.h | 29 +- indra/newview/llvoavatarself.cpp | 342 ++++++++-- indra/newview/llvoavatarself.h | 77 ++- 48 files changed, 2810 insertions(+), 358 deletions(-) create mode 100644 indra/newview/llagentwearablesfetch.cpp create mode 100644 indra/newview/llagentwearablesfetch.h diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index cdee35d9f65..7943c96d643 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -560,6 +560,7 @@ void LLAvatarAppearance::computeBodySize() #ifdef SHOW_DEBUG compareJointStateMaps(mLastBodySizeState, mCurrBodySizeState); #endif + bodySizeChanged(); } } @@ -1494,14 +1495,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 ); } } @@ -2143,7 +2144,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root LLAvatarAppearance::LLMaskedMorph::LLMaskedMorph(LLVisualParam *morph_target, BOOL invert, std::string layer) : mMorphTarget(morph_target), mInvert(invert), - mLayer(layer) + mLayer(std::move(layer)) { LLPolyMorphTarget *target = dynamic_cast<LLPolyMorphTarget*>(morph_target); if (target) diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index c721c86dd8e..6d2f720b93c 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -90,14 +90,14 @@ class LLAvatarAppearance : public LLCharacter // LLCharacter interface and related //-------------------------------------------------------------------- public: - /*virtual*/ LLJoint* getCharacterJoint(U32 num); + /*virtual*/ LLJoint* getCharacterJoint(U32 num) override; - /*virtual*/ const char* getAnimationPrefix() { return "avatar"; } - /*virtual*/ LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset); - /*virtual*/ LLJoint* findCollisionVolume(S32 volume_id); - /*virtual*/ S32 getCollisionVolumeID(std::string_view name); - /*virtual*/ LLPolyMesh* getHeadMesh(); - /*virtual*/ LLPolyMesh* getUpperBodyMesh(); + /*virtual*/ const char* getAnimationPrefix() override { return "avatar"; } + /*virtual*/ LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset) override; + /*virtual*/ LLJoint* findCollisionVolume(S32 volume_id) override; + /*virtual*/ S32 getCollisionVolumeID(std::string_view name) override; + /*virtual*/ LLPolyMesh* getHeadMesh() override; + /*virtual*/ LLPolyMesh* getUpperBodyMesh() override; /** Inherited ** ** @@ -110,6 +110,7 @@ class LLAvatarAppearance : public LLCharacter 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; @@ -134,7 +135,7 @@ class LLAvatarAppearance : public LLCharacter public: F32 getPelvisToFoot() const { return mPelvisToFoot; } - /*virtual*/ LLJoint* getRootJoint() { return mRoot; } + /*virtual*/ LLJoint* getRootJoint() override { return mRoot; } LLVector3 mHeadOffset; // current head position LLAvatarJoint *mRoot; @@ -160,6 +161,7 @@ class LLAvatarAppearance : public LLCharacter static BOOL parseSkeletonFile(const std::string& filename, LLXmlTree& skeleton_xml_tree); 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); @@ -243,7 +245,7 @@ class LLAvatarAppearance : public LLCharacter // Composites //-------------------------------------------------------------------- public: - virtual void invalidateComposite(LLTexLayerSet* layerset) = 0; + virtual void invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result) = 0; /******************************************************************************** ** ** @@ -278,7 +280,7 @@ class LLAvatarAppearance : public LLCharacter // 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); @@ -287,7 +289,7 @@ class LLAvatarAppearance : public LLCharacter //-------------------------------------------------------------------- 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 9e25c138d0f..e8263a3ac68 100644 --- a/indra/llappearance/lldriverparam.cpp +++ b/indra/llappearance/lldriverparam.cpp @@ -194,7 +194,7 @@ BOOL LLDriverParam::setInfo(LLDriverParamInfo *info) mID = info->mID; info->mDriverParam = this; - setWeight(getDefaultWeight()); + setWeight(getDefaultWeight(), FALSE ); return TRUE; } @@ -205,7 +205,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(); @@ -264,7 +264,7 @@ void LLDriverParam::setWeight(F32 weight) driven_weight = driven_min; } - setDrivenWeight(&driven,driven_weight); + setDrivenWeight(&driven,driven_weight,upload_bake); continue; } else @@ -288,13 +288,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); } } @@ -440,9 +440,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++ ) { @@ -451,16 +451,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++ ) { @@ -540,7 +540,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); } } } @@ -603,7 +603,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 && @@ -620,10 +620,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 dcff02fc375..1af6541a79e 100644 --- a/indra/llappearance/lldriverparam.h +++ b/indra/llappearance/lldriverparam.h @@ -65,9 +65,9 @@ class LLDriverParamInfo final : public LLViewerVisualParamInfo LLDriverParamInfo(); /*virtual*/ ~LLDriverParamInfo() = default; - /*virtual*/ BOOL parseXml(LLXmlTreeNode* node); + /*virtual*/ BOOL parseXml(LLXmlTreeNode* node) override; - /*virtual*/ void toStream(std::ostream &out); + /*virtual*/ void toStream(std::ostream &out) override; protected: typedef std::deque<LLDrivenEntryInfo> entry_info_list_t; @@ -107,24 +107,24 @@ class LLDriverParam final : public LLViewerVisualParam void updateCrossDrivenParams(LLWearableType::EType driven_type); - /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const; + /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const override; // 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*/ BOOL linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params); - /*virtual*/ void resetDrivenParams(); - /*virtual*/ bool isDriverParam() { return true; } + /*virtual*/ void apply( ESex sex ) override {} // apply is called separately for each driven param. + /*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) override; + /*virtual*/ void resetDrivenParams() override; + /*virtual*/ bool isDriverParam() override { return true; } // LLViewerVisualParam Virtual functions - /*virtual*/ F32 getTotalDistortion(); - /*virtual*/ const LLVector4a& getAvgDistortion(); - /*virtual*/ F32 getMaxDistortion(); - /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh); - /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh); - /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh); + /*virtual*/ F32 getTotalDistortion() override; + /*virtual*/ const LLVector4a& getAvgDistortion() override; + /*virtual*/ F32 getMaxDistortion() override; + /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) override; + /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) override; + /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) override; S32 getDrivenParamsCount() const; const LLViewerVisualParam* getDrivenParam(S32 index) const; @@ -136,7 +136,7 @@ class LLDriverParam final : public LLViewerVisualParam 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 c8837f3ae51..2d8ecce95fb 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 af8ea759a84..4b92af14572 100644 --- a/indra/llappearance/llpolyskeletaldistortion.cpp +++ b/indra/llappearance/llpolyskeletaldistortion.cpp @@ -121,7 +121,7 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info) } 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 7ce5714f06f..20d7f3fd7f7 100644 --- a/indra/llappearance/lltexglobalcolor.cpp +++ b/indra/llappearance/lltexglobalcolor.cpp @@ -98,9 +98,9 @@ LLTexParamGlobalColor::LLTexParamGlobalColor(LLTexGlobalColor* tex_global_color) 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 718685899af..629ef22bf37 100644 --- a/indra/llappearance/lltexglobalcolor.h +++ b/indra/llappearance/lltexglobalcolor.h @@ -76,10 +76,10 @@ class LLTexParamGlobalColor final : public LLTexLayerParamColor public: LLTexParamGlobalColor(LLTexGlobalColor *tex_color); virtual ~LLTexParamGlobalColor() = default; - /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const; + /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const override; protected: LLTexParamGlobalColor(const LLTexParamGlobalColor& pOther) = default; - /*virtual*/ void onGlobalColorChanged(); + /*virtual*/ void onGlobalColorChanged(bool upload_bake) override; private: LLTexGlobalColor* mTexGlobalColor; }; diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index 918d13d4758..fa2e86396d0 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -158,7 +158,7 @@ BOOL LLTexLayerSetBuffer::renderTexLayerSet(LLRenderTarget* bound_target) getCompositeWidth(), getCompositeHeight(), bound_target ); gGL.flush(); - midRenderTexLayerSet(success); + midRenderTexLayerSet(success, bound_target); if (use_shaders) { @@ -181,8 +181,8 @@ BOOL LLTexLayerSetBuffer::renderTexLayerSet(LLRenderTarget* bound_target) LLTexLayerSetInfo::LLTexLayerSetInfo() : mBodyRegion( "" ), - mWidth( 512 ), - mHeight( 512 ), + mWidth( 1024 ), + mHeight( 1024 ), mClearAlpha( TRUE ) { } diff --git a/indra/llappearance/lltexlayer.h b/indra/llappearance/lltexlayer.h index aaa32fd0296..a36e7754473 100644 --- a/indra/llappearance/lltexlayer.h +++ b/indra/llappearance/lltexlayer.h @@ -276,7 +276,7 @@ class LLTexLayerSetBuffer : public virtual LLRefCount void pushProjection() const; void popProjection() const; virtual void preRenderTexLayerSet(); - virtual void midRenderTexLayerSet(BOOL success) {} + virtual void midRenderTexLayerSet(BOOL success, LLRenderTarget* bound_target) {} virtual void postRenderTexLayerSet(BOOL success); virtual S32 getCompositeOriginX() const = 0; virtual S32 getCompositeOriginY() const = 0; diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp index a21696ad23a..79e3c165a1f 100644 --- a/indra/llappearance/lltexlayerparams.cpp +++ b/indra/llappearance/lltexlayerparams.cpp @@ -176,7 +176,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) { @@ -194,35 +194,35 @@ 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); } } @@ -460,7 +460,7 @@ LLColor4 LLTexLayerParamColor::getNetColor() const } -void LLTexLayerParamColor::setWeight(F32 weight) +void LLTexLayerParamColor::setWeight(F32 weight, BOOL upload_bake) { if (mIsAnimating) { @@ -486,10 +486,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); } } @@ -497,23 +497,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 1c593515019..0e66b1361c7 100644 --- a/indra/llappearance/lltexlayerparams.h +++ b/indra/llappearance/lltexlayerparams.h @@ -80,22 +80,22 @@ class LLTexLayerParamAlpha final : public LLTexLayerParam ll_aligned_free_16(ptr); } - /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const; + /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = nullptr) const override; // 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 apply( ESex avatar_sex ) override {} + /*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; } - /*virtual*/ F32 getMaxDistortion() { return 3.f; } - /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector4a(1.f, 1.f, 1.f);} - /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;}; - /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;}; + /*virtual*/ F32 getTotalDistortion() override { return 1.f; } + /*virtual*/ const LLVector4a& getAvgDistortion() override { return mAvgDistortionVec; } + /*virtual*/ F32 getMaxDistortion() override { return 3.f; } + /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) override { return LLVector4a(1.f, 1.f, 1.f);} + /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) override { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;}; + /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) override { index = 0; poly_mesh = NULL; return NULL;}; // New functions BOOL render( S32 x, S32 y, S32 width, S32 height ); @@ -129,7 +129,7 @@ class LLTexLayerParamAlphaInfo final : public LLViewerVisualParamInfo LLTexLayerParamAlphaInfo(); /*virtual*/ ~LLTexLayerParamAlphaInfo() = default; - /*virtual*/ BOOL parseXml(LLXmlTreeNode* node); + /*virtual*/ BOOL parseXml(LLXmlTreeNode* node) override; private: std::string mStaticImageFileName; @@ -177,26 +177,26 @@ class LLTexLayerParamColor : public LLTexLayerParam // 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 apply( ESex avatar_sex ) override {} + /*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); // LLViewerVisualParam Virtual functions - /*virtual*/ F32 getTotalDistortion() { return 1.f; } - /*virtual*/ const LLVector4a& getAvgDistortion() { return mAvgDistortionVec; } - /*virtual*/ F32 getMaxDistortion() { return 3.f; } - /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector4a(1.f, 1.f, 1.f); } - /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;}; - /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;}; + /*virtual*/ F32 getTotalDistortion() override { return 1.f; } + /*virtual*/ const LLVector4a& getAvgDistortion() override { return mAvgDistortionVec; } + /*virtual*/ F32 getMaxDistortion() override { return 3.f; } + /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) override { return LLVector4a(1.f, 1.f, 1.f); } + /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) override { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;}; + /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) override { index = 0; poly_mesh = NULL; return NULL;}; // New functions LLColor4 getNetColor() const; protected: LLTexLayerParamColor(const LLTexLayerParamColor& pOther) = default; - virtual void onGlobalColorChanged() {} + virtual void onGlobalColorChanged(bool upload_bake) {} private: LL_ALIGN_16(LLVector4a mAvgDistortionVec); } LL_ALIGN_POSTFIX(16); @@ -208,7 +208,7 @@ class LLTexLayerParamColorInfo final : public LLViewerVisualParamInfo public: LLTexLayerParamColorInfo(); virtual ~LLTexLayerParamColorInfo() = default; - BOOL parseXml( LLXmlTreeNode* node ); + BOOL parseXml( LLXmlTreeNode* node ) override; LLTexLayerParamColor::EColorOperation getOperation() const { return mOperation; } private: enum { MAX_COLOR_VALUES = 20 }; diff --git a/indra/llappearance/llviewervisualparam.cpp b/indra/llappearance/llviewervisualparam.cpp index 86d20b163c6..e083022d40d 100644 --- a/indra/llappearance/llviewervisualparam.cpp +++ b/indra/llappearance/llviewervisualparam.cpp @@ -134,7 +134,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 9ea632639cf..8b687069afa 100644 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -555,7 +555,7 @@ void LLWearable::revertValues() LLVisualParam *param = getVisualParam(id); if(param && !param->isDriverParam() ) { - setVisualParamWeight(id, value); + setVisualParamWeight(id, value, TRUE); } } @@ -567,7 +567,7 @@ void LLWearable::revertValues() LLVisualParam *param = getVisualParam(id); if(param && param->isDriverParam()) { - setVisualParamWeight(id, value); + setVisualParamWeight(id, value, TRUE); } } @@ -670,13 +670,13 @@ void LLWearable::addVisualParam(LLVisualParam *param) } -void LLWearable::setVisualParamWeight(S32 param_index, F32 value) +void LLWearable::setVisualParamWeight(S32 param_index, F32 value, BOOL upload_bake) { auto iter = mVisualParamIndexMap.find(param_index); if(iter != mVisualParamIndexMap.end()) { LLVisualParam *wearable_param = iter->second; - wearable_param->setWeight(value); + wearable_param->setWeight(value, upload_bake); } else { @@ -718,12 +718,12 @@ void LLWearable::getVisualParams(visual_param_vec_t &list) } } -void LLWearable::animateParams(F32 delta) +void LLWearable::animateParams(F32 delta, BOOL upload_bake) { for(const auto& param_pair : mVisualParamIndexMap) { LLVisualParam *param = (LLVisualParam*)param_pair.second; - param->animate(delta); + param->animate(delta, upload_bake); } } @@ -741,14 +741,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); } } } @@ -768,7 +768,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); } } } diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h index b72398b5ecb..aecb5088394 100644 --- a/indra/llappearance/llwearable.h +++ b/indra/llappearance/llwearable.h @@ -96,14 +96,14 @@ class LLWearable 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 afc0c3f9f8f..d20b3421d84 100644 --- a/indra/llcharacter/llcharacter.cpp +++ b/indra/llcharacter/llcharacter.cpp @@ -295,13 +295,13 @@ void LLCharacter::removeAnimationData(std::string_view 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(); auto 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; @@ -310,7 +310,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); @@ -318,7 +318,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; @@ -328,12 +328,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) { auto 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; @@ -402,7 +402,7 @@ void LLCharacter::clearVisualParamWeights() LLVisualParam* param = param_pair.second; 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 1471dfb0306..ae43116d780 100644 --- a/indra/llcharacter/llcharacter.h +++ b/indra/llcharacter/llcharacter.h @@ -193,9 +193,10 @@ class LLCharacter 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 34f0cf7bc12..f63cc632610 100644 --- a/indra/llcharacter/llvisualparam.cpp +++ b/indra/llcharacter/llvisualparam.cpp @@ -220,7 +220,7 @@ BOOL LLVisualParam::parseData(LLXmlTreeNode *node) //----------------------------------------------------------------------------- // setWeight() //----------------------------------------------------------------------------- -void LLVisualParam::setWeight(F32 weight) +void LLVisualParam::setWeight(F32 weight, BOOL upload_bake) { if (mIsAnimating) { @@ -238,19 +238,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; } @@ -270,7 +270,7 @@ void LLVisualParam::setAnimationTarget(F32 target_value) if (mNext) { - mNext->setAnimationTarget(target_value); + mNext->setAnimationTarget(target_value, upload_bake); } } @@ -295,24 +295,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 27c8ba2e6d9..41a6b808429 100644 --- a/indra/llcharacter/llvisualparam.h +++ b/indra/llcharacter/llvisualparam.h @@ -120,10 +120,10 @@ class LLVisualParam //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 f6efc865efb..c64785e195e 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -140,6 +140,7 @@ set(viewer_SOURCE_FILES alunzip.cpp alviewermenu.cpp groupchatlistener.cpp + llagentwearablesfetch.cpp llaccountingcostmanager.cpp lladdgridhandler.cpp llaisapi.cpp @@ -816,6 +817,7 @@ set(viewer_HEADER_FILES alviewermenu.h groupchatlistener.h llaccountingcost.h + llagentwearablesfetch.h llaccountingcostmanager.h lladdgridhandler.h llaisapi.h diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index da101a55db6..cbac637d057 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -472,6 +472,7 @@ LLAgent::LLAgent() : mCrouch(false), mVoiceConnected(false), + mAppearanceSerialNum(0), mMouselookModeInSignal(NULL), mMouselookModeOutSignal(NULL) { @@ -930,6 +931,28 @@ void LLAgent::standUp() // [/RLVa:KB] } +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; @@ -952,7 +975,6 @@ void LLAgent::capabilityReceivedCallback(const LLUUID ®ion_id, LLViewerRegion } } - //----------------------------------------------------------------------------- // setRegion() //----------------------------------------------------------------------------- @@ -1061,6 +1083,16 @@ void LLAgent::setRegion(LLViewerRegion *regionp) // [RLVa:KB] - Checked: 2011-05-27 (RLVa-1.4.0a) | Added: RLVa-1.4.0a LLFloaterMove::sUpdateMovementStatus(); // [/RLVa:KB] + // 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(); @@ -3946,6 +3978,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 = LLAvatarAppearance::getDictionary()->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++) @@ -4161,7 +4269,7 @@ bool LLAgent::hasPendingTeleportRequest() void LLAgent::startTeleportRequest() { - LL_INFOS("Telport") << "Agent handling start teleport request." << LL_ENDL; + LL_INFOS("Teleport") << "Agent handling start teleport request." << LL_ENDL; if(LLVoiceClient::instanceExists()) { LLVoiceClient::getInstance()->setHidden(TRUE); @@ -4829,6 +4937,211 @@ 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 (const auto& iter : LLAvatarAppearance::getDictionary()->getTextures()) + { + 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; + } + + LLViewerRegion* region = getRegion(); + if (!isAgentAvatarValid() || gAgentAvatarp->isEditingAppearance() + || (region && region->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 + LLVector3 body_size = gAgentAvatarp->mBodySize; + if (region && region->simulatorFeaturesReceived() && region->avatarHoverHeightEnabled()) { + body_size += 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(); + + if(textures_current) + { + for(U8 baked_index = 0; baked_index < gAgentAvatarp->getNumBakes(); baked_index++ ) + { + const ETextureIndex texture_index = LLAvatarAppearance::getDictionary()->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; + } + // if we're not wearing a universal + if ( (texture_index >= TEX_LEFT_ARM_BAKED && texture_index <= TEX_AUX3_BAKED) && !gAgentAvatarp->isWearingWearableType(LLWearableType::WT_UNIVERSAL)) + { + continue; // ignore universal that is also optional + } + // 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 < gAgentAvatarp->getNumBakes(); 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; + } + + if (baked_index == BAKED_SKIRT && !gAgentAvatarp->isWearingWearableType(LLWearableType::WT_SKIRT)) + { + LL_DEBUGS("Avatar") << "Not caching baked texture for unworn skirt." << LL_ENDL; + generate_valid_hash = FALSE; + } + + const LLUUID hash = gAgentWearables.computeBakedTextureHash((EBakedTextureIndex) baked_index, generate_valid_hash); + if (hash.notNull()) + { + ETextureIndex texture_index = LLAvatarAppearance::getDictionary()->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, nullptr, 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); @@ -5111,6 +5424,22 @@ 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 b48acff65f9..aa5e4c2b0d6 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -717,6 +717,7 @@ class LLAgent final : public LLOldEvents::LLObservable void handleTeleportFinished(); void handleTeleportFailed(); + void handleServerBakeRegionTransition(const LLUUID& region_id); static void addTPNearbyChatSeparator(); static void onCapabilitiesReceivedAfterTeleport(); @@ -855,6 +856,7 @@ class LLAgent final : public LLOldEvents::LLObservable private: BOOL mShowAvatar; // Should we render the avatar? + U32 mAppearanceSerialNum; //-------------------------------------------------------------------- // Rendering state bitmap helpers @@ -956,6 +958,8 @@ class LLAgent final : public LLOldEvents::LLObservable 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(); @@ -977,6 +981,7 @@ class LLAgent final : public LLOldEvents::LLObservable 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 ** ** @@ -1023,4 +1028,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 13ab1f878c2..89e2cd1dbce 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -56,6 +56,8 @@ #include "rlvlocks.h" // [/RLVa:KB] +#include "llagentwearablesfetch.h" +#include "llviewernetwork.h" LLAgentWearables gAgentWearables; BOOL LLAgentWearables::mInitialWearablesUpdateReceived = FALSE; @@ -227,6 +229,11 @@ void LLAgentWearables::initClass() void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar) { llassert(avatar); + if (!LLGridManager::getInstance()->isInSecondlife()) + { + avatar->outputRezTiming("Sending wearables request"); + sendAgentWearablesRequest(); + } setAvatarAppearance(avatar); } @@ -259,9 +266,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); @@ -317,7 +339,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::getInstance()->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); @@ -364,6 +460,11 @@ 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), @@ -375,7 +476,12 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 return; } - gAgentAvatarp->wearableUpdated(type); + gAgentAvatarp->wearableUpdated(type, TRUE); + + if (send_update) + { + sendAgentWearablesUpdate(); + } } } @@ -452,6 +558,8 @@ void LLAgentWearables::revertWearable(const LLWearableType::EType type, const U3 { wearable->revertValues(); } + + gAgent.sendAgentSetAppearance(); } void LLAgentWearables::saveAllWearables() @@ -464,8 +572,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. @@ -494,6 +604,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; } } @@ -614,6 +725,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)); @@ -635,7 +755,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); @@ -657,7 +778,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); } } @@ -665,6 +786,16 @@ 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); @@ -716,6 +847,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::getInstance()->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::getInstance()->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::getInstance()->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); @@ -883,6 +1165,30 @@ 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) { LLUUID first_item_id = getWearableItemID((LLWearableType::EType)type, index); @@ -917,6 +1223,13 @@ void LLAgentWearables::addWearableToAgentInventory(LLPointer<LLInventoryCallback void LLAgentWearables::removeWearable(const LLWearableType::EType type, bool do_remove_all, U32 index) { + if (gAgent.isTeen() && + (type == LLWearableType::WT_UNDERSHIRT || type == LLWearableType::WT_UNDERPANTS)) + { + // Can't take off underclothing in simple UI mode or on PG accounts + // TODO: enable the removing of a single undershirt/underpants if multiple are worn. - Nyx + return; + } if (getWearableCount(type) == 0) { // no wearables to remove @@ -991,7 +1304,7 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo if (old_wearable) { eraseWearable(old_wearable); - old_wearable->removeFromAvatar(); + old_wearable->removeFromAvatar(TRUE); } } // clearWearableType(type); @@ -1007,10 +1320,14 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo if (old_wearable) { eraseWearable(old_wearable); - old_wearable->removeFromAvatar(); + old_wearable->removeFromAvatar(TRUE); } } + queryWearableCache(); + + // Update the server + updateServer(); gInventory.notifyObservers(); } @@ -1044,6 +1361,7 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it continue; } } + if (type < 0 || type>=LLWearableType::WT_COUNT) { LL_WARNS() << "invalid type " << type << LL_ENDL; @@ -1174,7 +1492,7 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it // Start rendering & update the server mWearablesLoaded = TRUE; - + checkWearablesLoaded(); // [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-09-22 (Catznip-2.2) if (!mInitialWearablesLoaded) { @@ -1190,6 +1508,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; @@ -1249,6 +1570,12 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it // delete wearable; // return false; // } +// if (!new_item) +// { +// delete wearable; +// return false; +// } +// // switch(option) // { // case 0: // "Save" @@ -1309,8 +1636,81 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it // LL_INFOS() << "Replaced current element 0 for type " << type // << " size is now " << getWearableCount(type) << LL_ENDL; // } +// +// //LL_INFOS() << "LLVOAvatar::setWearableItem()" << LL_ENDL; +// queryWearableCache(); +// +// updateServer(); //} +void LLAgentWearables::queryWearableCache() +{ + if (!areWearablesLoaded() || (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion())) + { + return; + } + gAgentAvatarp->setIsUsingServerBakes(false); + + // 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 < gAgentAvatarp->getNumBakes(); 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 = LLAvatarAppearance::getDictionary()->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 //void LLAgentWearables::userRemoveWearable(const LLWearableType::EType &type, const U32 &index) @@ -1518,6 +1918,17 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra // [/RLVa:KB] } +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 @@ -1534,9 +1945,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; @@ -1546,7 +1968,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 ) { @@ -1556,7 +1978,7 @@ void LLAgentWearables::animateAllWearableParams(F32 delta) llassert(wearable); if (wearable) { - wearable->animateParams(delta); + wearable->animateParams(delta, upload_bake); } } } @@ -1698,6 +2120,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 730f738405d..788589a1d06 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -43,6 +43,7 @@ class LLInventoryItem; class LLVOAvatarSelf; class LLViewerWearable; +class LLInitialWearablesFetch; class LLViewerObject; class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearableData @@ -51,6 +52,7 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable // Constructors / destructors / Initializers //-------------------------------------------------------------------- public: + friend class LLInitialWearablesFetch; LLAgentWearables(); virtual ~LLAgentWearables(); @@ -61,6 +63,9 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable // LLInitClass interface static void initClass(); +protected: + void createStandardWearablesDone(S32 type, U32 index/* = 0*/); + void createStandardWearablesAllDone(); //-------------------------------------------------------------------- // Queries @@ -87,7 +92,7 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable // 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 @@ -111,7 +116,7 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable // Setters //-------------------------------------------------------------------- private: - /*virtual*/void wearableUpdated(LLWearable *wearable, BOOL removed); + /*virtual*/void wearableUpdated(LLWearable *wearable, BOOL removed) override; public: // void setWearableItem(LLInventoryItem* new_item, LLViewerWearable* wearable, bool do_append = false); void setWearableOutfit(const LLInventoryItem::item_array_t& items, const std::vector< LLViewerWearable* >& wearables); @@ -161,6 +166,22 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable 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 override; + void sendAgentWearablesUpdate(); + void sendAgentWearablesRequest(); + void queryWearableCache(); + void updateServer(); + static void onInitialWearableAssetArrived(LLViewerWearable* wearable, void* userdata); //-------------------------------------------------------------------- // Outfits @@ -173,7 +194,7 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable //-------------------------------------------------------------------- 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); @@ -199,6 +220,9 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable 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; + static llvo_vec_t getTempAttachments(); //-------------------------------------------------------------------- @@ -239,6 +263,7 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable static bool mInitialAttachmentsRequested; // [/RLVa:KB] BOOL mWearablesLoaded; + std::set<LLUUID> mItemsAwaitingWearableUpdate; /** * True if agent's outfit is being changed now. @@ -250,6 +275,18 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable // Support classes //-------------------------------------------------------------------------------- private: + + class createStandardWearablesAllDoneCallback final : public LLRefCount + { + protected: + ~createStandardWearablesAllDoneCallback(); + }; + class sendAgentWearablesUpdateCallback final : public LLRefCount + { + protected: + ~sendAgentWearablesUpdateCallback(); + }; + class AddWearableToAgentInventoryCallback : public LLInventoryCallback { public: @@ -269,7 +306,7 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable LLViewerWearable* wearable, U32 todo = CALL_NONE, const std::string description = ""); - virtual void fire(const LLUUID& inv_item); + void fire(const LLUUID& inv_item) override; private: LLWearableType::EType mType; U32 mIndex; diff --git a/indra/newview/llagentwearablesfetch.cpp b/indra/newview/llagentwearablesfetch.cpp new file mode 100644 index 00000000000..a431aaaa452 --- /dev/null +++ b/indra/newview/llagentwearablesfetch.cpp @@ -0,0 +1,585 @@ +/** + * @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" + + +void order_my_outfits_cb() +{ + if (!LLApp::isRunning()) + { + LL_WARNS() << "called during shutdown, skipping" << LL_ENDL; + return; + } + + const LLUUID& my_outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + if (my_outfits_id.isNull()) return; + + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(my_outfits_id, cats, items); + if (!cats) return; + + //My Outfits should at least contain saved initial outfit and one another outfit + if (cats->size() < 2) + { + LL_WARNS() << "My Outfits category was not populated properly" << LL_ENDL; + return; + } + + LL_INFOS() << "Starting updating My Outfits with wearables ordering information" << LL_ENDL; + + for (LLInventoryModel::cat_array_t::iterator outfit_iter = cats->begin(); + outfit_iter != cats->end(); ++outfit_iter) + { + const LLUUID& cat_id = (*outfit_iter)->getUUID(); + if (cat_id.isNull()) continue; + + // saved initial outfit already contains wearables ordering information + if (cat_id == LLAppearanceMgr::getInstance()->getBaseOutfitUUID()) continue; + + LLAppearanceMgr::getInstance()->updateClothingOrderingInfo(cat_id); + } + + LL_INFOS() << "Finished updating My Outfits with wearables ordering information" << LL_ENDL; +} + +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.empty()); + 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() + { + } + + void done() override + { + gInventory.removeObserver(this); + + // Link to all fetched items in COF. + LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy; + LLInventoryObject::const_object_list_t item_array; + for (auto& id : mIDs) + { + LLConstPointer<LLInventoryObject> item = gInventory.getItem(id); + if (!item) + { + LL_WARNS() << "fetch failed for item " << id << "!" << 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. + { + (void) LLAppearanceMgr::instance().getCOF(); + uuid_vec_t ids; + for (const auto& wearable_data : mAgentInitialWearables) + { + // Populate the current outfit folder with links to the wearables passed in the message + 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; + } + } + + // 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 (LLViewerObject* attached_object : attachment->mAttachedObjects) + { + 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; + } +} + +LLLibraryOutfitsFetch::LLLibraryOutfitsFetch(const LLUUID& my_outfits_id) : + LLInventoryFetchDescendentsObserver(my_outfits_id), + mCurrFetchStep(LOFS_FOLDER), + mOutfitsPopulated(false) +{ + LL_INFOS() << "created" << LL_ENDL; + + mMyOutfitsID = LLUUID::null; + mClothingID = LLUUID::null; + mLibraryClothingID = LLUUID::null; + mImportedClothingID = LLUUID::null; + mImportedClothingName = "Imported Library Clothing"; +} + +LLLibraryOutfitsFetch::~LLLibraryOutfitsFetch() +{ + LL_INFOS() << "destroyed" << LL_ENDL; +} + +void LLLibraryOutfitsFetch::done() +{ + LL_INFOS() << "start" << LL_ENDL; + + // Delay this until idle() routine, since it's a heavy operation and + // we also can't have it run within notifyObservers. + doOnIdleOneTime(boost::bind(&LLLibraryOutfitsFetch::doneIdle,this)); + gInventory.removeObserver(this); // Prevent doOnIdleOneTime from being added twice. +} + +void LLLibraryOutfitsFetch::doneIdle() +{ + LL_INFOS() << "start" << LL_ENDL; + + gInventory.addObserver(this); // Add this back in since it was taken out during ::done() + + switch (mCurrFetchStep) + { + case LOFS_FOLDER: + folderDone(); + mCurrFetchStep = LOFS_OUTFITS; + break; + case LOFS_OUTFITS: + outfitsDone(); + mCurrFetchStep = LOFS_LIBRARY; + break; + case LOFS_LIBRARY: + libraryDone(); + mCurrFetchStep = LOFS_IMPORTED; + break; + case LOFS_IMPORTED: + importedFolderDone(); + mCurrFetchStep = LOFS_CONTENTS; + break; + case LOFS_CONTENTS: + contentsDone(); + break; + default: + LL_WARNS() << "Got invalid state for outfit fetch: " << mCurrFetchStep << LL_ENDL; + mOutfitsPopulated = TRUE; + break; + } + + // We're completely done. Cleanup. + if (mOutfitsPopulated) + { + gInventory.removeObserver(this); + delete this; + return; + } +} + +void LLLibraryOutfitsFetch::folderDone() +{ + LL_INFOS() << "start" << LL_ENDL; + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t wearable_array; + gInventory.collectDescendents(mMyOutfitsID, cat_array, wearable_array, + LLInventoryModel::EXCLUDE_TRASH); + + // Early out if we already have items in My Outfits + // except the case when My Outfits contains just initial outfit + if (cat_array.size() > 1) + { + mOutfitsPopulated = true; + return; + } + + mClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); + mLibraryClothingID = gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_CLOTHING, false); + + // If Library->Clothing->Initial Outfits exists, use that. + LLNameCategoryCollector matchFolderFunctor("Initial Outfits"); + cat_array.clear(); + gInventory.collectDescendentsIf(mLibraryClothingID, + cat_array, wearable_array, + LLInventoryModel::EXCLUDE_TRASH, + matchFolderFunctor); + if (cat_array.size() > 0) + { + const LLViewerInventoryCategory *cat = cat_array.at(0); + mLibraryClothingID = cat->getUUID(); + } + + mComplete.clear(); + + // Get the complete information on the items in the inventory. + uuid_vec_t folders; + folders.push_back(mClothingID); + folders.push_back(mLibraryClothingID); + setFetchIDs(folders); + startFetch(); + if (isFinished()) + { + done(); + } +} + +void LLLibraryOutfitsFetch::outfitsDone() +{ + LL_INFOS() << "start" << LL_ENDL; + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t wearable_array; + uuid_vec_t folders; + + // Collect the contents of the Library's Clothing folder + gInventory.collectDescendents(mLibraryClothingID, cat_array, wearable_array, + LLInventoryModel::EXCLUDE_TRASH); + + llassert(cat_array.size() > 0); + for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin(); + iter != cat_array.end(); + ++iter) + { + const LLViewerInventoryCategory *cat = iter->get(); + + // Get the names and id's of every outfit in the library, skip "Ruth" + // because it's a low quality legacy outfit + if (cat->getName() != "Ruth") + { + // Get the name of every outfit in the library + folders.push_back(cat->getUUID()); + mLibraryClothingFolders.push_back(cat->getUUID()); + } + } + cat_array.clear(); + wearable_array.clear(); + + // Check if you already have an "Imported Library Clothing" folder + LLNameCategoryCollector matchFolderFunctor(mImportedClothingName); + gInventory.collectDescendentsIf(mClothingID, + cat_array, wearable_array, + LLInventoryModel::EXCLUDE_TRASH, + matchFolderFunctor); + if (cat_array.size() > 0) + { + const LLViewerInventoryCategory *cat = cat_array.at(0); + mImportedClothingID = cat->getUUID(); + } + + mComplete.clear(); + setFetchIDs(folders); + startFetch(); + if (isFinished()) + { + done(); + } +} + +class LLLibraryOutfitsCopyDone: public LLInventoryCallback +{ +public: + LLLibraryOutfitsCopyDone(LLLibraryOutfitsFetch * fetcher): + mFireCount(0), mLibraryOutfitsFetcher(fetcher) + { + } + + virtual ~LLLibraryOutfitsCopyDone() + { + if (!LLApp::isExiting() && mLibraryOutfitsFetcher) + { + gInventory.addObserver(mLibraryOutfitsFetcher); + mLibraryOutfitsFetcher->done(); + } + } + + /* virtual */ void fire(const LLUUID& inv_item) + { + mFireCount++; + } +private: + U32 mFireCount; + LLLibraryOutfitsFetch * mLibraryOutfitsFetcher; +}; + +// Copy the clothing folders from the library into the imported clothing folder +void LLLibraryOutfitsFetch::libraryDone() +{ + LL_INFOS() << "start" << LL_ENDL; + + if (mImportedClothingID != LLUUID::null) + { + // Skip straight to fetching the contents of the imported folder + importedFolderFetch(); + return; + } + + // Remove observer; next autopopulation step will be triggered externally by LLLibraryOutfitsCopyDone. + gInventory.removeObserver(this); + + LLPointer<LLInventoryCallback> copy_waiter = new LLLibraryOutfitsCopyDone(this); + mImportedClothingID = gInventory.createNewCategory(mClothingID, + LLFolderType::FT_NONE, + mImportedClothingName); + // Copy each folder from library into clothing unless it already exists. + for (uuid_vec_t::const_iterator iter = mLibraryClothingFolders.begin(); + iter != mLibraryClothingFolders.end(); + ++iter) + { + const LLUUID& src_folder_id = (*iter); // Library clothing folder ID + const LLViewerInventoryCategory *cat = gInventory.getCategory(src_folder_id); + if (!cat) + { + LL_WARNS() << "Library folder import for uuid:" << src_folder_id << " failed to find folder." << LL_ENDL; + continue; + } + + if (!LLAppearanceMgr::getInstance()->getCanMakeFolderIntoOutfit(src_folder_id)) + { + LL_INFOS() << "Skipping non-outfit folder name:" << cat->getName() << LL_ENDL; + continue; + } + + // Don't copy the category if it already exists. + LLNameCategoryCollector matchFolderFunctor(cat->getName()); + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t wearable_array; + gInventory.collectDescendentsIf(mImportedClothingID, + cat_array, wearable_array, + LLInventoryModel::EXCLUDE_TRASH, + matchFolderFunctor); + if (cat_array.size() > 0) + { + continue; + } + + LLUUID dst_folder_id = gInventory.createNewCategory(mImportedClothingID, + LLFolderType::FT_NONE, + cat->getName()); + LLAppearanceMgr::getInstance()->shallowCopyCategoryContents(src_folder_id, dst_folder_id, copy_waiter); + } +} + +void LLLibraryOutfitsFetch::importedFolderFetch() +{ + LL_INFOS() << "start" << LL_ENDL; + + // Fetch the contents of the Imported Clothing Folder + uuid_vec_t folders; + folders.push_back(mImportedClothingID); + + mComplete.clear(); + setFetchIDs(folders); + startFetch(); + if (isFinished()) + { + done(); + } +} + +void LLLibraryOutfitsFetch::importedFolderDone() +{ + LL_INFOS() << "start" << LL_ENDL; + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t wearable_array; + uuid_vec_t folders; + + // Collect the contents of the Imported Clothing folder + gInventory.collectDescendents(mImportedClothingID, cat_array, wearable_array, + LLInventoryModel::EXCLUDE_TRASH); + + for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin(); + iter != cat_array.end(); + ++iter) + { + const LLViewerInventoryCategory *cat = iter->get(); + + // Get the name of every imported outfit + folders.push_back(cat->getUUID()); + mImportedClothingFolders.push_back(cat->getUUID()); + } + + mComplete.clear(); + setFetchIDs(folders); + startFetch(); + if (isFinished()) + { + done(); + } +} + +void LLLibraryOutfitsFetch::contentsDone() +{ + LL_INFOS() << "start" << LL_ENDL; + + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t wearable_array; + + LLPointer<LLInventoryCallback> order_myoutfits_on_destroy = new LLBoostFuncInventoryCallback(no_op_inventory_func, order_my_outfits_cb); + + for (uuid_vec_t::const_iterator folder_iter = mImportedClothingFolders.begin(); + folder_iter != mImportedClothingFolders.end(); + ++folder_iter) + { + const LLUUID &folder_id = (*folder_iter); + const LLViewerInventoryCategory *cat = gInventory.getCategory(folder_id); + if (!cat) + { + LL_WARNS() << "Library folder import for uuid:" << folder_id << " failed to find folder." << LL_ENDL; + continue; + } + + //initial outfit should be already in My Outfits + if (cat->getName() == LLStartUp::getInitialOutfitName()) continue; + + // First, make a folder in the My Outfits directory. + LLUUID new_outfit_folder_id = gInventory.createNewCategory(mMyOutfitsID, LLFolderType::FT_OUTFIT, cat->getName()); + + cat_array.clear(); + wearable_array.clear(); + // Collect the contents of each imported clothing folder, so we can create new outfit links for it + gInventory.collectDescendents(folder_id, cat_array, wearable_array, + LLInventoryModel::EXCLUDE_TRASH); + + LLInventoryObject::const_object_list_t item_array; + for (LLInventoryModel::item_array_t::const_iterator wearable_iter = wearable_array.begin(); + wearable_iter != wearable_array.end(); + ++wearable_iter) + { + LLConstPointer<LLInventoryObject> item = wearable_iter->get(); + item_array.push_back(item); + } + + link_inventory_array(new_outfit_folder_id, item_array, order_myoutfits_on_destroy); + } + + mOutfitsPopulated = true; +} + diff --git a/indra/newview/llagentwearablesfetch.h b/indra/newview/llagentwearablesfetch.h new file mode 100644 index 00000000000..535db632251 --- /dev/null +++ b/indra/newview/llagentwearablesfetch.h @@ -0,0 +1,114 @@ +/** + * @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(); + void done() override; + + 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 +}; + +//-------------------------------------------------------------------- +// InitialWearablesFetch +// +// This grabs outfits from the Library and copies those over to the user's +// outfits folder, typically during first-ever login. +//-------------------------------------------------------------------- +class LLLibraryOutfitsFetch : public LLInventoryFetchDescendentsObserver +{ +public: + enum ELibraryOutfitFetchStep + { + LOFS_FOLDER = 0, + LOFS_OUTFITS, + LOFS_LIBRARY, + LOFS_IMPORTED, + LOFS_CONTENTS + }; + + LLLibraryOutfitsFetch(const LLUUID& my_outfits_id); + ~LLLibraryOutfitsFetch(); + + virtual void done(); + void doneIdle(); + LLUUID mMyOutfitsID; + void importedFolderFetch(); +protected: + void folderDone(); + void outfitsDone(); + void libraryDone(); + void importedFolderDone(); + void contentsDone(); + enum ELibraryOutfitFetchStep mCurrFetchStep; + uuid_vec_t mLibraryClothingFolders; + uuid_vec_t mImportedClothingFolders; + bool mOutfitsPopulated; + LLUUID mClothingID; + LLUUID mLibraryClothingID; + LLUUID mImportedClothingID; + std::string mImportedClothingName; +}; + +#endif // LL_AGENTWEARABLESINITIALFETCH_H diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 6f912b1860d..5e8ef78d797 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -4599,7 +4599,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/llemote.cpp b/indra/newview/llemote.cpp index b9ef297c005..99e94602bf2 100644 --- a/indra/newview/llemote.cpp +++ b/indra/newview/llemote.cpp @@ -79,13 +79,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(); } @@ -101,7 +101,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" ); @@ -110,7 +110,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(); @@ -127,13 +127,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 07ffef8aa08..7a5f63b7ace 100644 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -588,7 +588,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::getInstance()->setNeedsRebake(); } diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 16eaaafde67..cdec7825083 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -940,11 +940,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); @@ -981,7 +981,7 @@ void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl) { gAgentAvatarp->setLocalTexture(entry->mTextureIndex, image, FALSE, index); LLVisualParamHint::requestHintUpdates(); - gAgentAvatarp->wearableUpdated(type); + gAgentAvatarp->wearableUpdated(type, FALSE); } else { @@ -1010,9 +1010,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 @@ -1113,7 +1113,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); } @@ -1131,7 +1131,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) @@ -1603,7 +1603,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 { @@ -1619,7 +1619,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()); diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp index c97a9b49e9e..a24f03b9c43 100644 --- 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 bfa453a0ae1..a7e24b86b13 100644 --- a/indra/newview/llscrollingpanelparam.cpp +++ b/indra/newview/llscrollingpanelparam.cpp @@ -266,7 +266,7 @@ void LLScrollingPanelParam::onHintHeldDown( LLVisualParamHint* hint ) if (slider->getMinValue() < new_percent && new_percent < slider->getMaxValue()) { - mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight); + mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight, FALSE); mWearable->writeToAvatar(gAgentAvatarp); gAgentAvatarp->updateVisualParams(); @@ -299,7 +299,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 +333,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 fe7a3627235..b1ac39bfff7 100644 --- 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 04a202cd2e3..f32bbad72ab 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2145,7 +2145,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); } @@ -2206,22 +2207,22 @@ bool idle_startup() if (gAgent.isOutfitChosen() && (wearables_time > max_wearables_time)) { - LLNotificationsUtil::add("ClothingLoading"); + if (gInventory.isInventoryUsable()) + { + LLNotificationsUtil::add("ClothingLoading"); + } record(LLStatViewer::LOADING_WEARABLES_LONG_DELAY, wearables_time); LLStartUp::setStartupState( STATE_CLEANUP ); } + // wait for avatar to be completely loaded else if (gAgent.isFirstLogin() && isAgentAvatarValid() && gAgentAvatarp->isFullyLoaded()) { - // wait for avatar to be completely loaded - if (isAgentAvatarValid() - && gAgentAvatarp->isFullyLoaded()) - { - LL_DEBUGS("Avatar") << "avatar fully loaded" << LL_ENDL; - LLStartUp::setStartupState( STATE_CLEANUP ); - return TRUE; - } + + LL_DEBUGS("Avatar") << "avatar fully loaded" << LL_ENDL; + LLStartUp::setStartupState( STATE_CLEANUP ); + return TRUE; } else { @@ -2519,6 +2520,8 @@ void register_viewer_callbacks(LLMessageSystem* msg) msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation); msg->setHandlerFuncFast(_PREHASH_ObjectAnimation, process_object_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->setHandlerFuncFast(_PREHASH_SetFollowCamProperties, process_set_follow_cam_properties); @@ -2592,6 +2595,8 @@ void register_viewer_callbacks(LLMessageSystem* msg) // msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply, // LLFloaterRate::processReputationIndividualReply); + msg->setHandlerFuncFast(_PREHASH_AgentWearablesUpdate, LLAgentWearables::processAgentInitialWearablesUpdate ); + msg->setHandlerFuncFast(_PREHASH_ScriptControlChange, LLAgent::processScriptControlChange ); @@ -2772,7 +2777,10 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, } gAgent.setOutfitChosen(TRUE); - gAgentWearables.sendDummyAgentWearablesUpdate(); + if (LLGridManager::getInstance()->isInSecondlife()) + { + gAgentWearables.sendDummyAgentWearablesUpdate(); + } } std::string& LLStartUp::getInitialOutfitName() diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index 1351ec4d5c4..751eb1d26d4 100644 --- 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 8cdfe7feb82..6f3500c05ad 100644 --- a/indra/newview/lltoolmorph.cpp +++ b/indra/newview/lltoolmorph.cpp @@ -154,7 +154,7 @@ void LLVisualParamHint::preRender(BOOL clear_depth) wearable->setVolatile(TRUE); } mLastParamWeight = mVisualParam->getWeight(); - mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight); + mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight); gAgentAvatarp->setVisualParamWeight("Blink_Left", 0.f); gAgentAvatarp->setVisualParamWeight("Blink_Right", 0.f); @@ -253,8 +253,8 @@ BOOL LLVisualParamHint::render() gGL.setSceneBlendType(LLRender::BT_ALPHA); gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); } - gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight); - mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight); + gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight, FALSE); + 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 0965d21dde0..9d15ddce714 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3429,6 +3429,10 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) LL_INFOS("Teleport") << "Agent movement complete, setting state to TELEPORT_START_ARRIVAL" << LL_ENDL; 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 1ae35a67a46..a33596cf641 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -174,8 +174,8 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco if (!gAgentAvatarp) { gAgentAvatarp = new LLVOAvatarSelf(id, pcode, regionp); + gAgentWearables.setAvatarObject(gAgentAvatarp); // Set before instance init gAgentAvatarp->initInstance(); - gAgentWearables.setAvatarObject(gAgentAvatarp); } else { diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 2d1baf690f9..ae5e57c3284 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -596,7 +596,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 7b7c12a4c7a..ba403623d06 100644 --- a/indra/newview/llviewertexlayer.cpp +++ b/indra/newview/llviewertexlayer.cpp @@ -28,6 +28,9 @@ #include "llviewertexlayer.h" +#include "llfilesystem.h" +#include "llsdutil.h" + #include "llagent.h" #include "llimagej2c.h" #include "llnotificationsutil.h" @@ -35,11 +38,32 @@ #include "llglslshader.h" #include "llvoavatarself.h" #include "pipeline.h" +#include "llviewerassetupload.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) : + mID(id), + mAvatar(avatar), + mTexLayerSet(layerset), + mStartTime(LLFrameTimer::getTotalTime()), // Record starting time + mIsHighestRes(highest_res) +{ +} + //----------------------------------------------------------------------------- // LLViewerTexLayerSetBuffer // The composite image that a LLViewerTexLayerSet writes to. Each LLViewerTexLayerSet has one. @@ -53,12 +77,17 @@ LLViewerTexLayerSetBuffer::LLViewerTexLayerSetBuffer(LLTexLayerSet* const owner, // ORDER_LAST => must render these after the hints are created. LLTexLayerSetBuffer(owner), LLViewerDynamicTexture(width, height, 4, LLViewerDynamicTexture::ORDER_LAST, FALSE), + mNeedsUpload(FALSE), // Not used for any logic here, just to sync sending of updates + mNumLowresUploads(0), + mUploadPending(FALSE), + mUploadFailCount(0), mNeedsUpdate(TRUE), mNumLowresUpdates(0) { mGLTexturep->setNeedsAlphaAndPickMask(FALSE); LLViewerTexLayerSetBuffer::sGLByteCount += getSize(); + mNeedsUploadTimer.start(); mNeedsUpdateTimer.start(); } @@ -101,6 +130,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 +165,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 +198,7 @@ BOOL LLViewerTexLayerSetBuffer::needsRender() if (gAgentAvatarp->getBakedTE(getViewerTexLayerSet()) == LLAvatarAppearanceDefines::TEX_SKIRT_BAKED && !gAgentAvatarp->isWearingWearableType(LLWearableType::WT_SKIRT)) { + cancelUpload(); return FALSE; } @@ -158,9 +224,46 @@ void LLViewerTexLayerSetBuffer::postRenderTexLayerSet(BOOL success) } // virtual -void LLViewerTexLayerSetBuffer::midRenderTexLayerSet(BOOL success) +void LLViewerTexLayerSetBuffer::midRenderTexLayerSet(BOOL success, LLRenderTarget* bound_target) { + // 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()) + { + auto bakedTexIdx = layer_set->getBakedTexIndex(); + if(bakedTexIdx <= layer_set->getAvatar()->getNumBakes()) + { + layer_set->getAvatar()->debugBakedTextureUpload(bakedTexIdx, FALSE); // FALSE for start of upload, TRUE for finish. + doUpload(bound_target); + } + else + { + LL_DEBUGS("Avatar") << "Skipping bake for unsupported layer on this region" << LL_ENDL; + } + } + else + { + mUploadPending = FALSE; + mNeedsUpload = FALSE; + mNeedsUploadTimer.pause(); + layer_set->getAvatar()->setNewBakedTexture(layer_set->getBakedTexIndex(),IMG_INVISIBLE); + } + } + } + if (update_now) { doUpdate(); @@ -176,6 +279,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. @@ -213,6 +370,232 @@ BOOL LLViewerTexLayerSetBuffer::requestUpdateImmediate() return result; } +//========================================================================= +//----------------------------------------------------------------------------- +// Support classes +//----------------------------------------------------------------------------- +class ALTexLayerUploader final : public LLBufferedAssetUploadInfo +{ +public: + ALTexLayerUploader(LLUUID assetId, std::string texture, LLBakedUploadData* baked_upload_data); + ~ALTexLayerUploader(); + + LLSD prepareUpload() override; + LLSD generatePostBody() override; + LLUUID finishUpload(LLSD &result) override; + +private: + LLBakedUploadData* mBakedUploadData; +}; + +ALTexLayerUploader::ALTexLayerUploader(LLUUID assetId, std::string texture, LLBakedUploadData* baked_upload_data) : + LLBufferedAssetUploadInfo(LLUUID::null, LLAssetType::AT_TEXTURE, texture, NULL), + mBakedUploadData(baked_upload_data) +{ + setAssetId(assetId); +} + +ALTexLayerUploader::~ALTexLayerUploader() +{ + delete_and_clear(mBakedUploadData); +} + +LLSD ALTexLayerUploader::prepareUpload() +{ + return LLSD().with("success", LLSD::Boolean(true)); +} + +LLSD ALTexLayerUploader::generatePostBody() +{ + return LLBufferedAssetUploadInfo::generatePostBody(); +} + +LLUUID ALTexLayerUploader::finishUpload(LLSD &result) +{ + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]); + + LLUUID new_id = LLUUID(); + + if (status.getType() == HTTP_OK) + { + new_id = result["new_asset"].asUUID(); + std::string state = result["state"].asString(); + + LL_INFOS() << "result: " << state << " new_id: " << new_id << LL_ENDL; + if (state == "complete" + && mBakedUploadData != NULL) + { // Invoke + LLViewerTexLayerSetBuffer::onTextureUploadComplete(new_id, static_cast<void*>(mBakedUploadData), 0, LLExtStat::NONE); + mBakedUploadData = NULL; // deleted in onTextureUploadComplete() + return new_id; + } + } + + LL_WARNS() << "Baked texture upload resulted in: " << status.getType() << ll_pretty_print_sd(result) << LL_ENDL; + // Invoke the original callback with an error result + LLViewerTexLayerSetBuffer::onTextureUploadComplete(new_id, static_cast<void*>(mBakedUploadData), -1, LLExtStat::NONE); + mBakedUploadData = NULL; // deleted in onTextureUploadComplete() + return new_id; +} + +// 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(LLRenderTarget* bound_target) +{ + 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, bound_target); + + + // 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()); + LLFileSystem up_file(asset_id, LLAssetType::AT_TEXTURE, LLFileSystem::WRITE); + if (up_file.open() && up_file.write(compressedImage->getData(), compressedImage->getDataSize())) + { + up_file.close(); + // Read back the file and validate. + BOOL valid = FALSE; + std::string asset_data; + { + LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C; + S32 file_size = 0; + LLFileSystem file(asset_id, LLAssetType::AT_TEXTURE, LLFileSystem::READ); + file_size = file.getSize(); + U8* data = integrity_test->allocateData(file_size); + if (data && file.open()) + { + file.read(data, file_size); + file.close(); + asset_data.append(reinterpret_cast<char const*> (data), file_size); + 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.getRegionCapability("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. + { + // The responder will call LLViewerTexLayerSetBuffer::onTextureUploadComplete() + LLResourceUploadInfo::ptr_t asset_info(new ALTexLayerUploader(mUploadID, asset_data, baked_upload_data)); + LLViewerAssetUpload::EnqueueInventoryUpload(url, asset_info); + 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; + up_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. void LLViewerTexLayerSetBuffer::doUpdate() @@ -249,6 +632,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 +749,20 @@ void LLViewerTexLayerSet::requestUpdate() } } +void LLViewerTexLayerSet::requestUpload() +{ + createComposite(); + getViewerComposite()->requestUpload(); +} + +void LLViewerTexLayerSet::cancelUpload() +{ + if(mComposite) + { + getViewerComposite()->cancelUpload(); + } +} + void LLViewerTexLayerSet::updateComposite() { createComposite(); @@ -342,12 +815,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 3a83423df44..e549eb90f68 100644 --- a/indra/newview/llviewertexlayer.h +++ b/indra/newview/llviewertexlayer.h @@ -46,11 +46,13 @@ class LLViewerTexLayerSet final : public LLTexLayerSet LLViewerTexLayerSet(LLAvatarAppearance* const appearance); virtual ~LLViewerTexLayerSet(); - /*virtual*/void requestUpdate(); + /*virtual*/void requestUpdate() override; + void requestUpload(); + void cancelUpload(); BOOL isLocalTextureDataAvailable() const; BOOL isLocalTextureDataFinal() const; void updateComposite(); - /*virtual*/void createComposite(); + /*virtual*/void createComposite() override; void setUpdatesEnabled(BOOL b); BOOL getUpdatesEnabled() const { return mUpdatesEnabled; } @@ -78,12 +80,12 @@ class LLViewerTexLayerSetBuffer final : public LLTexLayerSetBuffer, public LLVie virtual ~LLViewerTexLayerSetBuffer(); public: - /*virtual*/ S8 getType() const; + /*virtual*/ S8 getType() const override; BOOL isInitialized(void) const; static void dumpTotalByteCount(); const std::string dumpTextureInfo() const; - virtual void restoreGLTexture(); - virtual void destroyGLTexture(); + void restoreGLTexture() override; + void destroyGLTexture() override; private: LLViewerTexLayerSet* getViewerTexLayerSet() { return dynamic_cast<LLViewerTexLayerSet*> (mTexLayerSet); } @@ -94,25 +96,51 @@ class LLViewerTexLayerSetBuffer final : public LLTexLayerSetBuffer, public LLVie //-------------------------------------------------------------------- // Tex Layer Render //-------------------------------------------------------------------- - virtual void preRenderTexLayerSet(); - virtual void midRenderTexLayerSet(BOOL success); - virtual void postRenderTexLayerSet(BOOL success); - virtual S32 getCompositeOriginX() const { return getOriginX(); } - virtual S32 getCompositeOriginY() const { return getOriginY(); } - virtual S32 getCompositeWidth() const { return getFullWidth(); } - virtual S32 getCompositeHeight() const { return getFullHeight(); } + void preRenderTexLayerSet() override; + void midRenderTexLayerSet(BOOL success, LLRenderTarget* bound_target) override; + void postRenderTexLayerSet(BOOL success) override; + S32 getCompositeOriginX() const override { return getOriginX(); } + S32 getCompositeOriginY() const override { return getOriginY(); } + S32 getCompositeWidth() const override { return getFullWidth(); } + S32 getCompositeHeight() const override { return getFullHeight(); } //-------------------------------------------------------------------- // Dynamic Texture Interface //-------------------------------------------------------------------- public: - /*virtual*/ BOOL needsRender(); + /*virtual*/ BOOL needsRender() override; protected: // Pass these along for tex layer rendering. - virtual void preRender(BOOL clear_depth) { preRenderTexLayerSet(); } - virtual void postRender(BOOL success) { postRenderTexLayerSet(success); } - virtual BOOL render() { return renderTexLayerSet(mBoundTarget); } - + void preRender(BOOL clear_depth) override { preRenderTexLayerSet(); } + void postRender(BOOL success) override { postRenderTexLayerSet(success); } + BOOL render() override { return renderTexLayerSet(mBoundTarget); } + + + //-------------------------------------------------------------------- + // 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(LLRenderTarget* bound_target); // 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 @@ class LLViewerTexLayerSetBuffer final : public LLTexLayerSetBuffer, public LLVie 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() = default; + 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 2f3584ca238..3c0575f4dfd 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1076,7 +1076,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(); mGLTexturep->setNeedsAlphaAndPickMask(TRUE); diff --git a/indra/newview/llviewerwearable.cpp b/indra/newview/llviewerwearable.cpp index abb3a4fa494..8f11eb0aabe 100644 --- a/indra/newview/llviewerwearable.cpp +++ b/indra/newview/llviewerwearable.cpp @@ -266,7 +266,7 @@ void LLViewerWearable::setParamsToDefaults() { if( (((LLViewerVisualParam*)param)->getWearableType() == mType ) && (param->isTweakable() ) ) { - setVisualParamWeight(param->getID(),param->getDefaultWeight()); + setVisualParamWeight(param->getID(),param->getDefaultWeight(), FALSE); } } } @@ -351,14 +351,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; @@ -377,7 +377,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 ); } } @@ -387,7 +387,7 @@ void LLViewerWearable::removeFromAvatar( LLWearableType::EType type) } gAgentAvatarp->updateVisualParams(); - gAgentAvatarp->wearableUpdated(type); + gAgentAvatarp->wearableUpdated(type, FALSE); } // Does not copy mAssetID. @@ -501,6 +501,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 cc99f6af2f7..47afa8f22df 100644 --- a/indra/newview/llviewerwearable.h +++ b/indra/newview/llviewerwearable.h @@ -62,8 +62,8 @@ class LLViewerWearable : public LLWearable 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 ); @@ -93,7 +93,7 @@ class LLViewerWearable : public LLWearable // 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 94aa251d000..289e26deb8f 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -682,6 +682,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mLastRezzedStatus(-1), mIsEditingAppearance(FALSE), mUseLocalAppearance(FALSE), + mUseServerBakes(FALSE), mLastUpdateRequestCOFVersion(-1), mLastUpdateReceivedCOFVersion(-1), mCachedMuteListUpdateTime(0), @@ -1086,7 +1087,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(); } @@ -2092,7 +2093,7 @@ void LLVOAvatar::applyDefaultParams() U8 value = it->second; F32 newWeight = U8_to_F32(value, param->getMinWeight(), param->getMaxWeight()); - param->setWeight(newWeight); + param->setWeight(newWeight, FALSE); // Most likely FALSE is correct here because it's used in resetSkeleton, which is a local operation } } @@ -2474,17 +2475,20 @@ LLViewerFetchedTexture *LLVOAvatar::getBakedTextureImage(const U8 te, const LLUU if (!result) { 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); } -#ifdef SHOW_DEBUG - LL_DEBUGS("Avatar") << avString() << "get server-bake image from URL " << url << LL_ENDL; -#endif - 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); @@ -2770,8 +2774,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(); @@ -2947,10 +2951,14 @@ void LLVOAvatar::idleUpdateAppearanceAnimation() { if (param->isTweakable()) { - param->stopAnimating(); + param->stopAnimating(FALSE); } } updateVisualParams(); + if (isSelf()) + { + gAgent.sendAgentSetAppearance(); + } } else { @@ -2966,7 +2974,7 @@ void LLVOAvatar::idleUpdateAppearanceAnimation() { if (param->isTweakable()) { - param->animate(morph_amt); + param->animate(morph_amt, FALSE); } } } @@ -3023,7 +3031,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 ) @@ -3031,7 +3039,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; @@ -3839,7 +3847,7 @@ void LLVOAvatar::updateAppearanceMessageDebugText() 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::instanceFast().getCOFVersion(); @@ -3849,7 +3857,9 @@ void LLVOAvatar::updateAppearanceMessageDebugText() { debug_line += llformat(" - cof: %d req: %d rcv:%d", curr_cof_version, last_request_cof_version, last_received_cof_version); - if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure")) + + static const LLCachedControl<bool> debug_force_appearance_request_failure(gSavedSettings, "DebugForceAppearanceRequestFailure"); + if (debug_force_appearance_request_failure) { debug_line += " FORCING ERRS"; } @@ -5475,6 +5485,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, TEX_LIST_STANDARD); + 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; @@ -5715,6 +5753,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 ); } } @@ -5868,19 +5919,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::instanceFast().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::instanceFast().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 = LLAvatarAppearance::getDictionary()->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 = LLAvatarAppearance::getDictionary()->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; } @@ -7367,11 +7421,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); } //----------------------------------------------------------------------------- @@ -8066,7 +8120,7 @@ void LLVOAvatar::rebuildAttachments() // [/SL:KB] // virtual -void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset) +void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result) { } @@ -8075,19 +8129,19 @@ 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)) @@ -8106,7 +8160,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(); } @@ -8322,7 +8376,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()) @@ -9363,13 +9417,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 @@ -9428,6 +9482,11 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) " (highest seen #" << mLastUpdateReceivedCOFVersion << ") (AISCOF=#" << aisCOFVersion << ")" << LL_ENDL; + if (mFirstTEMessageReceived && (appearance_version == 0)) + { + return; + } + if (mLastUpdateReceivedCOFVersion >= thisAppearanceVersion) { LL_WARNS("Avatar") << "Stale appearance received #" << thisAppearanceVersion << @@ -9478,6 +9537,8 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) mLastProcessedAppearance = contents; + setIsUsingServerBakes(appearance_version > 0); + bool slam_params = false; applyParsedAppearanceMessage(*contents, slam_params); if (getOverallAppearance() != AOA_NORMAL) @@ -9503,16 +9564,14 @@ void LLVOAvatar::applyParsedAppearanceMessage(LLAppearanceMessageContents& conte && mBakedTextureDatas[baked_index].mLastTextureID != IMG_DEFAULT && baked_index != BAKED_SKIRT && baked_index != BAKED_LEFT_ARM && baked_index != BAKED_LEFT_LEG && baked_index != BAKED_AUX1 && baked_index != BAKED_AUX2 && baked_index != BAKED_AUX3) { -#ifdef SHOW_DEBUG - LL_DEBUGS("Avatar") << avString() << " baked_index " << (S32) baked_index << " using mLastTextureID " << mBakedTextureDatas[baked_index].mLastTextureID << LL_ENDL; -#endif + 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)); } #ifdef SHOW_DEBUG 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; } #endif @@ -9556,12 +9615,12 @@ void LLVOAvatar::applyParsedAppearanceMessage(LLAppearanceMessageContents& conte if(is_first_appearance_message || slam_params) { //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); } } } @@ -9588,7 +9647,7 @@ void LLVOAvatar::applyParsedAppearanceMessage(LLAppearanceMessageContents& conte ESex new_sex = getSex(); if( old_sex != new_sex ) { - updateSexDependentLayerSets(); + updateSexDependentLayerSets(FALSE); } } @@ -10314,6 +10373,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.f : 0.f; + 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.f : 0.f, false); +} + // virtual void LLVOAvatar::removeMissingBakedTextures() { @@ -10560,7 +10652,6 @@ void LLVOAvatar::updateRiggingInfo() #endif } -// virtual void LLVOAvatar::onActiveOverrideMeshesChanged() { mJointRiggingInfoTab.setNeedsUpdate(true); diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 50e2faa60ad..bfa6802cbfc 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -234,7 +234,7 @@ class LLVOAvatar : size_t mLastRiggingInfoMeshCount = 0; std::set<LLUUID> mActiveOverrideMeshes; - virtual void onActiveOverrideMeshesChanged(); + void onActiveOverrideMeshesChanged(); /*virtual*/ const LLUUID& getID() const; /*virtual*/ void addDebugText(const std::string& text); @@ -552,7 +552,7 @@ class LLVOAvatar : // Global colors //-------------------------------------------------------------------- public: - /*virtual*/void onGlobalColorChanged(const LLTexGlobalColor* global_color); + /*virtual*/void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake) override; //-------------------------------------------------------------------- // Visibility @@ -728,7 +728,7 @@ class LLVOAvatar : // Composites //-------------------------------------------------------------------- public: - virtual void invalidateComposite(LLTexLayerSet* layerset); + void invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result) override; virtual void invalidateAll(); virtual void setCompositeUpdatesEnabled(bool b) {} virtual void setCompositeUpdatesEnabled(U32 index, bool b) {} @@ -761,9 +761,9 @@ class LLVOAvatar : public: void debugColorizeSubMeshes(U32 i, const LLColor4& color); - virtual void updateMeshTextures(); - void updateSexDependentLayerSets(); - virtual void dirtyMesh(); // Dirty the avatar mesh + void updateMeshTextures() final override; + void updateSexDependentLayerSets(BOOL upload_bake); + void dirtyMesh() final override; // Dirty the avatar mesh void updateMeshData(); void updateMeshVisibility(); LLViewerTexture* getBakedTexture(const U8 te); @@ -772,7 +772,7 @@ class LLVOAvatar : void releaseMeshData(); virtual void restoreMeshData(); private: - virtual void dirtyMesh(S32 priority); // Dirty the avatar mesh, with priority + void dirtyMesh(S32 priority) final override; // Dirty the avatar mesh, with priority LLViewerJoint* getViewerJoint(S32 idx); S32 mDirtyMesh; // 0 -- not dirty, 1 -- morphed, 2 -- LOD BOOL mMeshTexturesDirty; @@ -801,6 +801,7 @@ class LLVOAvatar : void applyParsedAppearanceMessage(LLAppearanceMessageContents& contents, bool slam_params); void hideSkirt(); void startAppearanceAnimation(); + /*virtual*/ void bodySizeChanged() override; //-------------------------------------------------------------------- // Appearance morphing @@ -811,11 +812,14 @@ class LLVOAvatar : // True if we are computing our appearance via local compositing // instead of baked textures, as for example during wearable // editing or when waiting for a subsequent server rebake. - /*virtual*/ BOOL isUsingLocalAppearance() const { return mUseLocalAppearance; } + /*virtual*/ BOOL isUsingLocalAppearance() const override { return mUseLocalAppearance; } + + BOOL isUsingServerBakes() const override; + 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; } + /*virtual*/ BOOL isEditingAppearance() const override { return mIsEditingAppearance; } // FIXME review isUsingLocalAppearance uses, some should be isEditing instead. @@ -825,6 +829,7 @@ class LLVOAvatar : 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 @@ -993,9 +998,9 @@ class LLVOAvatar : **/ public: - /*virtual*/ BOOL setParent(LLViewerObject* parent); - /*virtual*/ void addChild(LLViewerObject *childp); - /*virtual*/ void removeChild(LLViewerObject *childp); + /*virtual*/ BOOL setParent(LLViewerObject* parent) override; + /*virtual*/ void addChild(LLViewerObject *childp) override; + /*virtual*/ void removeChild(LLViewerObject *childp) override; //-------------------------------------------------------------------- // Sitting diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index e52f4a40db3..ee28b394897 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -197,6 +197,15 @@ 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; @@ -238,6 +247,7 @@ 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); mInitFlags |= 1<<2; @@ -245,14 +255,19 @@ void LLVOAvatarSelf::initInstance() 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))); LL_INFOS("Avatar") << avString() << " set hover height from debug setting " << hover_z << LL_ENDL; } + else if (!isUsingServerBakes()) + { + computeBodySize(); + } else { setHoverOffset(LLVector3(0.0, 0.0, 0.0)); @@ -262,9 +277,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)); } } @@ -735,35 +750,35 @@ LLJoint *LLVOAvatarSelf::getJoint(const std::string &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) { @@ -779,12 +794,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*/ @@ -810,7 +825,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(); @@ -904,18 +919,23 @@ void LLVOAvatarSelf::removeMissingBakedTextures() { LLViewerTexLayerSet *layerset = getTexLayerSet(i); layerset->setUpdatesEnabled(TRUE); - invalidateComposite(layerset); + invalidateComposite(layerset, FALSE); } updateMeshTextures(); + if (getRegion() && !getRegion()->getCentralBakeVersion()) + { + requestLayerSetUploads(); + } } } -// <FS:Beq> Check whether the BOM capability is different to last time we changed region (even across login) + void LLVOAvatarSelf::checkBOMRebakeRequired() { if(getRegion()) { auto newBOMStatus = getRegion()->bakesOnMeshEnabled(); - if((!gSavedSettings.getBool("CurrentlyUsingBakesOnMesh")) != newBOMStatus) + static const LLCachedControl<bool> using_bom(gSavedSettings, "CurrentlyUsingBakesOnMesh", true); + if(!using_bom != newBOMStatus) { // force a rebake when the last grid we were on (including previous login) had different BOM support // This replicates forceAppearanceUpdate rather than pulling in the whole of llavatarself. @@ -928,13 +948,12 @@ void LLVOAvatarSelf::checkBOMRebakeRequired() } } } -// </FS:Beq> void LLVOAvatarSelf::onSimulatorFeaturesReceived(const LLUUID& region_id) { LL_INFOS("Avatar") << "simulator features received, setting hover based on region props" << LL_ENDL; setHoverIfRegionEnabled(); - checkBOMRebakeRequired();// <FS:Beq/> BOM we may have stale cache, rebake may be needed + checkBOMRebakeRequired(); // BOM we may have stale cache, rebake may be needed } //virtual @@ -961,7 +980,7 @@ void LLVOAvatarSelf::updateRegion(LLViewerRegion *regionp) if (regionp->simulatorFeaturesReceived()) { setHoverIfRegionEnabled(); - checkBOMRebakeRequired();// <FS:Beq/> BOM we may have stale cache, rebake may be needed + checkBOMRebakeRequired(); } else { @@ -1129,7 +1148,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 (const auto& baked_pair : sAvatarDictionary->getBakedTextures()) { @@ -1146,13 +1165,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(); + } } //----------------------------------------------------------------------------- @@ -1581,6 +1607,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; @@ -1646,12 +1681,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(); +} + +// virtual +bool LLVOAvatarSelf::hasPendingBakedUploads() const +{ + for (U32 i = 0; i < getNumBakes(); i++) + { + LLViewerTexLayerSet* layerset = getTexLayerSet(i); + if (layerset && layerset->getViewerComposite() && layerset->getViewerComposite()->uploadPending()) + { + return true; + } + } + return false; } -void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset) +void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result) { LLViewerTexLayerSet *layer_set = dynamic_cast<LLViewerTexLayerSet*>(layerset); if( !layer_set || !layer_set->getUpdatesEnabled() ) @@ -1662,6 +1733,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() @@ -1669,7 +1750,7 @@ void LLVOAvatarSelf::invalidateAll() for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { LLViewerTexLayerSet *layerset = getTexLayerSet(i); - invalidateComposite(layerset); + invalidateComposite(layerset, TRUE); } //mDebugSelfLoadTimer.reset(); } @@ -2224,7 +2305,6 @@ const std::string LLVOAvatarSelf::debugDumpLocalTextureDataInfo(const LLViewerTe for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++) { const U32 discard_level = getLocalDiscardLevel(tex_index, wearable_index); - std::string discard_str = llformat("%d ",discard_level); text += llformat("%d ",discard_level); } } @@ -2428,6 +2508,49 @@ void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics() } } +void CheckAgentAppearanceService_httpSuccess( LLSD const &aData ) +{ + LL_DEBUGS("Avatar") << "OK" << LL_ENDL; +} + +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 CheckAgentAppearanceService_httpFailure( LLSD const &aData ) +{ + if (isAgentAvatarValid()) + { + LL_DEBUGS("Avatar") << "failed, will rebake " << aData << LL_ENDL; + forceAppearanceUpdate(); + } +} + +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()) + { + forceAppearanceUpdate(); + } + // query baked image service to check status. + std::string image_url = gAgentAvatarp->getImageURL(TEX_HEAD_BAKED, + getTE(TEX_HEAD_BAKED)->getID()); + + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpGet( image_url, CheckAgentAppearanceService_httpSuccess, CheckAgentAppearanceService_httpFailure ); +} + const LLUUID& LLVOAvatarSelf::grabBakedTexture(EBakedTextureIndex baked_index) const { if (canGrabBakedTexture(baked_index)) @@ -2584,6 +2707,81 @@ ETextureIndex LLVOAvatarSelf::getBakedTE( const LLViewerTexLayerSet* layerset ) return TEX_HEAD_BAKED; } + +void LLVOAvatarSelf::setNewBakedTexture(LLAvatarAppearanceDefines::EBakedTextureIndex i, const LLUUID &uuid) +{ + ETextureIndex index = LLAvatarAppearance::getDictionary()->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 = LLAvatarAppearance::getDictionary()->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 { @@ -2659,6 +2857,76 @@ 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) + { + 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 = LLAvatarAppearance::getDictionary()->getTextures().begin(); + iter != LLAvatarAppearance::getDictionary()->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) { @@ -2673,9 +2941,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 @@ -2738,9 +3007,6 @@ LLViewerTexLayerSet* LLVOAvatarSelf::getLayerSet(EBakedTextureIndex baked_index) return NULL; } - - - // static void LLVOAvatarSelf::onCustomizeStart(bool disable_camera_switch) { @@ -2772,6 +3038,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 (gSavedSettings.getBOOL("AppearanceCameraMovement") && !disable_camera_switch) @@ -2806,7 +3078,6 @@ bool LLVOAvatarSelf::sendAppearanceMessage(LLMessageSystem *mesgsys) const { const ETextureIndex index = tex_pair.first; const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = tex_pair.second; - // <FS:Beq> hide the surplus bakes and universals from non-BOM if( (index == TEX_SKIRT || index == TEX_SKIRT_TATTOO) && !gAgentAvatarp->isWearingWearableType(LLWearableType::WT_SKIRT) ) { // TODO(BEQ): combine this with clause below once proven it works. @@ -2816,7 +3087,6 @@ bool LLVOAvatarSelf::sendAppearanceMessage(LLMessageSystem *mesgsys) const entry->setID(IMG_DEFAULT_AVATAR); } if (!texture_dict->mIsBakedTexture || index >= getRegion()->getRegionMaxTEs()) - // </FS:Beq> { LLTextureEntry* entry = getTE((U8) index); texture_id[index] = entry->getID(); @@ -2831,9 +3101,7 @@ bool LLVOAvatarSelf::sendAppearanceMessage(LLMessageSystem *mesgsys) const { const ETextureIndex index = tex_pair.first; const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = tex_pair.second; - // <FS:Beq> hide the surplus bakes and universals from non-BOM if (!texture_dict->mIsBakedTexture || index >= getRegion()->getRegionMaxTEs()) - // </FS:Beq> { LLTextureEntry* entry = getTE((U8) index); entry->setID(texture_id[index]); @@ -2952,10 +3220,8 @@ void LLVOAvatarSelf::dumpWearableInfo(LLAPRFile& outfile) type_name.c_str(), wearable->getName().c_str() ); LLWearable::visual_param_vec_t v_params; wearable->getVisualParams(v_params); - for (LLWearable::visual_param_vec_t::iterator it = v_params.begin(); - it != v_params.end(); ++it) + for (LLVisualParam *param : v_params) { - LLVisualParam *param = *it; dump_visual_param(file, param, param->getWeight()); } } @@ -3015,4 +3281,4 @@ void LLVOAvatarSelf::dumpWearableInfo(LLAPRFile& outfile) // } // mPendingObjectDetach.clear(); //} -//// [/SL:KB] +//// [/SL:KB] \ No newline at end of file diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index 2c7e95a2ce5..3bc4c3557d5 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -55,11 +55,11 @@ class LLVOAvatarSelf final : public: LLVOAvatarSelf(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); virtual ~LLVOAvatarSelf(); - virtual void markDead(); - virtual void initInstance(); // Called after construction to initialize the class. + void markDead() override; + void initInstance() override; // Called after construction to initialize the class. void cleanup(); protected: - /*virtual*/ BOOL loadAvatar(); + /*virtual*/ BOOL loadAvatar() override; BOOL loadAvatarSelf(); BOOL buildSkeletonSelf(const LLAvatarSkeletonInfo *info); BOOL buildMenus(); @@ -80,28 +80,28 @@ class LLVOAvatarSelf final : boost::signals2::connection mRegionChangedSlot; void onSimulatorFeaturesReceived(const LLUUID& region_id); - /*virtual*/ void updateRegion(LLViewerRegion *regionp); - /*virtual*/ void idleUpdate(LLAgent &agent, const F64 &time); + /*virtual*/ void updateRegion(LLViewerRegion *regionp) override; + /*virtual*/ void idleUpdate(LLAgent &agent, const F64 &time) override; //-------------------------------------------------------------------- // LLCharacter interface and related //-------------------------------------------------------------------- public: - /*virtual*/ bool hasMotionFromSource(const LLUUID& source_id); - /*virtual*/ void stopMotionFromSource(const LLUUID& source_id); - /*virtual*/ void requestStopMotion(LLMotion* motion); - /*virtual*/ LLJoint* getJoint(const std::string &name); + /*virtual*/ bool hasMotionFromSource(const LLUUID& source_id) override; + /*virtual*/ void stopMotionFromSource(const LLUUID& source_id) override; + /*virtual*/ void requestStopMotion(LLMotion* motion) override; + /*virtual*/ LLJoint* getJoint(const std::string &name) override; - /*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*/ void updateVisualParams(); + /*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() override; void writeWearablesToAvatar(); - /*virtual*/ void idleUpdateAppearanceAnimation(); + /*virtual*/ void idleUpdateAppearanceAnimation() override; 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); /******************************************************************************** ** ** @@ -158,9 +158,9 @@ class LLVOAvatarSelf final : // LLVOAvatar Constants //-------------------------------------------------------------------- public: - /*virtual*/ LLViewerTexture::EBoostLevel getAvatarBoostLevel() const { return LLGLTexture::BOOST_AVATAR_SELF; } - /*virtual*/ LLViewerTexture::EBoostLevel getAvatarBakedBoostLevel() const { return LLGLTexture::BOOST_AVATAR_BAKED_SELF; } - /*virtual*/ S32 getTexImageSize() const { return LLVOAvatar::getTexImageSize()*4; } + /*virtual*/ LLViewerTexture::EBoostLevel getAvatarBoostLevel() const override { return LLGLTexture::BOOST_AVATAR_SELF; } + /*virtual*/ LLViewerTexture::EBoostLevel getAvatarBakedBoostLevel() const override { return LLGLTexture::BOOST_AVATAR_BAKED_SELF; } + /*virtual*/ S32 getTexImageSize() const override { return LLVOAvatar::getTexImageSize()*4; } /** Rendering ** ** @@ -175,14 +175,16 @@ class LLVOAvatarSelf final : // 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; - /*virtual*/ BOOL isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex type, LLViewerWearable *wearable) const; + /*virtual*/ BOOL isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const override; + /*virtual*/ BOOL isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex type, U32 index = 0) const override; + /*virtual*/ BOOL isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex type, LLViewerWearable *wearable) const override; //-------------------------------------------------------------------- @@ -193,19 +195,19 @@ class LLVOAvatarSelf final : LLViewerFetchedTexture* getLocalTextureGL(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const; const LLUUID& getLocalTextureID(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const; void setLocalTextureTE(U8 te, LLViewerTexture* image, U32 index); - /*virtual*/ void setLocalTexture(LLAvatarAppearanceDefines::ETextureIndex type, LLViewerTexture* tex, BOOL baked_version_exits, U32 index); + /*virtual*/ void setLocalTexture(LLAvatarAppearanceDefines::ETextureIndex type, LLViewerTexture* tex, BOOL baked_version_exits, U32 index) override; protected: - /*virtual*/ void setBakedReady(LLAvatarAppearanceDefines::ETextureIndex type, BOOL baked_version_exists, U32 index); + /*virtual*/ void setBakedReady(LLAvatarAppearanceDefines::ETextureIndex type, BOOL baked_version_exists, U32 index) override; void localTextureLoaded(BOOL succcess, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); void getLocalTextureByteCount(S32* gl_byte_count) const; - /*virtual*/ void addLocalTextureStats(LLAvatarAppearanceDefines::ETextureIndex i, LLViewerFetchedTexture* imagep, F32 texel_area_ratio, BOOL rendered, BOOL covered_by_baked); + /*virtual*/ void addLocalTextureStats(LLAvatarAppearanceDefines::ETextureIndex i, LLViewerFetchedTexture* imagep, F32 texel_area_ratio, BOOL rendered, BOOL covered_by_baked) override; LLLocalTextureObject* getLocalTextureObject(LLAvatarAppearanceDefines::ETextureIndex i, U32 index) const; private: static void onLocalTextureLoaded(BOOL succcess, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); - /*virtual*/ void setImage(const U8 te, LLViewerTexture *imagep, const U32 index); - /*virtual*/ LLViewerTexture* getImage(const U8 te, const U32 index) const; + /*virtual*/ void setImage(const U8 te, LLViewerTexture *imagep, const U32 index) override; + /*virtual*/ LLViewerTexture* getImage(const U8 te, const U32 index) const override; //-------------------------------------------------------------------- @@ -215,13 +217,21 @@ class LLVOAvatarSelf final : 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(); + /*virtual*/ void removeMissingBakedTextures() override; //-------------------------------------------------------------------- // 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; @@ -231,11 +241,11 @@ class LLVOAvatarSelf final : // Composites //-------------------------------------------------------------------- public: - /* virtual */ void invalidateComposite(LLTexLayerSet* layerset); - /* virtual */ void invalidateAll(); - /* virtual */ void setCompositeUpdatesEnabled(bool b); // only works for self - /* virtual */ void setCompositeUpdatesEnabled(U32 index, bool b); - /* virtual */ bool isCompositeUpdateEnabled(U32 index); + /* virtual */ void invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result) override; + /* virtual */ void invalidateAll() override; + /* virtual */ void setCompositeUpdatesEnabled(bool b) override; // only works for self + /* virtual */ void setCompositeUpdatesEnabled(U32 index, bool b) override; + /* virtual */ bool isCompositeUpdateEnabled(U32 index) override; void setupComposites(); void updateComposites(); @@ -273,7 +283,7 @@ class LLVOAvatarSelf final : **/ public: - void wearableUpdated(LLWearableType::EType type); + void wearableUpdated(LLWearableType::EType type, BOOL upload_result); protected: U32 getNumWearables(LLAvatarAppearanceDefines::ETextureIndex i) const; @@ -391,6 +401,7 @@ class LLVOAvatarSelf final : 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; -- GitLab