using System; using UnityEngine; using UnityEditor; using UnityEngine.UI; using UnityEngine.Serialization; using System.Text; using System.Linq; using System.IO; namespace Coffee.UIEffects { /// /// Dissolve effect for uGUI. /// [AddComponentMenu("UI/UIEffects/UIDissolve", 3)] public class UIDissolve : BaseMaterialEffect, IMaterialModifier { private const uint k_ShaderId = 0 << 3; private static readonly ParameterTexture s_ParamTex = new ParameterTexture(8, 128, "_ParamTex"); private static readonly int k_TransitionTexId = Shader.PropertyToID("_TransitionTex"); private bool _lastKeepAspectRatio; private EffectArea _lastEffectArea; private static Texture _defaultTransitionTexture; [Tooltip("Current location[0-1] for dissolve effect. 0 is not dissolved, 1 is completely dissolved.")] [FormerlySerializedAs("m_Location")] [SerializeField] [Range(0, 1)] float m_EffectFactor = 0.5f; [Tooltip("Edge width.")] [SerializeField] [Range(0, 1)] float m_Width = 0.5f; [Tooltip("Edge softness.")] [SerializeField] [Range(0, 1)] float m_Softness = 0.5f; [Tooltip("Edge color.")] [SerializeField] [ColorUsage(false)] Color m_Color = new Color(0.0f, 0.25f, 1.0f); [Tooltip("Edge color effect mode.")] [SerializeField] ColorMode m_ColorMode = ColorMode.Add; [Tooltip("Noise texture for dissolving (single channel texture).")] [SerializeField] [FormerlySerializedAs("m_NoiseTexture")] Texture m_TransitionTexture; [Header("Advanced Option")] [Tooltip("The area for effect.")] [SerializeField] protected EffectArea m_EffectArea; [Tooltip("Keep effect aspect ratio.")] [SerializeField] bool m_KeepAspectRatio; [Header("Effect Player")] [SerializeField] EffectPlayer m_Player; [Tooltip("Reverse the dissolve effect.")] [FormerlySerializedAs("m_ReverseAnimation")] [SerializeField] bool m_Reverse = false; /// /// Effect factor between 0(start) and 1(end). /// public float effectFactor { get { return this.m_EffectFactor; } set { value = Mathf.Clamp(value, 0, 1); if (Mathf.Approximately(this.m_EffectFactor, value)) return; this.m_EffectFactor = value; SetEffectParamsDirty(); } } /// /// Edge width. /// public float width { get { return this.m_Width; } set { value = Mathf.Clamp(value, 0, 1); if (Mathf.Approximately(this.m_Width, value)) return; this.m_Width = value; SetEffectParamsDirty(); } } /// /// Edge softness. /// public float softness { get { return this.m_Softness; } set { value = Mathf.Clamp(value, 0, 1); if (Mathf.Approximately(this.m_Softness, value)) return; this.m_Softness = value; SetEffectParamsDirty(); } } /// /// Edge color. /// public Color color { get { return this.m_Color; } set { if (this.m_Color == value) return; this.m_Color = value; SetEffectParamsDirty(); } } /// /// Noise texture. /// public Texture transitionTexture { get { return this.m_TransitionTexture ? this.m_TransitionTexture : defaultTransitionTexture; } set { if (this.m_TransitionTexture == value) return; this.m_TransitionTexture = value; SetMaterialDirty(); } } private static Texture defaultTransitionTexture { get { return _defaultTransitionTexture ? _defaultTransitionTexture : (_defaultTransitionTexture = Resources.Load("Default-Transition")); } } /// /// The area for effect. /// public EffectArea effectArea { get { return this.m_EffectArea; } set { if (this.m_EffectArea == value) return; this.m_EffectArea = value; SetVerticesDirty(); } } /// /// Keep aspect ratio. /// public bool keepAspectRatio { get { return this.m_KeepAspectRatio; } set { if (this.m_KeepAspectRatio == value) return; this.m_KeepAspectRatio = value; SetVerticesDirty(); } } /// /// Color effect mode. /// public ColorMode colorMode { get { return this.m_ColorMode; } set { if (this.m_ColorMode == value) return; this.m_ColorMode = value; SetMaterialDirty(); } } /// /// Gets the parameter texture. /// public override ParameterTexture paramTex { get { return s_ParamTex; } } public EffectPlayer effectPlayer { get { return this.m_Player ?? (this.m_Player = new EffectPlayer()); } } public override Hash128 GetMaterialHash(Material material) { if (!this.isActiveAndEnabled || !material || !material.shader) return k_InvalidHash; var shaderVariantId = (uint) ((int) this.m_ColorMode << 6); var resourceId = (uint) this.transitionTexture.GetInstanceID(); return new Hash128( (uint) material.GetInstanceID(), k_ShaderId + shaderVariantId, resourceId, 0 ); } public override void ModifyMaterial(Material newMaterial, Graphic graphic) { var connector = GraphicConnector.FindConnector(graphic); newMaterial.shader = Shader.Find(string.Format("Hidden/{0} (UIDissolve)", newMaterial.shader.name)); SetShaderVariants(newMaterial, this.m_ColorMode); newMaterial.SetTexture(k_TransitionTexId, this.transitionTexture); this.paramTex.RegisterMaterial(newMaterial); } /// /// Modifies the mesh. /// public override void ModifyMesh(VertexHelper vh, Graphic graphic) { if (!this.isActiveAndEnabled) return; // bool isText = isTMPro || graphic is Text; var normalizedIndex = this.paramTex.GetNormalizedIndex(this); // rect. var tex = this.transitionTexture; var aspectRatio = this.m_KeepAspectRatio && tex ? ((float) tex.width) / tex.height : -1; var rect = this.m_EffectArea.GetEffectArea(vh, this.rectTransform.rect, aspectRatio); // Calculate vertex position. var vertex = default(UIVertex); var count = vh.currentVertCount; for (var i = 0; i < count; i++) { vh.PopulateUIVertex(ref vertex, i); float x; float y; this.connector.GetPositionFactor(this.m_EffectArea, i, rect, vertex.position, out x, out y); vertex.uv0 = new Vector2( Packer.ToFloat(vertex.uv0.x, vertex.uv0.y), Packer.ToFloat(x, y, normalizedIndex) ); vh.SetUIVertex(vertex, i); } } protected override void SetEffectParamsDirty() { this.paramTex.SetData(this, 0, this.m_EffectFactor); // param1.x : location this.paramTex.SetData(this, 1, this.m_Width); // param1.y : width this.paramTex.SetData(this, 2, this.m_Softness); // param1.z : softness this.paramTex.SetData(this, 4, this.m_Color.r); // param2.x : red this.paramTex.SetData(this, 5, this.m_Color.g); // param2.y : green this.paramTex.SetData(this, 6, this.m_Color.b); // param2.z : blue } protected override void SetVerticesDirty() { base.SetVerticesDirty(); this._lastKeepAspectRatio = this.m_KeepAspectRatio; this._lastEffectArea = this.m_EffectArea; } protected override void OnDidApplyAnimationProperties() { base.OnDidApplyAnimationProperties(); if (this._lastKeepAspectRatio != this.m_KeepAspectRatio || this._lastEffectArea != this.m_EffectArea) SetVerticesDirty(); } /// /// Play effect. /// public void Play(bool reset = true) { this.effectPlayer.Play(reset); } /// /// Stop effect. /// public void Stop(bool reset = true) { this.effectPlayer.Stop(reset); } protected override void OnEnable() { base.OnEnable(); this.effectPlayer.OnEnable((f) => this.effectFactor = this.m_Reverse ? 1f - f : f); } protected override void OnDisable() { base.OnDisable(); this.effectPlayer.OnDisable(); } } }