using System; using UnityEngine; using UnityEngine.UI; namespace UIKit { [ExecuteInEditMode] public class UIElement : Image { private static readonly int widthProp = Shader.PropertyToID ("_Width"); private static readonly int heightProp = Shader.PropertyToID ("_Height"); private static readonly int cornerRadiusProp = Shader.PropertyToID ("_CornerRadius"); private static readonly int independentCornersProp = Shader.PropertyToID ("_EnableIndependentCorners"); private static readonly int independentCornerRadiiProp = Shader.PropertyToID ("_IndependentCornerRadii"); private static readonly int borderColorProp = Shader.PropertyToID ("_BorderColor"); private static readonly int borderProp = Shader.PropertyToID ("_Border"); private static readonly int shadowColorProp = Shader.PropertyToID ("_ShadowColor"); private static readonly int shadowBlurProp = Shader.PropertyToID ("_ShadowBlur"); private static readonly int shadowLayoutProp = Shader.PropertyToID ("_ShadowLayout"); private static readonly int innerShadowColorProp = Shader.PropertyToID ("_InnerShadowColor"); private static readonly int innerShadowBlurProp = Shader.PropertyToID ("_InnerShadowBlur"); private static readonly int innerShadowLayoutProp = Shader.PropertyToID ("_InnerShadowLayout"); private static readonly int imageWidthProp = Shader.PropertyToID ("_ImageWidth"); private static readonly int imageHeightProp = Shader.PropertyToID ("_ImageHeight"); private static readonly int imageOffsetXProp = Shader.PropertyToID ("_ImageOffsetX"); private static readonly int imageOffsetYProp = Shader.PropertyToID ("_ImageOffsetY"); private static readonly int imageColorProp = Shader.PropertyToID ("_ImageColor"); public float Radius; public bool EnableIndependentConers; public Vector4 IndependentCornerRadii; [HideInInspector] public float Border; [HideInInspector] public Color BorderColor; public Color ShadowColor; [Range (0, 150)] public float ShadowBlur; public float ShadowRadius; public Vector2 ShadowOffset; public Vector2 ShadowScale = Vector2.one; public bool EnableInnerShadow; public Color InnerShadowColor; [Range (0, 150)] public float InnerShadowBlur; public float InnerShadowRadius; public Vector2 InnerShadowOffset; public float InnerShadowSpread = 1; public Color ImageColor; public Vector2 ImageOffset; public Color PressedColor; // shadow, texture, inner shadow, border static Vector4 IsShadow = new Vector4 (1, 0, 0, 0); static Vector4 IsTexture = new Vector4 (0, 1, 0, 0); static Vector4 IsInnerShadow = new Vector4 (0, 0, 1, 0); static Vector4 IsBorder = new Vector4 (0, 0, 0, 1); public override Material material { get { if (m_Material == null) { m_Material = new Material (Shader.Find ("UIElement")); } return m_Material; } set { m_Material = value; } } protected override void OnPopulateMesh (VertexHelper vh) { var r = GetPixelAdjustedRect (); var v = GetVertexPositions (r); vh.Clear (); Vector2 roundedAndBorder = new Vector2 (Radius, Border); var uvs = GetUVValues (r); Vector2 uv1 = new Vector2 (uvs.x, uvs.y); Vector2 uv2 = new Vector2 (uvs.x, uvs.w); Vector2 uv3 = new Vector2 (uvs.z, uvs.w); Vector2 uv4 = new Vector2 (uvs.z, uvs.y); int i = 0; Vector2 shadowScale = ShadowScale * new Vector2 (ShadowBlur / 2f, ShadowBlur / 2f); vh.AddVert (new Vector3 (v.x - shadowScale.x + ShadowOffset.x, v.y - shadowScale.y + ShadowOffset.y), ShadowColor, uv1, Vector2.right, Vector3.zero, IsShadow); vh.AddVert (new Vector3 (v.x - shadowScale.x + ShadowOffset.x, v.w + shadowScale.y + ShadowOffset.y), ShadowColor, uv2, Vector2.right, Vector3.zero, IsShadow); vh.AddVert (new Vector3 (v.z + shadowScale.x + ShadowOffset.x, v.w + shadowScale.y + ShadowOffset.y), ShadowColor, uv3, Vector2.right, Vector3.zero, IsShadow); vh.AddVert (new Vector3 (v.z + shadowScale.x + ShadowOffset.x, v.y - shadowScale.y + ShadowOffset.y), ShadowColor, uv4, Vector2.right, Vector3.zero, IsShadow); vh.AddTriangle (i + 0, i + 1, i + 2); vh.AddTriangle (i + 2, i + 3, i + 0); i += 4; vh.AddVert (new Vector3 (v.x, v.y), color, uv1, Vector2.zero, Vector3.zero, sprite == null ? Vector4.zero : IsTexture); vh.AddVert (new Vector3 (v.x, v.w), color, uv2, Vector2.zero, Vector3.zero, sprite == null ? Vector4.zero : IsTexture); vh.AddVert (new Vector3 (v.z, v.w), color, uv3, Vector2.zero, Vector3.zero, sprite == null ? Vector4.zero : IsTexture); vh.AddVert (new Vector3 (v.z, v.y), color, uv4, Vector2.zero, Vector3.zero, sprite == null ? Vector4.zero : IsTexture); vh.AddTriangle (i + 0, i + 1, i + 2); vh.AddTriangle (i + 2, i + 3, i + 0); i += 4; vh.AddVert (new Vector3 (v.x, v.y), InnerShadowColor, uv1, Vector2.zero, new Vector3 (InnerShadowOffset.x, InnerShadowOffset.y, InnerShadowSpread), IsInnerShadow); vh.AddVert (new Vector3 (v.x, v.w), InnerShadowColor, uv2, Vector2.zero, new Vector3 (InnerShadowOffset.x, InnerShadowOffset.y, InnerShadowSpread), IsInnerShadow); vh.AddVert (new Vector3 (v.z, v.w), InnerShadowColor, uv3, Vector2.zero, new Vector3 (InnerShadowOffset.x, InnerShadowOffset.y, InnerShadowSpread), IsInnerShadow); vh.AddVert (new Vector3 (v.z, v.y), InnerShadowColor, uv4, Vector2.zero, new Vector3 (InnerShadowOffset.x, InnerShadowOffset.y, InnerShadowSpread), IsInnerShadow); vh.AddTriangle (i + 0, i + 1, i + 2); vh.AddTriangle (i + 2, i + 3, i + 0); } protected override void OnRectTransformDimensionsChange () { if (gameObject.activeInHierarchy) { SetMaterialProperties (); if (CanvasUpdateRegistry.IsRebuildingLayout ()) SetVerticesDirty (); else { SetVerticesDirty (); SetLayoutDirty (); } } } protected override void OnDidApplyAnimationProperties () { SetAllDirty (); } public override void SetAllDirty () { SetMaterialProperties (); base.SetAllDirty (); } private void SetMaterialProperties () { if (materialForRendering == null) return; var rect = ((RectTransform) transform).rect; materialForRendering.SetFloat (widthProp, rect == null ? 0 : rect.width); materialForRendering.SetFloat (heightProp, rect == null ? 0 : rect.height); materialForRendering.SetFloat (cornerRadiusProp, Radius * 2); if (EnableIndependentConers) { materialForRendering.EnableKeyword ("ENABLE_INDEPENDENT_CORNERS"); } else { materialForRendering.DisableKeyword ("ENABLE_INDEPENDENT_CORNERS"); } materialForRendering.SetInt (independentCornersProp, EnableIndependentConers ? 1 : 0); materialForRendering.SetVector (independentCornerRadiiProp, IndependentCornerRadii * 2); materialForRendering.SetFloat (borderProp, Border); materialForRendering.SetColor (borderColorProp, BorderColor); materialForRendering.SetColor (shadowColorProp, ShadowColor); materialForRendering.SetFloat (shadowBlurProp, ShadowBlur); materialForRendering.SetVector (shadowLayoutProp, new Vector4 (ShadowOffset.x, ShadowOffset.y, ShadowScale.x, ShadowScale.y)); materialForRendering.SetFloat (imageWidthProp, sprite == null ? 0 : sprite.rect.width); materialForRendering.SetFloat (imageHeightProp, sprite == null ? 0 : sprite.rect.height); materialForRendering.SetFloat (imageOffsetXProp, ImageOffset.x); materialForRendering.SetFloat (imageOffsetYProp, ImageOffset.y); materialForRendering.SetColor (imageColorProp, ImageColor); } private Vector4 GetVertexPositions (Rect r) { var v = new Vector4 (r.x, r.y, r.x + r.width, r.y + r.height); // float oneMinusFill = 1f - fillAmount; // if (fillStyle == FillStyle.HorizontalBackwards) { // v.x += r.width * oneMinusFill; // } else if (fillStyle == FillStyle.HorizontalForward) { // v.z -= r.width * oneMinusFill; // } else if (fillStyle == FillStyle.VerticalBackwards) { // v.y += r.height * oneMinusFill; // } else if (fillStyle == FillStyle.VerticalForward) { // v.w -= r.height * oneMinusFill; // } return v; } private Vector4 GetUVValues (Rect r) { var uvs = new Vector4 (0, 0, 1, 1); float oneMinusFill = 1f - fillAmount; // if (fillStyle == FillStyle.HorizontalBackwards) { // uvs.x = oneMinusFill; // } else if (fillStyle == FillStyle.HorizontalForward) { // uvs.z = fillAmount; // } else if (fillStyle == FillStyle.VerticalBackwards) { // uvs.y = oneMinusFill; // } else if (fillStyle == FillStyle.VerticalForward) { // uvs.w = fillAmount; // } return uvs; } } public static class UIElementExtension { public static void SetStyle (this UIElement element, UIStyle style) { element.Radius = style.Radius; element.EnableIndependentConers = style.ToggleIndependentRadii; element.IndependentCornerRadii = style.IndependentRadii; element.Border = style.Border; element.ShadowBlur = style.ShadowBlur; element.ShadowRadius = style.ShadowRadius; element.ShadowOffset = style.ShadowOffset; element.ShadowScale = style.ShadowScale; element.SetAllDirty (); } public static void SetColor (this UIElement element, UIColor color) { element.color = color.Color; element.BorderColor = color.Border; element.ShadowColor = color.Shadow; element.ImageColor = color.Content; element.PressedColor = color.Pressed; element.SetAllDirty (); } public static UIStyle GetStyle (this UIElement element) { UIStyle style = new UIStyle (); style.Radius = element.Radius; style.ToggleIndependentRadii = element.EnableIndependentConers; style.IndependentRadii = element.IndependentCornerRadii; style.Border = element.Border; style.ShadowBlur = element.ShadowBlur; style.ShadowRadius = element.ShadowRadius; style.ShadowOffset = element.ShadowOffset; style.ShadowScale = element.ShadowScale; return style; } public static UIColor GetColor (this UIElement element) { UIColor color = UIColor.Create (); color.Color = element.color; color.Border = element.BorderColor; color.Shadow = element.ShadowColor; color.Content = element.ImageColor; color.Pressed = element.PressedColor; return color; } } }