PageRenderTime 404ms CodeModel.GetById 180ms app.highlight 9ms RepoModel.GetById 212ms app.codeStats 0ms

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