Created
August 25, 2014 23:38
-
-
Save stramit/1726f520d152895aed97 to your computer and use it in GitHub Desktop.
Graphic
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using UnityEngine.Events; | |
using UnityEngine.EventSystems; | |
using UnityEngine.UI.CoroutineTween; | |
namespace UnityEngine.UI | |
{ | |
/// <summary> | |
/// Base class for all UI components that should be derived from when creating new Graphic types. | |
/// </summary> | |
[DisallowMultipleComponent] | |
[RequireComponent(typeof(CanvasRenderer))] | |
[RequireComponent(typeof(RectTransform))] | |
[ExecuteInEditMode] | |
public abstract class Graphic | |
: UIBehaviour, | |
ICanvasElement | |
{ | |
static protected Color32 s_White = Color.white; | |
static protected Material s_DefaultUI = null; | |
static protected Material s_DefaultText = null; | |
static protected Texture2D s_WhiteTexture = null; | |
/// <summary> | |
/// Default material used to draw everything if no explicit material was specified. | |
/// </summary> | |
static public Material defaultGraphicMaterial | |
{ | |
get | |
{ | |
if (s_DefaultUI == null) | |
{ | |
Shader shader = Shader.Find("UI/Default"); | |
s_DefaultUI = new Material(shader); | |
s_DefaultUI.hideFlags = HideFlags.DontSave; | |
s_DefaultUI.name = "Default UI Material"; | |
} | |
return s_DefaultUI; | |
} | |
} | |
// Temporary vertex array pool used to avoid memory allocations as much as possible | |
private static readonly ObjectPool<List<UIVertex>> s_VboPool = new ObjectPool<List<UIVertex>>(x => { if (x.Capacity < 300) x.Capacity = 300; }, l => l.Clear()); | |
// Cached and saved values | |
[RenamedSerializedData ("m_Mat")] | |
[SerializeField] protected Material m_Material; | |
[SerializeField] private Color m_Color = Color.white; | |
public Color color { get { return m_Color; } set { SetPropertyUtility.SetColor (ref m_Color, value, m_DirtyVertsCallback); } } | |
private float m_PixelsPerUnit = 1; // Don't serialize | |
public float pixelsPerUnit { get { return m_PixelsPerUnit; } set { SetPropertyUtility.SetStruct (ref m_PixelsPerUnit, value, m_DirtyAllCallback); } } | |
[NonSerialized] private RectTransform m_RectTransform; | |
[NonSerialized] private CanvasRenderer m_CanvasRender; | |
[NonSerialized] private Canvas m_Canvas; | |
[NonSerialized] private bool m_VertsDirty; | |
[NonSerialized] private bool m_MaterialDirty; | |
[NonSerialized] protected UnityAction m_DirtyAllCallback; | |
[NonSerialized] protected UnityAction m_DirtyVertsCallback; | |
[NonSerialized] protected UnityAction m_DirtyLayoutCallback; | |
[NonSerialized] protected UnityAction m_DirtyMaterialCallback; | |
// Tween controls for the Graphic | |
[NonSerialized] | |
private readonly TweenRunner<ColorTween> m_ColorTweenRunner; | |
// Called by Unity prior to deserialization, | |
// should not be called by users | |
protected Graphic() | |
{ | |
if (m_ColorTweenRunner == null) | |
m_ColorTweenRunner = new TweenRunner<ColorTween> (); | |
m_ColorTweenRunner.Init (this); | |
m_DirtyAllCallback = SetAllDirty; | |
m_DirtyVertsCallback = SetVerticesDirty; | |
m_DirtyLayoutCallback = SetLayoutDirty; | |
m_DirtyMaterialCallback = SetMaterialDirty; | |
} | |
public virtual void SetAllDirty() | |
{ | |
SetLayoutDirty (); | |
SetVerticesDirty (); | |
SetMaterialDirty (); | |
} | |
public virtual void SetLayoutDirty() | |
{ | |
if (!IsActive()) | |
return; | |
LayoutRebuilder.MarkLayoutForRebuild(rectTransform); | |
} | |
public virtual void SetVerticesDirty() | |
{ | |
if (!IsActive()) | |
return; | |
m_VertsDirty = true; | |
CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild (this); | |
} | |
public virtual void SetMaterialDirty() | |
{ | |
if (!IsActive()) | |
return; | |
m_MaterialDirty = true; | |
CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this); | |
} | |
protected override void OnRectTransformDimensionsChange () | |
{ | |
if (gameObject.activeInHierarchy) | |
{ | |
// prevent double dirtying... | |
if (CanvasUpdateRegistry.IsRebuildingLayout ()) | |
SetVerticesDirty (); | |
else | |
{ | |
SetVerticesDirty (); | |
SetLayoutDirty (); | |
} | |
} | |
} | |
protected override void OnBeforeTransformParentChanged() | |
{ | |
LayoutRebuilder.MarkLayoutForRebuild (rectTransform); | |
} | |
protected override void OnTransformParentChanged() | |
{ | |
if (!IsActive ()) | |
return; | |
CacheCanvas(); | |
SetAllDirty (); | |
} | |
/// <summary> | |
/// Absolute depth of the graphic, used by rendering and events -- lowest to highest. | |
/// </summary> | |
public int depth { get { return canvasRenderer.absoluteDepth; } } | |
/// <summary> | |
/// Transform gets cached for speed. | |
/// </summary> | |
public RectTransform rectTransform | |
{ | |
get { return m_RectTransform ?? (m_RectTransform = GetComponent<RectTransform>()); } | |
} | |
public Canvas canvas | |
{ | |
get { return m_Canvas; } | |
} | |
private void CacheCanvas() | |
{ | |
GraphicRegistry.UnregisterGraphicForCanvas(canvas, this); | |
m_Canvas = gameObject.GetComponentInParent<Canvas>(); | |
GraphicRegistry.RegisterGraphicForCanvas(canvas, this); | |
} | |
/// <summary> | |
/// UI Renderer component. | |
/// </summary> | |
public CanvasRenderer canvasRenderer | |
{ | |
get | |
{ | |
if (m_CanvasRender == null) | |
m_CanvasRender = GetComponent<CanvasRenderer>(); | |
return m_CanvasRender; | |
} | |
} | |
public virtual Material defaultMaterial | |
{ | |
get { return defaultGraphicMaterial; } | |
} | |
/// <summary> | |
/// Returns the material used by this Graphic. | |
/// </summary> | |
public virtual Material material | |
{ | |
get | |
{ | |
return (m_Material != null) ? m_Material : defaultMaterial; | |
} | |
set | |
{ | |
if (m_Material == value) | |
return; | |
m_Material = value; | |
SetMaterialDirty (); | |
} | |
} | |
public virtual Material materialForRendering | |
{ | |
get | |
{ | |
var components = ComponentListPool.Get (); | |
GetComponents(typeof(IMaterialModifier), components); | |
var currentMat = material; | |
for (var i = 0; i < components.Count; i++) | |
currentMat = (components[i] as IMaterialModifier).GetModifiedMaterial(currentMat); | |
ComponentListPool.Release (components); | |
return currentMat; | |
} | |
} | |
/// <summary> | |
/// Returns the texture used to draw this Graphic. | |
/// </summary> | |
public virtual Texture mainTexture | |
{ | |
get | |
{ | |
return s_WhiteTexture; | |
} | |
} | |
#region Unity Lifetime calls | |
/// <summary> | |
/// Mark the Graphic and the canvas as having been changed. | |
/// </summary> | |
protected override void OnEnable() | |
{ | |
#if UNITY_EDITOR | |
CanvasRenderer.onRequestRebuild += OnRebuildRequested; | |
#endif | |
if (s_WhiteTexture == null) | |
s_WhiteTexture = Texture2D.whiteTexture; | |
CacheCanvas (); | |
SetAllDirty(); | |
SendGraphicEnabledDisabled (); | |
} | |
/// <summary> | |
/// Clear references. | |
/// </summary> | |
protected override void OnDisable() | |
{ | |
#if UNITY_EDITOR | |
CanvasRenderer.onRequestRebuild -= OnRebuildRequested; | |
#endif | |
GraphicRegistry.UnregisterGraphicForCanvas (canvas, this); | |
CanvasUpdateRegistry.UnRegisterCanvasElementForRebuild (this); | |
if (canvasRenderer != null) | |
canvasRenderer.Clear (); | |
LayoutRebuilder.MarkLayoutForRebuild(rectTransform); | |
SendGraphicEnabledDisabled (); | |
} | |
private void SendGraphicEnabledDisabled() | |
{ | |
var components = ComponentListPool.Get(); | |
GetComponents(typeof(IGraphicEnabledDisabled), components); | |
for (int i = 0; i < components.Count; i++) | |
(components[i] as IGraphicEnabledDisabled).OnSiblingGraphicEnabledDisabled(); | |
ComponentListPool.Release(components); | |
} | |
#endregion | |
public virtual void Rebuild(CanvasUpdate update) | |
{ | |
switch (update) | |
{ | |
case CanvasUpdate.PreRender: | |
if (m_VertsDirty) | |
{ | |
UpdateGeometry (); | |
m_VertsDirty = false; | |
} | |
if (m_MaterialDirty) | |
{ | |
UpdateMaterial (); | |
m_MaterialDirty = false; | |
} | |
break; | |
} | |
} | |
/// <summary> | |
/// Update the renderer's vertices. | |
/// </summary> | |
protected virtual void UpdateGeometry () | |
{ | |
var vbo = s_VboPool.Get (); | |
if (rectTransform != null && rectTransform.rect.width >= 0 && rectTransform.rect.height >= 0) | |
OnFillVBO(vbo); | |
var components = ComponentListPool.Get(); | |
GetComponents(typeof(IVertexModifier), components); | |
for (var i = 0; i < components.Count; i++) | |
(components[i] as IVertexModifier).ModifyVertices(vbo); | |
ComponentListPool.Release (components); | |
canvasRenderer.SetVertices(vbo); | |
s_VboPool.Release (vbo); | |
} | |
/// <summary> | |
/// Update the renderer's material. | |
/// </summary> | |
protected virtual void UpdateMaterial () | |
{ | |
if (IsActive ()) | |
canvasRenderer.SetMaterial (materialForRendering, mainTexture); | |
} | |
/// <summary> | |
/// Fill the vertex buffer data. | |
/// </summary> | |
protected virtual void OnFillVBO(List<UIVertex> vbo) | |
{ | |
var r = GetPixelAdjustedRect(); | |
var v = new Vector4(r.x, r.y, r.x + r.width, r.y + r.height); | |
var vert = UIVertex.simpleVert; | |
vert.color = color; | |
vert.position = new Vector3(v.x, v.y); | |
vert.uv0 = new Vector2(0f, 0f); | |
vbo.Add(vert); | |
vert.position = new Vector3(v.x, v.w); | |
vert.uv0 = new Vector2(0f, 1f); | |
vbo.Add(vert); | |
vert.position = new Vector3(v.z, v.w); | |
vert.uv0 = new Vector2(1f, 1f); | |
vbo.Add(vert); | |
vert.position = new Vector3(v.z, v.y); | |
vert.uv0 = new Vector2(1f, 0f); | |
vbo.Add(vert); | |
} | |
#if UNITY_EDITOR | |
protected virtual void OnRebuildRequested () | |
{ | |
SetAllDirty (); | |
} | |
#endif | |
// Call from unity if animation properties have changed | |
protected override void OnDidApplyAnimationProperties() | |
{ | |
SetAllDirty (); | |
} | |
/// <summary> | |
/// Make the Graphic have the native size of its content. | |
/// </summary> | |
public virtual void SetNativeSize () { } | |
public virtual bool Raycast (Vector2 sp, Camera eventCamera) | |
{ | |
var t = transform; | |
var components = ComponentListPool.Get(); | |
while (t != null) | |
{ | |
t.GetComponents(components); | |
for (var i = 0; i < components.Count; i++) | |
{ | |
var filter = components[i] as ICanvasRaycastFilter; | |
if (filter == null) | |
continue; | |
if (!filter.IsRaycastLocationValid (sp, eventCamera)) | |
{ | |
ComponentListPool.Release (components); | |
return false; | |
} | |
} | |
t = t.parent; | |
} | |
ComponentListPool.Release(components); | |
return true; | |
} | |
#if UNITY_EDITOR | |
protected override void OnValidate() | |
{ | |
base.OnValidate (); | |
m_PixelsPerUnit = Mathf.Max (m_PixelsPerUnit, 0.01f); | |
SetAllDirty (); | |
} | |
#endif | |
public Vector2 PixelAdjustPoint (Vector2 point) | |
{ | |
if (!canvas || !canvas.pixelPerfect) | |
return point; | |
return RectTransformUtility.PixelAdjustPoint (point, transform, canvas); | |
} | |
public Rect GetPixelAdjustedRect () | |
{ | |
if (!canvas || !canvas.pixelPerfect) | |
return rectTransform.rect; | |
return RectTransformUtility.PixelAdjustRect(rectTransform, canvas); | |
} | |
public void CrossFadeColor(Color targetColor, float duration, bool ignoreTimeScale, bool useAlpha) | |
{ | |
CrossFadeColor(targetColor, duration, ignoreTimeScale, useAlpha, true); | |
} | |
private void CrossFadeColor(Color targetColor, float duration, bool ignoreTimeScale, bool useAlpha, bool useRGB) | |
{ | |
if (canvasRenderer == null || (!useRGB && !useAlpha)) | |
return; | |
Color currentColor = canvasRenderer.GetColor(); | |
if (currentColor.Equals(targetColor)) | |
return; | |
ColorTween.ColorTweenMode mode = (useRGB && useAlpha ? | |
ColorTween.ColorTweenMode.All : | |
(useRGB ? ColorTween.ColorTweenMode.RGB : ColorTween.ColorTweenMode.Alpha)); | |
var colorTween = new ColorTween {duration = duration, startColor = canvasRenderer.GetColor(), targetColor = targetColor}; | |
colorTween.AddOnChangedCallback (canvasRenderer.SetColor); | |
colorTween.ignoreTimeScale = ignoreTimeScale; | |
colorTween.tweenMode = mode; | |
m_ColorTweenRunner.StartTween(colorTween); | |
} | |
static private Color CreateColorFromAlpha(float alpha) | |
{ | |
var alphaColor = Color.black; | |
alphaColor.a = alpha; | |
return alphaColor; | |
} | |
public void CrossFadeAlpha(float alpha, float duration, bool ignoreTimeScale) | |
{ | |
CrossFadeColor(CreateColorFromAlpha(alpha), duration, ignoreTimeScale, true, false); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment