diff options
| -rw-r--r-- | indra/llprimitive/llgltfmaterial.cpp | 46 | ||||
| -rw-r--r-- | indra/llprimitive/llgltfmaterial.h | 12 | ||||
| -rw-r--r-- | indra/newview/llfetchedgltfmaterial.cpp | 49 | ||||
| -rw-r--r-- | indra/newview/llfetchedgltfmaterial.h | 3 | ||||
| -rw-r--r-- | indra/newview/lllocalbitmaps.cpp | 55 | ||||
| -rw-r--r-- | indra/newview/lllocalbitmaps.h | 12 | ||||
| -rw-r--r-- | indra/newview/llmaterialeditor.cpp | 121 | ||||
| -rw-r--r-- | indra/newview/llmaterialeditor.h | 13 | 
8 files changed, 283 insertions, 28 deletions
| diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp index f42c11ee21..6afd83904f 100644 --- a/indra/llprimitive/llgltfmaterial.cpp +++ b/indra/llprimitive/llgltfmaterial.cpp @@ -89,6 +89,11 @@ LLGLTFMaterial& LLGLTFMaterial::operator=(const LLGLTFMaterial& rhs)      mOverrideDoubleSided = rhs.mOverrideDoubleSided;      mOverrideAlphaMode = rhs.mOverrideAlphaMode; +    mLocalTextureIds = rhs.mLocalTextureIds; +    mLocalTextureTrackingIds = rhs.mLocalTextureTrackingIds; + +    updateTextureTracking(); +      return *this;  } @@ -765,3 +770,44 @@ LLUUID LLGLTFMaterial::getHash() const      return hash;  } +void LLGLTFMaterial::addLocalTextureTracking(const LLUUID& tracking_id, const LLUUID& tex_id) +{ +    mLocalTextureTrackingIds.insert(tracking_id); +    mLocalTextureIds.insert(tex_id); +} + +void LLGLTFMaterial::removeLocalTextureTracking(const LLUUID& tracking_id, const LLUUID& tex_id) +{ +    mLocalTextureTrackingIds.erase(tracking_id); +    mLocalTextureIds.erase(tex_id); +} + +bool LLGLTFMaterial::replaceLocalTexture(const LLUUID& old_id, const LLUUID& new_id) +{ +    bool res = false; + +    for (int i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) +    { +        if (mTextureId[i] == old_id) +        { +            mTextureId[i] = new_id; +            res = true; +        } +    } + +    mLocalTextureIds.erase(old_id); +    if (res) +    { +        mLocalTextureIds.insert(new_id); +    } + +    return res; +} + +void LLGLTFMaterial::updateTextureTracking() +{ +    if (mLocalTextureTrackingIds.size() > 0) +    { +        LL_WARNS() << "copied a material with local textures, but tracking not implemented" << LL_ENDL; +    } +} diff --git a/indra/llprimitive/llgltfmaterial.h b/indra/llprimitive/llgltfmaterial.h index 548e2c52f4..d45ada1561 100644 --- a/indra/llprimitive/llgltfmaterial.h +++ b/indra/llprimitive/llgltfmaterial.h @@ -223,8 +223,14 @@ public:      virtual void removeTextureEntry(LLTextureEntry* te) {};      // For local textures so that editor will know to track changes -    void setHasLocalTextures(bool val) { mHasLocalTextures = val; } -    bool hasLocalTextures() { return mHasLocalTextures; } +    void addLocalTextureTracking(const LLUUID& tracking_id, const LLUUID &tex_id); +    void removeLocalTextureTracking(const LLUUID& tracking_id, const LLUUID& tex_id); +    bool hasLocalTextures() { return !mLocalTextureIds.empty(); } +    virtual bool replaceLocalTexture(const LLUUID &old_id, const LLUUID& new_id); +    virtual void updateTextureTracking(); + +    uuid_set_t mLocalTextureIds; +    uuid_set_t mLocalTextureTrackingIds;  protected:      static LLVector2 vec2FromJson(const std::map<std::string, tinygltf::Value>& object, const char* key, const LLVector2& default_value); @@ -242,6 +248,4 @@ protected:      void writeToTexture(tinygltf::Model& model, T& texture_info, TextureInfo texture_info_id, bool force_write = false) const;      template<typename T>      static void writeToTexture(tinygltf::Model& model, T& texture_info, const LLUUID& texture_id, const TextureTransform& transform, bool force_write = false); - -    bool mHasLocalTextures;  }; diff --git a/indra/newview/llfetchedgltfmaterial.cpp b/indra/newview/llfetchedgltfmaterial.cpp index fc9d42bfb6..71a961ce49 100644 --- a/indra/newview/llfetchedgltfmaterial.cpp +++ b/indra/newview/llfetchedgltfmaterial.cpp @@ -144,6 +144,55 @@ void LLFetchedGLTFMaterial::bind(LLViewerTexture* media_tex)  } +LLViewerFetchedTexture* fetch_texture(const LLUUID& id) +{ +    LLViewerFetchedTexture* img = nullptr; +    if (id.notNull()) +    { +        img = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); +        img->addTextureStats(64.f * 64.f, TRUE); +    } +    return img; +}; + +bool LLFetchedGLTFMaterial::replaceLocalTexture(const LLUUID& old_id, const LLUUID& new_id) +{ +    bool res = false; +    if (mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR] == old_id) +    { +        mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR] = new_id; +        mBaseColorTexture = fetch_texture(new_id); +        res = true; +    } +    if (mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL] == old_id) +    { +        mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL] = new_id; +        mNormalTexture = fetch_texture(new_id); +        res = true; +    } +    if (mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS] == old_id) +    { +        mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS] = new_id; +        mMetallicRoughnessTexture = fetch_texture(new_id); +        res = true; +    } +    if (mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE] == old_id) +    { +        mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE] = new_id; +        mEmissiveTexture = fetch_texture(new_id); +        res = true; +    } +    return res; +} + +void LLFetchedGLTFMaterial::updateTextureTracking() +{ +    for (const LLUUID& id : mLocalTextureTrackingIds) +    { +        LLLocalBitmapMgr::getInstance()->associateGLTFMaterial(id, this); +    } +} +  void LLFetchedGLTFMaterial::materialBegin()  {      llassert(!mFetching); diff --git a/indra/newview/llfetchedgltfmaterial.h b/indra/newview/llfetchedgltfmaterial.h index 1668657281..02426bf088 100644 --- a/indra/newview/llfetchedgltfmaterial.h +++ b/indra/newview/llfetchedgltfmaterial.h @@ -50,6 +50,9 @@ public:      bool isFetching() const { return mFetching; } +    virtual bool replaceLocalTexture(const LLUUID& old_id, const LLUUID& new_id) override; +    virtual void updateTextureTracking() override; +      // Textures used for fetching/rendering      LLPointer<LLViewerFetchedTexture> mBaseColorTexture;      LLPointer<LLViewerFetchedTexture> mNormalTexture; diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 6f1e4c9419..88de575f91 100644 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -46,6 +46,7 @@  #include <ctime>  /* misc headers */ +#include "llgltfmaterial.h"  #include "llscrolllistctrl.h"  #include "lllocaltextureobject.h"  #include "llviewertexturelist.h" @@ -131,6 +132,14 @@ LLLocalBitmap::~LLLocalBitmap()  		LLLocalBitmapMgr::getInstance()->doRebake();  	} +    for (LLPointer<LLGLTFMaterial> &mat : mGLTFMaterialWithLocalTextures) +    { +        mat->removeLocalTextureTracking(getTrackingID(), getWorldID()); +    } + +    mChangedSignal(getTrackingID(), getWorldID(), LLUUID()); +    mChangedSignal.disconnect_all_slots(); +  	// delete self from gimagelist  	LLViewerFetchedTexture* image = gTextureList.findImage(mWorldID, TEX_LIST_STANDARD);  	gTextureList.deleteImage(image); @@ -278,6 +287,17 @@ boost::signals2::connection LLLocalBitmap::setChangedCallback(const LLLocalTextu      return mChangedSignal.connect(cb);  } +void LLLocalBitmap::addGLTFMaterial(LLGLTFMaterial* mat) +{ +    if (mat +        // dupplicate prevention +        && mat->mLocalTextureTrackingIds.find(getTrackingID()) == mat->mLocalTextureTrackingIds.end()) +    { +        mat->addLocalTextureTracking(getTrackingID(), getWorldID()); +        mGLTFMaterialWithLocalTextures.push_back(mat); +    } +} +  bool LLLocalBitmap::decodeBitmap(LLPointer<LLImageRaw> rawimg)  {  	bool decode_successful = false; @@ -355,7 +375,7 @@ void LLLocalBitmap::replaceIDs(const LLUUID& old_id, LLUUID new_id)  		return;  	} -    mChangedSignal(old_id, new_id); +    mChangedSignal(getTrackingID(), old_id, new_id);  	// processing updates per channel; makes the process scalable.  	// the only actual difference is in SetTE* call i.e. SetTETexture, SetTENormal, etc. @@ -389,8 +409,7 @@ void LLLocalBitmap::replaceIDs(const LLUUID& old_id, LLUUID new_id)  	updateUserLayers(old_id, new_id, LLWearableType::WT_UNDERPANTS);  	updateUserLayers(old_id, new_id, LLWearableType::WT_UNDERSHIRT); -    // Go over any local material - +    updateGLTFMaterials(old_id, new_id);  }  // this function sorts the faces from a getFaceList[getNumFaces] into a list of objects @@ -588,6 +607,24 @@ void LLLocalBitmap::updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableTyp  	}  } +void LLLocalBitmap::updateGLTFMaterials(LLUUID old_id, LLUUID new_id) +{ +    // Might be a better idea to hold this in LLGLTFMaterialList +    for (mat_list_t::iterator it = mGLTFMaterialWithLocalTextures.begin(); it != mGLTFMaterialWithLocalTextures.end();) +    { +        if ((*it)->replaceLocalTexture(old_id, new_id)) +        { +            ++it; +        } +        else +        { +            // matching id not found, no longer in use +            (*it)->removeLocalTextureTracking(getTrackingID(), new_id); +            it = mGLTFMaterialWithLocalTextures.erase(it); +        } +    } +} +  LLAvatarAppearanceDefines::ETextureIndex LLLocalBitmap::getTexIndex(  	LLWearableType::EType type, LLAvatarAppearanceDefines::EBakedTextureIndex baked_texind)  { @@ -1089,6 +1126,18 @@ boost::signals2::connection LLLocalBitmapMgr::setOnChangedCallback(const LLUUID      return boost::signals2::connection();  } +void LLLocalBitmapMgr::associateGLTFMaterial(const LLUUID tracking_id, LLGLTFMaterial* mat) +{ +    for (local_list_iter iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++) +    { +        LLLocalBitmap* unit = *iter; +        if (unit->getTrackingID() == tracking_id) +        { +            unit->addGLTFMaterial(mat); +        } +    } +} +  void LLLocalBitmapMgr::feedScrollList(LLScrollListCtrl* ctrl)  {  	if (ctrl) diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h index f36fd6d320..1fdf9dccbf 100644 --- a/indra/newview/lllocalbitmaps.h +++ b/indra/newview/lllocalbitmaps.h @@ -36,6 +36,7 @@  class LLScrollListCtrl;  class LLImageRaw;  class LLViewerObject; +class LLGLTFMaterial;  class LLLocalBitmap  { @@ -59,10 +60,12 @@ class LLLocalBitmap  		bool updateSelf(EUpdateType = UT_REGUPDATE); -        typedef boost::signals2::signal<void(const LLUUID& old_id, +        typedef boost::signals2::signal<void(const LLUUID& tracking_id, +                                             const LLUUID& old_id,                                               const LLUUID& new_id)> LLLocalTextureChangedSignal;          typedef LLLocalTextureChangedSignal::slot_type LLLocalTextureCallback;          boost::signals2::connection setChangedCallback(const LLLocalTextureCallback& cb); +        void addGLTFMaterial(LLGLTFMaterial* mat);  	private: /* self update private section */  		bool decodeBitmap(LLPointer<LLImageRaw> raw); @@ -71,6 +74,7 @@ class LLLocalBitmap  		void updateUserPrims(LLUUID old_id, LLUUID new_id, U32 channel);  		void updateUserVolumes(LLUUID old_id, LLUUID new_id, U32 channel);  		void updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableType::EType type); +        void updateGLTFMaterials(LLUUID old_id, LLUUID new_id);  		LLAvatarAppearanceDefines::ETextureIndex getTexIndex(LLWearableType::EType type, LLAvatarAppearanceDefines::EBakedTextureIndex baked_texind);  	private: /* private enums */ @@ -100,6 +104,11 @@ class LLLocalBitmap  		S32         mUpdateRetries;          LLLocalTextureChangedSignal	mChangedSignal; +        // Store a list of accosiated materials +        // Might be a better idea to hold this in LLGLTFMaterialList +        typedef std::vector<LLPointer<LLGLTFMaterial> > mat_list_t; +        mat_list_t mGLTFMaterialWithLocalTextures; +  };  class LLLocalBitmapTimer : public LLEventTimer @@ -130,6 +139,7 @@ public:      bool         isLocal(const LLUUID& world_id) const;  	std::string  getFilename(const LLUUID &tracking_id) const;      boost::signals2::connection setOnChangedCallback(const LLUUID tracking_id, const LLLocalBitmap::LLLocalTextureCallback& cb); +    void associateGLTFMaterial(const LLUUID tracking_id, LLGLTFMaterial* mat);  	void         feedScrollList(LLScrollListCtrl* ctrl);  	void         doUpdates(); diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 63d86cda61..b8e34b7409 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -363,6 +363,15 @@ LLMaterialEditor::LLMaterialEditor(const LLSD& key)      }  } +LLMaterialEditor::~LLMaterialEditor() +{ +    for (mat_connection_map_t::value_type cn : mTextureChangesUpdates) +    { +        cn.second.mConnection.disconnect(); +    } +    mTextureChangesUpdates.clear(); +} +  void LLMaterialEditor::setObjectID(const LLUUID& object_id)  {      LLPreview::setObjectID(object_id); @@ -532,11 +541,6 @@ void LLMaterialEditor::onClose(bool app_quitting)          mSelectionUpdateSlot.disconnect();      } -    for (boost::signals2::connection& cn : mTextureChangesUpdates) -    { -        cn.disconnect(); -    } -      LLPreview::onClose(app_quitting);  } @@ -866,7 +870,27 @@ void LLMaterialEditor::setEnableEditing(bool can_modify)      mNormalTextureCtrl->setEnabled(can_modify);  } -void LLMaterialEditor::replaceTexture(const LLUUID& old_id, const LLUUID& new_id) +void LLMaterialEditor::subscribeToLocalTexture(S32 dirty_flag, const LLUUID& tracking_id) +{ +    LocalTextureConnection info; +    info.mTrackingId = tracking_id; +    info.mConnection = LLLocalBitmapMgr::getInstance()->setOnChangedCallback(tracking_id, +                                                                             [this, dirty_flag](const LLUUID& tracking_id, const LLUUID& old_id, const LLUUID& new_id) +                                                                             { +                                                                                 if (new_id.isNull()) +                                                                                 { +                                                                                     mTextureChangesUpdates[dirty_flag].mConnection.disconnect(); +                                                                                     mTextureChangesUpdates.erase(dirty_flag); +                                                                                 } +                                                                                 else +                                                                                 { +                                                                                     replaceLocalTexture(old_id, new_id); +                                                                                 } +                                                                             }); +    mTextureChangesUpdates[dirty_flag] = info; +} + +void LLMaterialEditor::replaceLocalTexture(const LLUUID& old_id, const LLUUID& new_id)  {      // todo: might be a good idea to set mBaseColorTextureUploadId here      // and when texturectrl picks a local texture @@ -958,18 +982,17 @@ void LLMaterialEditor::onCommitTexture(LLUICtrl* ctrl, const LLSD& data, S32 dir              childSetValue(upload_fee_ctrl_name, getString("no_upload_fee_string"));          } +        // unsubcribe potential old callabck +        mat_connection_map_t::iterator found = mTextureChangesUpdates.find(dirty_flag); +        if (found != mTextureChangesUpdates.end()) +        { +            found->second.mConnection.disconnect(); +        } +          LLTextureCtrl* tex_ctrl = (LLTextureCtrl*)ctrl;          if (tex_ctrl->isImageLocal())          { -            // Theoretically LLSD should be smart enough to not need this, but for extra safety -            LLSD key = llsd_clone(getKey()); -            // Subscribe material editor to local texture updates -            mTextureChangesUpdates.push_back( -                LLLocalBitmapMgr::getInstance()->setOnChangedCallback(tex_ctrl->getLocalTrackingID(), -                                                                      [this](const LLUUID &old_id, const LLUUID& new_id) -                                                                      { -                                                                          replaceTexture(old_id, new_id); -                                                                      })); +            subscribeToLocalTexture(dirty_flag, tex_ctrl->getLocalTrackingID());          }      } @@ -988,9 +1011,8 @@ void update_local_texture(LLUICtrl* ctrl, LLGLTFMaterial* mat)      LLTextureCtrl* tex_ctrl = (LLTextureCtrl*)ctrl;      if (tex_ctrl->isImageLocal())      { -        mat->setHasLocalTextures(true); -        // Todo: subscrive material for an update -        // tex_ctrl->getLocalTrackingID(); +        // subscrive material to updates of local textures +        LLLocalBitmapMgr::getInstance()->associateGLTFMaterial(tex_ctrl->getLocalTrackingID(), mat);      }  } @@ -1465,6 +1487,20 @@ void LLMaterialEditor::finishInventoryUpload(LLUUID itemId, LLUUID newAssetId, L          {              me->refreshFromInventory(itemId);          } + +        if (me && !me->mTextureChangesUpdates.empty()) +        { +            const LLInventoryItem* item = me->getItem(); +            if (item) +            { +                // local materials were assigned, force load material and init tracking +                LLGLTFMaterial* mat = gGLTFMaterialList.getMaterial(item->getAssetUUID()); +                for (mat_connection_map_t::value_type val : me->mTextureChangesUpdates) +                { +                    LLLocalBitmapMgr::getInstance()->associateGLTFMaterial(val.second.mTrackingId, mat); +                } +            } +        }      }  } @@ -1479,6 +1515,16 @@ void LLMaterialEditor::finishTaskUpload(LLUUID itemId, LLUUID newAssetId, LLUUID          me->setAssetId(newAssetId);          me->refreshFromInventory();          me->setEnabled(true); + +        if (me && !me->mTextureChangesUpdates.empty()) +        { +            // local materials were assigned, force load material and init tracking +            LLGLTFMaterial* mat = gGLTFMaterialList.getMaterial(newAssetId); +            for (mat_connection_map_t::value_type val : me->mTextureChangesUpdates) +            { +                LLLocalBitmapMgr::getInstance()->associateGLTFMaterial(val.second.mTrackingId, mat); +            } +        }      }  } @@ -1512,6 +1558,17 @@ void LLMaterialEditor::finishSaveAs(              {                  me->loadAsset();                  me->setEnabled(true); + +                // Local texure support +                if (!me->mTextureChangesUpdates.empty()) +                { +                    // local materials were assigned, force load material and init tracking +                    LLGLTFMaterial* mat = gGLTFMaterialList.getMaterial(item->getAssetUUID()); +                    for (mat_connection_map_t::value_type val : me->mTextureChangesUpdates) +                    { +                        LLLocalBitmapMgr::getInstance()->associateGLTFMaterial(val.second.mTrackingId, mat); +                    } +                }              }          }          else if(has_unsaved_changes) @@ -2975,6 +3032,34 @@ void LLMaterialEditor::setFromGLTFMaterial(LLGLTFMaterial* mat)      setDoubleSided(mat->mDoubleSided);      setAlphaMode(mat->getAlphaMode());      setAlphaCutoff(mat->mAlphaCutoff); + + +    for (mat_connection_map_t::value_type cn : mTextureChangesUpdates) +    { +        cn.second.mConnection.disconnect(); +    } +    mTextureChangesUpdates.clear(); + +    for (const LLUUID& tracking_id : mat->mLocalTextureTrackingIds) +    { +        LLUUID world_id = LLLocalBitmapMgr::getInstance()->getWorldID(tracking_id); +        if (world_id == mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR]) +        { +            subscribeToLocalTexture(MATERIAL_BASE_COLOR_TEX_DIRTY, tracking_id); +        } +        if (world_id == mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS]) +        { +            subscribeToLocalTexture(MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY, tracking_id); +        } +        if (world_id == mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE]) +        { +            subscribeToLocalTexture(MATERIAL_EMISIVE_TEX_DIRTY, tracking_id); +        } +        if (world_id == mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL]) +        { +            subscribeToLocalTexture(MATERIAL_NORMAL_TEX_DIRTY, tracking_id); +        } +    }  }  bool LLMaterialEditor::setFromSelection() diff --git a/indra/newview/llmaterialeditor.h b/indra/newview/llmaterialeditor.h index 4af68adce2..fd8b259a1a 100644 --- a/indra/newview/llmaterialeditor.h +++ b/indra/newview/llmaterialeditor.h @@ -87,6 +87,7 @@ protected:  class LLMaterialEditor : public LLPreview, public LLVOInventoryListener  { public:  	LLMaterialEditor(const LLSD& key); +    ~LLMaterialEditor();      bool setFromGltfModel(const tinygltf::Model& model, S32 index, bool set_textures = false); @@ -219,7 +220,8 @@ class LLMaterialEditor : public LLPreview, public LLVOInventoryListener      void setCanSave(bool value);      void setEnableEditing(bool can_modify); -    void replaceTexture(const LLUUID& old_id, const LLUUID& new_id); // Local texture support +    void subscribeToLocalTexture(S32 dirty_flag, const LLUUID& tracking_id); +    void replaceLocalTexture(const LLUUID& old_id, const LLUUID& new_id); // Local texture support      void onCommitTexture(LLUICtrl* ctrl, const LLSD& data, S32 dirty_flag);      void onCancelCtrl(LLUICtrl* ctrl, const LLSD& data, S32 dirty_flag);      void onSelectCtrl(LLUICtrl* ctrl, const LLSD& data, S32 dirty_flag); @@ -307,6 +309,13 @@ private:      static bool mOverrideInProgress;      static bool mSelectionNeedsUpdate;      boost::signals2::connection mSelectionUpdateSlot; -    std::list <boost::signals2::connection> mTextureChangesUpdates; + +    struct LocalTextureConnection +    { +        LLUUID mTrackingId; +        boost::signals2::connection mConnection; +    }; +    typedef std::map<S32, LocalTextureConnection> mat_connection_map_t; +    mat_connection_map_t mTextureChangesUpdates;  }; | 
