diff options
Diffstat (limited to 'Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Graphics/Graphic.cs')
-rw-r--r-- | Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Graphics/Graphic.cs | 669 |
1 files changed, 669 insertions, 0 deletions
diff --git a/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Graphics/Graphic.cs b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Graphics/Graphic.cs new file mode 100644 index 0000000..21acfb4 --- /dev/null +++ b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Graphics/Graphic.cs @@ -0,0 +1,669 @@ +using System; +#if UNITY_EDITOR +using System.Reflection; +#endif +using UnityEngine.Events; +using UnityEngine.EventSystems; +using UnityEngine.Serialization; +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 Material s_DefaultUI = 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) + s_DefaultUI = Canvas.GetDefaultCanvasMaterial(); + return s_DefaultUI; + } + } + + // Cached and saved values + [FormerlySerializedAs("m_Mat")] + [SerializeField] protected Material m_Material; + + [SerializeField] private Color m_Color = Color.white; + public virtual Color color { get { return m_Color; } set { if (SetPropertyUtility.SetColor(ref m_Color, value)) SetVerticesDirty(); } } + + [SerializeField] private bool m_RaycastTarget = true; + public virtual bool raycastTarget { get { return m_RaycastTarget; } set { m_RaycastTarget = value; } } + + [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_OnDirtyLayoutCallback; + [NonSerialized] protected UnityAction m_OnDirtyVertsCallback; + [NonSerialized] protected UnityAction m_OnDirtyMaterialCallback; + + [NonSerialized] protected static Mesh s_Mesh; + [NonSerialized] private static readonly VertexHelper s_VertexHelper = new VertexHelper(); + + // Tween controls for the Graphic + [NonSerialized] + private readonly TweenRunner<ColorTween> m_ColorTweenRunner; + + protected bool useLegacyMeshGeneration { get; set; } + + // 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); + useLegacyMeshGeneration = true; + } + + public virtual void SetAllDirty() + { + SetLayoutDirty(); + SetVerticesDirty(); + SetMaterialDirty(); + } + + public virtual void SetLayoutDirty() + { + if (!IsActive()) + return; + + LayoutRebuilder.MarkLayoutForRebuild(rectTransform); + + if (m_OnDirtyLayoutCallback != null) + m_OnDirtyLayoutCallback(); + } + + public virtual void SetVerticesDirty() + { + if (!IsActive()) + return; + + m_VertsDirty = true; + CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this); + + if (m_OnDirtyVertsCallback != null) + m_OnDirtyVertsCallback(); + } + + public virtual void SetMaterialDirty() + { + if (!IsActive()) + return; + + m_MaterialDirty = true; + CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this); + + if (m_OnDirtyMaterialCallback != null) + m_OnDirtyMaterialCallback(); + } + + protected override void OnRectTransformDimensionsChange() + { + if (gameObject.activeInHierarchy) + { + // prevent double dirtying... + if (CanvasUpdateRegistry.IsRebuildingLayout()) + SetVerticesDirty(); + else + { + SetVerticesDirty(); + SetLayoutDirty(); + } + } + } + + protected override void OnBeforeTransformParentChanged() + { + GraphicRegistry.UnregisterGraphicForCanvas(canvas, this); + LayoutRebuilder.MarkLayoutForRebuild(rectTransform); + } + + protected override void OnTransformParentChanged() + { + base.OnTransformParentChanged(); + + m_Canvas = null; + + if (!IsActive()) + return; + + CacheCanvas(); + GraphicRegistry.RegisterGraphicForCanvas(canvas, this); + SetAllDirty(); + } + + // 在hierachy里的深度,依次增加 + /// <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 + { + if (m_Canvas == null) + CacheCanvas(); + return m_Canvas; + } + } + + // 找到父节点中最近的canvas + private void CacheCanvas() + { + var list = ListPool<Canvas>.Get(); + // 找到所有父节点中所有canvas,从里到外 + gameObject.GetComponentsInParent(false, list); + if (list.Count > 0) + { + // Find the first active and enabled canvas. + for (int i = 0; i < list.Count; ++i) + { + if (list[i].isActiveAndEnabled) + { + m_Canvas = list[i]; + break; + } + } + } + else + m_Canvas = null; + ListPool<Canvas>.Release(list); + } + + /// <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(); + } + } + + /// <summary>
+ /// 提交到CanvasRenderer用这个,要应用IMaterialModifier的修改结果
+ /// </summary> + public virtual Material materialForRendering + { + get + { + // 在这里调用IMaterialModifier的修改 + var components = ListPool<Component>.Get(); + GetComponents(typeof(IMaterialModifier), components); + + var currentMat = material; + for (var i = 0; i < components.Count; i++) + currentMat = (components[i] as IMaterialModifier).GetModifiedMaterial(currentMat); + ListPool<Component>.Release(components); + return currentMat; + } + } + + /// <summary> + /// Returns the texture used to draw this Graphic. + /// </summary> + public virtual Texture mainTexture + { + get + { + return s_WhiteTexture; + } + } + + /// <summary> + /// Mark the Graphic and the canvas as having been changed. + /// </summary> + protected override void OnEnable() + { + base.OnEnable(); + CacheCanvas(); + GraphicRegistry.RegisterGraphicForCanvas(canvas, this); + +#if UNITY_EDITOR + GraphicRebuildTracker.TrackGraphic(this); +#endif + if (s_WhiteTexture == null) + s_WhiteTexture = Texture2D.whiteTexture; + + SetAllDirty(); + } + + /// <summary> + /// Clear references. + /// </summary> + protected override void OnDisable() + { +#if UNITY_EDITOR + GraphicRebuildTracker.UnTrackGraphic(this); +#endif + GraphicRegistry.UnregisterGraphicForCanvas(canvas, this); + CanvasUpdateRegistry.UnRegisterCanvasElementForRebuild(this); + + if (canvasRenderer != null) + canvasRenderer.Clear(); + + LayoutRebuilder.MarkLayoutForRebuild(rectTransform); + + base.OnDisable(); + } + + protected override void OnCanvasHierarchyChanged() + { + // Use m_Cavas so we dont auto call CacheCanvas + Canvas currentCanvas = m_Canvas; + + // Clear the cached canvas. Will be fetched below if active. + m_Canvas = null; + + if (!IsActive()) + return; + + CacheCanvas(); + + if (currentCanvas != m_Canvas) + { + GraphicRegistry.UnregisterGraphicForCanvas(currentCanvas, this); + + // Only register if we are active and enabled as OnCanvasHierarchyChanged can get called + // during object destruction and we dont want to register ourself and then become null. + if (IsActive()) + GraphicRegistry.RegisterGraphicForCanvas(canvas, this); + } + } + + // canvas重建 + public virtual void Rebuild(CanvasUpdate update) + { + if (canvasRenderer.cull) + return; + + switch (update) + { + case CanvasUpdate.PreRender: + if (m_VertsDirty) + { + UpdateGeometry(); + m_VertsDirty = false; + } + if (m_MaterialDirty) + { + UpdateMaterial(); + m_MaterialDirty = false; + } + break; + } + } + + public virtual void LayoutComplete() + {} + + public virtual void GraphicUpdateComplete() + {} + + /// <summary> + /// Update the renderer's material. + /// </summary> + protected virtual void UpdateMaterial() + { + if (!IsActive()) + return; + + canvasRenderer.materialCount = 1; + canvasRenderer.SetMaterial(materialForRendering, 0); + canvasRenderer.SetTexture(mainTexture); // 设置_MainTex,会覆盖材质上设置的_MainTex + } + + //c 顶点重建 + /// <summary> + /// Update the renderer's vertices. + /// </summary> + protected virtual void UpdateGeometry() + { + if (useLegacyMeshGeneration) + DoLegacyMeshGeneration(); + else + DoMeshGeneration(); + } + + // 顶点重建,生成mesh + private void DoMeshGeneration() + { + if (rectTransform != null && rectTransform.rect.width >= 0 && rectTransform.rect.height >= 0) + OnPopulateMesh(s_VertexHelper); // 填充vertexHelper + else + s_VertexHelper.Clear(); // clear the vertex helper so invalid graphics dont draw. + + // 可以通过实现IMeshModifer修改mesh + var components = ListPool<Component>.Get(); + GetComponents(typeof(IMeshModifier), components); + + for (var i = 0; i < components.Count; i++) + ((IMeshModifier)components[i]).ModifyMesh(s_VertexHelper); + + ListPool<Component>.Release(components); + + s_VertexHelper.FillMesh(workerMesh); + + // 传入canvasRenderer作为mesh + canvasRenderer.SetMesh(workerMesh); + } + + private void DoLegacyMeshGeneration() + { + if (rectTransform != null && rectTransform.rect.width >= 0 && rectTransform.rect.height >= 0) + { +#pragma warning disable 618 + OnPopulateMesh(workerMesh); +#pragma warning restore 618 + } + else + { + workerMesh.Clear(); + } + + // 自定义流程 + var components = ListPool<Component>.Get(); + GetComponents(typeof(IMeshModifier), components); + + for (var i = 0; i < components.Count; i++) + { +#pragma warning disable 618 + ((IMeshModifier)components[i]).ModifyMesh(workerMesh); +#pragma warning restore 618 + } + + ListPool<Component>.Release(components); + canvasRenderer.SetMesh(workerMesh); + } + + protected static Mesh workerMesh + { + get + { + if (s_Mesh == null) + { + s_Mesh = new Mesh(); + s_Mesh.name = "Shared UI Mesh"; + s_Mesh.hideFlags = HideFlags.HideAndDontSave; + } + return s_Mesh; + } + } + + [Obsolete("Use OnPopulateMesh instead.", true)] + protected virtual void OnFillVBO(System.Collections.Generic.List<UIVertex> vbo) {} + + [Obsolete("Use OnPopulateMesh(VertexHelper vh) instead.", false)] + protected virtual void OnPopulateMesh(Mesh m) + { + OnPopulateMesh(s_VertexHelper); + s_VertexHelper.FillMesh(m); + } + + /// <summary> + /// Fill the vertex buffer data. + /// </summary> + protected virtual void OnPopulateMesh(VertexHelper vh) + { + var r = GetPixelAdjustedRect(); + var v = new Vector4(r.x, r.y, r.x + r.width, r.y + r.height); + + Color32 color32 = color; + vh.Clear(); + vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(0f, 0f)); + vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(0f, 1f)); + vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(1f, 1f)); + vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(1f, 0f)); + + vh.AddTriangle(0, 1, 2); + vh.AddTriangle(2, 3, 0); + } + +#if UNITY_EDITOR + public virtual void OnRebuildRequested() + { + // when rebuild is requested we need to rebuild all the graphics / + // and associated components... The correct way to do this is by + // calling OnValidate... Because MB's don't have a common base class + // we do this via reflection. It's nasty and ugly... Editor only. + var mbs = gameObject.GetComponents<MonoBehaviour>(); + foreach (var mb in mbs) + { + if (mb == null) + continue; + var methodInfo = mb.GetType().GetMethod("OnValidate", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + if (methodInfo != null) + methodInfo.Invoke(mb, null); + } + } + + protected override void Reset() + { + 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) + { + if (!isActiveAndEnabled) + return false; + + var t = transform; + var components = ListPool<Component>.Get(); + + bool ignoreParentGroups = false; + bool continueTraversal = true; + + while (t != null) + { + t.GetComponents(components); + for (var i = 0; i < components.Count; i++) + { + var canvas = components[i] as Canvas; + if (canvas != null && canvas.overrideSorting) + continueTraversal = false; + + // 如果实现了这个接口再进一步判断一下 + var filter = components[i] as ICanvasRaycastFilter; + + if (filter == null) + continue; + + var raycastValid = true; + + var group = components[i] as CanvasGroup; + if (group != null) + { + if (ignoreParentGroups == false && group.ignoreParentGroups) + { + ignoreParentGroups = true; + raycastValid = filter.IsRaycastLocationValid(sp, eventCamera); + } + else if (!ignoreParentGroups) + raycastValid = filter.IsRaycastLocationValid(sp, eventCamera); + } + else + { + raycastValid = filter.IsRaycastLocationValid(sp, eventCamera); + } + + if (!raycastValid) + { + ListPool<Component>.Release(components); + return false; + } + } + t = continueTraversal ? t.parent : null; + } + ListPool<Component>.Release(components); + return true; + } + +#if UNITY_EDITOR + protected override void OnValidate() + { + base.OnValidate(); + SetAllDirty(); + } + +#endif + + public Vector2 PixelAdjustPoint(Vector2 point) + { + if (!canvas || canvas.renderMode == RenderMode.WorldSpace || canvas.scaleFactor == 0.0f || !canvas.pixelPerfect) + return point; + else + { + return RectTransformUtility.PixelAdjustPoint(point, transform, canvas); + } + } + + public Rect GetPixelAdjustedRect() + { + if (!canvas || canvas.renderMode == RenderMode.WorldSpace || canvas.scaleFactor == 0.0f || !canvas.pixelPerfect) + return rectTransform.rect; + else + return RectTransformUtility.PixelAdjustRect(rectTransform, canvas); + } + + public virtual void CrossFadeColor(Color targetColor, float duration, bool ignoreTimeScale, bool useAlpha) + { + CrossFadeColor(targetColor, duration, ignoreTimeScale, useAlpha, true); + } + + public virtual 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)) + { + m_ColorTweenRunner.StopTween(); + 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 virtual void CrossFadeAlpha(float alpha, float duration, bool ignoreTimeScale) + { + CrossFadeColor(CreateColorFromAlpha(alpha), duration, ignoreTimeScale, true, false); + } + + public void RegisterDirtyLayoutCallback(UnityAction action) + { + m_OnDirtyLayoutCallback += action; + } + + public void UnregisterDirtyLayoutCallback(UnityAction action) + { + m_OnDirtyLayoutCallback -= action; + } + + public void RegisterDirtyVerticesCallback(UnityAction action) + { + m_OnDirtyVertsCallback += action; + } + + public void UnregisterDirtyVerticesCallback(UnityAction action) + { + m_OnDirtyVertsCallback -= action; + } + + public void RegisterDirtyMaterialCallback(UnityAction action) + { + m_OnDirtyMaterialCallback += action; + } + + public void UnregisterDirtyMaterialCallback(UnityAction action) + { + m_OnDirtyMaterialCallback -= action; + } + } +} |