using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Sprites; using UnityEngine.UI; namespace BF { [AddComponentMenu("UI/Effects/Mirror", 20)] [RequireComponent(typeof(Graphic))] public class Mirror : BaseMeshEffect { public enum MirrorType { /// /// 水平 /// Horizontal, /// /// 垂直 /// Vertical, /// /// 四分之一 /// 相当于水平,然后再垂直 /// Quarter, } /// /// 镜像类型 /// [SerializeField] private MirrorType m_MirrorType = MirrorType.Horizontal; public MirrorType mirrorType { get { return m_MirrorType; } set { if (m_MirrorType != value) { m_MirrorType = value; if(graphic != null){ graphic.SetVerticesDirty(); } } } } [NonSerialized] private RectTransform m_RectTransform; public RectTransform rectTransform { get { return m_RectTransform ?? (m_RectTransform = GetComponent()); } } [NonSerialized] private List m_UIVertexList = new List(); /// /// 设置原始尺寸 /// public void SetNativeSize() { if (graphic != null && graphic is Image) { Sprite overrideSprite = (graphic as Image).overrideSprite; if(overrideSprite != null){ float w = overrideSprite.rect.width / (graphic as Image).pixelsPerUnit; float h = overrideSprite.rect.height / (graphic as Image).pixelsPerUnit; rectTransform.anchorMax = rectTransform.anchorMin; switch (m_MirrorType) { case MirrorType.Horizontal: rectTransform.sizeDelta = new Vector2(w * 2, h); break; case MirrorType.Vertical: rectTransform.sizeDelta = new Vector2(w, h * 2); break; case MirrorType.Quarter: rectTransform.sizeDelta = new Vector2(w * 2, h * 2); break; } graphic.SetVerticesDirty(); } } } public override void ModifyMesh(VertexHelper vh) { if (!IsActive()) { return; } vh.GetUIVertexStream(m_UIVertexList); int count = m_UIVertexList.Count; if (graphic is Image) { Image.Type type = (graphic as Image).type; switch (type) { case Image.Type.Simple: DrawSimple(m_UIVertexList, count); break; case Image.Type.Sliced: DrawSliced(m_UIVertexList, count); break; case Image.Type.Tiled: break; case Image.Type.Filled: break; } } else { DrawSimple(m_UIVertexList, count); } vh.Clear(); vh.AddUIVertexTriangleStream(m_UIVertexList); m_UIVertexList.Clear(); } /// /// 绘制Simple版 /// /// /// protected void DrawSimple(List output, int count) { Rect rect = graphic.GetPixelAdjustedRect(); SimpleScale(rect, output, count); switch (m_MirrorType) { case MirrorType.Horizontal: ExtendCapacity(output, count); MirrorVerts(rect, output, count, true); break; case MirrorType.Vertical: ExtendCapacity(output, count); MirrorVerts(rect, output, count, false); break; case MirrorType.Quarter: ExtendCapacity(output, count * 3); MirrorVerts(rect, output, count, true); MirrorVerts(rect, output, count * 2, false); break; } } /// /// 绘制Sliced版 /// /// /// protected void DrawSliced(List output, int count) { if (!(graphic as Image).hasBorder) { DrawSimple(output, count); } Rect rect = graphic.GetPixelAdjustedRect(); SlicedScale(rect, output, count); count = SliceExcludeVerts(output, count); switch (m_MirrorType) { case MirrorType.Horizontal: ExtendCapacity(output, count); MirrorVerts(rect, output, count, true); break; case MirrorType.Vertical: ExtendCapacity(output, count); MirrorVerts(rect, output, count, false); break; case MirrorType.Quarter: ExtendCapacity(output, count * 3); MirrorVerts(rect, output, count, true); MirrorVerts(rect, output, count * 2, false); break; } } /// /// 扩展容量 /// /// /// protected void ExtendCapacity(List verts, int addCount) { var neededCapacity = verts.Count + addCount; if (verts.Capacity < neededCapacity) { verts.Capacity = neededCapacity; } } /// /// Simple缩放位移顶点(减半) /// /// /// /// protected void SimpleScale(Rect rect, List verts, int count) { for (int i = 0; i < count; i++) { UIVertex vertex = verts[i]; Vector3 position = vertex.position; if (m_MirrorType == MirrorType.Horizontal || m_MirrorType == MirrorType.Quarter) { position.x = (position.x + rect.x) * 0.5f; } if (m_MirrorType == MirrorType.Vertical || m_MirrorType == MirrorType.Quarter) { position.y = (position.y + rect.y) * 0.5f; } vertex.position = position; verts[i] = vertex; } } /// /// Sliced缩放位移顶点(减半) /// /// /// /// protected void SlicedScale(Rect rect, List verts, int count) { Vector4 border = GetAdjustedBorders(rect); float halfWidth = rect.width * 0.5f; float halfHeight = rect.height * 0.5f; for (int i = 0; i < count; i++) { UIVertex vertex = verts[i]; Vector3 position = vertex.position; if (m_MirrorType == MirrorType.Horizontal || m_MirrorType == MirrorType.Quarter) { if (halfWidth < border.x && position.x >= rect.center.x) { position.x = rect.center.x; } else if (position.x >= border.x) { position.x = (position.x + rect.x) * 0.5f; } } if (m_MirrorType == MirrorType.Vertical || m_MirrorType == MirrorType.Quarter) { if (halfHeight < border.y && position.y >= rect.center.y) { position.y = rect.center.y; } else if (position.y >= border.y) { position.y = (position.y + rect.y) * 0.5f; } } vertex.position = position; verts[i] = vertex; } } /// /// 镜像顶点 /// /// /// /// /// protected void MirrorVerts(Rect rect, List verts, int count, bool isHorizontal = true) { for (int i = 0; i < count; i++) { UIVertex vertex = verts[i]; Vector3 position = vertex.position; if (isHorizontal) { position.x = rect.center.x * 2 - position.x; } else { position.y = rect.center.y * 2 - position.y; } vertex.position = position; verts.Add(vertex); } } /// /// 清理掉不能成三角面的顶点 /// /// /// /// protected int SliceExcludeVerts(List verts, int count) { int realCount = count; int i = 0; while (i < realCount) { UIVertex v1 = verts[i]; UIVertex v2 = verts[i + 1]; UIVertex v3 = verts[i + 2]; if (v1.position == v2.position || v2.position == v3.position || v3.position == v1.position) { verts[i] = verts[realCount - 3]; verts[i + 1] = verts[realCount - 2]; verts[i + 2] = verts[realCount - 1]; realCount -= 3; continue; } i += 3; } if (realCount < count) { verts.RemoveRange(realCount, count - realCount); } return realCount; } /// /// 返回矫正过的范围 /// /// /// protected Vector4 GetAdjustedBorders(Rect rect) { Sprite overrideSprite = (graphic as Image).overrideSprite; Vector4 border = overrideSprite.border; border = border / (graphic as Image).pixelsPerUnit; for (int axis = 0; axis <= 1; axis++) { float combinedBorders = border[axis] + border[axis + 2]; if (rect.size[axis] < combinedBorders && combinedBorders != 0) { float borderScaleRatio = rect.size[axis] / combinedBorders; border[axis] *= borderScaleRatio; border[axis + 2] *= borderScaleRatio; } } return border; } } }