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
- }
- }
|