DisplayObject.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace CommonLang.Geometry.SceneGraph2D
  6. {
  7. public class DisplayNode : IDisposable
  8. {
  9. public string Name { get; set; }
  10. public DisplayNode()
  11. {
  12. }
  13. //-------------------------------------------------------------------------------------------------------------
  14. #region Tint
  15. public float Alpha { get; set; }
  16. /// <summary>
  17. /// Color RGB
  18. /// </summary>
  19. public uint Color { get; set; }
  20. #endregion
  21. //-------------------------------------------------------------------------------------------------------------
  22. #region Transform
  23. private ITransform transform = Factory.Instance.CreateTransform();
  24. private Vector2[] temp_pts = new Vector2[1];
  25. public Vector2 Translation
  26. {
  27. get { return transform.Translation; }
  28. set { transform.Translation = value; }
  29. }
  30. public float Rotation
  31. {
  32. get { return transform.Rotation; }
  33. set { transform.Rotation = value; }
  34. }
  35. public Vector2 Scale
  36. {
  37. get { return transform.Scale; }
  38. set { transform.Scale = value; }
  39. }
  40. public Vector2 LocalToParent(Vector2 p)
  41. {
  42. temp_pts[0] = p;
  43. transform.LocalToParent(temp_pts);
  44. return temp_pts[0];
  45. }
  46. public Vector2 ParentToLocal(Vector2 p)
  47. {
  48. temp_pts[0] = p;
  49. transform.ParentToLocal(temp_pts);
  50. return temp_pts[0];
  51. }
  52. public Vector2 LocalToRoot(Vector2 p)
  53. {
  54. temp_pts[0] = p;
  55. this.TransformLocalToRoot(temp_pts);
  56. return temp_pts[0];
  57. }
  58. public Vector2 RootToLocal(Vector2 p)
  59. {
  60. temp_pts[0] = p;
  61. this.TransformRootToLocal(temp_pts);
  62. return temp_pts[0];
  63. }
  64. /// <summary>
  65. /// 本地坐标转换为父节点坐标
  66. /// </summary>
  67. public void TransformLocalToParent(Vector2[] pts)
  68. {
  69. transform.LocalToParent(pts);
  70. }
  71. /// <summary>
  72. /// 父节点坐标转换为本地坐标
  73. /// </summary>
  74. public void TransformParentToLocal(Vector2[] pts)
  75. {
  76. transform.ParentToLocal(pts);
  77. }
  78. /// <summary>
  79. /// 屏幕坐标转换为本地坐标
  80. /// </summary>
  81. public void TransformRootToLocal(Vector2[] pts)
  82. {
  83. if (parent != null)
  84. {
  85. using (var path = ListObjectPool<DisplayNode>.AllocAutoRelease())
  86. {
  87. SceneGraphTreePath(path);
  88. foreach (var node in path)
  89. {
  90. node.transform.ParentToLocal(pts);
  91. }
  92. }
  93. }
  94. }
  95. /// <summary>
  96. /// 本地坐标转换为屏幕坐标
  97. /// </summary>
  98. public void TransformLocalToRoot(Vector2[] pts)
  99. {
  100. if (parent != null)
  101. {
  102. var curnode = this;
  103. do
  104. {
  105. curnode.transform.LocalToParent(pts);
  106. curnode = curnode.Parent;
  107. }
  108. while (curnode != null);
  109. }
  110. }
  111. #endregion
  112. //-------------------------------------------------------------------------------------------------------------
  113. #region IDisposable
  114. private bool disposedValue = false; // 要检测冗余调用
  115. protected virtual void Dispose(bool disposing)
  116. {
  117. if (!disposedValue)
  118. {
  119. if (disposing)
  120. {
  121. // TODO: 释放托管状态(托管对象)。
  122. }
  123. // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
  124. // TODO: 将大型字段设置为 null。
  125. disposedValue = true;
  126. }
  127. }
  128. // TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
  129. // ~DisplayNode() {
  130. // // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
  131. // Dispose(false);
  132. // }
  133. // 添加此代码以正确实现可处置模式。
  134. public void Dispose()
  135. {
  136. // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
  137. Dispose(true);
  138. // TODO: 如果在以上内容中替代了终结器,则取消注释以下行。
  139. // GC.SuppressFinalize(this);
  140. }
  141. #endregion
  142. //-------------------------------------------------------------------------------------------------------------
  143. #region Children
  144. private readonly List<DisplayNode> children = new List<DisplayNode>();
  145. internal DisplayNode parent;
  146. public DisplayNode Parent { get { return parent; } }
  147. public int NumChildren { get { return children.Count; } }
  148. public DisplayRoot Root
  149. {
  150. get
  151. {
  152. var currentObject = this;
  153. do
  154. {
  155. if (currentObject is DisplayRoot)
  156. {
  157. return currentObject as DisplayRoot;
  158. }
  159. currentObject = currentObject.parent;
  160. }
  161. while (currentObject != null);
  162. return null;
  163. }
  164. }
  165. internal void InternalSetParent(DisplayNode node)
  166. {
  167. // check for a recursion
  168. DisplayNode ancestor = node;
  169. while (ancestor != this && ancestor != null)
  170. ancestor = ancestor.parent;
  171. if (ancestor == this)
  172. throw new Exception("An object cannot be added as a child to itself or one of its children (or children's children, etc.)");
  173. else
  174. parent = node;
  175. }
  176. internal void InternalAddChild(DisplayNode child, int index)
  177. {
  178. child.RemoveFromParent();
  179. child.InternalSetParent(this);
  180. children.Insert(index, child);
  181. }
  182. internal void InternalRemoveChild(DisplayNode child, bool dispose)
  183. {
  184. children.Remove(child);
  185. child.parent = null;
  186. }
  187. public bool ContainsChild(DisplayNode child)
  188. {
  189. while (child != null)
  190. {
  191. if (child == this)
  192. return true;
  193. else
  194. child = child.Parent;
  195. }
  196. return false;
  197. }
  198. public void AddChildAt(DisplayNode child, int index)
  199. {
  200. if (child == null || index < 0)
  201. {
  202. //LogError("AddChildAt Error :Child can not be null or index < 0");
  203. return;
  204. }
  205. if (child.Parent == this)
  206. {
  207. SetChildIndex(child, index);
  208. }
  209. else
  210. {
  211. InternalAddChild(child, index);
  212. }
  213. }
  214. public void AddChild(DisplayNode child)
  215. {
  216. AddChildAt(child, NumChildren);
  217. }
  218. public void RemoveChildByName(string name, bool dispose = true)
  219. {
  220. foreach (DisplayNode child in children)
  221. {
  222. if (child.Name.Equals(name))
  223. {
  224. InternalRemoveChild(child, dispose);
  225. break;
  226. }
  227. }
  228. }
  229. public void RemoveChild(DisplayNode child, bool dispose = true)
  230. {
  231. int result = children.IndexOf(child);
  232. if (result != -1)
  233. {
  234. RemoveChildAt(result, dispose);
  235. }
  236. }
  237. public void RemoveChildAt(int index, bool dispose = true)
  238. {
  239. if (index >= 0 && index < children.Count)
  240. {
  241. DisplayNode child = children[index];
  242. if (child.parent == this)
  243. {
  244. InternalRemoveChild(child, dispose);
  245. }
  246. }
  247. else
  248. {
  249. throw new Exception("RemoveChild Error :: mChildren Out of Bounds");
  250. }
  251. }
  252. public void RemoveChildren(int beginIndex, int endIndex, bool dispose = true)
  253. {
  254. if (endIndex < 0 || endIndex >= NumChildren)
  255. endIndex = NumChildren - 1;
  256. for (int i = beginIndex; i <= endIndex; ++i)
  257. RemoveChildAt(beginIndex, dispose);
  258. }
  259. public void RemoveAllChildren(bool dispose = true)
  260. {
  261. RemoveChildren(0, -1, dispose);
  262. }
  263. public void RemoveFromParent(bool dispose = true)
  264. {
  265. if (parent != null)
  266. {
  267. parent.RemoveChild(this, dispose);
  268. }
  269. }
  270. public void SetChildIndex(DisplayNode child, int index)
  271. {
  272. int oldIndex = GetChildIndex(child);
  273. if (oldIndex == -1)
  274. {
  275. //LogError("SetChildIndex Error: oldIndex = -1");
  276. return;
  277. }
  278. //logic list.
  279. children.RemoveAt(oldIndex);
  280. if (index > children.Count)
  281. {
  282. index = children.Count;
  283. }
  284. children.Insert(index, child);
  285. }
  286. public int GetChildIndex(DisplayNode child)
  287. {
  288. if (child == null)
  289. {
  290. //LogError("UIBase GetChildIndex() child == null");
  291. return -1;
  292. }
  293. return children.IndexOf(child);
  294. }
  295. public DisplayNode GetChildAt(int index)
  296. {
  297. if (index >= 0 && index < NumChildren)
  298. return children[index];
  299. else
  300. throw new Exception("Invalid child index");
  301. }
  302. public void SwapChildren(DisplayNode child1, DisplayNode child2)
  303. {
  304. int index1 = GetChildIndex(child1);
  305. int index2 = GetChildIndex(child2);
  306. if (index1 == -1 || index2 == -1)
  307. throw new Exception("Not a child of this container");
  308. SwapChildrenAt(index1, index2);
  309. }
  310. public void SwapChildrenAt(int index1, int index2)
  311. {
  312. DisplayNode child1 = GetChildAt(index1);
  313. DisplayNode child2 = GetChildAt(index2);
  314. if (child1 != null && child2 != null)
  315. {
  316. children[index1] = child2;
  317. children[index2] = child1;
  318. }
  319. }
  320. /// <summary>
  321. /// 获取所有节点
  322. /// </summary>
  323. /// <param name="list"></param>
  324. /// <param name="recursion"></param>
  325. public void GetChildren(List<DisplayNode> list, bool recursion = false)
  326. {
  327. list.AddRange(children);
  328. if (recursion)
  329. {
  330. foreach (var c in children)
  331. {
  332. c.GetChildren(list, recursion);
  333. }
  334. }
  335. }
  336. /// <summary>
  337. /// 获取场景数路径,从当前节点一直到根节点
  338. /// </summary>
  339. public void SceneGraphTreePath(List<DisplayNode> ret)
  340. {
  341. var curnode = this;
  342. do
  343. {
  344. ret.Insert(0, curnode);
  345. curnode = curnode.Parent;
  346. }
  347. while (curnode != null);
  348. }
  349. #endregion
  350. //-------------------------------------------------------------------------------------------------------------
  351. #region Visit
  352. /// <summary>
  353. /// 遍历所有节点
  354. /// </summary>
  355. /// <param name="action">return true for break</param>
  356. /// <param name="recursion"></param>
  357. public bool ForEachChildren(Predicate<DisplayNode> action, bool recursion = false)
  358. {
  359. using (var list = ListObjectPool<DisplayNode>.AllocAutoRelease())
  360. {
  361. list.AddRange(children);
  362. for (int i = 0; i < list.Count; ++i)
  363. {
  364. if (action(list[i])) { return true; }
  365. }
  366. if (recursion)
  367. {
  368. for (int i = 0; i < list.Count; ++i)
  369. {
  370. if (list[i].ForEachChildren(action, recursion))
  371. {
  372. return true;
  373. }
  374. }
  375. }
  376. }
  377. return false;
  378. }
  379. public virtual void Visit(IGraphics g)
  380. {
  381. g.PushTransform();
  382. try
  383. {
  384. g.Transform(this.transform);
  385. OnDrawBegin(g);
  386. for (int i = 0; i < children.Count; ++i)
  387. {
  388. children[i].Visit(g);
  389. }
  390. OnDrawAfter(g);
  391. }
  392. finally
  393. {
  394. g.PopTransform();
  395. }
  396. }
  397. /// <summary>
  398. /// 子节点前渲染
  399. /// </summary>
  400. /// <param name="g"></param>
  401. protected virtual void OnDrawBegin(IGraphics g) { }
  402. /// <summary>
  403. /// 子节点后渲染
  404. /// </summary>
  405. /// <param name="g"></param>
  406. protected virtual void OnDrawAfter(IGraphics g) { }
  407. public virtual DisplayNode HitTest(Vector2 point)
  408. {
  409. for (int i = children.Count - 1; i >= 0; --i)
  410. {
  411. var child = children[i];
  412. temp_pts[0] = point;
  413. var local = child.ParentToLocal(point);
  414. var hit = child.HitTest(local);
  415. if (hit != null)
  416. {
  417. return hit;
  418. }
  419. }
  420. if (OnHitTest(ref point))
  421. {
  422. return this;
  423. }
  424. return null;
  425. }
  426. protected virtual bool OnHitTest(ref Vector2 localPoint) { return false; }
  427. #endregion
  428. }
  429. }