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 } }