| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421 | using System;using UnityEngine;using UnityEngine.UI;namespace MPUIKIT {    [AddComponentMenu("UI/MPUI/MPImageBasic")]    public class MPImageBasic : Image {        #region SerializedFields        [SerializeField] private DrawShape m_DrawShape = DrawShape.None;        [SerializeField] private Type m_ImageType = Type.Simple;                                                                           // Mapping in Vertex Stream        [SerializeField] private float m_StrokeWidth;                               // MapTo -> UV2.x        [SerializeField] private float m_FalloffDistance = 0.5f;                    // MapTo -> UV2.y        [SerializeField] private float m_OutlineWidth;                              // MapTo -> Normal.x        [SerializeField] private Color m_OutlineColor = Color.black;                // MapTo -> Tangent.x, Tangent.y, Tangent.z, Tangent.w        [SerializeField] private float m_ShapeRotation;                             // MapTo -> UV3.x Compressed        [SerializeField] private bool m_ConstrainRotation = true;                   // MapTo -> UV3.x Compressed        [SerializeField] private bool m_FlipHorizontal;                             // MapTo -> UV3.x Compressed        [SerializeField] private bool m_FlipVertical;                               // MapTo -> UV3.x Compressed        [SerializeField] private CornerStyleType m_CornerStyle;                     // MapTo -> UV3.y        [SerializeField] private Vector4 m_RectangleCornerRadius;                   // MapTo -> Normal.y, Normal.z compressed        [SerializeField] private Vector3 m_TriangleCornerRadius;                    // MapTo -> Normal.y, Normal.z compressed#pragma warning disable        // ReSharper disable once NotAccessedField.Local        [SerializeField] private bool m_TriangleUniformCornerRadius = true;        // ReSharper disable once NotAccessedField.Local        [SerializeField] private bool m_RectangleUniformCornerRadius = true;#pragma warning restore        [SerializeField] private float m_CircleRadius;                              // MapTo -> Normal.y        [SerializeField] private bool m_CircleFitToRect = true;                     // MapTo -> Normal.z        [SerializeField] private int m_NStarPolygonSideCount = 3;                   // MapTo -> Normal.y compressed        [SerializeField] private float m_NStarPolygonInset = 2f;                    // MapTo -> Normal.y compressed        [SerializeField] private float m_NStarPolygonCornerRadius;                  // MapTo -> Normal.z                #endregion        #region Public Accessors        public DrawShape Shape { get => m_DrawShape;            set {                m_DrawShape = value;                m_Material = null;                base.SetMaterialDirty();                base.SetVerticesDirty();            }        }        public float StrokeWidth {            get => m_StrokeWidth;            set {                Vector2 size = GetPixelAdjustedRect().size;                m_StrokeWidth = Mathf.Clamp(value, 0, Mathf.Min(size.x, size.y) * 0.5f);                base.SetVerticesDirty();            }        }        public float FallOffDistance {            get => m_FalloffDistance;            set {                m_FalloffDistance = Mathf.Max(0, value);                base.SetVerticesDirty();            }        }        public float OutlineWidth {            get => m_OutlineWidth;            set {                m_OutlineWidth = Mathf.Max(0,value);                base.SetVerticesDirty();            }        }        public Color OutlineColor {            get => m_OutlineColor;            set {                m_OutlineColor = value;                base.SetVerticesDirty();            }        }        public float ShapeRotation {            get => m_ShapeRotation;            set {                m_ShapeRotation = value % 360;                ConstrainRotationValue();                base.SetVerticesDirty();            }        }        public bool ConstrainRotation {            get => m_ConstrainRotation;            set {                m_ConstrainRotation = value;                ConstrainRotationValue();                base.SetVerticesDirty();            }        }        public bool FlipHorizontal {            get => m_FlipHorizontal;            set {                m_FlipHorizontal = value;                 base.SetVerticesDirty();            }        }        public bool FlipVertical {            get => m_FlipVertical;            set {                m_FlipVertical = value;                 base.SetVerticesDirty();            }        }                /// <summary>        /// Type of the image. Only two types are supported. Simple and Filled.        /// Default and fallback value is Simple.        /// </summary>        public new Type type {            get => m_ImageType;            set {                if (m_ImageType != value) {                    switch (value) {                        case Type.Simple:                        case Type.Filled:                            if (sprite) m_ImageType = value;                            break;                        case Type.Tiled:                        case Type.Sliced:                            break;                        default:                            throw new ArgumentOutOfRangeException(value.ToString(), value, null);                    }                }                if(base.type != m_ImageType) base.type = m_ImageType;                base.SetAllDirty();            }        }                public CornerStyleType CornerStyle {            get => m_CornerStyle;            set {                m_CornerStyle = value;                base.SetVerticesDirty();            }        }        public Vector3 TriangleCornerRadius {            get => m_TriangleCornerRadius;            set {                Vector2 size = GetPixelAdjustedRect().size;                float zMax = size.x * 0.5f;                m_TriangleCornerRadius.z = Mathf.Clamp(value.z, 0, zMax);                float hMax = Mathf.Min(size.x, size.y) * 0.3f;                                m_TriangleCornerRadius.x = Mathf.Clamp(value.x, 0, hMax);                m_TriangleCornerRadius.y = Mathf.Clamp(value.y, 0, hMax);                                base.SetVerticesDirty();            }        }        public Vector4 RectangleCornerRadius {            get => m_RectangleCornerRadius;            set            {                m_RectangleCornerRadius = value;                base.SetVerticesDirty();            }        }        public float CircleRadius {            get => m_CircleRadius;            set {                m_CircleRadius = Mathf.Clamp(value, 0, GetMinSize());                base.SetVerticesDirty();            }        }        public bool CircleFitToRect {            get => m_CircleFitToRect;            set {                m_CircleFitToRect = value;                base.SetVerticesDirty();            }        }        public float NStarPolygonCornerRadius {            get => m_NStarPolygonCornerRadius;            set {                float halfHeight = GetPixelAdjustedRect().height * 0.5f;                m_NStarPolygonCornerRadius = Mathf.Clamp(value, m_NStarPolygonSideCount == 2? 0.1f : 0f, halfHeight);                base.SetVerticesDirty();            }        }        public float NStarPolygonInset {            get => m_NStarPolygonInset;            set {                m_NStarPolygonInset = Mathf.Clamp(value, 2f, m_NStarPolygonSideCount);                base.SetVerticesDirty();            }        }        public int NStarPolygonSideCount {            get => m_NStarPolygonSideCount;            set {                m_NStarPolygonSideCount = Mathf.Clamp(value, 2, 10);                base.SetVerticesDirty();            }        }                #endregion                public override Material material {            get            {                switch (m_DrawShape)                {                    case DrawShape.None:                         return Canvas.GetDefaultCanvasMaterial();                    case DrawShape.Circle:                    case DrawShape.Triangle:                    case DrawShape.Rectangle:                        return MPMaterials.GetMaterial((int)m_DrawShape - 1, m_StrokeWidth > 0f, m_OutlineWidth > 0f);                    case DrawShape.Pentagon:                    case DrawShape.Hexagon:                    case DrawShape.NStarPolygon:                        return MPMaterials.GetMaterial(3, m_StrokeWidth > 0f, m_OutlineWidth > 0f);                    default:                        throw new ArgumentOutOfRangeException();                }            }            set => Debug.LogWarning("Setting Material of MPImageBasic has no effect.");        }        public override float preferredWidth => sprite == MPImageUtility.EmptySprite ? 0 : base.preferredWidth;        public override float preferredHeight => sprite == MPImageUtility.EmptySprite ? 0 : base.preferredHeight;        protected override void OnEnable() {            base.OnEnable();            MPImageUtility.FixAdditionalShaderChannelsInCanvas(canvas);            if (sprite == null) sprite = MPImageUtility.EmptySprite;        }        #if UNITY_EDITOR        protected override void OnValidate() {            base.OnValidate();            Shape = m_DrawShape;            if (sprite == null) sprite = MPImageUtility.EmptySprite;            type = m_ImageType;            StrokeWidth = m_StrokeWidth;            FallOffDistance = m_FalloffDistance;            OutlineWidth = m_OutlineWidth;            OutlineColor = m_OutlineColor;            ShapeRotation = m_ShapeRotation;            ConstrainRotation = m_ConstrainRotation;            FlipHorizontal = m_FlipHorizontal;            FlipVertical = m_FlipVertical;            CornerStyle = m_CornerStyle;        }#endif        private float GetMinSizeHalf() {            return GetMinSize() * 0.5f;        }        private float GetMinSize() {            Vector2 size = GetPixelAdjustedRect().size;            return Mathf.Min(size.x, size.y);        }        private void ConstrainRotationValue() {            if (!m_ConstrainRotation) return;            float finalRotation =  m_ShapeRotation - (m_ShapeRotation % 90);            if (Mathf.Abs(finalRotation) >= 360) finalRotation = 0;            m_ShapeRotation =  finalRotation;        }                protected override void OnTransformParentChanged() {            base.OnTransformParentChanged();            MPImageUtility.FixAdditionalShaderChannelsInCanvas(canvas);            base.SetVerticesDirty();        }        private MPVertexStream CreateVertexStream() {            MPVertexStream stream = new MPVertexStream();            RectTransform rectT = rectTransform;            stream.RectTransform = rectT;            Rect r = GetPixelAdjustedRect();            stream.Uv1 = new Vector2(r.width + m_FalloffDistance, r.height + m_FalloffDistance);            float packedRotData =                PackRotationData(m_ShapeRotation, m_ConstrainRotation, m_FlipHorizontal, m_FlipVertical);            stream.Uv3 = new Vector2(packedRotData, (float)m_CornerStyle);            stream.Tangent = QualitySettings.activeColorSpace == ColorSpace.Linear? m_OutlineColor.linear : m_OutlineColor;            Vector3 normal = new Vector3();            normal.x = m_OutlineWidth;            normal.y = m_StrokeWidth;            normal.z = m_FalloffDistance;                        Vector4 data;            Vector2 shapeProps;            switch (m_DrawShape) {                case DrawShape.Circle:                    shapeProps = new Vector2(m_CircleRadius, m_CircleFitToRect ? 1 : 0);                    break;                case DrawShape.Triangle:                    data = m_TriangleCornerRadius;                    data = data / Mathf.Min(r.width, r.height);                    shapeProps = MPImageUtility.Encode_0_1_16(data);                    break;                case DrawShape.Rectangle:                    data = FixRadius(m_RectangleCornerRadius);                    data = data / Mathf.Min(r.width, r.height);                    shapeProps = MPImageUtility.Encode_0_1_16(data);                    break;                case DrawShape.NStarPolygon:                    data = new Vector4(m_NStarPolygonSideCount, m_NStarPolygonCornerRadius, m_NStarPolygonInset);                    data = data / Mathf.Min(r.width, r.height);                    shapeProps = MPImageUtility.Encode_0_1_16(data);                    break;                default:                    shapeProps = Vector2.zero;                    break;            }            stream.Uv2 = shapeProps;                        stream.Normal = normal;            return stream;        }        private float PackRotationData(float rotation, bool constrainRotation, bool flipH, bool flipV) {            int c = constrainRotation ? 1 : 0;            c += flipH ? 10 : 0;            c += flipV ? 100 : 0;            float cr = rotation % 360f;            float sign = cr >= 0 ? 1 : -1;            cr = Mathf.Abs(cr) / 360f;            cr = (cr + c) * sign;            return cr;        }                void UnPackRotation(float f) {            float r = 0, x = 0, y = 0, z = 0;                        float sign = f >= 0.0f ? 1 : -1;            f = Mathf.Abs(f);            r = fract(f) * 360f * sign;                        f = Mathf.Floor(f);            float p = f / 100f;            z = Mathf.Floor(p);            p = fract(p) * 10f;            y = Mathf.Floor(p);            p = fract(p) * 10f;            x = Mathf.Round(p);            // Debug.Log($"Rotation: {r}, X: {x}, Y: {y}, Z: {z}");            float fract(float val) {                val = Mathf.Abs(val);                float ret = val - Mathf.Floor(val);                return ret;            }        }        protected override void OnRectTransformDimensionsChange()        {            base.OnRectTransformDimensionsChange();            base.SetVerticesDirty();        }        private Vector4 FixRadius(Vector4 radius)        {            Rect rect = rectTransform.rect;                        radius = Vector4.Max(radius, Vector4.zero);            radius = Vector4.Min(radius, Vector4.one * Mathf.Min(rect.width, rect.height));            float scaleFactor =                 Mathf.Min (                    Mathf.Min (                        Mathf.Min (                            Mathf.Min (                                rect.width / (radius.x + radius.y),                                 rect.width / (radius.z + radius.w)),                            rect.height / (radius.x + radius.w)),                         rect.height / (radius.z + radius.y)),                     1f);            return radius * scaleFactor;        }        protected override void OnPopulateMesh(VertexHelper toFill) {            base.OnPopulateMesh(toFill);            MPVertexStream stream = CreateVertexStream();                        UIVertex uiVert = new UIVertex();            for (int i = 0; i < toFill.currentVertCount; i++) {                toFill.PopulateUIVertex(ref uiVert, i);                                //uiVert.position += ((Vector3)uiVert.uv0 - new Vector3(0.5f, 0.5f)) * m_FalloffDistance;                uiVert.uv1 = stream.Uv1;                uiVert.uv2 = stream.Uv2;                uiVert.uv3 = stream.Uv3;                uiVert.normal = stream.Normal;                uiVert.tangent = stream.Tangent;                                toFill.SetUIVertex(uiVert, i);            }        }#if UNITY_EDITOR        protected override void Reset() {            base.Reset();            if (sprite == null) sprite = MPImageUtility.EmptySprite;        }#else        void Reset() {            if (sprite == null) sprite = MPImageUtility.EmptySprite;        }#endif    }}
 |