AxibugEmuOnline/AxibugEmuOnline.Client/Assets/Plugins/Coffee/UIExtensions/UIEffect/Scripts/UIShadow.cs

462 lines
11 KiB
C#
Raw Permalink Normal View History

2024-08-16 14:45:44 +08:00
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI;
#if UNITY_EDITOR
using System.IO;
using System.Linq;
using UnityEditor;
#endif
namespace Coffee.UIExtensions
{
/// <summary>
/// UIEffect.
/// </summary>
[RequireComponent(typeof(Graphic))]
[AddComponentMenu("UI/UIEffect/UIShadow", 100)]
public class UIShadow : BaseMeshEffect, IParameterTexture
#if UNITY_EDITOR
, ISerializationCallbackReceiver
#endif
{
/// <summary>
/// Additional shadow.
/// </summary>
[System.Obsolete]
[System.Serializable]
public class AdditionalShadow
{
/// <summary>
/// How far is the blurring shadow from the graphic.
/// </summary>
[FormerlySerializedAs("shadowBlur")]
[Range(0, 1)] public float blur = 0.25f;
/// <summary>
/// Shadow effect mode.
/// </summary>
[FormerlySerializedAs("shadowMode")]
public ShadowStyle style = ShadowStyle.Shadow;
/// <summary>
/// Color for the shadow effect.
/// </summary>
[FormerlySerializedAs("shadowColor")]
public Color effectColor = Color.black;
/// <summary>
/// How far is the shadow from the graphic.
/// </summary>
public Vector2 effectDistance = new Vector2(1f, -1f);
/// <summary>
/// Should the shadow inherit the alpha from the graphic?
/// </summary>
public bool useGraphicAlpha = true;
}
//################################
// Serialize Members.
//################################
[Tooltip("How far is the blurring shadow from the graphic.")]
[FormerlySerializedAs("m_Blur")]
[SerializeField][Range(0, 1)] float m_BlurFactor = 1;
[Tooltip("Shadow effect style.")]
[SerializeField] ShadowStyle m_Style = ShadowStyle.Shadow;
#pragma warning disable 0414
[HideInInspector][System.Obsolete]
[SerializeField] List<AdditionalShadow> m_AdditionalShadows = new List<AdditionalShadow>();
#pragma warning restore 0414
[SerializeField]
private Color m_EffectColor = new Color (0f, 0f, 0f, 0.5f);
[SerializeField]
private Vector2 m_EffectDistance = new Vector2 (1f, -1f);
[SerializeField]
private bool m_UseGraphicAlpha = true;
private const float kMaxEffectDistance = 600f;
public Color effectColor
{
get { return m_EffectColor; }
set
{
m_EffectColor = value;
if (graphic != null)
graphic.SetVerticesDirty ();
}
}
public Vector2 effectDistance
{
get { return m_EffectDistance; }
set
{
if (value.x > kMaxEffectDistance)
value.x = kMaxEffectDistance;
if (value.x < -kMaxEffectDistance)
value.x = -kMaxEffectDistance;
if (value.y > kMaxEffectDistance)
value.y = kMaxEffectDistance;
if (value.y < -kMaxEffectDistance)
value.y = -kMaxEffectDistance;
if (m_EffectDistance == value)
return;
m_EffectDistance = value;
if (graphic != null)
graphic.SetVerticesDirty ();
}
}
public bool useGraphicAlpha
{
get { return m_UseGraphicAlpha; }
set
{
m_UseGraphicAlpha = value;
if (graphic != null)
graphic.SetVerticesDirty ();
}
}
//################################
// Public Members.
//################################
/// <summary>
/// How far is the blurring shadow from the graphic.
/// </summary>
[System.Obsolete("Use blurFactor instead (UnityUpgradable) -> blurFactor")]
public float blur
{
get { return m_BlurFactor; }
set
{
m_BlurFactor = Mathf.Clamp(value, 0, 2);
_SetDirty();
}
}
/// <summary>
/// How far is the blurring shadow from the graphic.
/// </summary>
public float blurFactor
{
get { return m_BlurFactor; }
set
{
m_BlurFactor = Mathf.Clamp(value, 0, 2);
_SetDirty();
}
}
/// <summary>
/// Shadow effect style.
/// </summary>
public ShadowStyle style
{
get { return m_Style; }
set
{
m_Style = value;
_SetDirty();
}
}
/// <summary>
/// Gets or sets the parameter index.
/// </summary>
public int parameterIndex { get; set; }
/// <summary>
/// Gets the parameter texture.
/// </summary>
public ParameterTexture ptex{ get; private set; }
int _graphicVertexCount;
static readonly List<UIShadow> tmpShadows = new List<UIShadow>();
protected override void OnEnable()
{
base.OnEnable();
_uiEffect = GetComponent<UIEffect>();
if (_uiEffect)
{
ptex = _uiEffect.ptex;
ptex.Register(this);
}
#if TMP_PRESENT
if (isTMPro)
{
textMeshPro.onCullStateChanged.AddListener (OnCullStateChanged);
}
#endif
}
protected override void OnDisable()
{
base.OnDisable();
_uiEffect = null;
if (ptex != null)
{
ptex.Unregister(this);
ptex = null;
}
}
#if UNITY_EDITOR
protected override void OnValidate ()
{
effectDistance = m_EffectDistance;
base.OnValidate ();
}
#endif
#if TMP_PRESENT
protected void OnCullStateChanged (bool state)
{
SetVerticesDirty ();
}
Vector2 res;
protected override void LateUpdate ()
{
if (res.x != Screen.width || res.y != Screen.height)
{
res.x = Screen.width;
res.y = Screen.height;
SetVerticesDirty ();
}
if (textMeshPro && transform.hasChanged)
{
transform.hasChanged = false;
}
base.LateUpdate ();
}
#endif
/// <summary>
/// Modifies the mesh.
/// </summary>
public override void ModifyMesh(VertexHelper vh)
{
if (!isActiveAndEnabled || vh.currentVertCount <= 0 || m_Style == ShadowStyle.None)
{
return;
}
vh.GetUIVertexStream(s_Verts);
GetComponents<UIShadow>(tmpShadows);
foreach (var s in tmpShadows)
{
if (s.isActiveAndEnabled)
{
if (s == this)
{
foreach (var s2 in tmpShadows)
{
s2._graphicVertexCount = s_Verts.Count;
}
}
break;
}
}
tmpShadows.Clear();
//================================
// Append shadow vertices.
//================================
{
_uiEffect = _uiEffect ?? GetComponent<UIEffect>();
var start = s_Verts.Count - _graphicVertexCount;
var end = s_Verts.Count;
if (ptex != null && _uiEffect && _uiEffect.isActiveAndEnabled)
{
ptex.SetData(this, 0, _uiEffect.effectFactor); // param.x : effect factor
ptex.SetData(this, 1, 255); // param.y : color factor
ptex.SetData(this, 2, m_BlurFactor); // param.z : blur factor
}
_ApplyShadow(s_Verts, effectColor, ref start, ref end, effectDistance, style, useGraphicAlpha);
}
vh.Clear();
vh.AddUIVertexTriangleStream(s_Verts);
s_Verts.Clear();
}
UIEffect _uiEffect;
//################################
// Private Members.
//################################
static readonly List<UIVertex> s_Verts = new List<UIVertex>(4096);
/// <summary>
/// Append shadow vertices.
/// * It is similar to Shadow component implementation.
/// </summary>
void _ApplyShadow(List<UIVertex> verts, Color color, ref int start, ref int end, Vector2 effectDistance, ShadowStyle style, bool useGraphicAlpha)
{
if (style == ShadowStyle.None || color.a <= 0)
return;
// Append Shadow.
_ApplyShadowZeroAlloc(s_Verts, color, ref start, ref end, effectDistance.x, effectDistance.y, useGraphicAlpha);
// Append Shadow3.
if (ShadowStyle.Shadow3 == style)
{
_ApplyShadowZeroAlloc(s_Verts, color, ref start, ref end, effectDistance.x, 0, useGraphicAlpha);
_ApplyShadowZeroAlloc(s_Verts, color, ref start, ref end, 0, effectDistance.y, useGraphicAlpha);
}
// Append Outline.
else if (ShadowStyle.Outline == style)
{
_ApplyShadowZeroAlloc(s_Verts, color, ref start, ref end, effectDistance.x, -effectDistance.y, useGraphicAlpha);
_ApplyShadowZeroAlloc(s_Verts, color, ref start, ref end, -effectDistance.x, effectDistance.y, useGraphicAlpha);
_ApplyShadowZeroAlloc(s_Verts, color, ref start, ref end, -effectDistance.x, -effectDistance.y, useGraphicAlpha);
}
// Append Outline8.
else if (ShadowStyle.Outline8 == style)
{
_ApplyShadowZeroAlloc(s_Verts, color, ref start, ref end, effectDistance.x, -effectDistance.y, useGraphicAlpha);
_ApplyShadowZeroAlloc(s_Verts, color, ref start, ref end, -effectDistance.x, effectDistance.y, useGraphicAlpha);
_ApplyShadowZeroAlloc(s_Verts, color, ref start, ref end, -effectDistance.x, -effectDistance.y, useGraphicAlpha);
_ApplyShadowZeroAlloc(s_Verts, color, ref start, ref end, -effectDistance.x, 0, useGraphicAlpha);
_ApplyShadowZeroAlloc(s_Verts, color, ref start, ref end, 0, -effectDistance.y, useGraphicAlpha);
_ApplyShadowZeroAlloc(s_Verts, color, ref start, ref end, effectDistance.x, 0, useGraphicAlpha);
_ApplyShadowZeroAlloc(s_Verts, color, ref start, ref end, 0, effectDistance.y, useGraphicAlpha);
}
}
/// <summary>
/// Append shadow vertices.
/// * It is similar to Shadow component implementation.
/// </summary>
void _ApplyShadowZeroAlloc(List<UIVertex> verts, Color color, ref int start, ref int end, float x, float y, bool useGraphicAlpha)
{
// Check list capacity.
int count = end - start;
var neededCapacity = verts.Count + count;
if (verts.Capacity < neededCapacity)
verts.Capacity *= 2;
float normalizedIndex = ptex != null && _uiEffect && _uiEffect.isActiveAndEnabled
? ptex.GetNormalizedIndex(this)
: -1;
// Add
UIVertex vt = default(UIVertex);
for (int i = 0; i < count; i++)
{
verts.Add(vt);
}
// Move
for (int i = verts.Count - 1; count <= i; i--)
{
verts[i] = verts[i - count];
}
// Append shadow vertices to the front of list.
// * The original vertex is pushed backward.
for (int i = 0; i < count; ++i)
{
vt = verts[i + start + count];
Vector3 v = vt.position;
vt.position.Set(v.x + x, v.y + y, v.z);
Color vertColor = effectColor;
vertColor.a = useGraphicAlpha ? color.a * vt.color.a / 255 : color.a;
vt.color = vertColor;
// Set UIEffect prameters
if (0 <= normalizedIndex)
{
vt.uv0 = new Vector2(
vt.uv0.x,
normalizedIndex
);
}
verts[i] = vt;
}
// Update next shadow offset.
start = end;
end = verts.Count;
}
/// <summary>
/// Mark the UIEffect as dirty.
/// </summary>
void _SetDirty()
{
if (graphic)
graphic.SetVerticesDirty();
}
#if UNITY_EDITOR
public void OnBeforeSerialize()
{
}
public void OnAfterDeserialize()
{
EditorApplication.delayCall += UpgradeIfNeeded;
}
#pragma warning disable 0612
void UpgradeIfNeeded()
{
if (0 < m_AdditionalShadows.Count)
{
foreach (var s in m_AdditionalShadows)
{
if (s.style == ShadowStyle.None)
{
continue;
}
var shadow = gameObject.AddComponent<UIShadow>();
shadow.style = s.style;
shadow.effectDistance = s.effectDistance;
shadow.effectColor = s.effectColor;
shadow.useGraphicAlpha = s.useGraphicAlpha;
shadow.blurFactor = s.blur;
}
m_AdditionalShadows = null;
}
}
#pragma warning restore 0612
#endif
}
}