//---------------------------------------------- // NGUI: Next-Gen UI kit // Copyright © 2011-2015 Tasharen Entertainment //---------------------------------------------- using UnityEngine; using System.Collections.Generic; using Thousandto.Launcher.ExternalLibs; /// /// Sprite is a textured element in the UI hierarchy. /// [ExecuteInEditMode] [AddComponentMenu("NGUI/UI/NGUI Sprite")] public class UISprite : UIBasicSprite { // Cached and saved values [HideInInspector][SerializeField] UIAtlas mAtlas; [HideInInspector][SerializeField] string mSpriteName; // Deprecated, no longer used [HideInInspector][SerializeField] bool mFillCenter = true; [System.NonSerialized] protected UISpriteData mSprite; [System.NonSerialized] bool mSpriteSet = false; /// /// Retrieve the material used by the font. /// public override Material material { get { return (mAtlas != null) ? mAtlas.spriteMaterial : null; } } /// /// Atlas used by this widget. /// /// public UIAtlas atlas { get { if (mAtlas != null) { return mAtlas; } return mAtlas; } set { if (mAtlas != value) { RemoveFromPanel(); mAtlas = value; mSpriteSet = false; mSprite = null; // Automatically choose the first sprite if (string.IsNullOrEmpty(mSpriteName)) { if (mAtlas != null && mAtlas.spriteList.Count > 0) { SetAtlasSprite(mAtlas.spriteList[0]); mSpriteName = mSprite.name; } } // Re-link the sprite if (!string.IsNullOrEmpty(mSpriteName)) { string sprite = mSpriteName; mSpriteName = ""; spriteName = sprite; MarkAsChanged(); } } } } /// /// Sprite within the atlas used to draw this widget. /// public string spriteName { get { return mSpriteName; } set { if (string.IsNullOrEmpty(value)) { // If the sprite name hasn't been set yet, no need to do anything if (string.IsNullOrEmpty(mSpriteName)) return; // Clear the sprite name and the sprite reference mSpriteName = ""; mSprite = null; mChanged = true; mSpriteSet = false; } else if (mSpriteName != value) { // If the sprite name changes, the sprite reference should also be updated mSpriteName = value; mSprite = null; mChanged = true; mSpriteSet = false; } } } /// /// Is there a valid sprite to work with? /// public bool isValid { get { return GetAtlasSprite() != null; } } /// /// Whether the center part of the sprite will be filled or not. Turn it off if you want only to borders to show up. /// [System.Obsolete("Use 'centerType' instead")] public bool fillCenter { get { return centerType != AdvancedType.Invisible; } set { if (value != (centerType != AdvancedType.Invisible)) { centerType = value ? AdvancedType.Sliced : AdvancedType.Invisible; MarkAsChanged(); } } } /// /// Sliced sprites generally have a border. X = left, Y = bottom, Z = right, W = top. /// public override Vector4 border { get { UISpriteData sp = GetAtlasSprite(); if (sp == null) return base.border; return new Vector4(sp.borderLeft, sp.borderBottom, sp.borderRight, sp.borderTop); } } /// /// Size of the pixel -- used for drawing. /// override public float pixelSize { get { return mAtlas != null ? mAtlas.pixelSize : 1f; } } /// /// Minimum allowed width for this widget. /// override public int minWidth { get { if (type == Type.Sliced || type == Type.Advanced) { float ps = pixelSize; Vector4 b = border * pixelSize; int min = Mathf.RoundToInt(b.x + b.z); UISpriteData sp = GetAtlasSprite(); if (sp != null) min += Mathf.RoundToInt(ps * (sp.paddingLeft + sp.paddingRight)); return Mathf.Max(base.minWidth, ((min & 1) == 1) ? min + 1 : min); } return base.minWidth; } } /// /// Minimum allowed height for this widget. /// override public int minHeight { get { if (type == Type.Sliced || type == Type.Advanced) { float ps = pixelSize; Vector4 b = border * pixelSize; int min = Mathf.RoundToInt(b.y + b.w); UISpriteData sp = GetAtlasSprite(); if (sp != null) min += Mathf.RoundToInt(ps * (sp.paddingTop + sp.paddingBottom)); return Mathf.Max(base.minHeight, ((min & 1) == 1) ? min + 1 : min); } return base.minHeight; } } /// /// Sprite's dimensions used for drawing. X = left, Y = bottom, Z = right, W = top. /// This function automatically adds 1 pixel on the edge if the sprite's dimensions are not even. /// It's used to achieve pixel-perfect sprites even when an odd dimension sprite happens to be centered. /// public override Vector4 drawingDimensions { get { Vector2 offset = pivotOffset; float x0 = -offset.x * mWidth; float y0 = -offset.y * mHeight; float x1 = x0 + mWidth; float y1 = y0 + mHeight; if (GetAtlasSprite() != null && mType != Type.Tiled) { int padLeft = mSprite.paddingLeft; int padBottom = mSprite.paddingBottom; int padRight = mSprite.paddingRight; int padTop = mSprite.paddingTop; if (mType != Type.Simple) { float ps = pixelSize; if (ps != 1f) { padLeft = Mathf.RoundToInt(ps * padLeft); padBottom = Mathf.RoundToInt(ps * padBottom); padRight = Mathf.RoundToInt(ps * padRight); padTop = Mathf.RoundToInt(ps * padTop); } } int w = mSprite.width + padLeft + padRight; int h = mSprite.height + padBottom + padTop; float px = 1f; float py = 1f; if (w > 0 && h > 0 && (mType == Type.Simple || mType == Type.Filled)) { if ((w & 1) != 0) ++padRight; if ((h & 1) != 0) ++padTop; px = (1f / w) * mWidth; py = (1f / h) * mHeight; } if (mFlip == Flip.Horizontally || mFlip == Flip.Both) { x0 += padRight * px; x1 -= padLeft * px; } else { x0 += padLeft * px; x1 -= padRight * px; } if (mFlip == Flip.Vertically || mFlip == Flip.Both) { y0 += padTop * py; y1 -= padBottom * py; } else { y0 += padBottom * py; y1 -= padTop * py; } } Vector4 br = (mAtlas != null) ? border * pixelSize : Vector4.zero; float fw = br.x + br.z; float fh = br.y + br.w; float vx = Mathf.Lerp(x0, x1 - fw, mDrawRegion.x); float vy = Mathf.Lerp(y0, y1 - fh, mDrawRegion.y); float vz = Mathf.Lerp(x0 + fw, x1, mDrawRegion.z); float vw = Mathf.Lerp(y0 + fh, y1, mDrawRegion.w); return new Vector4(vx, vy, vz, vw); } } /// /// Whether the texture is using a premultiplied alpha material. /// public override bool premultipliedAlpha { get { return (mAtlas != null) && mAtlas.premultipliedAlpha; } } /// /// Retrieve the atlas sprite referenced by the spriteName field. /// public UISpriteData GetAtlasSprite () { if (!mSpriteSet) mSprite = null; if (mSprite == null && mAtlas != null) { if (!string.IsNullOrEmpty(mSpriteName)) { UISpriteData sp = mAtlas.GetSprite(mSpriteName); if (sp == null) return null; SetAtlasSprite(sp); } if (mSprite == null && mAtlas.spriteList.Count > 0) { UISpriteData sp = mAtlas.spriteList[0]; if (sp == null) return null; SetAtlasSprite(sp); if (mSprite == null) { Debug.LogError(mAtlas.name + " seems to have a null sprite!"); return null; } mSpriteName = mSprite.name; } } return mSprite; } /// /// Set the atlas sprite directly. /// protected void SetAtlasSprite (UISpriteData sp) { mChanged = true; mSpriteSet = true; if (sp != null) { mSprite = sp; mSpriteName = mSprite.name; } else { mSpriteName = (mSprite != null) ? mSprite.name : ""; mSprite = sp; } } /// /// Adjust the scale of the widget to make it pixel-perfect. /// public override void MakePixelPerfect () { if (!isValid) return; base.MakePixelPerfect(); if (mType == Type.Tiled) return; UISpriteData sp = GetAtlasSprite(); if (sp == null) return; Texture tex = mainTexture; if (tex == null) return; if (mType == Type.Simple || mType == Type.Filled || !sp.hasBorder) { if (tex != null) { int x = Mathf.RoundToInt(pixelSize * (sp.width + sp.paddingLeft + sp.paddingRight)); int y = Mathf.RoundToInt(pixelSize * (sp.height + sp.paddingTop + sp.paddingBottom)); if ((x & 1) == 1) ++x; if ((y & 1) == 1) ++y; width = x; height = y; } } } /// /// Auto-upgrade. /// protected override void OnInit () { if (!mFillCenter) { mFillCenter = true; centerType = AdvancedType.Invisible; #if UNITY_EDITOR NGUITools.SetDirty(this); #endif } base.OnInit(); } /// /// Update the UV coordinates. /// protected override bool OnUpdate () { var result = base.OnUpdate(); if (mChanged || !mSpriteSet) { mSpriteSet = true; mSprite = null; mChanged = true; } return result; } /// /// Virtual function called by the UIPanel that fills the buffers. /// public override void OnFill(BetterList verts, BetterList uvs, BetterList cols) { Texture tex = mainTexture; if (tex == null) return; if (mSprite == null) mSprite = atlas.GetSprite(spriteName); if (mSprite == null) return; Rect outer = new Rect(mSprite.x, mSprite.y, mSprite.width, mSprite.height); Rect inner = new Rect(mSprite.x + mSprite.borderLeft, mSprite.y + mSprite.borderTop, mSprite.width - mSprite.borderLeft - mSprite.borderRight, mSprite.height - mSprite.borderBottom - mSprite.borderTop); outer = NGUIMath.ConvertToTexCoords(outer, tex.width, tex.height); inner = NGUIMath.ConvertToTexCoords(inner, tex.width, tex.height); int offset = verts != null ? verts.size : 0; Fill(verts, uvs, cols, outer, inner); if (onPostFill != null) //优化NGUI GC //because we might change geometry's verts uvs cols value in Fill onPostFill(this, offset, geometry.verts, geometry.uvs, geometry.cols); //#else //onPostFill(this, offset, verts, uvs, cols); //优化NGUI GC } }