/src/away3d/core/sort/RenderableMergeSort.as

http://github.com/away3d/away3d-core-fp11 · ActionScript · 184 lines · 131 code · 32 blank · 21 comment · 46 complexity · 343a712e669f6dfafa1cd8ccd84b2c6f MD5 · raw file

  1. package away3d.core.sort
  2. {
  3. import away3d.arcane;
  4. import away3d.core.data.RenderableListItem;
  5. import away3d.core.traverse.EntityCollector;
  6. use namespace arcane;
  7. /**
  8. * RenderableSorter sorts the potentially visible IRenderable objects collected by EntityCollector for optimal
  9. * rendering performance. Objects are sorted first by material, then by distance to the camera. Opaque objects
  10. * are sorted front to back, while objects that require blending are sorted back to front, to ensure correct
  11. * blending.
  12. */
  13. public class RenderableMergeSort implements IEntitySorter
  14. {
  15. /**
  16. * Creates a RenderableSorter objects
  17. */
  18. public function RenderableMergeSort()
  19. {
  20. }
  21. /**
  22. * @inheritDoc
  23. */
  24. public function sort(collector:EntityCollector):void
  25. {
  26. collector.opaqueRenderableHead = mergeSortByMaterial(collector.opaqueRenderableHead);
  27. collector.blendedRenderableHead = mergeSortByDepth(collector.blendedRenderableHead);
  28. }
  29. private function mergeSortByDepth(head:RenderableListItem):RenderableListItem
  30. {
  31. var headB:RenderableListItem;
  32. var fast:RenderableListItem, slow:RenderableListItem;
  33. if (!head || !head.next)
  34. return head;
  35. // split in two sublists
  36. slow = head;
  37. fast = head.next;
  38. while (fast) {
  39. fast = fast.next;
  40. if (fast) {
  41. slow = slow.next;
  42. fast = fast.next;
  43. }
  44. }
  45. headB = slow.next;
  46. slow.next = null;
  47. // recurse
  48. head = mergeSortByDepth(head);
  49. headB = mergeSortByDepth(headB);
  50. // merge sublists while respecting order
  51. var result:RenderableListItem;
  52. var curr:RenderableListItem;
  53. var l:RenderableListItem;
  54. if (!head)
  55. return headB;
  56. if (!headB)
  57. return head;
  58. while (head && headB && head != null && headB != null) {
  59. if (head.zIndex < headB.zIndex) {
  60. l = head;
  61. head = head.next;
  62. } else {
  63. l = headB;
  64. headB = headB.next;
  65. }
  66. if (!result)
  67. result = l;
  68. else
  69. curr.next = l;
  70. curr = l;
  71. }
  72. if (head)
  73. curr.next = head;
  74. else if (headB)
  75. curr.next = headB;
  76. return result;
  77. }
  78. private function mergeSortByMaterial(head:RenderableListItem):RenderableListItem
  79. {
  80. var headB:RenderableListItem;
  81. var fast:RenderableListItem, slow:RenderableListItem;
  82. if (!head || !head.next)
  83. return head;
  84. // split in two sublists
  85. slow = head;
  86. fast = head.next;
  87. while (fast) {
  88. fast = fast.next;
  89. if (fast) {
  90. slow = slow.next;
  91. fast = fast.next;
  92. }
  93. }
  94. headB = slow.next;
  95. slow.next = null;
  96. // recurse
  97. head = mergeSortByMaterial(head);
  98. headB = mergeSortByMaterial(headB);
  99. // merge sublists while respecting order
  100. var result:RenderableListItem;
  101. var curr:RenderableListItem;
  102. var l:RenderableListItem;
  103. var cmp:int;
  104. if (!head)
  105. return headB;
  106. if (!headB)
  107. return head;
  108. while (head && headB && head != null && headB != null) {
  109. // first sort per render order id (reduces program3D switches),
  110. // then on material id (reduces setting props),
  111. // then on zIndex (reduces overdraw)
  112. var aid:uint = head.renderOrderId;
  113. var bid:uint = headB.renderOrderId;
  114. if (aid == bid) {
  115. var ma:uint = head.materialId;
  116. var mb:uint = headB.materialId;
  117. if (ma == mb) {
  118. if (head.zIndex < headB.zIndex)
  119. cmp = 1;
  120. else
  121. cmp = -1;
  122. } else if (ma > mb)
  123. cmp = 1;
  124. else
  125. cmp = -1;
  126. } else if (aid > bid)
  127. cmp = 1;
  128. else
  129. cmp = -1;
  130. if (cmp < 0) {
  131. l = head;
  132. head = head.next;
  133. } else {
  134. l = headB;
  135. headB = headB.next;
  136. }
  137. if (!result) {
  138. result = l;
  139. curr = l;
  140. } else {
  141. curr.next = l;
  142. curr = l;
  143. }
  144. }
  145. if (head)
  146. curr.next = head;
  147. else if (headB)
  148. curr.next = headB;
  149. return result;
  150. }
  151. }
  152. }