2342 lines
60 KiB
C#
2342 lines
60 KiB
C#
|
//----------------------------------------------
|
||
|
// NGUI: Next-Gen UI kit
|
||
|
// Copyright © 2011-2015 Tasharen Entertainment
|
||
|
//----------------------------------------------
|
||
|
#define FUNCELL_MODIFIED
|
||
|
|
||
|
using UnityEngine;
|
||
|
using System.Collections.Generic;
|
||
|
|
||
|
#if !UNITY_5_4
|
||
|
using UnityEngine.Profiling;
|
||
|
#endif
|
||
|
|
||
|
/// <summary>
|
||
|
/// UI Panel is responsible for collecting, sorting and updating widgets in addition to generating widgets' geometry.
|
||
|
/// </summary>
|
||
|
|
||
|
[ExecuteInEditMode]
|
||
|
[AddComponentMenu("NGUI/UI/NGUI Panel")]
|
||
|
public class UIPanel : UIRect
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// List of active panels.
|
||
|
/// </summary>
|
||
|
|
||
|
static public List<UIPanel> list = new List<UIPanel>();
|
||
|
static private List<int> idList = new List<int>();
|
||
|
static private bool listNeedSort = false;
|
||
|
|
||
|
public enum RenderQueue
|
||
|
{
|
||
|
Automatic,
|
||
|
StartAt,
|
||
|
Explicit,
|
||
|
}
|
||
|
|
||
|
public delegate void OnGeometryUpdated ();
|
||
|
|
||
|
/// <summary>
|
||
|
/// Notification triggered when the panel's geometry get rebuilt. It's mainly here for debugging purposes.
|
||
|
/// </summary>
|
||
|
|
||
|
public OnGeometryUpdated onGeometryUpdated;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Whether this panel will show up in the panel tool (set this to 'false' for dynamically created temporary panels)
|
||
|
/// </summary>
|
||
|
|
||
|
public bool showInPanelTool = true;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Whether normals and tangents will be generated for all meshes
|
||
|
/// </summary>
|
||
|
|
||
|
public bool generateNormals = false;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Whether widgets drawn by this panel are static (won't move). This will improve performance.
|
||
|
/// </summary>
|
||
|
|
||
|
public bool widgetsAreStatic = false;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Whether widgets will be culled while the panel is being dragged.
|
||
|
/// Having this on improves performance, but turning it off will reduce garbage collection.
|
||
|
/// </summary>
|
||
|
|
||
|
public bool cullWhileDragging = true;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Optimization flag. Makes the assumption that the panel's geometry
|
||
|
/// will always be on screen and the bounds don't need to be re-calculated.
|
||
|
/// </summary>
|
||
|
|
||
|
public bool alwaysOnScreen = false;
|
||
|
|
||
|
/// <summary>
|
||
|
/// By default, non-clipped panels use the camera's bounds, and the panel's position has no effect.
|
||
|
/// If you want the panel's position to actually be used with anchors, set this field to 'true'.
|
||
|
/// </summary>
|
||
|
|
||
|
public bool anchorOffset = false;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Whether the soft border will be used as padding.
|
||
|
/// </summary>
|
||
|
|
||
|
public bool softBorderPadding = true;
|
||
|
|
||
|
/// <summary>
|
||
|
/// By default all panels manage render queues of their draw calls themselves by incrementing them
|
||
|
/// so that the geometry is drawn in the proper order. You can alter this behaviour.
|
||
|
/// </summary>
|
||
|
|
||
|
public RenderQueue renderQueue = RenderQueue.Automatic;
|
||
|
public static int lateUpdateRate = 0;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Render queue used by the panel. The default value of '3000' is the equivalent of "Transparent".
|
||
|
/// This property is only used if 'renderQueue' is set to something other than "Automatic".
|
||
|
/// </summary>
|
||
|
|
||
|
public int startingRenderQueue = 3100;
|
||
|
|
||
|
/// <summary>
|
||
|
/// List of widgets managed by this panel. Do not attempt to modify this list yourself.
|
||
|
/// </summary>
|
||
|
|
||
|
[System.NonSerialized]
|
||
|
public List<UIWidget> widgets = new List<UIWidget>();
|
||
|
|
||
|
/// <summary>
|
||
|
/// List of draw calls created by this panel. Do not attempt to modify this list yourself.
|
||
|
/// </summary>
|
||
|
|
||
|
[System.NonSerialized]
|
||
|
public List<UIDrawCall> drawCalls = new List<UIDrawCall>();
|
||
|
|
||
|
/// <summary>
|
||
|
/// Matrix that will transform the specified world coordinates to relative-to-panel coordinates.
|
||
|
/// </summary>
|
||
|
|
||
|
[System.NonSerialized]
|
||
|
public Matrix4x4 worldToLocal = Matrix4x4.identity;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Cached clip range passed to the draw call's shader.
|
||
|
/// </summary>
|
||
|
|
||
|
[System.NonSerialized]
|
||
|
public Vector4 drawCallClipRange = new Vector4(0f, 0f, 1f, 1f);
|
||
|
|
||
|
public delegate void OnClippingMoved (UIPanel panel);
|
||
|
|
||
|
|
||
|
|
||
|
/// <summary>
|
||
|
/// Event callback that's triggered when the panel's clip region gets moved.
|
||
|
/// </summary>
|
||
|
|
||
|
public OnClippingMoved onClipMove;
|
||
|
#if FUNCELL_MODIFIED
|
||
|
public delegate void OnParentChanged(UIPanel panel);
|
||
|
public OnParentChanged onParentChanged;
|
||
|
#endif
|
||
|
|
||
|
// Clip texture feature contributed by the community: http://www.tasharen.com/forum/index.php?topic=9268.0
|
||
|
[HideInInspector][SerializeField] Texture2D mClipTexture = null;
|
||
|
|
||
|
// Panel's alpha (affects the alpha of all widgets)
|
||
|
[HideInInspector][SerializeField] float mAlpha = 1f;
|
||
|
#if FUNCELL_MODIFIED
|
||
|
private float _oldAlpha = -1;
|
||
|
[System.NonSerialized] public float oldFinalAlpha = 1f;
|
||
|
[System.NonSerialized] public bool updateDrawCall = false;
|
||
|
#endif
|
||
|
|
||
|
// Clipping rectangle
|
||
|
[HideInInspector][SerializeField] UIDrawCall.Clipping mClipping = UIDrawCall.Clipping.None;
|
||
|
[HideInInspector][SerializeField] Vector4 mClipRange = new Vector4(0f, 0f, 300f, 200f);
|
||
|
[HideInInspector][SerializeField] Vector2 mClipSoftness = new Vector2(4f, 4f);
|
||
|
[HideInInspector][SerializeField] int mDepth = 0;
|
||
|
[HideInInspector][SerializeField] int mSortingOrder = 0;
|
||
|
|
||
|
// Whether a full rebuild of geometry buffers is required
|
||
|
bool mRebuild = false;
|
||
|
bool mResized = false;
|
||
|
|
||
|
[SerializeField] Vector2 mClipOffset = Vector2.zero;
|
||
|
|
||
|
int mMatrixFrame = -1;
|
||
|
int mAlphaFrameID = 0;
|
||
|
int mLayer = -1;
|
||
|
|
||
|
// Values used for visibility checks
|
||
|
static float[] mTemp = new float[4];
|
||
|
Vector2 mMin = Vector2.zero;
|
||
|
Vector2 mMax = Vector2.zero;
|
||
|
bool mHalfPixelOffset = false;
|
||
|
bool mSortWidgets = false;
|
||
|
bool mUpdateScroll = false;
|
||
|
|
||
|
#if FUNCELL_MODIFIED
|
||
|
//设置渐变的隐藏边(left,right,top,bottom)
|
||
|
[HideInInspector]
|
||
|
[SerializeField]
|
||
|
Vector4 mClipSoftnessHide = Vector4.one;
|
||
|
/// <summary>
|
||
|
/// 设置渐变的隐藏边(left,right,top,bottom)
|
||
|
/// </summary>
|
||
|
public Vector4 ClipSoftnessHide
|
||
|
{
|
||
|
get { return mClipSoftnessHide; }
|
||
|
set
|
||
|
{
|
||
|
mClipSoftnessHide = value;
|
||
|
if (mClipSoftnessHide.x > 0) mClipSoftnessHide.x = 1;
|
||
|
if (mClipSoftnessHide.y > 0) mClipSoftnessHide.y = 1;
|
||
|
if (mClipSoftnessHide.z > 0) mClipSoftnessHide.z = 1;
|
||
|
if (mClipSoftnessHide.w > 0) mClipSoftnessHide.w = 1;
|
||
|
}
|
||
|
}
|
||
|
//当前是否挂起
|
||
|
private bool _IsSuspend = false;
|
||
|
private int _suspendFrameCount = -1;
|
||
|
//当前是否挂起
|
||
|
public bool IsSuspend {
|
||
|
get
|
||
|
{
|
||
|
return _IsSuspend && _suspendFrameCount < Time.frameCount;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
if (_IsSuspend != value)
|
||
|
{
|
||
|
_suspendFrameCount = Time.frameCount + 1;
|
||
|
_IsSuspend = value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public delegate void OnRenderQueueChanged(int sq);
|
||
|
//RenderQueue改变的回调操作
|
||
|
public OnRenderQueueChanged onRenderQueueChanged;
|
||
|
|
||
|
#endif
|
||
|
/// <summary>
|
||
|
/// Helper property that returns the first unused depth value.
|
||
|
/// </summary>
|
||
|
|
||
|
static public int nextUnusedDepth
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
int highest = int.MinValue;
|
||
|
for (int i = 0, imax = list.Count; i < imax; ++i)
|
||
|
highest = Mathf.Max(highest, list[i].depth);
|
||
|
return (highest == int.MinValue) ? 0 : highest + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Whether the rectangle can be anchored.
|
||
|
/// </summary>
|
||
|
|
||
|
public override bool canBeAnchored { get { return mClipping != UIDrawCall.Clipping.None; } }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Panel's alpha affects everything drawn by the panel.
|
||
|
/// </summary>
|
||
|
|
||
|
public override float alpha
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return mAlpha;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
float val = Mathf.Clamp01(value);
|
||
|
|
||
|
if (mAlpha != val)
|
||
|
{
|
||
|
mAlphaFrameID = -1;
|
||
|
mResized = true;
|
||
|
mAlpha = val;
|
||
|
SetDirty();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Panels can have their own depth value that will change the order with which everything they manage gets drawn.
|
||
|
/// </summary>
|
||
|
|
||
|
public int depth
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return mDepth;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
if (mDepth != value)
|
||
|
{
|
||
|
mDepth = value;
|
||
|
#if UNITY_EDITOR
|
||
|
NGUITools.SetDirty(this);
|
||
|
#endif
|
||
|
//list.Sort(CompareFunc);
|
||
|
listNeedSort = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Sorting order value for the panel's draw calls, to be used with Unity's 2D system.
|
||
|
/// </summary>
|
||
|
|
||
|
public int sortingOrder
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return mSortingOrder;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
if (mSortingOrder != value)
|
||
|
{
|
||
|
mSortingOrder = value;
|
||
|
#if UNITY_EDITOR
|
||
|
NGUITools.SetDirty(this);
|
||
|
#endif
|
||
|
UpdateDrawCalls();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Function that can be used to depth-sort panels.
|
||
|
/// </summary>
|
||
|
|
||
|
static public int CompareFunc (UIPanel a, UIPanel b)
|
||
|
{
|
||
|
if (a != b && a != null && b != null)
|
||
|
{
|
||
|
if (a.mDepth < b.mDepth) return -1;
|
||
|
if (a.mDepth > b.mDepth) return 1;
|
||
|
return (a.GetHashCode() < b.GetHashCode()) ? -1 : 1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Panel's width in pixels.
|
||
|
/// </summary>
|
||
|
|
||
|
public float width { get { return GetViewSize().x; } }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Panel's height in pixels.
|
||
|
/// </summary>
|
||
|
|
||
|
public float height { get { return GetViewSize().y; } }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Whether the panel's drawn geometry needs to be offset by a half-pixel.
|
||
|
/// </summary>
|
||
|
|
||
|
public bool halfPixelOffset { get { return mHalfPixelOffset; } }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Whether the camera is used to draw UI geometry.
|
||
|
/// </summary>
|
||
|
|
||
|
#if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7
|
||
|
public bool usedForUI { get { return (anchorCamera != null && mCam.isOrthoGraphic); } }
|
||
|
#else
|
||
|
public bool usedForUI { get { return (anchorCamera != null && mCam.orthographic); } }
|
||
|
#endif
|
||
|
|
||
|
/// <summary>
|
||
|
/// Directx9 pixel offset, used for drawing.
|
||
|
/// </summary>
|
||
|
|
||
|
public Vector3 drawCallOffset
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
#if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7
|
||
|
if (anchorCamera != null && mCam.isOrthoGraphic)
|
||
|
#else
|
||
|
if (anchorCamera != null && mCam.orthographic)
|
||
|
#endif
|
||
|
{
|
||
|
Vector2 size = GetWindowSize();
|
||
|
float pixelSize = (root != null) ? root.pixelSizeAdjustment : 1f;
|
||
|
float mod = (pixelSize / size.y) / mCam.orthographicSize;
|
||
|
|
||
|
bool x = mHalfPixelOffset;
|
||
|
bool y = mHalfPixelOffset;
|
||
|
|
||
|
if ((Mathf.RoundToInt(size.x) & 1) == 1) x = !x;
|
||
|
if ((Mathf.RoundToInt(size.y) & 1) == 1) y = !y;
|
||
|
|
||
|
return new Vector3(x ? -mod : 0f, y ? mod : 0f);
|
||
|
}
|
||
|
return Vector3.zero;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Clipping method used by all draw calls.
|
||
|
/// </summary>
|
||
|
|
||
|
public UIDrawCall.Clipping clipping
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return mClipping;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
if (mClipping != value)
|
||
|
{
|
||
|
mResized = true;
|
||
|
mClipping = value;
|
||
|
mMatrixFrame = -1;
|
||
|
#if UNITY_EDITOR
|
||
|
if (!Application.isPlaying) UpdateDrawCalls();
|
||
|
#endif
|
||
|
|
||
|
#if FUNCELL_MODIFIED
|
||
|
if (onClipMove != null) onClipMove(this);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
UIPanel mParentPanel = null;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reference to the parent panel, if any.
|
||
|
/// </summary>
|
||
|
|
||
|
public UIPanel parentPanel { get { return mParentPanel; } }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Number of times the panel's contents get clipped.
|
||
|
/// </summary>
|
||
|
|
||
|
public int clipCount
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
int count = 0;
|
||
|
UIPanel p = this;
|
||
|
|
||
|
while (p != null)
|
||
|
{
|
||
|
if (p.mClipping == UIDrawCall.Clipping.SoftClip || p.mClipping == UIDrawCall.Clipping.TextureMask) ++count;
|
||
|
p = p.mParentPanel;
|
||
|
}
|
||
|
return count;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Whether the panel will actually perform clipping of children.
|
||
|
/// </summary>
|
||
|
|
||
|
public bool hasClipping { get { return mClipping == UIDrawCall.Clipping.SoftClip || mClipping == UIDrawCall.Clipping.TextureMask; } }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Whether the panel will actually perform clipping of children.
|
||
|
/// </summary>
|
||
|
|
||
|
public bool hasCumulativeClipping { get { return clipCount != 0; } }
|
||
|
|
||
|
[System.Obsolete("Use 'hasClipping' or 'hasCumulativeClipping' instead")]
|
||
|
public bool clipsChildren { get { return hasCumulativeClipping; } }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Clipping area offset used to make it possible to move clipped panels (scroll views) efficiently.
|
||
|
/// Scroll views move by adjusting the clip offset by one value, and the transform position by the inverse.
|
||
|
/// This makes it possible to not have to rebuild the geometry, greatly improving performance.
|
||
|
/// </summary>
|
||
|
|
||
|
public Vector2 clipOffset
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return mClipOffset;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
|
||
|
if (Mathf.Abs(mClipOffset.x - value.x) > 0.001f ||
|
||
|
Mathf.Abs(mClipOffset.y - value.y) > 0.001f)
|
||
|
{
|
||
|
mClipOffset = value;
|
||
|
InvalidateClipping();
|
||
|
|
||
|
// Call the event delegate
|
||
|
if (onClipMove != null) onClipMove(this);
|
||
|
#if UNITY_EDITOR
|
||
|
if (!Application.isPlaying) UpdateDrawCalls();
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Invalidate the panel's clipping, calling child panels in turn.
|
||
|
/// </summary>
|
||
|
|
||
|
void InvalidateClipping ()
|
||
|
{
|
||
|
mResized = true;
|
||
|
mMatrixFrame = -1;
|
||
|
|
||
|
for (int i = 0, imax = list.Count; i < imax; ++i)
|
||
|
{
|
||
|
UIPanel p = list[i];
|
||
|
if (p != this && p.parentPanel == this)
|
||
|
p.InvalidateClipping();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Texture used to clip the region.
|
||
|
/// </summary>
|
||
|
|
||
|
public Texture2D clipTexture
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return mClipTexture;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
if (mClipTexture != value)
|
||
|
{
|
||
|
mClipTexture = value;
|
||
|
#if UNITY_EDITOR
|
||
|
if (!Application.isPlaying) UpdateDrawCalls();
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Clipping position (XY) and size (ZW).
|
||
|
/// Note that you should not be modifying this property at run-time to reposition the clipping. Adjust clipOffset instead.
|
||
|
/// </summary>
|
||
|
|
||
|
[System.Obsolete("Use 'finalClipRegion' or 'baseClipRegion' instead")]
|
||
|
public Vector4 clipRange
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return baseClipRegion;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
baseClipRegion = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Clipping position (XY) and size (ZW).
|
||
|
/// Note that you should not be modifying this property at run-time to reposition the clipping. Adjust clipOffset instead.
|
||
|
/// </summary>
|
||
|
|
||
|
public Vector4 baseClipRegion
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return mClipRange;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
if (Mathf.Abs(mClipRange.x - value.x) > 0.001f ||
|
||
|
Mathf.Abs(mClipRange.y - value.y) > 0.001f ||
|
||
|
Mathf.Abs(mClipRange.z - value.z) > 0.001f ||
|
||
|
Mathf.Abs(mClipRange.w - value.w) > 0.001f)
|
||
|
{
|
||
|
mResized = true;
|
||
|
mClipRange = value;
|
||
|
mMatrixFrame = -1;
|
||
|
|
||
|
UIScrollView sv = GetComponent<UIScrollView>();
|
||
|
if (sv != null) sv.UpdatePosition();
|
||
|
if (onClipMove != null) onClipMove(this);
|
||
|
#if UNITY_EDITOR
|
||
|
if (!Application.isPlaying) UpdateDrawCalls();
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Final clipping region after the offset has been taken into consideration. XY = center, ZW = size.
|
||
|
/// </summary>
|
||
|
|
||
|
public Vector4 finalClipRegion
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
Vector2 size = GetViewSize();
|
||
|
|
||
|
if (mClipping != UIDrawCall.Clipping.None)
|
||
|
{
|
||
|
return new Vector4(mClipRange.x + mClipOffset.x, mClipRange.y + mClipOffset.y, size.x, size.y);
|
||
|
}
|
||
|
return new Vector4(0f, 0f, size.x, size.y);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if FUNCELL_MODIFIED
|
||
|
/// <summary>
|
||
|
/// 获取世界坐标的左上和右下的坐标 XY = LeftTop,ZW=RightBottom
|
||
|
/// </summary>
|
||
|
public Vector4 finalClipRectByWorld
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
|
||
|
if (mClipping != UIDrawCall.Clipping.None)
|
||
|
{
|
||
|
|
||
|
//Debug.Log(":::::Range:" + mClipRange + ";;" + transform.position + ";;");
|
||
|
Vector4 localPos = new Vector4()
|
||
|
{
|
||
|
x = mClipRange.x + mClipOffset.x - mClipRange.z / 2,
|
||
|
y = mClipRange.y + mClipOffset.y - mClipRange.w / 2,
|
||
|
z = mClipRange.x + mClipOffset.x + mClipRange.z / 2,
|
||
|
w = mClipRange.y + mClipOffset.y + mClipRange.w / 2
|
||
|
};
|
||
|
|
||
|
Vector3 worldClipXY = transform.TransformPoint(localPos.x, localPos.y, 0);
|
||
|
Vector3 worldClipZW = transform.TransformPoint(localPos.z, localPos.w, 0);
|
||
|
|
||
|
return new Vector4()
|
||
|
{
|
||
|
x = worldClipXY.x,
|
||
|
y = worldClipXY.y,
|
||
|
z = worldClipZW.x,
|
||
|
w = worldClipZW.y
|
||
|
};
|
||
|
|
||
|
}
|
||
|
return new Vector4(-50000, -50000, 50000, 50000);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/// <summary>
|
||
|
/// Clipping softness is used if the clipped style is set to "Soft".
|
||
|
/// </summary>
|
||
|
|
||
|
public Vector2 clipSoftness
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return mClipSoftness;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
if (mClipSoftness != value)
|
||
|
{
|
||
|
mClipSoftness = value;
|
||
|
#if UNITY_EDITOR
|
||
|
if (!Application.isPlaying) UpdateDrawCalls();
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Temporary variable to avoid GC allocation
|
||
|
static Vector3[] mCorners = new Vector3[4];
|
||
|
|
||
|
/// <summary>
|
||
|
/// Local-space corners of the panel's clipping rectangle. The order is bottom-left, top-left, top-right, bottom-right.
|
||
|
/// </summary>
|
||
|
|
||
|
public override Vector3[] localCorners
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (mClipping == UIDrawCall.Clipping.None)
|
||
|
{
|
||
|
Vector3[] corners = worldCorners;
|
||
|
Transform wt = cachedTransform;
|
||
|
for (int i = 0; i < 4; ++i) corners[i] = wt.InverseTransformPoint(corners[i]);
|
||
|
return corners;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
float x0 = mClipOffset.x + mClipRange.x - 0.5f * mClipRange.z;
|
||
|
float y0 = mClipOffset.y + mClipRange.y - 0.5f * mClipRange.w;
|
||
|
float x1 = x0 + mClipRange.z;
|
||
|
float y1 = y0 + mClipRange.w;
|
||
|
|
||
|
mCorners[0] = new Vector3(x0, y0);
|
||
|
mCorners[1] = new Vector3(x0, y1);
|
||
|
mCorners[2] = new Vector3(x1, y1);
|
||
|
mCorners[3] = new Vector3(x1, y0);
|
||
|
}
|
||
|
return mCorners;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// World-space corners of the panel's clipping rectangle. The order is bottom-left, top-left, top-right, bottom-right.
|
||
|
/// </summary>
|
||
|
|
||
|
public override Vector3[] worldCorners
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (mClipping != UIDrawCall.Clipping.None)
|
||
|
{
|
||
|
float x0 = mClipOffset.x + mClipRange.x - 0.5f * mClipRange.z;
|
||
|
float y0 = mClipOffset.y + mClipRange.y - 0.5f * mClipRange.w;
|
||
|
float x1 = x0 + mClipRange.z;
|
||
|
float y1 = y0 + mClipRange.w;
|
||
|
|
||
|
Transform wt = cachedTransform;
|
||
|
|
||
|
mCorners[0] = wt.TransformPoint(x0, y0, 0f);
|
||
|
mCorners[1] = wt.TransformPoint(x0, y1, 0f);
|
||
|
mCorners[2] = wt.TransformPoint(x1, y1, 0f);
|
||
|
mCorners[3] = wt.TransformPoint(x1, y0, 0f);
|
||
|
}
|
||
|
else if (anchorCamera != null)
|
||
|
{
|
||
|
Vector3[] corners = mCam.GetWorldCorners(cameraRayDistance);
|
||
|
|
||
|
//if (anchorOffset && (mCam == null || mCam.transform.parent != cachedTransform))
|
||
|
//{
|
||
|
// Vector3 off = cachedTransform.position;
|
||
|
// for (int i = 0; i < 4; ++i)
|
||
|
// corners[i] += off;
|
||
|
//}
|
||
|
return corners;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Vector2 size = GetViewSize();
|
||
|
|
||
|
float x0 = -0.5f * size.x;
|
||
|
float y0 = -0.5f * size.y;
|
||
|
float x1 = x0 + size.x;
|
||
|
float y1 = y0 + size.y;
|
||
|
|
||
|
mCorners[0] = new Vector3(x0, y0);
|
||
|
mCorners[1] = new Vector3(x0, y1);
|
||
|
mCorners[2] = new Vector3(x1, y1);
|
||
|
mCorners[3] = new Vector3(x1, y0);
|
||
|
|
||
|
if (anchorOffset && (mCam == null || mCam.transform.parent != cachedTransform))
|
||
|
{
|
||
|
Vector3 off = cachedTransform.position;
|
||
|
for (int i = 0; i < 4; ++i)
|
||
|
mCorners[i] += off;
|
||
|
}
|
||
|
}
|
||
|
return mCorners;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Get the sides of the rectangle relative to the specified transform.
|
||
|
/// The order is left, top, right, bottom.
|
||
|
/// </summary>
|
||
|
|
||
|
public override Vector3[] GetSides (Transform relativeTo)
|
||
|
{
|
||
|
if (mClipping != UIDrawCall.Clipping.None)
|
||
|
{
|
||
|
float x0 = mClipOffset.x + mClipRange.x - 0.5f * mClipRange.z;
|
||
|
float y0 = mClipOffset.y + mClipRange.y - 0.5f * mClipRange.w;
|
||
|
float x1 = x0 + mClipRange.z;
|
||
|
float y1 = y0 + mClipRange.w;
|
||
|
float hx = (x0 + x1) * 0.5f;
|
||
|
float hy = (y0 + y1) * 0.5f;
|
||
|
|
||
|
Transform wt = cachedTransform;
|
||
|
|
||
|
mSides[0] = wt.TransformPoint(x0, hy, 0f);
|
||
|
mSides[1] = wt.TransformPoint(hx, y1, 0f);
|
||
|
mSides[2] = wt.TransformPoint(x1, hy, 0f);
|
||
|
mSides[3] = wt.TransformPoint(hx, y0, 0f);
|
||
|
|
||
|
if (relativeTo != null)
|
||
|
{
|
||
|
for (int i = 0; i < 4; ++i)
|
||
|
mSides[i] = relativeTo.InverseTransformPoint(mSides[i]);
|
||
|
}
|
||
|
return mSides;
|
||
|
}
|
||
|
else if (anchorCamera != null && anchorOffset)
|
||
|
{
|
||
|
Vector3[] sides = mCam.GetSides(cameraRayDistance);
|
||
|
Vector3 off = cachedTransform.position;
|
||
|
for (int i = 0; i < 4; ++i)
|
||
|
sides[i] += off;
|
||
|
|
||
|
if (relativeTo != null)
|
||
|
{
|
||
|
for (int i = 0; i < 4; ++i)
|
||
|
sides[i] = relativeTo.InverseTransformPoint(sides[i]);
|
||
|
}
|
||
|
return sides;
|
||
|
}
|
||
|
return base.GetSides(relativeTo);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Invalidating the panel should reset its alpha.
|
||
|
/// </summary>
|
||
|
|
||
|
public override void Invalidate (bool includeChildren, bool onlyAlphaChange = false)
|
||
|
{
|
||
|
mAlphaFrameID = -1;
|
||
|
base.Invalidate(includeChildren, onlyAlphaChange);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Widget's final alpha, after taking the panel's alpha into account.
|
||
|
/// </summary>
|
||
|
|
||
|
public override float CalculateFinalAlpha (int frameID)
|
||
|
{
|
||
|
#if UNITY_EDITOR
|
||
|
if (mAlphaFrameID != frameID || !Application.isPlaying)
|
||
|
#else
|
||
|
if (mAlphaFrameID != frameID)
|
||
|
#endif
|
||
|
{
|
||
|
mAlphaFrameID = frameID;
|
||
|
UIRect pt = parent;
|
||
|
finalAlpha = (pt != null) ? pt.CalculateFinalAlpha(frameID) * mAlpha : mAlpha;
|
||
|
}
|
||
|
return finalAlpha;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Set the panel's rectangle.
|
||
|
/// </summary>
|
||
|
|
||
|
public override void SetRect (float x, float y, float width, float height)
|
||
|
{
|
||
|
int finalWidth = Mathf.FloorToInt(width + 0.5f);
|
||
|
int finalHeight = Mathf.FloorToInt(height + 0.5f);
|
||
|
|
||
|
finalWidth = ((finalWidth >> 1) << 1);
|
||
|
finalHeight = ((finalHeight >> 1) << 1);
|
||
|
|
||
|
Transform t = cachedTransform;
|
||
|
Vector3 pos = t.localPosition;
|
||
|
pos.x = Mathf.Floor(x + 0.5f);
|
||
|
pos.y = Mathf.Floor(y + 0.5f);
|
||
|
|
||
|
if (finalWidth < 2) finalWidth = 2;
|
||
|
if (finalHeight < 2) finalHeight = 2;
|
||
|
|
||
|
baseClipRegion = new Vector4(pos.x, pos.y, finalWidth, finalHeight);
|
||
|
|
||
|
if (isAnchored)
|
||
|
{
|
||
|
t = t.parent;
|
||
|
|
||
|
if (leftAnchor.target) leftAnchor.SetHorizontal(t, x);
|
||
|
if (rightAnchor.target) rightAnchor.SetHorizontal(t, x + width);
|
||
|
if (bottomAnchor.target) bottomAnchor.SetVertical(t, y);
|
||
|
if (topAnchor.target) topAnchor.SetVertical(t, y + height);
|
||
|
#if UNITY_EDITOR
|
||
|
NGUITools.SetDirty(this);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns whether the specified rectangle is visible by the panel. The coordinates must be in world space.
|
||
|
/// </summary>
|
||
|
|
||
|
#if UNITY_FLASH
|
||
|
public bool IsVisible (Vector3 aa, Vector3 bb, Vector3 cc, Vector3 dd)
|
||
|
#else
|
||
|
public bool IsVisible (Vector3 a, Vector3 b, Vector3 c, Vector3 d)
|
||
|
#endif
|
||
|
{
|
||
|
UpdateTransformMatrix();
|
||
|
|
||
|
// Transform the specified points from world space to local space
|
||
|
#if UNITY_FLASH
|
||
|
// http://www.tasharen.com/forum/index.php?topic=11390.0
|
||
|
Vector3 a = worldToLocal.MultiplyPoint3x4(aa);
|
||
|
Vector3 b = worldToLocal.MultiplyPoint3x4(bb);
|
||
|
Vector3 c = worldToLocal.MultiplyPoint3x4(cc);
|
||
|
Vector3 d = worldToLocal.MultiplyPoint3x4(dd);
|
||
|
#else
|
||
|
a = worldToLocal.MultiplyPoint3x4(a);
|
||
|
b = worldToLocal.MultiplyPoint3x4(b);
|
||
|
c = worldToLocal.MultiplyPoint3x4(c);
|
||
|
d = worldToLocal.MultiplyPoint3x4(d);
|
||
|
#endif
|
||
|
mTemp[0] = a.x;
|
||
|
mTemp[1] = b.x;
|
||
|
mTemp[2] = c.x;
|
||
|
mTemp[3] = d.x;
|
||
|
|
||
|
float minX = Mathf.Min(mTemp);
|
||
|
float maxX = Mathf.Max(mTemp);
|
||
|
|
||
|
mTemp[0] = a.y;
|
||
|
mTemp[1] = b.y;
|
||
|
mTemp[2] = c.y;
|
||
|
mTemp[3] = d.y;
|
||
|
|
||
|
float minY = Mathf.Min(mTemp);
|
||
|
float maxY = Mathf.Max(mTemp);
|
||
|
|
||
|
if (maxX < mMin.x) return false;
|
||
|
if (maxY < mMin.y) return false;
|
||
|
if (minX > mMax.x) return false;
|
||
|
if (minY > mMax.y) return false;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns whether the specified world position is within the panel's bounds determined by the clipping rect.
|
||
|
/// </summary>
|
||
|
|
||
|
public bool IsVisible (Vector3 worldPos)
|
||
|
{
|
||
|
if (mAlpha < 0.001f) return false;
|
||
|
if (mClipping == UIDrawCall.Clipping.None ||
|
||
|
mClipping == UIDrawCall.Clipping.ConstrainButDontClip) return true;
|
||
|
|
||
|
UpdateTransformMatrix();
|
||
|
|
||
|
Vector3 pos = worldToLocal.MultiplyPoint3x4(worldPos);
|
||
|
if (pos.x < mMin.x) return false;
|
||
|
if (pos.y < mMin.y) return false;
|
||
|
if (pos.x > mMax.x) return false;
|
||
|
if (pos.y > mMax.y) return false;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns whether the specified widget is visible by the panel.
|
||
|
/// </summary>
|
||
|
|
||
|
public bool IsVisible (UIWidget w)
|
||
|
{
|
||
|
UIPanel p = this;
|
||
|
Vector3[] corners = null;
|
||
|
|
||
|
while (p != null)
|
||
|
{
|
||
|
if ((p.mClipping == UIDrawCall.Clipping.None || p.mClipping == UIDrawCall.Clipping.ConstrainButDontClip) && !w.hideIfOffScreen)
|
||
|
{
|
||
|
p = p.mParentPanel;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (corners == null) corners = w.worldCorners;
|
||
|
if (!p.IsVisible(corners[0], corners[1], corners[2], corners[3])) return false;
|
||
|
p = p.mParentPanel;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Whether the specified widget is going to be affected by this panel in any way.
|
||
|
/// </summary>
|
||
|
|
||
|
public bool Affects (UIWidget w)
|
||
|
{
|
||
|
if (w == null) return false;
|
||
|
|
||
|
UIPanel expected = w.panel;
|
||
|
if (expected == null) return false;
|
||
|
|
||
|
UIPanel p = this;
|
||
|
|
||
|
while (p != null)
|
||
|
{
|
||
|
if (p == expected) return true;
|
||
|
if (!p.hasCumulativeClipping) return false;
|
||
|
p = p.mParentPanel;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Causes all draw calls to be re-created on the next update.
|
||
|
/// </summary>
|
||
|
|
||
|
[ContextMenu("Force Refresh")]
|
||
|
public void RebuildAllDrawCalls () { mRebuild = true; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Invalidate the panel's draw calls, forcing them to be rebuilt on the next update.
|
||
|
/// This call also affects all children.
|
||
|
/// </summary>
|
||
|
|
||
|
public void SetDirty ()
|
||
|
{
|
||
|
//刷新所有drawcall
|
||
|
for (int i = 0, imax = drawCalls.Count; i < imax; ++i)
|
||
|
drawCalls[i].isDirty = true;
|
||
|
Invalidate(true, true);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Cache components.
|
||
|
/// </summary>
|
||
|
|
||
|
protected override void Awake ()
|
||
|
{
|
||
|
base.Awake();
|
||
|
|
||
|
mHalfPixelOffset = (Application.platform == RuntimePlatform.WindowsPlayer ||
|
||
|
Application.platform == RuntimePlatform.WindowsEditor);
|
||
|
|
||
|
// Only DirectX 9 needs the half-pixel offset
|
||
|
if (mHalfPixelOffset && SystemInfo.graphicsDeviceVersion.Contains("Direct3D"))
|
||
|
mHalfPixelOffset = (SystemInfo.graphicsShaderLevel < 40);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Find the parent panel, if we have one.
|
||
|
/// </summary>
|
||
|
|
||
|
void FindParent ()
|
||
|
{
|
||
|
Transform parent = cachedTransform.parent;
|
||
|
mParentPanel = (parent != null) ? NGUITools.FindInParents<UIPanel>(parent.gameObject) : null;
|
||
|
#if FUNCELL_MODIFIED
|
||
|
if (onParentChanged != null) onParentChanged(this);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Find the parent panel, if we have one.
|
||
|
/// </summary>
|
||
|
|
||
|
public override void ParentHasChanged ()
|
||
|
{
|
||
|
base.ParentHasChanged();
|
||
|
FindParent();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Layer is used to ensure that if it changes, widgets get moved as well.
|
||
|
/// </summary>
|
||
|
|
||
|
protected override void OnStart ()
|
||
|
{
|
||
|
mLayer = cachedGameObject.layer;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reset the frame IDs.
|
||
|
/// </summary>
|
||
|
protected override void OnEnable ()
|
||
|
{
|
||
|
mRebuild = true;
|
||
|
mAlphaFrameID = -1;
|
||
|
mMatrixFrame = -1;
|
||
|
OnStart();
|
||
|
base.OnEnable();
|
||
|
mMatrixFrame = -1;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Mark all widgets as having been changed so the draw calls get re-created.
|
||
|
/// </summary>
|
||
|
|
||
|
protected override void OnInit ()
|
||
|
{
|
||
|
if (idList.Contains(this.GetHashCode())) return;
|
||
|
base.OnInit();
|
||
|
FindParent();
|
||
|
|
||
|
#if FUNCELL_MODIFIED
|
||
|
/*
|
||
|
// Apparently having a rigidbody helps
|
||
|
#if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7
|
||
|
if (rigidbody == null && mParentPanel == null)
|
||
|
#else
|
||
|
if (GetComponent<Rigidbody>() == null && mParentPanel == null)
|
||
|
#endif
|
||
|
{
|
||
|
UICamera uic = (anchorCamera != null) ? mCam.GetComponent<UICamera>() : null;
|
||
|
|
||
|
if (uic != null)
|
||
|
{
|
||
|
if (uic.eventType == UICamera.EventType.UI_3D || uic.eventType == UICamera.EventType.World_3D)
|
||
|
{
|
||
|
Rigidbody rb = gameObject.AddComponent<Rigidbody>();
|
||
|
rb.isKinematic = true;
|
||
|
rb.useGravity = false;
|
||
|
}
|
||
|
// It's unclear if this helps 2D physics or not, so leaving it disabled for now.
|
||
|
// Note that when enabling this, the 'if (rigidbody == null)' statement above should be adjusted as well.
|
||
|
//else
|
||
|
//{
|
||
|
// Rigidbody2D rb = gameObject.AddComponent<Rigidbody2D>();
|
||
|
// rb.isKinematic = true;
|
||
|
//}
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
#else
|
||
|
// Apparently having a rigidbody helps
|
||
|
#if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7
|
||
|
if (rigidbody == null && mParentPanel == null)
|
||
|
#else
|
||
|
if (GetComponent<Rigidbody>() == null && mParentPanel == null)
|
||
|
#endif
|
||
|
{
|
||
|
UICamera uic = (anchorCamera != null) ? mCam.GetComponent<UICamera>() : null;
|
||
|
|
||
|
if (uic != null)
|
||
|
{
|
||
|
if (uic.eventType == UICamera.EventType.UI_3D || uic.eventType == UICamera.EventType.World_3D)
|
||
|
{
|
||
|
Rigidbody rb = gameObject.AddComponent<Rigidbody>();
|
||
|
rb.isKinematic = true;
|
||
|
rb.useGravity = false;
|
||
|
}
|
||
|
// It's unclear if this helps 2D physics or not, so leaving it disabled for now.
|
||
|
// Note that when enabling this, the 'if (rigidbody == null)' statement above should be adjusted as well.
|
||
|
//else
|
||
|
//{
|
||
|
// Rigidbody2D rb = gameObject.AddComponent<Rigidbody2D>();
|
||
|
// rb.isKinematic = true;
|
||
|
//}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
mRebuild = true;
|
||
|
mAlphaFrameID = -1;
|
||
|
mMatrixFrame = -1;
|
||
|
|
||
|
list.Add(this);
|
||
|
idList.Add(this.GetHashCode());
|
||
|
listNeedSort = true;
|
||
|
#if FUNCELL_MODIFIED
|
||
|
SelfUpdate();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Destroy all draw calls we've created when this script gets disabled.
|
||
|
/// </summary>
|
||
|
|
||
|
protected override void OnDisable ()
|
||
|
{
|
||
|
for (int i = 0, imax = drawCalls.Count; i < imax; ++i)
|
||
|
{
|
||
|
UIDrawCall dc = drawCalls[i];
|
||
|
if (dc != null) UIDrawCall.Destroy(dc);
|
||
|
}
|
||
|
|
||
|
drawCalls.Clear();
|
||
|
//优化调用时长
|
||
|
//list.Remove(this);
|
||
|
RemoveFromPanelList(list,idList, this);
|
||
|
|
||
|
mAlphaFrameID = -1;
|
||
|
mMatrixFrame = -1;
|
||
|
|
||
|
if (list.Count == 0)
|
||
|
{
|
||
|
UIDrawCall.ReleaseAll();
|
||
|
mUpdateFrame = -1;
|
||
|
}
|
||
|
base.OnDisable();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Update the world-to-local transform matrix as well as clipping bounds.
|
||
|
/// </summary>
|
||
|
|
||
|
void UpdateTransformMatrix ()
|
||
|
{
|
||
|
int fc = Time.frameCount;
|
||
|
|
||
|
if (cachedTransform.hasChanged)
|
||
|
{
|
||
|
mTrans.hasChanged = false;
|
||
|
mMatrixFrame = -1;
|
||
|
}
|
||
|
|
||
|
if (mMatrixFrame != fc)
|
||
|
{
|
||
|
mMatrixFrame = fc;
|
||
|
worldToLocal = mTrans.worldToLocalMatrix;
|
||
|
|
||
|
Vector2 size = GetViewSize() * 0.5f;
|
||
|
|
||
|
float x = mClipOffset.x + mClipRange.x;
|
||
|
float y = mClipOffset.y + mClipRange.y;
|
||
|
|
||
|
mMin.x = x - size.x;
|
||
|
mMin.y = y - size.y;
|
||
|
mMax.x = x + size.x;
|
||
|
mMax.y = y + size.y;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Update the edges after the anchors have been updated.
|
||
|
/// </summary>
|
||
|
|
||
|
protected override void OnAnchor ()
|
||
|
{
|
||
|
// No clipping = no edges to anchor
|
||
|
if (mClipping == UIDrawCall.Clipping.None) return;
|
||
|
|
||
|
Transform trans = cachedTransform;
|
||
|
Transform parent = trans.parent;
|
||
|
|
||
|
Vector2 size = GetViewSize();
|
||
|
Vector2 offset = trans.localPosition;
|
||
|
|
||
|
float lt, bt, rt, tt;
|
||
|
|
||
|
// Attempt to fast-path if all anchors match
|
||
|
if (leftAnchor.target == bottomAnchor.target &&
|
||
|
leftAnchor.target == rightAnchor.target &&
|
||
|
leftAnchor.target == topAnchor.target)
|
||
|
{
|
||
|
Vector3[] sides = leftAnchor.GetSides(parent);
|
||
|
|
||
|
if (sides != null)
|
||
|
{
|
||
|
lt = NGUIMath.Lerp(sides[0].x, sides[2].x, leftAnchor.relative) + leftAnchor.absolute;
|
||
|
rt = NGUIMath.Lerp(sides[0].x, sides[2].x, rightAnchor.relative) + rightAnchor.absolute;
|
||
|
bt = NGUIMath.Lerp(sides[3].y, sides[1].y, bottomAnchor.relative) + bottomAnchor.absolute;
|
||
|
tt = NGUIMath.Lerp(sides[3].y, sides[1].y, topAnchor.relative) + topAnchor.absolute;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Anchored to a single transform
|
||
|
Vector2 lp = GetLocalPos(leftAnchor, parent);
|
||
|
lt = lp.x + leftAnchor.absolute;
|
||
|
bt = lp.y + bottomAnchor.absolute;
|
||
|
rt = lp.x + rightAnchor.absolute;
|
||
|
tt = lp.y + topAnchor.absolute;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Left anchor point
|
||
|
if (leftAnchor.target)
|
||
|
{
|
||
|
Vector3[] sides = leftAnchor.GetSides(parent);
|
||
|
|
||
|
if (sides != null)
|
||
|
{
|
||
|
lt = NGUIMath.Lerp(sides[0].x, sides[2].x, leftAnchor.relative) + leftAnchor.absolute;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lt = GetLocalPos(leftAnchor, parent).x + leftAnchor.absolute;
|
||
|
}
|
||
|
}
|
||
|
else lt = mClipRange.x - 0.5f * size.x;
|
||
|
|
||
|
// Right anchor point
|
||
|
if (rightAnchor.target)
|
||
|
{
|
||
|
Vector3[] sides = rightAnchor.GetSides(parent);
|
||
|
|
||
|
if (sides != null)
|
||
|
{
|
||
|
rt = NGUIMath.Lerp(sides[0].x, sides[2].x, rightAnchor.relative) + rightAnchor.absolute;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rt = GetLocalPos(rightAnchor, parent).x + rightAnchor.absolute;
|
||
|
}
|
||
|
}
|
||
|
else rt = mClipRange.x + 0.5f * size.x;
|
||
|
|
||
|
// Bottom anchor point
|
||
|
if (bottomAnchor.target)
|
||
|
{
|
||
|
Vector3[] sides = bottomAnchor.GetSides(parent);
|
||
|
|
||
|
if (sides != null)
|
||
|
{
|
||
|
bt = NGUIMath.Lerp(sides[3].y, sides[1].y, bottomAnchor.relative) + bottomAnchor.absolute;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bt = GetLocalPos(bottomAnchor, parent).y + bottomAnchor.absolute;
|
||
|
}
|
||
|
}
|
||
|
else bt = mClipRange.y - 0.5f * size.y;
|
||
|
|
||
|
// Top anchor point
|
||
|
if (topAnchor.target)
|
||
|
{
|
||
|
Vector3[] sides = topAnchor.GetSides(parent);
|
||
|
|
||
|
if (sides != null)
|
||
|
{
|
||
|
tt = NGUIMath.Lerp(sides[3].y, sides[1].y, topAnchor.relative) + topAnchor.absolute;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
tt = GetLocalPos(topAnchor, parent).y + topAnchor.absolute;
|
||
|
}
|
||
|
}
|
||
|
else tt = mClipRange.y + 0.5f * size.y;
|
||
|
}
|
||
|
|
||
|
// Take the offset into consideration
|
||
|
lt -= offset.x + mClipOffset.x;
|
||
|
rt -= offset.x + mClipOffset.x;
|
||
|
bt -= offset.y + mClipOffset.y;
|
||
|
tt -= offset.y + mClipOffset.y;
|
||
|
|
||
|
// Calculate the new position, width and height
|
||
|
float newX = Mathf.Lerp(lt, rt, 0.5f);
|
||
|
float newY = Mathf.Lerp(bt, tt, 0.5f);
|
||
|
float w = rt - lt;
|
||
|
float h = tt - bt;
|
||
|
|
||
|
float minx = Mathf.Max(2f, mClipSoftness.x);
|
||
|
float miny = Mathf.Max(2f, mClipSoftness.y);
|
||
|
|
||
|
if (w < minx) w = minx;
|
||
|
if (h < miny) h = miny;
|
||
|
|
||
|
// Update the clipping range
|
||
|
baseClipRegion = new Vector4(newX, newY, w, h);
|
||
|
if(AnchorChanged != null)
|
||
|
{
|
||
|
AnchorChanged(cachedTransform);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int mUpdateFrame = -1;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Update all panels and draw calls.
|
||
|
/// </summary>
|
||
|
#if FUNCELL_MODIFIED
|
||
|
public static void PanelLateUpdate(int frameCount)
|
||
|
{
|
||
|
if (lateUpdateRate > 0 && frameCount % lateUpdateRate != 0)
|
||
|
return;
|
||
|
|
||
|
#if UNITY_EDITOR
|
||
|
if (mUpdateFrame != frameCount || !Application.isPlaying)
|
||
|
#else
|
||
|
if (mUpdateFrame != frameCount)
|
||
|
#endif
|
||
|
{
|
||
|
SortPanelList();
|
||
|
mUpdateFrame = Time.frameCount;
|
||
|
// Update each panel in order
|
||
|
for (int i = 0, imax = list.Count; i < imax; ++i)
|
||
|
{
|
||
|
list[i].UpdateSelf();
|
||
|
}
|
||
|
int rq = 3100;
|
||
|
|
||
|
// Update all draw calls, making them draw in the right order
|
||
|
for (int i = 0, imax = list.Count; i < imax; ++i)
|
||
|
{
|
||
|
UIPanel p = list[i];
|
||
|
if (p.renderQueue == RenderQueue.Automatic)
|
||
|
{
|
||
|
if (p.startingRenderQueue != rq)
|
||
|
{
|
||
|
p.startingRenderQueue = rq;
|
||
|
if (p.onRenderQueueChanged != null)
|
||
|
p.onRenderQueueChanged(rq);
|
||
|
}
|
||
|
if (p.updateDrawCall)
|
||
|
{
|
||
|
p.UpdateDrawCalls();
|
||
|
}
|
||
|
rq += p.drawCalls.Count;
|
||
|
rq += 7;
|
||
|
}
|
||
|
else if (p.renderQueue == RenderQueue.StartAt)
|
||
|
{
|
||
|
if (p.updateDrawCall)
|
||
|
{
|
||
|
p.UpdateDrawCalls();
|
||
|
}
|
||
|
if (p.drawCalls.Count != 0)
|
||
|
rq = Mathf.Max(rq, p.startingRenderQueue + p.drawCalls.Count);
|
||
|
}
|
||
|
else // Explicit
|
||
|
{
|
||
|
if (p.updateDrawCall)
|
||
|
{
|
||
|
p.UpdateDrawCalls();
|
||
|
}
|
||
|
if (p.drawCalls.Count != 0)
|
||
|
rq = Mathf.Max(rq, p.startingRenderQueue + 1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#else
|
||
|
void LateUpdate ()
|
||
|
{
|
||
|
#if UNITY_EDITOR
|
||
|
if (mUpdateFrame != Time.frameCount || !Application.isPlaying)
|
||
|
#else
|
||
|
if (mUpdateFrame != Time.frameCount)
|
||
|
#endif
|
||
|
{
|
||
|
if (IsSuspend) return;
|
||
|
SortPanelList();
|
||
|
mUpdateFrame = Time.frameCount;
|
||
|
// Update each panel in order
|
||
|
for (int i = 0, imax = list.Count; i < imax; ++i)
|
||
|
list[i].UpdateSelf();
|
||
|
|
||
|
int rq = 3100;
|
||
|
|
||
|
// Update all draw calls, making them draw in the right order
|
||
|
for (int i = 0, imax = list.Count; i < imax; ++i)
|
||
|
{
|
||
|
UIPanel p = list[i];
|
||
|
|
||
|
if (p.renderQueue == RenderQueue.Automatic)
|
||
|
{
|
||
|
if (p.startingRenderQueue != rq)
|
||
|
{
|
||
|
p.startingRenderQueue = rq;
|
||
|
#if FUNCELL_MODIFIED
|
||
|
if(p.onRenderQueueChanged != null)
|
||
|
p.onRenderQueueChanged(rq);
|
||
|
#endif
|
||
|
}
|
||
|
p.UpdateDrawCalls();
|
||
|
rq += p.drawCalls.Count;
|
||
|
rq += 5;
|
||
|
}
|
||
|
else if (p.renderQueue == RenderQueue.StartAt)
|
||
|
{
|
||
|
p.UpdateDrawCalls();
|
||
|
if (p.drawCalls.Count != 0)
|
||
|
rq = Mathf.Max(rq, p.startingRenderQueue + p.drawCalls.Count);
|
||
|
}
|
||
|
else // Explicit
|
||
|
{
|
||
|
p.UpdateDrawCalls();
|
||
|
if (p.drawCalls.Count != 0)
|
||
|
rq = Mathf.Max(rq, p.startingRenderQueue + 1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/// <summary>
|
||
|
/// Update the panel, all of its widgets and draw calls.
|
||
|
/// </summary>
|
||
|
|
||
|
void UpdateSelf ()
|
||
|
{
|
||
|
#if FUNCELL_MODIFIED
|
||
|
if (IsSuspend || (oldFinalAlpha <= 0f && finalAlpha <= 0f))
|
||
|
{
|
||
|
updateDrawCall = false;
|
||
|
return;
|
||
|
}
|
||
|
oldFinalAlpha = finalAlpha;
|
||
|
updateDrawCall = true;
|
||
|
#else
|
||
|
if (IsSuspend) return;
|
||
|
#endif
|
||
|
|
||
|
UpdateTransformMatrix();
|
||
|
UpdateLayers();
|
||
|
UpdateWidgets();
|
||
|
|
||
|
if (mRebuild)
|
||
|
{
|
||
|
mRebuild = false;
|
||
|
FillAllDrawCalls();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (int i = 0; i < drawCalls.Count; )
|
||
|
{
|
||
|
UIDrawCall dc = drawCalls[i];
|
||
|
|
||
|
if (dc.isDirty && !FillDrawCall(dc))
|
||
|
{
|
||
|
UIDrawCall.Destroy(dc);
|
||
|
drawCalls.RemoveAt(i);
|
||
|
continue;
|
||
|
}
|
||
|
++i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (mUpdateScroll)
|
||
|
{
|
||
|
mUpdateScroll = false;
|
||
|
UIScrollView sv = GetComponent<UIScrollView>();
|
||
|
if (sv != null) sv.UpdateScrollbars();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Immediately sort all child widgets.
|
||
|
/// </summary>
|
||
|
|
||
|
public void SortWidgets ()
|
||
|
{
|
||
|
mSortWidgets = false;
|
||
|
widgets.Sort(UIWidget.PanelCompareFunc);
|
||
|
}
|
||
|
|
||
|
//优化NGUI GC
|
||
|
static List<UIWidget> widgetsInDrawCall = new List<UIWidget>();
|
||
|
|
||
|
void FillDrawCallBuffers(UIDrawCall dc, int verticesCount)
|
||
|
{
|
||
|
dc.CheckCacke(verticesCount);
|
||
|
for (int i = 0; i < widgetsInDrawCall.Count; ++i)
|
||
|
{
|
||
|
var widget = widgetsInDrawCall[i];
|
||
|
if (generateNormals) widget.WriteToBuffers(dc.verts, dc.uvs, dc.cols, dc.norms, dc.tans);
|
||
|
else widget.WriteToBuffers(dc.verts, dc.uvs, dc.cols, null, null);
|
||
|
}
|
||
|
widgetsInDrawCall.Clear();
|
||
|
}
|
||
|
//优化NGUI GC
|
||
|
|
||
|
/// <summary>
|
||
|
/// Fill the geometry fully, processing all widgets and re-creating all draw calls.
|
||
|
/// </summary>
|
||
|
|
||
|
public void FillAllDrawCalls()
|
||
|
{
|
||
|
for (int i = 0, max = drawCalls.Count; i < max; ++i)
|
||
|
{
|
||
|
UIDrawCall.Destroy(drawCalls[i]);
|
||
|
}
|
||
|
drawCalls.Clear();
|
||
|
|
||
|
Material mat = null;
|
||
|
Texture tex = null;
|
||
|
Shader sdr = null;
|
||
|
#if FUNCELL_MODIFIED
|
||
|
bool isGray = false;
|
||
|
bool isFlowLight = false;
|
||
|
bool isOverlay = false;
|
||
|
Vector3Int flowColor = Vector3Int.zero;
|
||
|
Vector3Int flowParam = Vector3Int.zero;
|
||
|
#endif
|
||
|
UIDrawCall dc = null;
|
||
|
//优化NGUI GC
|
||
|
int verticesCount = 0;
|
||
|
//优化NGUI GC
|
||
|
if (mSortWidgets) SortWidgets();
|
||
|
for (int i = 0, max = widgets.Count; i < max; ++i)
|
||
|
{
|
||
|
UIWidget w = widgets[i];
|
||
|
|
||
|
if (w.isVisible && w.hasVertices)
|
||
|
{
|
||
|
Material mt = w.material;
|
||
|
Texture tx = w.mainTexture;
|
||
|
Shader sd = w.shader;
|
||
|
|
||
|
#if FUNCELL_MODIFIED
|
||
|
bool ig = w.IsGray;
|
||
|
bool ifl = w.IsFlowLight;
|
||
|
bool iol = w.IsOverlay;
|
||
|
Vector3Int ifc = w.FlowColor;
|
||
|
Vector3Int ifp = w.FlowParam;
|
||
|
#endif
|
||
|
#if FUNCELL_MODIFIED
|
||
|
if (mat != mt || tex != tx || sdr != sd || ig != isGray || iol != isOverlay || ifl != isFlowLight || (ifl && (ifc != flowColor || ifp != flowParam)))
|
||
|
#else
|
||
|
if (mat != mt || tex != tx || sdr != sd)
|
||
|
#endif
|
||
|
{
|
||
|
//优化NGUI GC
|
||
|
if (dc != null && verticesCount != 0)
|
||
|
//#else
|
||
|
//if (dc != null && dc.verts.size != 0)
|
||
|
//优化NGUI GC
|
||
|
{
|
||
|
drawCalls.Add(dc);
|
||
|
//优化NGUI GC
|
||
|
FillDrawCallBuffers(dc, verticesCount);
|
||
|
verticesCount = 0;
|
||
|
//优化NGUI GC
|
||
|
dc.UpdateGeometry();
|
||
|
dc.onRender = mOnRender;
|
||
|
mOnRender = null;
|
||
|
dc = null;
|
||
|
}
|
||
|
|
||
|
mat = mt;
|
||
|
tex = tx;
|
||
|
sdr = sd;
|
||
|
#if FUNCELL_MODIFIED
|
||
|
isGray = ig;
|
||
|
isFlowLight = ifl;
|
||
|
isOverlay = iol;
|
||
|
flowColor = ifc;
|
||
|
flowParam = ifp;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
if (mat != null || sdr != null || tex != null)
|
||
|
{
|
||
|
if (dc == null)
|
||
|
{
|
||
|
dc = UIDrawCall.Create(this, mat, tex, sdr);
|
||
|
dc.depthStart = w.depth;
|
||
|
dc.depthEnd = dc.depthStart;
|
||
|
#if FUNCELL_MODIFIED
|
||
|
dc.IsGray = w.IsGray;
|
||
|
dc.IsFlowLight = w.IsFlowLight;
|
||
|
dc.IsOverlay = w.IsOverlay;
|
||
|
dc.FlowColor = w.FlowColor;
|
||
|
dc.FlowParam = w.FlowParam;
|
||
|
#endif
|
||
|
dc.panel = this;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int rd = w.depth;
|
||
|
if (rd < dc.depthStart) dc.depthStart = rd;
|
||
|
if (rd > dc.depthEnd) dc.depthEnd = rd;
|
||
|
}
|
||
|
|
||
|
w.drawCall = dc;
|
||
|
//#if !OPTIMISE_NGUI_GC_ALLOC
|
||
|
//if (generateNormals) w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, dc.norms, dc.tans, dc.uv2s);
|
||
|
//else w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, null, null, dc.uv2s);
|
||
|
//#else
|
||
|
//优化NGUI GC
|
||
|
if (w.mOnRender != null)
|
||
|
{
|
||
|
if (mOnRender == null) mOnRender = w.mOnRender;
|
||
|
else mOnRender += w.mOnRender;
|
||
|
}
|
||
|
widgetsInDrawCall.Add(w);
|
||
|
verticesCount += w.geometry.verts.size;
|
||
|
//优化NGUI GC
|
||
|
}
|
||
|
}
|
||
|
else w.drawCall = null;
|
||
|
}
|
||
|
//优化NGUI GC
|
||
|
if (dc != null && verticesCount != 0)
|
||
|
//#else
|
||
|
//if (dc != null && dc.verts.size != 0)
|
||
|
//优化NGUI GC
|
||
|
{
|
||
|
drawCalls.Add(dc);
|
||
|
//优化NGUI GC
|
||
|
FillDrawCallBuffers(dc, verticesCount);
|
||
|
//优化NGUI GC
|
||
|
dc.UpdateGeometry();
|
||
|
dc.onRender = mOnRender;
|
||
|
mOnRender = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
UIDrawCall.OnRenderCallback mOnRender;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Fill the geometry for the specified draw call.
|
||
|
/// </summary>
|
||
|
|
||
|
public bool FillDrawCall(UIDrawCall dc)
|
||
|
{
|
||
|
if (dc != null)
|
||
|
{
|
||
|
dc.isDirty = false;
|
||
|
//优化NGUI GC
|
||
|
int verticesCount = 0;
|
||
|
//优化NGUI GC
|
||
|
for (int i = 0; i < widgets.Count;)
|
||
|
{
|
||
|
UIWidget w = widgets[i];
|
||
|
|
||
|
if (w == null)
|
||
|
{
|
||
|
#if UNITY_EDITOR
|
||
|
Debug.LogError("This should never happen");
|
||
|
#endif
|
||
|
widgets.RemoveAt(i);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (w.drawCall == dc)
|
||
|
{
|
||
|
if (w.isVisible && w.hasVertices)
|
||
|
{
|
||
|
//#if !OPTIMISE_NGUI_GC_ALLOC
|
||
|
//if (generateNormals) w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, dc.norms, dc.tans, dc.uv2s);
|
||
|
//else w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, null, null, dc.uv2s);
|
||
|
if (w.mOnRender != null)
|
||
|
{
|
||
|
if (mOnRender == null) mOnRender = w.mOnRender;
|
||
|
else mOnRender += w.mOnRender;
|
||
|
}
|
||
|
//优化NGUI GC
|
||
|
widgetsInDrawCall.Add(w);
|
||
|
verticesCount += w.geometry.verts.size;
|
||
|
//优化NGUI GC
|
||
|
}
|
||
|
else w.drawCall = null;
|
||
|
}
|
||
|
++i;
|
||
|
}
|
||
|
//#if !OPTIMISE_NGUI_GC_ALLOC
|
||
|
//if (dc.verts.size != 0)
|
||
|
//{
|
||
|
//优化NGUI GC
|
||
|
if (verticesCount != 0)
|
||
|
{
|
||
|
FillDrawCallBuffers(dc, verticesCount);
|
||
|
//优化NGUI GC
|
||
|
dc.UpdateGeometry();
|
||
|
dc.onRender = mOnRender;
|
||
|
mOnRender = null;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Update all draw calls associated with the panel.
|
||
|
/// </summary>
|
||
|
|
||
|
void UpdateDrawCalls ()
|
||
|
{
|
||
|
if (IsSuspend) return;
|
||
|
|
||
|
Transform trans = cachedTransform;
|
||
|
bool isUI = usedForUI;
|
||
|
|
||
|
if (clipping != UIDrawCall.Clipping.None)
|
||
|
{
|
||
|
drawCallClipRange = finalClipRegion;
|
||
|
drawCallClipRange.z *= 0.5f;
|
||
|
drawCallClipRange.w *= 0.5f;
|
||
|
}
|
||
|
else drawCallClipRange = Vector4.zero;
|
||
|
|
||
|
int w = Screen.width;
|
||
|
int h = Screen.height;
|
||
|
|
||
|
// Legacy functionality
|
||
|
if (drawCallClipRange.z == 0f) drawCallClipRange.z = w * 0.5f;
|
||
|
if (drawCallClipRange.w == 0f) drawCallClipRange.w = h * 0.5f;
|
||
|
|
||
|
// DirectX 9 half-pixel offset
|
||
|
if (halfPixelOffset)
|
||
|
{
|
||
|
drawCallClipRange.x -= 0.5f;
|
||
|
drawCallClipRange.y += 0.5f;
|
||
|
}
|
||
|
|
||
|
Vector3 pos;
|
||
|
|
||
|
if (isUI)
|
||
|
{
|
||
|
Transform parent = cachedTransform.parent;
|
||
|
pos = cachedTransform.localPosition;
|
||
|
|
||
|
if (clipping != UIDrawCall.Clipping.None)
|
||
|
{
|
||
|
pos.x = Mathf.RoundToInt(pos.x);
|
||
|
pos.y = Mathf.RoundToInt(pos.y);
|
||
|
}
|
||
|
|
||
|
if (parent != null) pos = parent.TransformPoint(pos);
|
||
|
pos += drawCallOffset;
|
||
|
}
|
||
|
else pos = trans.position;
|
||
|
|
||
|
Quaternion rot = trans.rotation;
|
||
|
Vector3 scale = trans.lossyScale;
|
||
|
|
||
|
for (int i = 0; i < drawCalls.Count; ++i)
|
||
|
{
|
||
|
UIDrawCall dc = drawCalls[i];
|
||
|
|
||
|
Transform t = dc.cachedTransform;
|
||
|
t.position = pos;
|
||
|
t.rotation = rot;
|
||
|
t.localScale = scale;
|
||
|
|
||
|
dc.renderQueue = (renderQueue == RenderQueue.Explicit) ? startingRenderQueue : startingRenderQueue + i;
|
||
|
dc.alwaysOnScreen = alwaysOnScreen &&
|
||
|
(mClipping == UIDrawCall.Clipping.None || mClipping == UIDrawCall.Clipping.ConstrainButDontClip);
|
||
|
dc.sortingOrder = mSortingOrder;
|
||
|
dc.clipTexture = mClipTexture;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Update the widget layers if the panel's layer has changed.
|
||
|
/// </summary>
|
||
|
|
||
|
void UpdateLayers ()
|
||
|
{
|
||
|
// Always move widgets to the panel's layer
|
||
|
if (mLayer != cachedGameObject.layer)
|
||
|
{
|
||
|
mLayer = mGo.layer;
|
||
|
|
||
|
for (int i = 0, imax = widgets.Count; i < imax; ++i)
|
||
|
{
|
||
|
UIWidget w = widgets[i];
|
||
|
if (w && w.parent == this) w.gameObject.layer = mLayer;
|
||
|
}
|
||
|
|
||
|
ResetAnchors();
|
||
|
|
||
|
for (int i = 0; i < drawCalls.Count; ++i)
|
||
|
drawCalls[i].gameObject.layer = mLayer;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool mForced = false;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Update all of the widgets belonging to this panel.
|
||
|
/// </summary>
|
||
|
|
||
|
void UpdateWidgets()
|
||
|
{
|
||
|
bool changed = false;
|
||
|
bool forceVisible = false;
|
||
|
bool clipped = hasCumulativeClipping;
|
||
|
|
||
|
if (!cullWhileDragging)
|
||
|
{
|
||
|
for (int i = 0; i < UIScrollView.list.size; ++i)
|
||
|
{
|
||
|
UIScrollView sv = UIScrollView.list[i];
|
||
|
if (sv.panel == this && sv.isDragging) forceVisible = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (mForced != forceVisible)
|
||
|
{
|
||
|
mForced = forceVisible;
|
||
|
mResized = true;
|
||
|
}
|
||
|
|
||
|
var appIsPlaying = Application.isPlaying;
|
||
|
// Update all widgets
|
||
|
int frame = Time.frameCount;
|
||
|
var thisHashCode = this.GetHashCode();
|
||
|
for (int i = 0, imax = widgets.Count; i < imax; ++i)
|
||
|
{
|
||
|
UIWidget w = widgets[i];
|
||
|
if(w.IsOnlyWidget)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
// If the widget is visible, update it
|
||
|
if (w.panel.GetHashCode() == thisHashCode && w.enabled)
|
||
|
{
|
||
|
#if UNITY_EDITOR
|
||
|
// When an object is dragged from Project view to Scene view, its Z is...
|
||
|
// odd, to say the least. Force it if possible.
|
||
|
if (!appIsPlaying)
|
||
|
{
|
||
|
Transform t = w.cachedTransform;
|
||
|
|
||
|
if (t.hideFlags != HideFlags.HideInHierarchy)
|
||
|
{
|
||
|
t = (t.parent != null && t.parent.hideFlags == HideFlags.HideInHierarchy) ?
|
||
|
t.parent : null;
|
||
|
}
|
||
|
|
||
|
if (t != null)
|
||
|
{
|
||
|
for (; ; )
|
||
|
{
|
||
|
if (t.parent == null) break;
|
||
|
if (t.parent.hideFlags == HideFlags.HideInHierarchy) t = t.parent;
|
||
|
else break;
|
||
|
}
|
||
|
|
||
|
if (t != null)
|
||
|
{
|
||
|
Vector3 pos = t.localPosition;
|
||
|
pos.x = Mathf.Round(pos.x);
|
||
|
pos.y = Mathf.Round(pos.y);
|
||
|
pos.z = 0f;
|
||
|
|
||
|
if (Vector3.SqrMagnitude(t.localPosition - pos) > 0.0001f)
|
||
|
t.localPosition = pos;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
// First update the widget's transform
|
||
|
if (w.UpdateTransform(frame) || mResized)
|
||
|
{
|
||
|
// Only proceed to checking the widget's visibility if it actually moved
|
||
|
#if FUNCELL_MODIFIED
|
||
|
bool vis = forceVisible || (w.finalAlpha > 0.001f);
|
||
|
#else
|
||
|
bool vis = forceVisible || (w.CalculateCumulativeAlpha(frame) > 0.001f);
|
||
|
#endif
|
||
|
w.UpdateVisibility(vis, forceVisible || ((clipped || w.hideIfOffScreen) ? IsVisible(w) : true));
|
||
|
}
|
||
|
|
||
|
// Update the widget's geometry if necessary
|
||
|
if (w.UpdateGeometry(frame))
|
||
|
{
|
||
|
changed = true;
|
||
|
//Debug.Log("Geometry changed: " + w.name + " " + frame, w);
|
||
|
|
||
|
if (!mRebuild)
|
||
|
{
|
||
|
// Find an existing draw call, if possible
|
||
|
if (w.drawCall != null) w.drawCall.isDirty = true;
|
||
|
else FindDrawCall(w);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Inform the changed event listeners
|
||
|
if (changed && onGeometryUpdated != null) onGeometryUpdated();
|
||
|
mResized = false;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Insert the specified widget into one of the existing draw calls if possible.
|
||
|
/// If it's not possible, and a new draw call is required, 'null' is returned
|
||
|
/// because draw call creation is a delayed operation.
|
||
|
/// </summary>
|
||
|
|
||
|
public UIDrawCall FindDrawCall (UIWidget w)
|
||
|
{
|
||
|
if (w.GetType() == widgetType)
|
||
|
{
|
||
|
return null;
|
||
|
}
|
||
|
Material mat = w.material;
|
||
|
Texture tex = w.mainTexture;
|
||
|
int depth = w.depth;
|
||
|
bool isGray = w.IsGray;
|
||
|
bool isFlowLight = w.IsFlowLight;
|
||
|
bool isOverlay = w.IsOverlay;
|
||
|
|
||
|
for (int i = 0; i < drawCalls.Count; ++i)
|
||
|
{
|
||
|
UIDrawCall dc = drawCalls[i];
|
||
|
int dcStart = (i == 0) ? int.MinValue : drawCalls[i - 1].depthEnd + 1;
|
||
|
int dcEnd = (i + 1 == drawCalls.Count) ? int.MaxValue : drawCalls[i + 1].depthStart - 1;
|
||
|
|
||
|
if (dcStart <= depth && dcEnd >= depth)
|
||
|
{
|
||
|
if (dc.baseMaterial == mat
|
||
|
&& dc.mainTexture == tex
|
||
|
&& dc.IsGray == isGray
|
||
|
&& dc.IsFlowLight == isFlowLight
|
||
|
&& dc.IsOverlay == isOverlay
|
||
|
)
|
||
|
{
|
||
|
if (w.isVisible)
|
||
|
{
|
||
|
w.drawCall = dc;
|
||
|
if (w.hasVertices) dc.isDirty = true;
|
||
|
return dc;
|
||
|
}
|
||
|
}
|
||
|
else mRebuild = true;
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
mRebuild = true;
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
private static System.Type widgetType = typeof(UIWidget);
|
||
|
/// <summary>
|
||
|
/// Make the following widget be managed by the panel.
|
||
|
/// </summary>
|
||
|
|
||
|
public void AddWidget (UIWidget w)
|
||
|
{
|
||
|
#if FUNCELL_MODIFIED
|
||
|
if(w.GetType() == widgetType && !w.hasBoxCollider)
|
||
|
{
|
||
|
w.IsOnlyWidget = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
w.IsOnlyWidget = false;
|
||
|
}
|
||
|
#endif
|
||
|
mUpdateScroll = true;
|
||
|
|
||
|
if (widgets.Count == 0)
|
||
|
{
|
||
|
widgets.Add(w);
|
||
|
}
|
||
|
else if (mSortWidgets)
|
||
|
{
|
||
|
widgets.Add(w);
|
||
|
SortWidgets();
|
||
|
}
|
||
|
else if (UIWidget.PanelCompareFunc(w, widgets[0]) == -1)
|
||
|
{
|
||
|
widgets.Insert(0, w);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (int i = widgets.Count; i > 0; )
|
||
|
{
|
||
|
if (UIWidget.PanelCompareFunc(w, widgets[--i]) == -1) continue;
|
||
|
widgets.Insert(i+1, w);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
FindDrawCall(w);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Remove the widget from its current draw call, invalidating everything as needed.
|
||
|
/// </summary>
|
||
|
|
||
|
public void RemoveWidget (UIWidget w)
|
||
|
{
|
||
|
//if (widgets.Remove(w) && w.drawCall != null)
|
||
|
if (RemoveFromWidgetList(widgets, w) && w.drawCall != null)
|
||
|
{
|
||
|
int depth = w.depth;
|
||
|
if (depth == w.drawCall.depthStart || depth == w.drawCall.depthEnd)
|
||
|
mRebuild = true;
|
||
|
|
||
|
w.drawCall.isDirty = true;
|
||
|
w.drawCall = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Immediately refresh the panel.
|
||
|
/// </summary>
|
||
|
|
||
|
public void Refresh ()
|
||
|
{
|
||
|
mRebuild = true;
|
||
|
mUpdateFrame = -1;
|
||
|
#if FUNCELL_MODIFIED
|
||
|
PanelLateUpdate(Time.frameCount);
|
||
|
#else
|
||
|
if (list.Count > 0) list[0].LateUpdate();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Calculate the offset needed to be constrained within the panel's bounds.
|
||
|
/// </summary>
|
||
|
|
||
|
public virtual Vector3 CalculateConstrainOffset (Vector2 min, Vector2 max)
|
||
|
{
|
||
|
Vector4 cr = finalClipRegion;
|
||
|
|
||
|
float offsetX = cr.z * 0.5f;
|
||
|
float offsetY = cr.w * 0.5f;
|
||
|
|
||
|
Vector2 minRect = new Vector2(min.x, min.y);
|
||
|
Vector2 maxRect = new Vector2(max.x, max.y);
|
||
|
Vector2 minArea = new Vector2(cr.x - offsetX, cr.y - offsetY);
|
||
|
Vector2 maxArea = new Vector2(cr.x + offsetX, cr.y + offsetY);
|
||
|
|
||
|
if (softBorderPadding && clipping == UIDrawCall.Clipping.SoftClip)
|
||
|
{
|
||
|
minArea.x += mClipSoftness.x;
|
||
|
minArea.y += mClipSoftness.y;
|
||
|
maxArea.x -= mClipSoftness.x;
|
||
|
maxArea.y -= mClipSoftness.y;
|
||
|
}
|
||
|
return NGUIMath.ConstrainRect(minRect, maxRect, minArea, maxArea);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Constrain the current target position to be within panel bounds.
|
||
|
/// </summary>
|
||
|
|
||
|
public bool ConstrainTargetToBounds (Transform target, ref Bounds targetBounds, bool immediate)
|
||
|
{
|
||
|
Vector3 min = targetBounds.min;
|
||
|
Vector3 max = targetBounds.max;
|
||
|
|
||
|
float ps = 1f;
|
||
|
|
||
|
if (mClipping == UIDrawCall.Clipping.None)
|
||
|
{
|
||
|
UIRoot rt = root;
|
||
|
if (rt != null) ps = rt.pixelSizeAdjustment;
|
||
|
}
|
||
|
|
||
|
if (ps != 1f)
|
||
|
{
|
||
|
min /= ps;
|
||
|
max /= ps;
|
||
|
}
|
||
|
|
||
|
Vector3 offset = CalculateConstrainOffset(min, max) * ps;
|
||
|
|
||
|
if (offset.sqrMagnitude > 0f)
|
||
|
{
|
||
|
if (immediate)
|
||
|
{
|
||
|
target.localPosition += offset;
|
||
|
targetBounds.center += offset;
|
||
|
SpringPosition sp = target.GetComponent<SpringPosition>();
|
||
|
if (sp != null) sp.enabled = false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SpringPosition sp = SpringPosition.Begin(target.gameObject, target.localPosition + offset, 13f);
|
||
|
sp.ignoreTimeScale = true;
|
||
|
sp.worldSpace = false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Constrain the specified target to be within the panel's bounds.
|
||
|
/// </summary>
|
||
|
|
||
|
public bool ConstrainTargetToBounds (Transform target, bool immediate)
|
||
|
{
|
||
|
Bounds bounds = NGUIMath.CalculateRelativeWidgetBounds(cachedTransform, target);
|
||
|
return ConstrainTargetToBounds(target, ref bounds, immediate);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 对Panel的List进行排序
|
||
|
/// </summary>
|
||
|
static public void SortPanelList()
|
||
|
{
|
||
|
if (listNeedSort)
|
||
|
{
|
||
|
list.Sort(CompareFunc);
|
||
|
listNeedSort = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Find the UIPanel responsible for handling the specified transform.
|
||
|
/// </summary>
|
||
|
|
||
|
static public UIPanel Find (Transform trans) { return Find(trans, false, -1); }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Find the UIPanel responsible for handling the specified transform.
|
||
|
/// </summary>
|
||
|
|
||
|
static public UIPanel Find (Transform trans, bool createIfMissing) { return Find(trans, createIfMissing, -1); }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Find the UIPanel responsible for handling the specified transform.
|
||
|
/// </summary>
|
||
|
|
||
|
static public UIPanel Find (Transform trans, bool createIfMissing, int layer)
|
||
|
{
|
||
|
UIPanel panel = NGUITools.FindInParents<UIPanel>(trans);
|
||
|
if (panel != null) return panel;
|
||
|
while (trans.parent != null) trans = trans.parent;
|
||
|
return createIfMissing ? NGUITools.CreateUI(trans, false, layer) : null;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Get the size of the game window in pixels.
|
||
|
/// </summary>
|
||
|
|
||
|
public Vector2 GetWindowSize ()
|
||
|
{
|
||
|
UIRoot rt = root;
|
||
|
Vector2 size = NGUITools.screenSize;
|
||
|
if (rt != null) size *= rt.GetPixelSizeAdjustment(Mathf.RoundToInt(size.y));
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Panel's size -- which is either the clipping rect, or the screen dimensions.
|
||
|
/// </summary>
|
||
|
|
||
|
public Vector2 GetViewSize ()
|
||
|
{
|
||
|
if (mClipping != UIDrawCall.Clipping.None)
|
||
|
return new Vector2(mClipRange.z, mClipRange.w);
|
||
|
|
||
|
Vector2 size = NGUITools.screenSize;
|
||
|
//UIRoot rt = root;
|
||
|
//if (rt != null) size *= rt.pixelSizeAdjustment;
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
public static bool RemoveFromWidgetList(List<UIWidget> list, UIWidget widget)
|
||
|
{
|
||
|
if (widget == null)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
var instId = widget.GetHashCode();
|
||
|
for (int i = 0, max = list.Count; i < max; ++i)
|
||
|
{
|
||
|
if (list[i].GetHashCode() == instId)
|
||
|
{
|
||
|
list.RemoveAt(i);
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
public static void RemoveFromPanelList(List<UIPanel> list,List<int> idList, UIPanel panel)
|
||
|
{
|
||
|
if(panel == null)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
var instId = panel.GetHashCode();
|
||
|
for (int i = 0, max = list.Count; i < max; ++i)
|
||
|
{
|
||
|
if(list[i].GetHashCode() == instId)
|
||
|
{
|
||
|
list.RemoveAt(i);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
idList.Remove(instId);
|
||
|
}
|
||
|
|
||
|
#if FUNCELL_MODIFIED
|
||
|
public override void SelfCalculateFinalAlpha(float parentAlpha)
|
||
|
{
|
||
|
finalAlpha = parentAlpha * mAlpha;
|
||
|
for (int i = 0; i < mChildren.size; ++i)
|
||
|
{
|
||
|
mChildren[i].SelfCalculateFinalAlpha(finalAlpha);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected override bool OnUpdate()
|
||
|
{
|
||
|
//updatealpha
|
||
|
if (_oldAlpha != mAlpha)
|
||
|
{
|
||
|
_oldAlpha = mAlpha;
|
||
|
var parentAlpha = 1f;
|
||
|
if (parent != null)
|
||
|
{
|
||
|
parentAlpha = parent.finalAlpha;
|
||
|
}
|
||
|
SelfCalculateFinalAlpha(parentAlpha);
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if UNITY_EDITOR
|
||
|
/// <summary>
|
||
|
/// Draw a visible pink outline for the clipped area.
|
||
|
/// </summary>
|
||
|
|
||
|
void OnDrawGizmos ()
|
||
|
{
|
||
|
if (anchorCamera == null) return;
|
||
|
|
||
|
bool clip = (mClipping != UIDrawCall.Clipping.None);
|
||
|
Transform t = clip ? transform : mCam.transform;
|
||
|
|
||
|
Vector3[] corners = worldCorners;
|
||
|
for (int i = 0; i < 4; ++i) corners[i] = t.InverseTransformPoint(corners[i]);
|
||
|
Vector3 pos = Vector3.Lerp(corners[0], corners[2], 0.5f);
|
||
|
Vector3 size = corners[2] - corners[0];
|
||
|
|
||
|
GameObject go = UnityEditor.Selection.activeGameObject;
|
||
|
bool isUsingThisPanel = (go != null) && (NGUITools.FindInParents<UIPanel>(go) == this);
|
||
|
bool isSelected = (UnityEditor.Selection.activeGameObject == gameObject);
|
||
|
bool detailedView = (isSelected && isUsingThisPanel);
|
||
|
bool detailedClipped = detailedView && mClipping == UIDrawCall.Clipping.SoftClip;
|
||
|
|
||
|
Gizmos.matrix = t.localToWorldMatrix;
|
||
|
|
||
|
#if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7
|
||
|
if (isUsingThisPanel && !clip && mCam.isOrthoGraphic)
|
||
|
#else
|
||
|
if (isUsingThisPanel && !clip && mCam.orthographic)
|
||
|
#endif
|
||
|
{
|
||
|
UIRoot rt = root;
|
||
|
|
||
|
if (rt != null && rt.scalingStyle != UIRoot.Scaling.Flexible)
|
||
|
{
|
||
|
float width = rt.manualWidth;
|
||
|
float height = rt.manualHeight;
|
||
|
|
||
|
float x0 = -0.5f * width;
|
||
|
float y0 = -0.5f * height;
|
||
|
float x1 = x0 + width;
|
||
|
float y1 = y0 + height;
|
||
|
|
||
|
corners[0] = new Vector3(x0, y0);
|
||
|
corners[1] = new Vector3(x0, y1);
|
||
|
corners[2] = new Vector3(x1, y1);
|
||
|
corners[3] = new Vector3(x1, y0);
|
||
|
|
||
|
Vector3 szPos = Vector3.Lerp(corners[0], corners[2], 0.5f);
|
||
|
Vector3 szSize = corners[2] - corners[0];
|
||
|
|
||
|
Gizmos.color = new Color(0f, 0.75f, 1f);
|
||
|
Gizmos.DrawWireCube(szPos, szSize);
|
||
|
}
|
||
|
}
|
||
|
Gizmos.color = (isUsingThisPanel && !detailedClipped) ? new Color(1f, 0f, 0.5f) : new Color(0.5f, 0f, 0.5f);
|
||
|
Gizmos.DrawWireCube(pos, size);
|
||
|
|
||
|
if (detailedView)
|
||
|
{
|
||
|
if (detailedClipped)
|
||
|
{
|
||
|
Gizmos.color = new Color(1f, 0f, 0.5f);
|
||
|
size.x -= mClipSoftness.x * 2f;
|
||
|
size.y -= mClipSoftness.y * 2f;
|
||
|
Gizmos.DrawWireCube(pos, size);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif // UNITY_EDITOR
|
||
|
}
|