using System; using System.Collections.Generic; using UnityEngine; using Object = UnityEngine.Object; namespace FairyGUI { /// /// /// public enum DestroyMethod { Destroy, Unload, None, ReleaseTemp, Custom } /// /// /// public class NTexture { /// /// This event will trigger when a texture is destroying if its destroyMethod is Custom /// public static event Action CustomDestroyMethod; /// /// /// public Rect uvRect; /// /// /// public bool rotated; /// /// /// public int refCount; /// /// /// public float lastActive; /// /// /// public DestroyMethod destroyMethod; /// /// This event will trigger when texture reloaded and size changed. /// public event Action onSizeChanged; /// /// This event will trigger when ref count is zero. /// public event Action onRelease; Texture _nativeTexture; Texture _alphaTexture; Rect _region; Vector2 _offset; Vector2 _originalSize; NTexture _root; Dictionary _materialManagers; internal static Texture2D CreateEmptyTexture() { Texture2D emptyTexture = new Texture2D(1, 1, TextureFormat.RGB24, false); emptyTexture.name = "White Texture"; emptyTexture.hideFlags = DisplayObject.hideFlags; emptyTexture.SetPixel(0, 0, Color.white); emptyTexture.Apply(); return emptyTexture; } static NTexture _empty; /// /// /// public static NTexture Empty { get { if (_empty == null) _empty = new NTexture(CreateEmptyTexture()); return _empty; } } /// /// /// public static void DisposeEmpty() { if (_empty != null) { NTexture tmp = _empty; _empty = null; tmp.Dispose(); } } /// /// /// /// public NTexture(Texture texture) : this(texture, null, 1, 1) { } /// /// /// /// /// /// public NTexture(Texture texture, Texture alphaTexture, float xScale, float yScale) { _root = this; _nativeTexture = texture; _alphaTexture = alphaTexture; uvRect = new Rect(0, 0, xScale, yScale); if (yScale < 0) { uvRect.y = -yScale; uvRect.yMax = 0; } if (xScale < 0) { uvRect.x = -xScale; uvRect.xMax = 0; } if (_nativeTexture != null) _originalSize = new Vector2(_nativeTexture.width, _nativeTexture.height); _region = new Rect(0, 0, _originalSize.x, _originalSize.y); } /// /// /// /// /// public NTexture(Texture texture, Rect region) { _root = this; _nativeTexture = texture; _region = region; _originalSize = new Vector2(_region.width, _region.height); if (_nativeTexture != null) uvRect = new Rect(region.x / _nativeTexture.width, 1 - region.yMax / _nativeTexture.height, region.width / _nativeTexture.width, region.height / _nativeTexture.height); else uvRect.Set(0, 0, 1, 1); } /// /// /// /// /// /// public NTexture(NTexture root, Rect region, bool rotated) { _root = root; this.rotated = rotated; region.x += root._region.x; region.y += root._region.y; uvRect = new Rect(region.x * root.uvRect.width / root.width, 1 - region.yMax * root.uvRect.height / root.height, region.width * root.uvRect.width / root.width, region.height * root.uvRect.height / root.height); if (rotated) { float tmp = region.width; region.width = region.height; region.height = tmp; tmp = uvRect.width; uvRect.width = uvRect.height; uvRect.height = tmp; } _region = region; _originalSize = _region.size; } /// /// /// /// /// /// /// /// public NTexture(NTexture root, Rect region, bool rotated, Vector2 originalSize, Vector2 offset) : this(root, region, rotated) { _originalSize = originalSize; _offset = offset; } /// /// /// /// public NTexture(Sprite sprite) { Rect rect = sprite.textureRect; rect.y = sprite.texture.height - rect.yMax; _root = this; _nativeTexture = sprite.texture; _region = rect; _originalSize = new Vector2(_region.width, _region.height); uvRect = new Rect(_region.x / _nativeTexture.width, 1 - _region.yMax / _nativeTexture.height, _region.width / _nativeTexture.width, _region.height / _nativeTexture.height); } /// /// /// public int width { get { return (int)_region.width; } } /// /// /// public int height { get { return (int)_region.height; } } /// /// /// public Vector2 offset { get { return _offset; } set { _offset = value; } } /// /// /// public Vector2 originalSize { get { return _originalSize; } set { _originalSize = value; } } /// /// /// /// /// public Rect GetDrawRect(Rect drawRect) { if (_originalSize.x == _region.width && _originalSize.y == _region.height) return drawRect; float sx = drawRect.width / _originalSize.x; float sy = drawRect.height / _originalSize.y; return new Rect(_offset.x * sx, _offset.y * sy, _region.width * sx, _region.height * sy); } /// /// /// /// public void GetUV(Vector2[] uv) { uv[0] = uvRect.position; uv[1] = new Vector2(uvRect.xMin, uvRect.yMax); uv[2] = new Vector2(uvRect.xMax, uvRect.yMax); uv[3] = new Vector2(uvRect.xMax, uvRect.yMin); if (rotated) { float xMin = uvRect.xMin; float yMin = uvRect.yMin; float yMax = uvRect.yMax; float tmp; for (int i = 0; i < 4; i++) { Vector2 m = uv[i]; tmp = m.y; m.y = yMin + m.x - xMin; m.x = xMin + yMax - tmp; uv[i] = m; } } } /// /// /// public NTexture root { get { return _root; } } /// /// /// public bool disposed { get { return _root == null; } } /// /// /// public Texture nativeTexture { get { return _root != null ? _root._nativeTexture : null; } } /// /// /// public Texture alphaTexture { get { return _root != null ? _root._alphaTexture : null; } } /// /// /// public MaterialManager GetMaterialManager(string shaderName) { if (_root != this) { if (_root == null) return null; else return _root.GetMaterialManager(shaderName); } if (_materialManagers == null) _materialManagers = new Dictionary(); MaterialManager mm; if (!_materialManagers.TryGetValue(shaderName, out mm)) { mm = new MaterialManager(this, ShaderConfig.GetShader(shaderName)); _materialManagers.Add(shaderName, mm); } return mm; } /// /// /// public void Unload() { Unload(false); } /// /// /// public void Unload(bool destroyMaterials) { if (this == _empty) return; if (_root != this) throw new Exception("Unload is not allow to call on none root NTexture."); if (_nativeTexture != null) { DestroyTexture(); if (destroyMaterials) DestroyMaterials(); else RefreshMaterials(); } } /// /// /// /// /// public void Reload(Texture nativeTexture, Texture alphaTexture) { if (_root != this) throw new System.Exception("Reload is not allow to call on none root NTexture."); if (_nativeTexture != null && _nativeTexture != nativeTexture) DestroyTexture(); _nativeTexture = nativeTexture; _alphaTexture = alphaTexture; Vector2 lastSize = _originalSize; if (_nativeTexture != null) _originalSize = new Vector2(_nativeTexture.width, _nativeTexture.height); else _originalSize = Vector2.zero; _region = new Rect(0, 0, _originalSize.x, _originalSize.y); RefreshMaterials(); if (onSizeChanged != null && lastSize != _originalSize) onSizeChanged(this); } void DestroyTexture() { switch (destroyMethod) { case DestroyMethod.Destroy: Object.DestroyImmediate(_nativeTexture, true); if (_alphaTexture != null) Object.DestroyImmediate(_alphaTexture, true); break; case DestroyMethod.Unload: Resources.UnloadAsset(_nativeTexture); if (_alphaTexture != null) Resources.UnloadAsset(_alphaTexture); break; case DestroyMethod.ReleaseTemp: RenderTexture.ReleaseTemporary((RenderTexture)_nativeTexture); if (_alphaTexture is RenderTexture) RenderTexture.ReleaseTemporary((RenderTexture)_alphaTexture); break; case DestroyMethod.Custom: if (CustomDestroyMethod == null) Debug.LogWarning("NTexture.CustomDestroyMethod must be set to handle DestroyMethod.Custom"); else { CustomDestroyMethod(_nativeTexture); if (_alphaTexture != null) CustomDestroyMethod(_alphaTexture); } break; } _nativeTexture = null; _alphaTexture = null; } void RefreshMaterials() { if (_materialManagers != null && _materialManagers.Count > 0) { Dictionary.Enumerator iter = _materialManagers.GetEnumerator(); while (iter.MoveNext()) iter.Current.Value.RefreshMaterials(); iter.Dispose(); } } void DestroyMaterials() { if (_materialManagers != null && _materialManagers.Count > 0) { Dictionary.Enumerator iter = _materialManagers.GetEnumerator(); while (iter.MoveNext()) iter.Current.Value.DestroyMaterials(); iter.Dispose(); } } public void AddRef() { if (_root == null) //disposed return; if (_root != this && refCount == 0) _root.AddRef(); refCount++; } public void ReleaseRef() { if (_root == null) //disposed return; refCount--; if (refCount == 0) { if (_root != this) _root.ReleaseRef(); if (onRelease != null) onRelease(this); } } /// /// /// public void Dispose() { if (this == _empty) return; if (_root == this) Unload(true); _root = null; onSizeChanged = null; onRelease = null; } } }