context: using UnityEngine;
  
  /// <summary>
  /// Functionality common to both NGUI and 2D sprites brought out into a single common parent.
  /// Mostly contains everything related to drawing the sprite.
  /// </summary>
  
  public abstract class UIBasicSprite : UIWidget
  {
  	public enum Type
  	{
  		Simple,
  		Sliced,
  		Tiled,
  		Filled,
  		Advanced,
  	}
  
  	public enum FillDirection
  	{
  		Horizontal,
  		Vertical,
  		Radial90,
  		Radial180,
  		Radial360,
  	}
  
  	public enum AdvancedType
  	{
  		Invisible,
  		Sliced,
  		Tiled,
  	}
  
  	public enum Flip
  	{
  		Nothing,
  		Horizontally,
  		Vertically,
  		Both,
  	}
  
  	[HideInInspector][SerializeField] protected Type mType = Type.Simple;
  	[HideInInspector][SerializeField] protected FillDirection mFillDirection = FillDirection.Radial360;
  	[Range(0f, 1f)]
  	[HideInInspector][SerializeField] protected float mFillAmount = 1.0f;
  	[HideInInspector][SerializeField] protected bool mInvert = false;
  	[HideInInspector][SerializeField] protected Flip mFlip = Flip.Nothing;
  
  	// Cached to avoid allocations
  	[System.NonSerialized] Rect mInnerUV = new Rect();
  	[System.NonSerialized] Rect mOuterUV = new Rect();
  
  	/// <summary>
  	/// When the sprite type is advanced, this determines whether the center is tiled or sliced.
  	/// </summary>
  
  	public AdvancedType centerType = AdvancedType.Sliced;
  
  	/// <summary>
  	/// When the sprite type is advanced, this determines whether the left edge is tiled or sliced.
  	/// </summary>
  
  	public AdvancedType leftType = AdvancedType.Sliced;
  
  	/// <summary>
  	/// When the sprite type is advanced, this determines whether the right edge is tiled or sliced.
  	/// </summary>
  
  	public AdvancedType rightType = AdvancedType.Sliced;
  
  	/// <summary>
  	/// When the sprite type is advanced, this determines whether the bottom edge is tiled or sliced.
  	/// </summary>
  
  	public AdvancedType bottomType = AdvancedType.Sliced;
  
  	/// <summary>
  	/// When the sprite type is advanced, this determines whether the top edge is tiled or sliced.
  	/// </summary>
  
  	public AdvancedType topType = AdvancedType.Sliced;
  
  	/// <summary>
  	/// How the sprite is drawn. It's virtual for legacy reasons (UISlicedSprite, UITiledSprite, UIFilledSprite).
  	/// </summary>
  
  	public virtual Type type
  	{
  		get
  		{
  			return mType;
  		}
  		set
  		{
  			if (mType != value)
  			{
  				mType = value;
  				MarkAsChanged();
  			}
  		}
  	}
  
  	/// <summary>
  	/// Sprite flip setting.
  	/// </summary>
  
  	public Flip flip
  	{
  		get
  		{
  			return mFlip;
  		}
  		set
  		{
  			if (mFlip != value)
  			{
  				mFlip = value;
  				MarkAsChanged();
  			}
  		}
  	}
  
  	/// <summary>
  	/// Direction of the cut procedure.
  	/// </summary>
  
  	public FillDirection fillDirection
  	{
  		get
  		{
  			return mFillDirection;
  		}
  		set
  		{
  			if (mFillDirection != value)
  			{
  				mFillDirection = value;
  				mChanged = true;
  			}
  		}
  	}
  
  	/// <summary>
  	/// Amount of the sprite shown. 0-1 range with 0 being nothing shown, and 1 being the full sprite.
  	/// </summary>
  
  	public float fillAmount
  	{
  		get
  		{
  			return mFillAmount;
  		}
  		set
  		{
  			float val = Mathf.Clamp01(value);
  
  			if (mFillAmount != val)
  			{
  				mFillAmount = val;
  				mChanged = true;
  			}
  		}
  	}
  
  	/// <summary>
  	/// Minimum allowed width for this widget.
  	/// </summary>
  
  	override public int minWidth
  	{
  		get
  		{
  			if (type == Type.Sliced || type == Type.Advanced)
  			{
  				Vector4 b = border * pixelSize;
  				int min = Mathf.RoundToInt(b.x + b.z);
  				return Mathf.Max(base.minWidth, ((min & 1) == 1) ? min + 1 : min);
  			}
  			return base.minWidth;
  		}
  	}
  
  	/// <summary>
  	/// Minimum allowed height for this widget.
  	/// </summary>
  
  	override public int minHeight
  	{
  		get
  		{
  			if (type == Type.Sliced || type == Type.Advanced)
  			{
  				Vector4 b = border * pixelSize;
  				int min = Mathf.RoundToInt(b.y + b.w);
  				return Mathf.Max(base.minHeight, ((min & 1) == 1) ? min + 1 : min);
  			}
  			return base.minHeight;
  		}
  	}
  
  	/// <summary>
  	/// Whether the sprite should be filled in the opposite direction.
  	/// </summary>
  
  	public bool invert
  	{
  		get
  		{
  			return mInvert;
  		}
  		set
  		{
  			if (mInvert != value)
  			{
  				mInvert = value;
  				mChanged = true;
  			}
  		}
  	}
  
  	/// <summary>
  	/// Whether the widget has a border for 9-slicing.
  	/// </summary>
  
  	public bool hasBorder
  	{
  		get
  		{
  			Vector4 br = border;
  			return (br.x != 0f || br.y != 0f || br.z != 0f || br.w != 0f);
  		}
  	}
  
  	/// <summary>
  	/// Whether the sprite's material is using a pre-multiplied alpha shader.
  	/// </summary>
  
  	public virtual bool premultipliedAlpha { get { return false; } }
  
  	/// <summary>
  	/// Size of the pixel. Overwritten in the NGUI sprite to pull a value from the atlas.
  	/// </summary>
  
  	public virtual float pixelSize { get { return 1f; } }
  
  #if UNITY_EDITOR
  	/// <summary>
  	/// Keep sane values.
  	/// </summary>
  
  	protected override void OnValidate ()
  	{
  		base.OnValidate();
  		mFillAmount = Mathf.Clamp01(mFillAmount);
  	}
  #endif
  
  #region Fill Functions
  	// Static variables to reduce garbage collection
  	static protected Vector2[] mTempPos = new Vector2[4];
  	static protected Vector2[] mTempUVs = new Vector2[4];
  
  	/// <summary>
  	/// Convenience function that returns the drawn UVs after flipping gets considered.
  	/// X = left, Y = bottom, Z = right, W = top.
  	/// </summary>
  
  	Vector4 drawingUVs
  	{
  		get
  		{
  			switch (mFlip)
  			{
  				case Flip.Horizontally: return new Vector4(mOuterUV.xMax, mOuterUV.yMin, mOuterUV.xMin, mOuterUV.yMax);
  				case Flip.Vertically: return new Vector4(mOuterUV.xMin, mOuterUV.yMax, mOuterUV.xMax, mOuterUV.yMin);
  				case Flip.Both: return new Vector4(mOuterUV.xMax, mOuterUV.yMax, mOuterUV.xMin, mOuterUV.yMin);
  				default: return new Vector4(mOuterUV.xMin, mOuterUV.yMin, mOuterUV.xMax, mOuterUV.yMax);
  			}
  		}
  	}
  
  	/// <summary>
  	/// Final widget's color passed to the draw buffer.
  	/// </summary>
  
  	Color32 drawingColor
  	{
  		get
  		{
  			Color colF = color;
  			colF.a = finalAlpha;
  			return premultipliedAlpha ? NGUITools.ApplyPMA(colF) : colF;
  		}
  	}
  
  	/// <summary>
  	/// Fill the draw buffers.
  	/// </summary>
  
  	protected void Fill (BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color32> cols, Rect outer, Rect inner)
  	{
  		mOuterUV = outer;
  		mInnerUV = inner;
  
  		switch (type)
  		{
  			case Type.Simple:
  			SimpleFill(verts, uvs, cols);
  			break;
  
  			case Type.Sliced:
  			SlicedFill(verts, uvs, cols);
  			break;
  
  			case Type.Filled:
  			FilledFill(verts, uvs, cols);
  			break;
  
  			case Type.Tiled:
  			TiledFill(verts, uvs, cols);
  			break;
  
  			case Type.Advanced:
  			AdvancedFill(verts, uvs, cols);
  			break;
  		}
  	}
  
  	/// <summary>
  	/// Regular sprite fill function is quite simple.
  	/// </summary>
  
  	void SimpleFill (BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color32> cols)
  	{
  		Vector4 v = drawingDimensions;
  		Vector4 u = drawingUVs;
  		Color32 c = drawingColor;
  
  		verts.Add(new Vector3(v.x, v.y));
  		verts.Add(new Vector3(v.x, v.w));
  		verts.Add(new Vector3(v.z, v.w));
  		verts.Add(new Vector3(v.z, v.y));
  
  		uvs.Add(new Vector2(u.x, u.y));
  		uvs.Add(new Vector2(u.x, u.w));
  		uvs.Add(new Vector2(u.z, u.w));
  		uvs.Add(new Vector2(u.z, u.y));
  
  		cols.Add(c);
  		cols.Add(c);
  		cols.Add(c);
  		cols.Add(c);
  	}
  
  	/// <summary>
  	/// Sliced sprite fill function is more complicated as it generates 9 quads instead of 1.
  	/// </summary>
  
  	void SlicedFill (BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color32> cols)
  	{
  		Vector4 br = border * pixelSize;
  		
  		if (br.x == 0f && br.y == 0f && br.z == 0f && br.w == 0f)
  		{
  			SimpleFill(verts, uvs, cols);
  			return;
  		}
  
  		Color32 c = drawingColor;
  		Vector4 v = drawingDimensions;
  
  		mTempPos[0].x = v.x;
  		mTempPos[0].y = v.y;
  		mTempPos[3].x = v.z;
  		mTempPos[3].y = v.w;
  
  		if (mFlip == Flip.Horizontally || mFlip == Flip.Both)
  		{
  			mTempPos[1].x = mTempPos[0].x + br.z;
  			mTempPos[2].x = mTempPos[3].x - br.x;
  
  			mTempUVs[3].x = mOuterUV.xMin;
  			mTempUVs[2].x = mInnerUV.xMin;
  			mTempUVs[1].x = mInnerUV.xMax;
  			mTempUVs[0].x = mOuterUV.xMax;
  		}
  		else
  		{
  			mTempPos[1].x = mTempPos[0].x + br.x;
  			mTempPos[2].x = mTempPos[3].x - br.z;
  
  			mTempUVs[0].x = mOuterUV.xMin;
  			mTempUVs[1].x = mInnerUV.xMin;
  			mTempUVs[2].x = mInnerUV.xMax;
  			mTempUVs[3].x = mOuterUV.xMax;
  		}
  
  		if (mFlip == Flip.Vertically || mFlip == Flip.Both)
  		{
  			mTempPos[1].y = mTempPos[0].y + br.w;
  			mTempPos[2].y = mTempPos[3].y - br.y;
  
  			mTempUVs[3].y = mOuterUV.yMin;
  			mTempUVs[2].y = mInnerUV.yMin;
  			mTempUVs[1].y = mInnerUV.yMax;
  			mTempUVs[0].y = mOuterUV.yMax;
  		}
  		else
  		{
  			mTempPos[1].y = mTempPos[0].y + br.y;
  			mTempPos[2].y = mTempPos[3].y - br.w;
  
  			mTempUVs[0].y = mOuterUV.yMin;
  			mTempUVs[1].y = mInnerUV.yMin;
  			mTempUVs[2].y = mInnerUV.yMax;
  			mTempUVs[3].y = mOuterUV.yMax;
  		}
  
  		for (int x = 0; x < 3; ++x)
  		{
  			int x2 = x + 1;
  
  			for (int y = 0; y < 3; ++y)
  			{
  				if (centerType == AdvancedType.Invisible && x == 1 && y == 1) continue;
  
  				int y2 = y + 1;
  
  				verts.Add(new Vector3(mTempPos[x].x, mTempPos[y].y));
  				verts.Add(new Vector3(mTempPos[x].x, mTempPos[y2].y));
  				verts.Add(new Vector3(mTempPos[x2].x, mTempPos[y2].y));
  				verts.Add(new Vector3(mTempPos[x2].x, mTempPos[y].y));
  
  				uvs.Add(new Vector2(mTempUVs[x].x, mTempUVs[y].y));
  				uvs.Add(new Vector2(mTempUVs[x].x, mTempUVs[y2].y));
  				uvs.Add(new Vector2(mTempUVs[x2].x, mTempUVs[y2].y));
  				uvs.Add(new Vector2(mTempUVs[x2].x, mTempUVs[y].y));
  
  				cols.Add(c);
  				cols.Add(c);
  				cols.Add(c);
  				cols.Add(c);
  			}
  		}
  	}
  
  	/// <summary>
  	/// Tiled sprite fill function.
  	/// </summary>
  
  	void TiledFill (BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color32> cols)
  	{
  		Texture tex = mainTexture;
  		if (tex == null) return;
  
  		Vector2 size = new Vector2(mInnerUV.width * tex.width, mInnerUV.height * tex.height);
  		size *= pixelSize;
  		if (tex == null || size.x < 2f || size.y < 2f) return;
  
  		Color32 c = drawingColor;
  		Vector4 v = drawingDimensions;
  		Vector4 u;
  
  		if (mFlip == Flip.Horizontally || mFlip == Flip.Both)
  		{
  			u.x = mInnerUV.xMax;
  			u.z = mInnerUV.xMin;
  		}
  		else
  		{
  			u.x = mInnerUV.xMin;
  			u.z = mInnerUV.xMax;
  		}
  
  		if (mFlip == Flip.Vertically || mFlip == Flip.Both)
  		{
  			u.y = mInnerUV.yMax;
  			u.w = mInnerUV.yMin;
  		}
  		else
  		{
  			u.y = mInnerUV.yMin;
  			u.w = mInnerUV.yMax;
  		}
  
  		float x0 = v.x;
  		float y0 = v.y;
  
  		float u0 = u.x;
  		float v0 = u.y;
  
  		while (y0 < v.w)
  		{
  			x0 = v.x;
  			float y1 = y0 + size.y;
  			float v1 = u.w;
  
  			if (y1 > v.w)
  			{
  				v1 = Mathf.Lerp(u.y, u.w, (v.w - y0) / size.y);
  				y1 = v.w;
  			}
  
  			while (x0 < v.z)
  			{
  				float x1 = x0 + size.x;
  				float u1 = u.z;
  
  				if (x1 > v.z)
  				{
  					u1 = Mathf.Lerp(u.x, u.z, (v.z - x0) / size.x);
  					x1 = v.z;
  				}
  
  				verts.Add(new Vector3(x0, y0));
  				verts.Add(new Vector3(x0, y1));
  				verts.Add(new Vector3(x1, y1));
  				verts.Add(new Vector3(x1, y0));
  
  				uvs.Add(new Vector2(u0, v0));
  				uvs.Add(new Vector2(u0, v1));
  				uvs.Add(new Vector2(u1, v1));
  				uvs.Add(new Vector2(u1, v0));
  
  				cols.Add(c);
  				cols.Add(c);
  				cols.Add(c);
  				cols.Add(c);
  
  				x0 += size.x;
  			}
  			y0 += size.y;
  		}
  	}
  
  	/// <summary>
  	/// Filled sprite fill function.
  	/// </summary>
  
  	void FilledFill (BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color32> cols)
  	{
  		if (mFillAmount < 0.001f) return;
  
  		Vector4 v = drawingDimensions;
  		Vector4 u = drawingUVs;
  		Color32 c = drawingColor;
  
  		// Horizontal and vertical filled sprites are simple -- just end the sprite prematurely
  		if (mFillDirection == FillDirection.Horizontal || mFillDirection == FillDirection.Vertical)
  		{
  			if (mFillDirection == FillDirection.Horizontal)
  			{
  				float fill = (u.z - u.x) * mFillAmount;
  
  				if (mInvert)
  				{
  					v.x = v.z - (v.z - v.x) * mFillAmount;
  					u.x = u.z - fill;
  				}
  				else
  				{
  					v.z = v.x + (v.z - v.x) * mFillAmount;
  					u.z = u.x + fill;
  				}
  			}
  			else if (mFillDirection == FillDirection.Vertical)
  			{
  				float fill = (u.w - u.y) * mFillAmount;
  
  				if (mInvert)
  				{
  					v.y = v.w - (v.w - v.y) * mFillAmount;
  					u.y = u.w - fill;
  				}
  				else
  				{
  					v.w = v.y + (v.w - v.y) * mFillAmount;
  					u.w = u.y + fill;
  				}
  			}
  		}
  
  		mTempPos[0] = new Vector2(v.x, v.y);
  		mTempPos[1] = new Vector2(v.x, v.w);
  		mTempPos[2] = new Vector2(v.z, v.w);
  		mTempPos[3] = new Vector2(v.z, v.y);
  
  		mTempUVs[0] = new Vector2(u.x, u.y);
  		mTempUVs[1] = new Vector2(u.x, u.w);
  		mTempUVs[2] = new Vector2(u.z, u.w);
  		mTempUVs[3] = new Vector2(u.z, u.y);
  
  		if (mFillAmount < 1f)
  		{
  			if (mFillDirection == FillDirection.Radial90)
  			{
  				if (RadialCut(mTempPos, mTempUVs, mFillAmount, mInvert, 0))
  				{
  					for (int i = 0; i < 4; ++i)
  					{
  						verts.Add(mTempPos[i]);
  						uvs.Add(mTempUVs[i]);
  						cols.Add(c);
  					}
  				}
  				return;
  			}
  
  			if (mFillDirection == FillDirection.Radial180)
  			{
  				for (int side = 0; side < 2; ++side)
  				{
  					float fx0, fx1, fy0, fy1;
  
  					fy0 = 0f;
  					fy1 = 1f;
  
  					if (side == 0) { fx0 = 0f; fx1 = 0.5f; }
  					else { fx0 = 0.5f; fx1 = 1f; }
  
  					mTempPos[0].x = Mathf.Lerp(v.x, v.z, fx0);
  					mTempPos[1].x = mTempPos[0].x;
  					mTempPos[2].x = Mathf.Lerp(v.x, v.z, fx1);
  					mTempPos[3].x = mTempPos[2].x;
  
  					mTempPos[0].y = Mathf.Lerp(v.y, v.w, fy0);
  					mTempPos[1].y = Mathf.Lerp(v.y, v.w, fy1);
  					mTempPos[2].y = mTempPos[1].y;
  
gt: 					mTempPos[3].y = mTempPos[0].y;