namespace UIWidgets { using System; using UnityEngine; using UnityEngine.Serialization; using UnityEngine.UI; /// /// UV1 effect. /// [RequireComponent(typeof(RectTransform))] [RequireComponent(typeof(Graphic))] public abstract class UV1Effect : BaseMeshEffect, IMaterialModifier, IMeshModifier { /// /// UV mode. /// public enum UVMode { /// /// UV1.y limited by width. /// x in [0, 1]; y in [0, 1 / (width / height)] /// X = 0, /// /// UV1.x limited by height. /// x in [0, 1 / (height / width)]; y in [0, 1] /// Y = 1, /// /// UV1.x is not limited by size. /// x in [0, 1]; y in [0, 1] /// One = 2, /// /// If width more that height then works as X mode; otherwise Y mode. /// Max = 3, } /// /// Shader. /// [SerializeField] [FormerlySerializedAs("RippleShader")] protected Shader EffectShader; /// /// Base material. /// [NonSerialized] protected Material BaseMaterial; /// /// Ring material. /// [NonSerialized] protected Material EffectMaterial; [NonSerialized] RectTransform rectTransform; /// /// RectTransform component. /// protected RectTransform RectTransform { get { if (rectTransform == null) { rectTransform = transform as RectTransform; } return rectTransform; } } UVMode mode = UVMode.X; /// /// If enabled set UV1.y is limited by horizontal size. /// protected UVMode Mode { get { return mode; } set { if (mode != value) { mode = value; graphic.SetVerticesDirty(); } } } /// /// Process the enable event. /// protected override void OnEnable() { base.OnEnable(); if (graphic != null) { graphic.SetVerticesDirty(); } } /// /// Process the disable event. /// protected override void OnDisable() { if (graphic != null) { graphic.SetMaterialDirty(); } base.OnDisable(); } /// /// Process the animation event. /// protected override void OnDidApplyAnimationProperties() { if (graphic != null) { graphic.SetMaterialDirty(); } base.OnDidApplyAnimationProperties(); } #if UNITY_EDITOR /// /// Process the validate event. /// protected override void OnValidate() { base.OnValidate(); if (graphic != null) { UpdateMaterial(); } } #endif /// /// Process the dimensions change event. /// protected override void OnRectTransformDimensionsChange() { base.OnRectTransformDimensionsChange(); UpdateMaterial(); } /// /// Add uv1 to the mesh. /// /// Vertex helper. public override void ModifyMesh(VertexHelper vh) { var size = RectTransform.rect.size; if ((size.x < 0f) || (size.y < 0f)) { return; } var vertex = default(UIVertex); // get min and max position to calculate uv1 vh.PopulateUIVertex(ref vertex, 0); var min_x = vertex.position.x; var max_x = min_x; var min_y = vertex.position.y; var max_y = min_y; for (int i = 1; i < vh.currentVertCount; i++) { vh.PopulateUIVertex(ref vertex, i); min_x = Math.Min(min_x, vertex.position.x); max_x = Math.Max(max_x, vertex.position.x); min_y = Math.Min(min_y, vertex.position.y); max_y = Math.Max(max_y, vertex.position.y); } // set uv1 for the shader var width = max_x - min_x; var height = max_y - min_y; Vector2 aspect_ratio; switch (Mode) { case UVMode.X: aspect_ratio = new Vector2(1f, size.x / size.y); break; case UVMode.Y: aspect_ratio = new Vector2(size.y / size.x, 1f); break; case UVMode.One: aspect_ratio = Vector2.one; break; case UVMode.Max: aspect_ratio = (size.x >= size.y) ? new Vector2(1f, size.x / size.y) : new Vector2(size.y / size.x, 1f); break; default: throw new NotSupportedException(string.Format("Unknown UVMode: {0}", EnumHelper.ToString(Mode))); } for (int i = 0; i < vh.currentVertCount; i++) { vh.PopulateUIVertex(ref vertex, i); vertex.uv1 = new Vector2( (vertex.position.x - min_x) / width / aspect_ratio.x, (vertex.position.y - min_y) / height / aspect_ratio.y); vh.SetUIVertex(vertex, i); } } /// /// Init material. /// protected virtual void InitMaterial() { SetMaterialProperties(); } /// /// Set material properties. /// protected abstract void SetMaterialProperties(); /// /// Update material. /// protected virtual void UpdateMaterial() { SetMaterialProperties(); if (EffectMaterial != null) { graphic.SetMaterialDirty(); } } /// /// Get modified material. /// /// Base material. /// Modified material. public virtual Material GetModifiedMaterial(Material newBaseMaterial) { if ((BaseMaterial != null) && (newBaseMaterial.GetInstanceID() == BaseMaterial.GetInstanceID())) { return EffectMaterial; } if (EffectMaterial != null) { #if UNITY_EDITOR DestroyImmediate(EffectMaterial); #else Destroy(EffectMaterial); #endif } BaseMaterial = newBaseMaterial; EffectMaterial = new Material(newBaseMaterial) { shader = EffectShader, }; InitMaterial(); return EffectMaterial; } } }