using FairyGUI; using System.Collections.Generic; using UnityEngine; using XGame.Framework.Asyncs; namespace XGame.Framework.FGUI { /// /// 修复图集合批 参考链接:https://zhuanlan.zhihu.com/p/689636245 /// internal partial class FguiModule : IGloaderHandle { public class LoadedAsset { public string addressable; public Sprite sprite; public NTexture nTexture; } /// /// 已加载过的资源 /// private Dictionary _loadedAssetsMap = new Dictionary(); /// /// key:sprite.texture /// value:NTexture 用作Sprite的root /// private Dictionary _textureRootMap = new Dictionary(); IAsync IGloaderHandle.LoadNTexture(string addressableName) { if (_loadedAssetsMap.ContainsKey(addressableName)) { // 已经加载完 var asyncGroup = new AsyncGroup(); asyncGroup.End(); return asyncGroup; } //TODO 需要识别Sprite还是Texture var loadAsync = _assetModule.LoadAsync(addressableName); loadAsync.On(_ => { var result = loadAsync.Result; if (result == null) { Log.Debug($"IGloaderHandle.LoadNTexture failed. addressable:{addressableName}"); return; } if (CreateNTexture(addressableName, result) == false) { //已经有其他loader加载完成 _assetModule.Recycle(result); } }); return loadAsync; } NTexture IGloaderHandle.GetNTexture(string addressableName) { if (_loadedAssetsMap.TryGetValue(addressableName, out var asset)) { return asset.nTexture; } // 可能是加载失败,也可能是没有加载过 Log.Debug($"找不到NTexture,确认IGloaderHandle.LoadNTexture是否已经加载成功. Name:{addressableName}"); return default; } private bool CreateNTexture(string addressable, Sprite sprite) { if (_loadedAssetsMap.ContainsKey(addressable)) { // 已经有其他loader加载完成 return false; } if (!_textureRootMap.TryGetValue(sprite.texture, out var root)) { _textureRootMap[sprite.texture] = root = new NTexture(sprite.texture); root.destroyMethod = DestroyMethod.None; } Rect region = sprite.textureRect; //textureRect 会去掉边缘全透明的部分 region.y = sprite.texture.height - region.yMax; var nTexture = new NTexture(root, region, false); //注册release事件,Gloader在Dispose时,只会触发 NGraphics.Dispose() => _texture.ReleaseRef(); nTexture.onRelease += OnReleaseNTexture; nTexture.destroyMethod = DestroyMethod.None; var border = sprite.border; // if (border != Vector4.zero) { // sprite.rect: 精灵的真实尺寸 sprite.texture 图集的贴图 nTexture.spriteScale9Grid = new Rect(border.x, border.w, sprite.rect.width - border.x - border.z, sprite.rect.height - border.y - border.w); } //Log.Info($"CreateNTexture Name:{addressable} width:{sprite.texture.width} height:{sprite.texture.height} rect:{sprite.rect} textureRect:{sprite.textureRect} border:{sprite.border} Scale9Grid:{nTexture.spriteScale9Grid}"); _loadedAssetsMap.Add(addressable, new LoadedAsset() { addressable = addressable, sprite = sprite, nTexture = nTexture, }); return true; } private bool TryGetLoadedAsset(NTexture nTexture, out LoadedAsset asset) { foreach (var item in _loadedAssetsMap) { if (item.Value.nTexture == nTexture) { asset = item.Value; return true; } } asset = default; return false; } private void OnReleaseNTexture(NTexture nTexture) { if (TryGetLoadedAsset(nTexture, out var asset)) { //Log.Debug($"OnReleaseNTexture Addressable:{asset.addressable}"); _loadedAssetsMap.Remove(asset.addressable); if (nTexture.root.refCount <= 0) { _textureRootMap.Remove(asset.sprite.texture); } _assetModule.Recycle(asset.sprite); } } /// /// 清空所有Gloader加载的资源 /// /// public void ClearGloaderAssets() { foreach (var item in _loadedAssetsMap) { _assetModule.Recycle(item.Value.sprite); } _loadedAssetsMap.Clear(); _textureRootMap.Clear(); } } }