using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CommonLang.Geometry.SceneGraph2D
{
public class DisplayNode : IDisposable
{
public string Name { get; set; }
public DisplayNode()
{
}
//-------------------------------------------------------------------------------------------------------------
#region Tint
public float Alpha { get; set; }
///
/// Color RGB
///
public uint Color { get; set; }
#endregion
//-------------------------------------------------------------------------------------------------------------
#region Transform
private ITransform transform = Factory.Instance.CreateTransform();
private Vector2[] temp_pts = new Vector2[1];
public Vector2 Translation
{
get { return transform.Translation; }
set { transform.Translation = value; }
}
public float Rotation
{
get { return transform.Rotation; }
set { transform.Rotation = value; }
}
public Vector2 Scale
{
get { return transform.Scale; }
set { transform.Scale = value; }
}
public Vector2 LocalToParent(Vector2 p)
{
temp_pts[0] = p;
transform.LocalToParent(temp_pts);
return temp_pts[0];
}
public Vector2 ParentToLocal(Vector2 p)
{
temp_pts[0] = p;
transform.ParentToLocal(temp_pts);
return temp_pts[0];
}
public Vector2 LocalToRoot(Vector2 p)
{
temp_pts[0] = p;
this.TransformLocalToRoot(temp_pts);
return temp_pts[0];
}
public Vector2 RootToLocal(Vector2 p)
{
temp_pts[0] = p;
this.TransformRootToLocal(temp_pts);
return temp_pts[0];
}
///
/// 本地坐标转换为父节点坐标
///
public void TransformLocalToParent(Vector2[] pts)
{
transform.LocalToParent(pts);
}
///
/// 父节点坐标转换为本地坐标
///
public void TransformParentToLocal(Vector2[] pts)
{
transform.ParentToLocal(pts);
}
///
/// 屏幕坐标转换为本地坐标
///
public void TransformRootToLocal(Vector2[] pts)
{
if (parent != null)
{
using (var path = ListObjectPool.AllocAutoRelease())
{
SceneGraphTreePath(path);
foreach (var node in path)
{
node.transform.ParentToLocal(pts);
}
}
}
}
///
/// 本地坐标转换为屏幕坐标
///
public void TransformLocalToRoot(Vector2[] pts)
{
if (parent != null)
{
var curnode = this;
do
{
curnode.transform.LocalToParent(pts);
curnode = curnode.Parent;
}
while (curnode != null);
}
}
#endregion
//-------------------------------------------------------------------------------------------------------------
#region IDisposable
private bool disposedValue = false; // 要检测冗余调用
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// TODO: 释放托管状态(托管对象)。
}
// TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
// TODO: 将大型字段设置为 null。
disposedValue = true;
}
}
// TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
// ~DisplayNode() {
// // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
// Dispose(false);
// }
// 添加此代码以正确实现可处置模式。
public void Dispose()
{
// 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
Dispose(true);
// TODO: 如果在以上内容中替代了终结器,则取消注释以下行。
// GC.SuppressFinalize(this);
}
#endregion
//-------------------------------------------------------------------------------------------------------------
#region Children
private readonly List children = new List();
internal DisplayNode parent;
public DisplayNode Parent { get { return parent; } }
public int NumChildren { get { return children.Count; } }
public DisplayRoot Root
{
get
{
var currentObject = this;
do
{
if (currentObject is DisplayRoot)
{
return currentObject as DisplayRoot;
}
currentObject = currentObject.parent;
}
while (currentObject != null);
return null;
}
}
internal void InternalSetParent(DisplayNode node)
{
// check for a recursion
DisplayNode ancestor = node;
while (ancestor != this && ancestor != null)
ancestor = ancestor.parent;
if (ancestor == this)
throw new Exception("An object cannot be added as a child to itself or one of its children (or children's children, etc.)");
else
parent = node;
}
internal void InternalAddChild(DisplayNode child, int index)
{
child.RemoveFromParent();
child.InternalSetParent(this);
children.Insert(index, child);
}
internal void InternalRemoveChild(DisplayNode child, bool dispose)
{
children.Remove(child);
child.parent = null;
}
public bool ContainsChild(DisplayNode child)
{
while (child != null)
{
if (child == this)
return true;
else
child = child.Parent;
}
return false;
}
public void AddChildAt(DisplayNode child, int index)
{
if (child == null || index < 0)
{
//LogError("AddChildAt Error :Child can not be null or index < 0");
return;
}
if (child.Parent == this)
{
SetChildIndex(child, index);
}
else
{
InternalAddChild(child, index);
}
}
public void AddChild(DisplayNode child)
{
AddChildAt(child, NumChildren);
}
public void RemoveChildByName(string name, bool dispose = true)
{
foreach (DisplayNode child in children)
{
if (child.Name.Equals(name))
{
InternalRemoveChild(child, dispose);
break;
}
}
}
public void RemoveChild(DisplayNode child, bool dispose = true)
{
int result = children.IndexOf(child);
if (result != -1)
{
RemoveChildAt(result, dispose);
}
}
public void RemoveChildAt(int index, bool dispose = true)
{
if (index >= 0 && index < children.Count)
{
DisplayNode child = children[index];
if (child.parent == this)
{
InternalRemoveChild(child, dispose);
}
}
else
{
throw new Exception("RemoveChild Error :: mChildren Out of Bounds");
}
}
public void RemoveChildren(int beginIndex, int endIndex, bool dispose = true)
{
if (endIndex < 0 || endIndex >= NumChildren)
endIndex = NumChildren - 1;
for (int i = beginIndex; i <= endIndex; ++i)
RemoveChildAt(beginIndex, dispose);
}
public void RemoveAllChildren(bool dispose = true)
{
RemoveChildren(0, -1, dispose);
}
public void RemoveFromParent(bool dispose = true)
{
if (parent != null)
{
parent.RemoveChild(this, dispose);
}
}
public void SetChildIndex(DisplayNode child, int index)
{
int oldIndex = GetChildIndex(child);
if (oldIndex == -1)
{
//LogError("SetChildIndex Error: oldIndex = -1");
return;
}
//logic list.
children.RemoveAt(oldIndex);
if (index > children.Count)
{
index = children.Count;
}
children.Insert(index, child);
}
public int GetChildIndex(DisplayNode child)
{
if (child == null)
{
//LogError("UIBase GetChildIndex() child == null");
return -1;
}
return children.IndexOf(child);
}
public DisplayNode GetChildAt(int index)
{
if (index >= 0 && index < NumChildren)
return children[index];
else
throw new Exception("Invalid child index");
}
public void SwapChildren(DisplayNode child1, DisplayNode child2)
{
int index1 = GetChildIndex(child1);
int index2 = GetChildIndex(child2);
if (index1 == -1 || index2 == -1)
throw new Exception("Not a child of this container");
SwapChildrenAt(index1, index2);
}
public void SwapChildrenAt(int index1, int index2)
{
DisplayNode child1 = GetChildAt(index1);
DisplayNode child2 = GetChildAt(index2);
if (child1 != null && child2 != null)
{
children[index1] = child2;
children[index2] = child1;
}
}
///
/// 获取所有节点
///
///
///
public void GetChildren(List list, bool recursion = false)
{
list.AddRange(children);
if (recursion)
{
foreach (var c in children)
{
c.GetChildren(list, recursion);
}
}
}
///
/// 获取场景数路径,从当前节点一直到根节点
///
public void SceneGraphTreePath(List ret)
{
var curnode = this;
do
{
ret.Insert(0, curnode);
curnode = curnode.Parent;
}
while (curnode != null);
}
#endregion
//-------------------------------------------------------------------------------------------------------------
#region Visit
///
/// 遍历所有节点
///
/// return true for break
///
public bool ForEachChildren(Predicate action, bool recursion = false)
{
using (var list = ListObjectPool.AllocAutoRelease())
{
list.AddRange(children);
for (int i = 0; i < list.Count; ++i)
{
if (action(list[i])) { return true; }
}
if (recursion)
{
for (int i = 0; i < list.Count; ++i)
{
if (list[i].ForEachChildren(action, recursion))
{
return true;
}
}
}
}
return false;
}
public virtual void Visit(IGraphics g)
{
g.PushTransform();
try
{
g.Transform(this.transform);
OnDrawBegin(g);
for (int i = 0; i < children.Count; ++i)
{
children[i].Visit(g);
}
OnDrawAfter(g);
}
finally
{
g.PopTransform();
}
}
///
/// 子节点前渲染
///
///
protected virtual void OnDrawBegin(IGraphics g) { }
///
/// 子节点后渲染
///
///
protected virtual void OnDrawAfter(IGraphics g) { }
public virtual DisplayNode HitTest(Vector2 point)
{
for (int i = children.Count - 1; i >= 0; --i)
{
var child = children[i];
temp_pts[0] = point;
var local = child.ParentToLocal(point);
var hit = child.HitTest(local);
if (hit != null)
{
return hit;
}
}
if (OnHitTest(ref point))
{
return this;
}
return null;
}
protected virtual bool OnHitTest(ref Vector2 localPoint) { return false; }
#endregion
}
}