2025-06-07 17:43:34 +08:00

1922 lines
60 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Text;
using UnityEngine;
using FairyGUI.Utils;
using System.Collections.Generic;
namespace FairyGUI
{
/// <summary>
///
/// </summary>
public class DisplayObject : EventDispatcher, IBatchable
{
/// <summary>
///
/// </summary>
public string name;
/// <summary>
///
/// </summary>
public Container parent { get; private set; }
/// <summary>
///
/// </summary>
public GameObject gameObject { get; protected set; }
/// <summary>
///
/// </summary>
public Transform cachedTransform { get; protected set; }
/// <summary>
///
/// </summary>
public NGraphics graphics { get; protected set; }
/// <summary>
///
/// </summary>
public NGraphics paintingGraphics { get; protected set; }
/// <summary>
///
/// </summary>
public event Action onPaint;
/// <summary>
///
/// </summary>
public GObject gOwner;
/// <summary>
///
/// </summary>
public uint id;
bool _visible;
bool _touchable;
Vector2 _pivot;
Vector3 _pivotOffset;
Vector3 _rotation; //由于万向锁,单独旋转一个轴是会影响到其他轴的,所以这里需要单独保存
Vector2 _skew;
int _renderingOrder;
float _alpha;
bool _grayed;
BlendMode _blendMode;
IFilter _filter;
Transform _home;
string _cursor;
bool _perspective;
int _focalLength;
Vector3 _pixelPerfectAdjustment;
int _checkPixelPerfect;
EventListener _onClick;
EventListener _onRightClick;
EventListener _onTouchBegin;
EventListener _onTouchMove;
EventListener _onTouchEnd;
EventListener _onRollOver;
EventListener _onRollOut;
EventListener _onMouseWheel;
EventListener _onAddedToStage;
EventListener _onRemovedFromStage;
EventListener _onKeyDown;
EventListener _onClickLink;
EventListener _onFocusIn;
EventListener _onFocusOut;
protected internal int _paintingMode; //1-滤镜2-blendMode4-transformMatrix, 8-cacheAsBitmap
protected internal PaintingInfo _paintingInfo;
protected Rect _contentRect;
protected NGraphics.VertexMatrix _vertexMatrix;
protected internal Flags _flags;
internal static uint _gInstanceCounter;
internal static HideFlags hideFlags = HideFlags.None;
public DisplayObject()
{
id = _gInstanceCounter++;
_alpha = 1;
_visible = true;
_touchable = true;
_blendMode = BlendMode.Normal;
_focalLength = 2000;
_flags |= Flags.OutlineChanged;
if (UIConfig.makePixelPerfect)
_flags |= Flags.PixelPerfect;
}
/// <summary>
///
/// </summary>
public EventListener onClick
{
get { return _onClick ?? (_onClick = new EventListener(this, "onClick")); }
}
/// <summary>
///
/// </summary>
public EventListener onRightClick
{
get { return _onRightClick ?? (_onRightClick = new EventListener(this, "onRightClick")); }
}
/// <summary>
///
/// </summary>
public EventListener onTouchBegin
{
get { return _onTouchBegin ?? (_onTouchBegin = new EventListener(this, "onTouchBegin")); }
}
/// <summary>
///
/// </summary>
public EventListener onTouchMove
{
get { return _onTouchMove ?? (_onTouchMove = new EventListener(this, "onTouchMove")); }
}
/// <summary>
///
/// </summary>
public EventListener onTouchEnd
{
get { return _onTouchEnd ?? (_onTouchEnd = new EventListener(this, "onTouchEnd")); }
}
/// <summary>
///
/// </summary>
public EventListener onRollOver
{
get { return _onRollOver ?? (_onRollOver = new EventListener(this, "onRollOver")); }
}
/// <summary>
///
/// </summary>
public EventListener onRollOut
{
get { return _onRollOut ?? (_onRollOut = new EventListener(this, "onRollOut")); }
}
/// <summary>
///
/// </summary>
public EventListener onMouseWheel
{
get { return _onMouseWheel ?? (_onMouseWheel = new EventListener(this, "onMouseWheel")); }
}
/// <summary>
///
/// </summary>
public EventListener onAddedToStage
{
get { return _onAddedToStage ?? (_onAddedToStage = new EventListener(this, "onAddedToStage")); }
}
/// <summary>
///
/// </summary>
public EventListener onRemovedFromStage
{
get { return _onRemovedFromStage ?? (_onRemovedFromStage = new EventListener(this, "onRemovedFromStage")); }
}
/// <summary>
///
/// </summary>
public EventListener onKeyDown
{
get { return _onKeyDown ?? (_onKeyDown = new EventListener(this, "onKeyDown")); }
}
/// <summary>
///
/// </summary>
public EventListener onClickLink
{
get { return _onClickLink ?? (_onClickLink = new EventListener(this, "onClickLink")); }
}
/// <summary>
///
/// </summary>
public EventListener onFocusIn
{
get { return _onFocusIn ?? (_onFocusIn = new EventListener(this, "onFocusIn")); }
}
/// <summary>
///
/// </summary>
public EventListener onFocusOut
{
get { return _onFocusOut ?? (_onFocusOut = new EventListener(this, "onFocusOut")); }
}
protected void CreateGameObject(string gameObjectName)
{
gameObject = new GameObject(gameObjectName);
cachedTransform = gameObject.transform;
if (Application.isPlaying)
{
UnityEngine.Object.DontDestroyOnLoad(gameObject);
DisplayObjectInfo info = gameObject.AddComponent<DisplayObjectInfo>();
info.displayObject = this;
}
gameObject.hideFlags = DisplayObject.hideFlags;
gameObject.SetActive(false);
}
protected void SetGameObject(GameObject gameObject)
{
this.gameObject = gameObject;
this.cachedTransform = gameObject.transform;
_rotation = cachedTransform.localEulerAngles;
_flags |= Flags.UserGameObject;
}
protected void DestroyGameObject()
{
if ((_flags & Flags.UserGameObject) == 0 && gameObject != null)
{
if (Application.isPlaying)
GameObject.Destroy(gameObject);
else
GameObject.DestroyImmediate(gameObject);
gameObject = null;
cachedTransform = null;
}
}
/// <summary>
///
/// </summary>
public float alpha
{
get { return _alpha; }
set { _alpha = value; }
}
/// <summary>
///
/// </summary>
public bool grayed
{
get { return _grayed; }
set { _grayed = value; }
}
/// <summary>
///
/// </summary>
public bool visible
{
get { return _visible; }
set
{
if (_visible != value)
{
_visible = value;
_flags |= Flags.OutlineChanged;
if (parent != null && _visible)
{
gameObject.SetActive(true);
InvalidateBatchingState();
if (this is Container)
((Container)this).InvalidateBatchingState(true);
}
else
gameObject.SetActive(false);
}
}
}
/// <summary>
///
/// </summary>
public float x
{
get { return cachedTransform.localPosition.x; }
set
{
SetPosition(value, -cachedTransform.localPosition.y, cachedTransform.localPosition.z);
}
}
/// <summary>
///
/// </summary>
public float y
{
get { return -cachedTransform.localPosition.y; }
set
{
SetPosition(cachedTransform.localPosition.x, value, cachedTransform.localPosition.z);
}
}
/// <summary>
///
/// </summary>
public float z
{
get { return cachedTransform.localPosition.z; }
set
{
SetPosition(cachedTransform.localPosition.x, -cachedTransform.localPosition.y, value);
}
}
/// <summary>
///
/// </summary>
public Vector2 xy
{
get { return new Vector2(this.x, this.y); }
set { SetPosition(value.x, value.y, cachedTransform.localPosition.z); }
}
/// <summary>
///
/// </summary>
public Vector3 position
{
get { return new Vector3(this.x, this.y, this.z); }
set { SetPosition(value.x, value.y, value.z); }
}
/// <summary>
///
/// </summary>
/// <param name="xv"></param>
/// <param name="yv"></param>
public void SetXY(float xv, float yv)
{
SetPosition(xv, yv, cachedTransform.localPosition.z);
}
/// <summary>
///
/// </summary>
/// <param name="xv"></param>
/// <param name="yv"></param>
/// <param name="zv"></param>
public void SetPosition(float xv, float yv, float zv)
{
Vector3 v = new Vector3();
v.x = xv;
v.y = -yv;
v.z = zv;
if (v != cachedTransform.localPosition)
{
cachedTransform.localPosition = v;
_flags |= Flags.OutlineChanged;
if ((_flags & Flags.PixelPerfect) != 0)
{
//总在下一帧再完成PixelPerfect这样当物体在连续运动时不会因为PixelPerfect而发生抖动。
_checkPixelPerfect = Time.frameCount;
_pixelPerfectAdjustment = Vector3.zero;
}
}
}
/// <summary>
/// If the object position is align by pixel
/// </summary>
public bool pixelPerfect
{
get { return (_flags & Flags.PixelPerfect) != 0; }
set
{
if (value)
_flags |= Flags.PixelPerfect;
else
_flags &= ~Flags.PixelPerfect;
}
}
/// <summary>
///
/// </summary>
public float width
{
get
{
EnsureSizeCorrect();
return _contentRect.width;
}
set
{
if (!Mathf.Approximately(value, _contentRect.width))
{
_contentRect.width = value;
_flags |= Flags.WidthChanged;
_flags &= ~Flags.HeightChanged;
OnSizeChanged();
}
}
}
/// <summary>
///
/// </summary>
public float height
{
get
{
EnsureSizeCorrect();
return _contentRect.height;
}
set
{
if (!Mathf.Approximately(value, _contentRect.height))
{
_contentRect.height = value;
_flags &= ~Flags.WidthChanged;
_flags |= Flags.HeightChanged;
OnSizeChanged();
}
}
}
/// <summary>
///
/// </summary>
public Vector2 size
{
get
{
EnsureSizeCorrect();
return _contentRect.size;
}
set
{
SetSize(value.x, value.y);
}
}
/// <summary>
///
/// </summary>
/// <param name="wv"></param>
/// <param name="hv"></param>
public void SetSize(float wv, float hv)
{
if (!Mathf.Approximately(wv, _contentRect.width))
_flags |= Flags.WidthChanged;
else
_flags &= ~Flags.WidthChanged;
if (!Mathf.Approximately(hv, _contentRect.height))
_flags |= Flags.HeightChanged;
else
_flags &= ~Flags.HeightChanged;
if ((_flags & Flags.WidthChanged) != 0 || (_flags & Flags.HeightChanged) != 0)
{
_contentRect.width = wv;
_contentRect.height = hv;
OnSizeChanged();
}
}
virtual public void EnsureSizeCorrect()
{
}
virtual protected void OnSizeChanged()
{
ApplyPivot();
if (_paintingInfo != null)
_paintingInfo.flag = 1;
if (graphics != null)
graphics.contentRect = _contentRect;
_flags |= Flags.OutlineChanged;
}
/// <summary>
///
/// </summary>
public float scaleX
{
get { return cachedTransform.localScale.x; }
set
{
Vector3 v = cachedTransform.localScale;
v.x = v.z = ValidateScale(value);
cachedTransform.localScale = v;
_flags |= Flags.OutlineChanged;
ApplyPivot();
}
}
/// <summary>
///
/// </summary>
public float scaleY
{
get { return cachedTransform.localScale.y; }
set
{
Vector3 v = cachedTransform.localScale;
v.y = ValidateScale(value);
cachedTransform.localScale = v;
_flags |= Flags.OutlineChanged;
ApplyPivot();
}
}
/// <summary>
///
/// </summary>
/// <param name="xv"></param>
/// <param name="yv"></param>
public void SetScale(float xv, float yv)
{
Vector3 v = new Vector3();
v.x = v.z = ValidateScale(xv);
v.y = ValidateScale(yv);
cachedTransform.localScale = v;
_flags |= Flags.OutlineChanged;
ApplyPivot();
}
/// <summary>
/// 在scale过小情况极端情况=0当使用Transform的坐标变换时变换到世界再从世界变换到本地会由于精度问题造成结果错误。
/// 这种错误会导致Batching错误因为Batching会使用缓存的outline。
/// 这里限制一下scale的最小值作为当前解决方案。
/// 这个方案并不完美因为限制了本地scale值并不能保证对世界scale不会过小。
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private float ValidateScale(float value)
{
if (value >= 0 && value < 0.001f)
value = 0.001f;
else if (value < 0 && value > -0.001f)
value = -0.001f;
return value;
}
/// <summary>
///
/// </summary>
public Vector2 scale
{
get { return cachedTransform.localScale; }
set
{
SetScale(value.x, value.y);
}
}
/// <summary>
///
/// </summary>
public float rotation
{
get
{
//和Unity默认的旋转方向相反
return -_rotation.z;
}
set
{
_rotation.z = -value;
_flags |= Flags.OutlineChanged;
if (_perspective)
UpdateTransformMatrix();
else
{
cachedTransform.localEulerAngles = _rotation;
ApplyPivot();
}
}
}
/// <summary>
///
/// </summary>
public float rotationX
{
get
{
return _rotation.x;
}
set
{
_rotation.x = value;
_flags |= Flags.OutlineChanged;
if (_perspective)
UpdateTransformMatrix();
else
{
cachedTransform.localEulerAngles = _rotation;
ApplyPivot();
}
}
}
/// <summary>
///
/// </summary>
public float rotationY
{
get
{
return _rotation.y;
}
set
{
_rotation.y = value;
_flags |= Flags.OutlineChanged;
if (_perspective)
UpdateTransformMatrix();
else
{
cachedTransform.localEulerAngles = _rotation;
ApplyPivot();
}
}
}
/// <summary>
///
/// </summary>
public Vector2 skew
{
get { return _skew; }
set
{
_skew = value;
_flags |= Flags.OutlineChanged;
if (!Application.isPlaying) //编辑期间不支持!!
return;
UpdateTransformMatrix();
}
}
/// <summary>
/// 当对象处于ScreenSpace也就是使用正交相机渲染时对象虽然可以绕X轴或者Y轴旋转但没有透视效果。设置perspective可以模拟出透视效果。
/// </summary>
public bool perspective
{
get
{
return _perspective;
}
set
{
if (_perspective != value)
{
_perspective = value;
if (_perspective)//屏蔽Unity自身的旋转变换
cachedTransform.localEulerAngles = Vector3.zero;
else
cachedTransform.localEulerAngles = _rotation;
ApplyPivot();
UpdateTransformMatrix();
}
}
}
/// <summary>
///
/// </summary>
public int focalLength
{
get { return _focalLength; }
set
{
if (value <= 0)
value = 1;
_focalLength = value;
if (_vertexMatrix != null)
UpdateTransformMatrix();
}
}
void UpdateTransformMatrix()
{
Matrix4x4 matrix = Matrix4x4.identity;
if (_skew.x != 0 || _skew.y != 0)
ToolSet.SkewMatrix(ref matrix, _skew.x, _skew.y);
if (_perspective)
matrix *= Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(_rotation), Vector3.one);
if (matrix.isIdentity)
_vertexMatrix = null;
else if (_vertexMatrix == null)
_vertexMatrix = new NGraphics.VertexMatrix();
//组件的transformMatrix是通过paintingMode实现的因为全部通过矩阵变换的话和unity自身的变换混杂在一起无力理清。
if (_vertexMatrix != null)
{
_vertexMatrix.matrix = matrix;
_vertexMatrix.cameraPos = new Vector3(_pivot.x * _contentRect.width, -_pivot.y * _contentRect.height, _focalLength);
if (graphics == null)
EnterPaintingMode(4, null);
}
else
{
if (graphics == null)
LeavePaintingMode(4);
}
if (_paintingMode > 0)
{
paintingGraphics.vertexMatrix = _vertexMatrix;
_paintingInfo.flag = 1;
}
else if (graphics != null)
graphics.vertexMatrix = _vertexMatrix;
_flags |= Flags.OutlineChanged;
}
/// <summary>
///
/// </summary>
public Vector2 pivot
{
get { return _pivot; }
set
{
Vector3 deltaPivot = new Vector2((value.x - _pivot.x) * _contentRect.width, (_pivot.y - value.y) * _contentRect.height);
Vector3 oldOffset = _pivotOffset;
_pivot = value;
UpdatePivotOffset();
Vector3 v = cachedTransform.localPosition;
v += oldOffset - _pivotOffset + deltaPivot;
cachedTransform.localPosition = v;
_flags |= Flags.OutlineChanged;
}
}
void UpdatePivotOffset()
{
float px = _pivot.x * _contentRect.width;
float py = _pivot.y * _contentRect.height;
//注意这里不用处理skew因为在顶点变换里有对pivot的处理
Matrix4x4 matrix = Matrix4x4.TRS(Vector3.zero, cachedTransform.localRotation, cachedTransform.localScale);
_pivotOffset = matrix.MultiplyPoint(new Vector3(px, -py, 0));
if (_vertexMatrix != null)
_vertexMatrix.cameraPos = new Vector3(_pivot.x * _contentRect.width, -_pivot.y * _contentRect.height, _focalLength);
}
void ApplyPivot()
{
if (_pivot.x != 0 || _pivot.y != 0)
{
Vector3 oldOffset = _pivotOffset;
UpdatePivotOffset();
Vector3 v = cachedTransform.localPosition;
if ((_flags & Flags.PixelPerfect) != 0)
{
v -= _pixelPerfectAdjustment;
_checkPixelPerfect = Time.frameCount;
_pixelPerfectAdjustment = Vector3.zero;
}
v += oldOffset - _pivotOffset;
cachedTransform.localPosition = v;
_flags |= Flags.OutlineChanged;
}
}
/// <summary>
/// This is the pivot position
/// </summary>
public Vector3 location
{
get
{
Vector3 pos = this.position;
pos.x += _pivotOffset.x;
pos.y -= _pivotOffset.y;
pos.z += _pivotOffset.z;
return pos;
}
set
{
this.SetPosition(value.x - _pivotOffset.x, value.y + _pivotOffset.y, value.z - _pivotOffset.z);
}
}
/// <summary>
///
/// </summary>
public Material material
{
get
{
if (graphics != null)
return graphics.material;
else
return null;
}
set
{
if (graphics != null)
graphics.material = value;
}
}
/// <summary>
///
/// </summary>
public string shader
{
get
{
if (graphics != null)
return graphics.shader;
else
return null;
}
set
{
if (graphics != null)
graphics.shader = value;
}
}
/// <summary>
///
/// </summary>
public int renderingOrder
{
get
{
return _renderingOrder;
}
}
virtual public void SetRenderingOrder(UpdateContext context, bool inBatch)
{
if ((_flags & Flags.GameObjectDisposed) != 0)
{
DisplayDisposedWarning();
return;
}
_renderingOrder = context.renderingOrder;
if (graphics != null)
graphics.SetRenderingOrder(context, inBatch);
else
context.renderingOrder++;
if (_paintingMode > 0)
paintingGraphics.renderingOrder = _renderingOrder;
}
/// <summary>
///
/// </summary>
public int layer
{
get
{
if (_paintingMode > 0)
return paintingGraphics.gameObject.layer;
else
return gameObject.layer;
}
set
{
SetLayer(value, false);
}
}
/// <summary>
/// If the object can be focused?
/// </summary>
public bool focusable
{
get { return (_flags & Flags.NotFocusable) == 0; }
set
{
if (value)
_flags &= ~Flags.NotFocusable;
else
_flags |= Flags.NotFocusable;
}
}
/// <summary>
/// If the object can be navigated by TAB?
/// </summary>
public bool tabStop
{
get { return (_flags & Flags.TabStop) != 0; }
set
{
if (value)
_flags |= Flags.TabStop;
else
_flags &= ~Flags.TabStop;
}
}
/// <summary>
/// If the object focused?
/// </summary>
public bool focused
{
get
{
return Stage.inst.focus == this || (this is Container) && ((Container)this).IsAncestorOf(Stage.inst.focus);
}
}
internal bool _AcceptTab()
{
if (_touchable && _visible
&& ((_flags & Flags.TabStop) != 0 || (_flags & Flags.TabStopChildren) != 0)
&& (_flags & Flags.NotFocusable) == 0)
{
Stage.inst.SetFocus(this, true);
return true;
}
else
return false;
}
/// <summary>
///
/// </summary>
/// <value></value>
public string cursor
{
get { return _cursor; }
set
{
_cursor = value;
if (Application.isPlaying
&& (this == Stage.inst.touchTarget || (this is Container) && ((Container)this).IsAncestorOf(Stage.inst.touchTarget)))
{
Stage.inst._ChangeCursor(_cursor);
}
}
}
/// <summary>
///
/// </summary>
public bool isDisposed
{
get { return (_flags & Flags.Disposed) != 0 || gameObject == null; }
}
internal void InternalSetParent(Container value)
{
if (parent != value)
{
if (value == null && (parent._flags & Flags.Disposed) != 0)
parent = value;
else
{
parent = value;
UpdateHierarchy();
}
_flags |= Flags.OutlineChanged;
}
}
/// <summary>
///
/// </summary>
public Container topmost
{
get
{
DisplayObject currentObject = this;
while (currentObject.parent != null)
currentObject = currentObject.parent;
return currentObject as Container;
}
}
/// <summary>
///
/// </summary>
public Stage stage
{
get
{
return topmost as Stage;
}
}
/// <summary>
///
/// </summary>
public Container worldSpaceContainer
{
get
{
Container wsc = null;
DisplayObject currentObject = this;
while (currentObject.parent != null)
{
if ((currentObject is Container) && ((Container)currentObject).renderMode == RenderMode.WorldSpace)
{
wsc = (Container)currentObject;
break;
}
currentObject = currentObject.parent;
}
return wsc;
}
}
/// <summary>
///
/// </summary>
public bool touchable
{
get { return _touchable; }
set
{
if (_touchable != value)
{
_touchable = value;
if (this is Container)
{
ColliderHitTest hitArea = ((Container)this).hitArea as ColliderHitTest;
if (hitArea != null)
hitArea.collider.enabled = value;
}
}
}
}
/// <summary>
///
/// </summary>
/// <value></value>
public bool touchDisabled
{
get { return (_flags & Flags.TouchDisabled) != 0; }
}
/// <summary>
/// 进入绘画模式整个对象将画到一张RenderTexture上然后这种贴图将代替原有的显示内容。
/// 可以在onPaint回调里对这张纹理进行进一步操作实现特殊效果。
/// </summary>
public void EnterPaintingMode()
{
EnterPaintingMode(16384, null, 1);
}
/// <summary>
/// 进入绘画模式整个对象将画到一张RenderTexture上然后这种贴图将代替原有的显示内容。
/// 可以在onPaint回调里对这张纹理进行进一步操作实现特殊效果。
/// 可能有多个地方要求进入绘画模式这里用requestorId加以区别取值是1、2、4、8、16以此类推。1024内内部保留。用户自定义的id从1024开始。
/// </summary>
/// <param name="requestId">请求者id</param>
/// <param name="extend">纹理四周的留空。如果特殊处理后的内容大于原内容,那么这里的设置可以使纹理扩大。</param>
public void EnterPaintingMode(int requestorId, Margin? extend)
{
EnterPaintingMode(requestorId, extend, 1);
}
/// <summary>
/// 进入绘画模式整个对象将画到一张RenderTexture上然后这种贴图将代替原有的显示内容。
/// 可以在onPaint回调里对这张纹理进行进一步操作实现特殊效果。
/// 可能有多个地方要求进入绘画模式这里用requestorId加以区别取值是1、2、4、8、16以此类推。1024内内部保留。用户自定义的id从1024开始。
/// </summary>
/// <param name="requestorId">请求者id</param>
/// <param name="extend">扩展纹理。如果特殊处理后的内容大于原内容,那么这里的设置可以使纹理扩大。</param>
/// <param name="scale">附加一个缩放系数</param>
public void EnterPaintingMode(int requestorId, Margin? extend, float scale)
{
bool first = _paintingMode == 0;
_paintingMode |= requestorId;
if (first)
{
if (_paintingInfo == null)
{
_paintingInfo = new PaintingInfo()
{
captureDelegate = Capture,
scale = 1
};
}
if (paintingGraphics == null)
{
if (graphics == null)
paintingGraphics = new NGraphics(this.gameObject);
else
{
GameObject go = new GameObject(this.gameObject.name + " (Painter)");
go.layer = this.gameObject.layer;
go.transform.SetParent(cachedTransform, false);
go.hideFlags = DisplayObject.hideFlags;
paintingGraphics = new NGraphics(go);
}
}
else
paintingGraphics.enabled = true;
paintingGraphics.vertexMatrix = null;
if (this is Container)
{
((Container)this).SetChildrenLayer(CaptureCamera.hiddenLayer);
((Container)this).UpdateBatchingFlags();
}
else
this.InvalidateBatchingState();
if (graphics != null)
_SetLayerDirect(CaptureCamera.hiddenLayer);
}
if (extend != null)
_paintingInfo.extend = (Margin)extend;
_paintingInfo.scale = scale;
_paintingInfo.flag = 1;
}
/// <summary>
/// 离开绘画模式
/// </summary>
/// <param name="requestId"></param>
public void LeavePaintingMode(int requestorId)
{
if (_paintingMode == 0 || (_flags & Flags.Disposed) != 0)
return;
_paintingMode ^= requestorId;
if (_paintingMode == 0)
{
paintingGraphics.enabled = false;
if (this is Container)
{
((Container)this).SetChildrenLayer(this.layer);
((Container)this).UpdateBatchingFlags();
}
else
this.InvalidateBatchingState();
if (graphics != null)
_SetLayerDirect(paintingGraphics.gameObject.layer);
}
}
/// <summary>
///
/// </summary>
public bool paintingMode
{
get { return _paintingMode > 0; }
}
/// <summary>
/// 将整个显示对象(如果是容器,则容器包含的整个显示列表)静态化,所有内容被缓冲到一张纹理上。
/// DC将保持为1。CPU消耗将降到最低。但对象的任何变化不会更新。
/// 当cacheAsBitmap已经为true时再次调用cacheAsBitmap=true将会刷新对象一次。
/// </summary>
public bool cacheAsBitmap
{
get { return (_flags & Flags.CacheAsBitmap) != 0; }
set
{
if (value)
{
_flags |= Flags.CacheAsBitmap;
EnterPaintingMode(8, null, UIContentScaler.scaleFactor);
}
else
{
_flags &= ~Flags.CacheAsBitmap;
LeavePaintingMode(8);
}
}
}
/// <summary>
///
/// </summary>
/// <param name="extend"></param>
/// <param name="scale"></param>
/// <returns></returns>
public Texture2D GetScreenShot(Margin? extend, float scale)
{
EnterPaintingMode(8, null, scale);
UpdatePainting();
Capture();
Texture2D output;
if (paintingGraphics.texture == null)
output = new Texture2D(1, 1, TextureFormat.RGBA32, false, true);
else
{
RenderTexture rt = (RenderTexture)paintingGraphics.texture.nativeTexture;
output = new Texture2D(rt.width, rt.height, TextureFormat.RGBA32, false, true);
RenderTexture old = RenderTexture.active;
RenderTexture.active = rt;
output.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
output.Apply();
RenderTexture.active = old;
}
LeavePaintingMode(8);
return output;
}
/// <summary>
///
/// </summary>
public IFilter filter
{
get
{
return _filter;
}
set
{
if (!Application.isPlaying) //编辑期间不支持!!
return;
if (value == _filter)
return;
if (_filter != null)
_filter.Dispose();
if (value != null && value.target != null)
value.target.filter = null;
_filter = value;
if (_filter != null)
_filter.target = this;
}
}
/// <summary>
///
/// </summary>
public BlendMode blendMode
{
get { return _blendMode; }
set
{
_blendMode = value;
InvalidateBatchingState();
if (graphics == null)
{
if (_blendMode != BlendMode.Normal)
{
if (!Application.isPlaying) //Not supported in edit mode
return;
EnterPaintingMode(2, null);
paintingGraphics.blendMode = _blendMode;
}
else
LeavePaintingMode(2);
}
else
graphics.blendMode = _blendMode;
}
}
/// <summary>
///
/// </summary>
/// <param name="targetSpace"></param>
/// <returns></returns>
virtual public Rect GetBounds(DisplayObject targetSpace)
{
EnsureSizeCorrect();
if (targetSpace == this) // optimization
{
return _contentRect;
}
else if (targetSpace == parent && _rotation.z == 0)
{
return new Rect(cachedTransform.localPosition.x, -cachedTransform.localPosition.y,
_contentRect.width * cachedTransform.localScale.x, _contentRect.height * cachedTransform.localScale.y);
}
else
return TransformRect(_contentRect, targetSpace);
}
internal DisplayObject InternalHitTest()
{
if (_visible && (!HitTestContext.forTouch || _touchable))
return HitTest();
else
return null;
}
internal DisplayObject InternalHitTestMask()
{
if (_visible)
return HitTest();
else
return null;
}
virtual protected DisplayObject HitTest()
{
Rect rect = GetBounds(this);
if (rect.width == 0 || rect.height == 0)
return null;
Vector2 localPoint = WorldToLocal(HitTestContext.worldPoint, HitTestContext.direction);
if (rect.Contains(localPoint))
return this;
else
return null;
}
/// <summary>
/// 将舞台坐标转换为本地坐标
/// </summary>
/// <param name="point"></param>
/// <returns></returns>
public Vector2 GlobalToLocal(Vector2 point)
{
Container wsc = this.worldSpaceContainer;
if (wsc != null)//I am in a world space
{
Camera cam = wsc.GetRenderCamera();
Vector3 worldPoint;
Vector3 direction;
Vector3 screenPoint = new Vector3();
screenPoint.x = point.x;
screenPoint.y = Screen.height - point.y;
if (wsc.hitArea is MeshColliderHitTest)
{
Ray ray = cam.ScreenPointToRay(screenPoint);
RaycastHit hit;
if (((MeshColliderHitTest)wsc.hitArea).collider.Raycast(ray, out hit, 100))
{
point = new Vector2(hit.textureCoord.x * _contentRect.width, (1 - hit.textureCoord.y) * _contentRect.height);
worldPoint = Stage.inst.cachedTransform.TransformPoint(point.x, -point.y, 0);
direction = Vector3.back;
}
else //当射线没有击中模型时,无法确定本地坐标
return new Vector2(float.NaN, float.NaN);
}
else
{
screenPoint.z = cam.WorldToScreenPoint(this.cachedTransform.position).z;
worldPoint = cam.ScreenToWorldPoint(screenPoint);
Ray ray = cam.ScreenPointToRay(screenPoint);
direction = Vector3.zero - ray.direction;
}
return this.WorldToLocal(worldPoint, direction);
}
else //I am in stage space
{
Vector3 worldPoint = Stage.inst.cachedTransform.TransformPoint(point.x, -point.y, 0);
return this.WorldToLocal(worldPoint, Vector3.back);
}
}
/// <summary>
/// 将本地坐标转换为舞台坐标
/// </summary>
/// <param name="point"></param>
/// <returns></returns>
public Vector2 LocalToGlobal(Vector2 point)
{
Container wsc = this.worldSpaceContainer;
Vector3 worldPoint = this.cachedTransform.TransformPoint(point.x, -point.y, 0);
if (wsc != null)
{
if (wsc.hitArea is MeshColliderHitTest) //Not supported for UIPainter, use TransfromPoint instead.
return new Vector2(float.NaN, float.NaN);
Vector3 screePoint = wsc.GetRenderCamera().WorldToScreenPoint(worldPoint);
return new Vector2(screePoint.x, Stage.inst.size.y - screePoint.y);
}
else
{
point = Stage.inst.cachedTransform.InverseTransformPoint(worldPoint);
point.y = -point.y;
return point;
}
}
/// <summary>
/// 转换世界坐标点到等效的本地xy平面的点。等效的意思是他们在屏幕方向看到的位置一样。
/// 返回的点是在对象的本地坐标空间且z=0
/// </summary>
/// <param name="worldPoint"></param>
/// <param name="direction"></param>
/// <returns></returns>
public Vector3 WorldToLocal(Vector3 worldPoint, Vector3 direction)
{
Vector3 localPoint = this.cachedTransform.InverseTransformPoint(worldPoint);
if (localPoint.z != 0) //如果对象绕x轴或y轴旋转过或者对象是在透视相机那么z值可能不为0
{
//将世界坐标的摄影机方向在本地空间上投射求出与xy平面的交点
direction = this.cachedTransform.InverseTransformDirection(direction);
float distOnLine = Vector3.Dot(Vector3.zero - localPoint, Vector3.forward) / Vector3.Dot(direction, Vector3.forward);
if (float.IsInfinity(distOnLine))
return Vector2.zero;
localPoint = localPoint + direction * distOnLine;
}
else if (_vertexMatrix != null)
{
Vector3 center = _vertexMatrix.cameraPos;
center.z = 0;
center -= _vertexMatrix.matrix.MultiplyPoint(center);
Matrix4x4 mm = _vertexMatrix.matrix.inverse;
localPoint -= center;
localPoint = mm.MultiplyPoint(localPoint);
Vector3 camPos = mm.MultiplyPoint(_vertexMatrix.cameraPos);
Vector3 vec = localPoint - camPos;
float lambda = -camPos.z / vec.z;
localPoint = camPos + lambda * vec;
localPoint.z = 0;
}
localPoint.y = -localPoint.y;
return localPoint;
}
/// <summary>
///
/// </summary>
/// <param name="localPoint"></param>
/// <returns></returns>
public Vector3 LocalToWorld(Vector3 localPoint)
{
localPoint.y = -localPoint.y;
if (_vertexMatrix != null)
{
Vector3 center = _vertexMatrix.cameraPos;
center.z = 0;
center -= _vertexMatrix.matrix.MultiplyPoint(center);
localPoint = _vertexMatrix.matrix.MultiplyPoint(localPoint);
localPoint += center;
Vector3 camPos = _vertexMatrix.cameraPos;
Vector3 vec = localPoint - camPos;
float lambda = -camPos.z / vec.z;
localPoint = camPos + lambda * vec;
localPoint.z = 0;
}
return this.cachedTransform.TransformPoint(localPoint);
}
/// <summary>
///
/// </summary>
/// <param name="point"></param>
/// <param name="targetSpace">null if to world space</param>
/// <returns></returns>
public Vector2 TransformPoint(Vector2 point, DisplayObject targetSpace)
{
if (targetSpace == this)
return point;
point = LocalToWorld(point);
if (targetSpace != null)
point = targetSpace.WorldToLocal(point, Vector3.back);
return point;
}
/// <summary>
///
/// </summary>
/// <param name="rect"></param>
/// <param name="targetSpace">null if to world space</param>
/// <returns></returns>
public Rect TransformRect(Rect rect, DisplayObject targetSpace)
{
if (targetSpace == this)
return rect;
if (targetSpace == parent && _rotation.z == 0) // optimization
{
Vector3 vec = cachedTransform.localScale;
return new Rect((this.x + rect.x) * vec.x, (this.y + rect.y) * vec.y,
rect.width * vec.x, rect.height * vec.y);
}
else
{
Vector4 vec4 = new Vector4(float.MaxValue, float.MaxValue, float.MinValue, float.MinValue);
TransformRectPoint(rect.xMin, rect.yMin, targetSpace, ref vec4);
TransformRectPoint(rect.xMax, rect.yMin, targetSpace, ref vec4);
TransformRectPoint(rect.xMin, rect.yMax, targetSpace, ref vec4);
TransformRectPoint(rect.xMax, rect.yMax, targetSpace, ref vec4);
return Rect.MinMaxRect(vec4.x, vec4.y, vec4.z, vec4.w);
}
}
protected void TransformRectPoint(float px, float py, DisplayObject targetSpace, ref Vector4 vec4)
{
Vector2 v = TransformPoint(new Vector2(px, py), targetSpace);
if (vec4.x > v.x) vec4.x = v.x;
if (vec4.z < v.x) vec4.z = v.x;
if (vec4.y > v.y) vec4.y = v.y;
if (vec4.w < v.y) vec4.w = v.y;
}
/// <summary>
///
/// </summary>
public void RemoveFromParent()
{
if (parent != null)
parent.RemoveChild(this);
}
/// <summary>
///
/// </summary>
public void InvalidateBatchingState()
{
if (parent != null)
parent.InvalidateBatchingState(true);
}
virtual public void Update(UpdateContext context)
{
if (_checkPixelPerfect != 0)
{
if (_rotation == Vector3.zero)
{
Vector3 v = cachedTransform.localPosition;
v.x = Mathf.Round(v.x);
v.y = Mathf.Round(v.y);
_pixelPerfectAdjustment = v - cachedTransform.localPosition;
if (_pixelPerfectAdjustment != Vector3.zero)
cachedTransform.localPosition = v;
}
_checkPixelPerfect = 0;
}
if (graphics != null)
graphics.Update(context, context.alpha * _alpha, context.grayed | _grayed);
if (_paintingMode != 0)
{
UpdatePainting();
//如果是容器Capture要等到Container.Update的最后执行因为容器中可能也有需要Capture的内容要等他们完成后再进行容器的Capture。
if (!(this is Container))
{
if ((_flags & Flags.CacheAsBitmap) == 0 || _paintingInfo.flag != 2)
UpdateContext.OnEnd += _paintingInfo.captureDelegate;
}
paintingGraphics.Update(context, 1, false);
}
if (_filter != null)
_filter.Update();
Stats.ObjectCount++;
}
void UpdatePainting()
{
NTexture paintingTexture = paintingGraphics.texture;
if (paintingTexture != null && paintingTexture.disposed) //Texture可能已被Stage.MonitorTexture销毁
{
paintingTexture = null;
_paintingInfo.flag = 1;
}
if (_paintingInfo.flag == 1)
{
_paintingInfo.flag = 0;
//从优化考虑决定使用绘画模式的容器都需要明确指定大小而不是自动计算包围。这在UI使用上并没有问题因为组件总是有固定大小的
Margin extend = _paintingInfo.extend;
paintingGraphics.contentRect = new Rect(-extend.left, -extend.top, _contentRect.width + extend.left + extend.right, _contentRect.height + extend.top + extend.bottom);
int textureWidth = Mathf.RoundToInt(paintingGraphics.contentRect.width * _paintingInfo.scale);
int textureHeight = Mathf.RoundToInt(paintingGraphics.contentRect.height * _paintingInfo.scale);
if (paintingTexture == null || paintingTexture.width != textureWidth || paintingTexture.height != textureHeight)
{
if (paintingTexture != null)
paintingTexture.Dispose();
if (textureWidth > 0 && textureHeight > 0)
{
paintingTexture = new NTexture(CaptureCamera.CreateRenderTexture(textureWidth, textureHeight, UIConfig.depthSupportForPaintingMode));
Stage.inst.MonitorTexture(paintingTexture);
}
else
paintingTexture = null;
paintingGraphics.texture = paintingTexture;
}
}
if (paintingTexture != null)
paintingTexture.lastActive = Time.time;
}
void Capture()
{
if (paintingGraphics.texture == null)
return;
Vector2 offset = new Vector2(_paintingInfo.extend.left, _paintingInfo.extend.top);
CaptureCamera.Capture(this, (RenderTexture)paintingGraphics.texture.nativeTexture, paintingGraphics.contentRect.height, offset);
_paintingInfo.flag = 2; //2表示已完成一次Capture
if (onPaint != null)
onPaint();
}
/// <summary>
/// 为对象设置一个默认的父Transform。当对象不在显示列表里时它的GameObject挂到哪里。
/// </summary>
public Transform home
{
get { return _home; }
set
{
_home = value;
if (value != null && cachedTransform.parent == null)
cachedTransform.SetParent(value, false);
}
}
void UpdateHierarchy()
{
if ((_flags & Flags.GameObjectDisposed) != 0)
return;
if ((_flags & Flags.UserGameObject) != 0)
{
//we dont change transform parent of this object
if (gameObject != null)
{
if (parent != null && visible)
gameObject.SetActive(true);
else
gameObject.SetActive(false);
}
}
else if (parent != null)
{
cachedTransform.SetParent(parent.cachedTransform, false);
if (_visible)
gameObject.SetActive(true);
int layerValue = parent.gameObject.layer;
if (parent._paintingMode != 0)
layerValue = CaptureCamera.hiddenLayer;
SetLayer(layerValue, true);
}
else if ((_flags & Flags.Disposed) == 0 && this.gameObject != null && !StageEngine.beingQuit)
{
if (Application.isPlaying)
{
if (gOwner == null || gOwner.parent == null)//如果gOwner还有parent的话说明只是暂时的隐藏
{
cachedTransform.SetParent(_home, false);
if (_home == null)
UnityEngine.Object.DontDestroyOnLoad(this.gameObject);
}
}
gameObject.SetActive(false);
}
}
virtual protected bool SetLayer(int value, bool fromParent)
{
if ((_flags & Flags.LayerSet) != 0) //setted
{
if (fromParent)
return false;
}
else if ((_flags & Flags.LayerFromParent) != 0) //inherit from parent
{
if (!fromParent)
_flags |= Flags.LayerSet;
}
else
{
if (fromParent)
_flags |= Flags.LayerFromParent;
else
_flags |= Flags.LayerSet;
}
if (_paintingMode > 0)
paintingGraphics.gameObject.layer = value;
else if (gameObject.layer != value)
{
_SetLayerDirect(value);
if (this is Container)
{
int cnt = ((Container)this).numChildren;
for (int i = 0; i < cnt; i++)
{
DisplayObject child = ((Container)this).GetChildAt(i);
child.SetLayer(value, true);
}
}
}
return true;
}
virtual internal void _SetLayerDirect(int value)
{
gameObject.layer = value;
if (graphics != null && graphics.subInstances != null)
{
foreach (var g in graphics.subInstances)
{
g.gameObject.layer = value;
}
}
}
virtual public void Dispose()
{
if ((_flags & Flags.Disposed) != 0)
return;
_flags |= Flags.Disposed;
RemoveFromParent();
RemoveEventListeners();
if (graphics != null)
graphics.Dispose();
if (_filter != null)
_filter.Dispose();
if (paintingGraphics != null)
{
if (paintingGraphics.texture != null)
paintingGraphics.texture.Dispose();
paintingGraphics.Dispose();
if (paintingGraphics.gameObject != this.gameObject)
{
if (Application.isPlaying)
UnityEngine.Object.Destroy(paintingGraphics.gameObject);
else
UnityEngine.Object.DestroyImmediate(paintingGraphics.gameObject);
}
}
DestroyGameObject();
}
internal void DisplayDisposedWarning()
{
if ((_flags & Flags.DisposedWarning) == 0)
{
_flags |= Flags.DisposedWarning;
StringBuilder sb = new StringBuilder();
sb.Append("DisplayObject is still in use but GameObject was disposed. (");
if (gOwner != null)
{
sb.Append("type=").Append(gOwner.GetType().Name).Append(", x=").Append(gOwner.x).Append(", y=").Append(gOwner.y).Append(", name=").Append(gOwner.name);
if (gOwner.packageItem != null)
sb.Append(", res=" + gOwner.packageItem.name);
}
else
{
sb.Append("id=").Append(id).Append(", type=").Append(this.GetType().Name).Append(", name=").Append(name);
}
sb.Append(")");
Debug.LogError(sb.ToString());
}
}
BatchElement _batchElement;
virtual public BatchElement AddToBatch(List<BatchElement> batchElements, bool force)
{
if (graphics != null || force)
{
if (_batchElement == null)
_batchElement = new BatchElement(this, null);
_batchElement.material = material;
_batchElement.breakBatch = (_flags & Flags.SkipBatching) != 0;
batchElements.Add(_batchElement);
if (graphics != null && graphics.subInstances != null)
{
foreach (var g in graphics.subInstances)
{
var m = g.material;
if (m != null)
{
var subBatchElement = g._batchElement;
if (subBatchElement == null)
subBatchElement = new BatchElement(g, _batchElement.bounds);
subBatchElement.material = m;
batchElements.Add(subBatchElement);
}
}
}
return _batchElement;
}
else
return null;
}
protected internal class PaintingInfo
{
public Action captureDelegate; //缓存这个delegate可以防止Capture状态下每帧104B的GC
public Margin extend;
public float scale;
public int flag;
}
[Flags]
public enum Flags
{
Disposed = 1,
UserGameObject = 2,
TouchDisabled = 4,
OutlineChanged = 8,
UpdatingSize = 0x10,
WidthChanged = 0x20,
HeightChanged = 0x40,
PixelPerfect = 0x80,
LayerSet = 0x100,
LayerFromParent = 0x200,
NotFocusable = 0x400,
TabStop = 0x800,
TabStopChildren = 0x1000,
FairyBatching = 0x2000,
BatchingRequested = 0x4000,
BatchingRoot = 0x8000,
SkipBatching = 0x10000,
CacheAsBitmap = 0x20000,
GameObjectDisposed = 0x40000,
DisposedWarning = 0x80000
}
}
/// <summary>
///
/// </summary>
public class DisplayObjectInfo : MonoBehaviour
{
/// <summary>
///
/// /// </summary>
[System.NonSerialized]
public DisplayObject displayObject;
private void OnDestroy()
{
if (displayObject != null)
displayObject._flags |= DisplayObject.Flags.GameObjectDisposed;
}
}
}