Newer
Older
exporter / FramePacker.as
package
{
	import flash.geom.*;
	import flash.display.*;
	public class FramePacker
	{
		private var sheets:Array;	// [RectanglePacker]
		private var frames:Array;	// [FrameInfo]
		public void FramePacker(frames:Array)
		{
			this.frames = frames.filter(function(i:FrameInfo) { return i.frame != null; });
		}
import Packer.RectanglePacker;
import Packer.RectangleNode;
		
		private function GetMaxSize(frames:Array):Point
		{
			if (frames.length == 0) return new Point();
			return new Point(Math.max.apply(Math, frames.map(function(i:FrameInfo) { return i.frame.width; })),
							 Math.max.apply(Math, frames.map(function(i:FrameInfo) { return i.frame.width; })));
		}
		
		private function GetArea(frames:Array):int
		{
			var area = 0;
			for (var i in frames)
			{
				if (frames[i] instanceof FrameInfo)
				{
					area += frames[i].frame.width * frames[i].frame.height;
				}
				if (frames[i] instanceof BitmapData || frames[i] instanceof Rectangle)
				{
					area += frames[i].width * frames[i].height;
				}
			}
			return area;
		}
		
		public const AreaUsedMultiplier = 1.3;		// guess how much more sheet space we use than actual space taken up by frames
		
		public function Pack():Boolean
		{
			sheets = new Array();
			var index = 0;
			while (index < frames.length)
			{
				var now:Array = frames.slice(index);
				
				var max:Point = GetMaxSize(now);
				var area:int = GetArea(now);
				
				var exponent = Math.floor(Math.log(area * AreaUsedMultiplier) / Math.log(2));
				var sizeX:int = Math.pow(2, exponent);
				var sizeY:int = startSizeX;
				
				var sheet:RectanglePacker = new RectanglePacker(sizeX, sizeY);
				
				var startIndex = index;
				while (index < frames.length)
				{
					var done = false;
					var nodes:Array = new Array();
					var sorted:Array = now.sortOn(now, Array.RETURNINDEXEDARRAY | Array.DESCENDING, function(a:FrameInfo, b:FrameInfo) { return (a.frame.width * a.frame.height) - (b.frame.width - b.frame.height); });
					for (var sortedI = 0; sortedI < now.length; sortedI++)
					{
						var i = nodes[sorted[sortedI]];
						var node:RectangleNode = sheet.Insert(now[i].frame.width, now[i].frame.height);
						if (node == null)
						{
							if (sortedI == 0)
							{
								Exporter.Instance.Print("Failure: item too large to pack on sheet");
								return false;
							}
							break;
						}
						else
						{
							nodes.push(node);
						}							
					}
					if (nodes.length == now.length)
					{
						// stop the loop, attempt the 75% check here
						index += nodes.length;
					}
					else
					{
						if (sizeX == sizeY)
						{
							sizeX *= 2;
						}
						else
						{
							sizeY *= 2;
						}
						if (sizeX > 2048 || sizeY > 2048)
						{
							index += now.length;
						}
					}
				}

				if (index > startIndex)
				{
					for (var i = startIndex; i < index; i++)
					{
						frames[i].sheetIndex = sheets.length;
						frames[i].rect = nodes[i - startIndex].Rect;
					}
					sheets.push(sheet);
				}				
			}
			
			return output;
		}
		
		private function PackFrames(toPack:Array, sizeX:int, sizeY:int):Array
		{
			
		}
	}
}