MaxRectsBinPack + Compact
< Cheating with initial box sizes to avoid interstitial spaces. >
+ benchmarking of the different packing methods
/**
* Copyright FLASHMAFIA ( http://wonderfl.net/user/FLASHMAFIA )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/5l6A
*/
package {
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.utils.getTimer;
[SWF(width = '465', height = '465')]
public class BinPack extends Sprite//
{
private const NUM_BOXES : uint = 700;
private const METHOD_NAME : Vector.<String> = Vector.<String>(['BSSF', 'BLSF', 'BAF', 'BL', 'CP']);
/* */
private var pack : MaxRectsBinPack = new MaxRectsBinPack();
private var dtf : DOSTxT = new DOSTxT(465, 32, 0x282624, 0xA8A6A4);
private var msg : Vector.<String> = new Vector.<String>(3, true);
private var boxes : Vector.<Node> = new Vector.<Node>(NUM_BOXES, true);
private var curMethod : int = (5 * Math.random()) >> 0;
private var fcnt : int;
public function BinPack() {
/* */
stage.stageFocusRect = tabChildren = tabEnabled = mouseChildren = mouseEnabled = false;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.LOW;
stage.frameRate = 16;
opaqueBackground = 0x0;
/* */
var i : int = boxes.length;
while (i-- != 0) {
var w : int = (1 << (3 + ((3 * Math.random()) >> 0)));
var h : int = (1 << (3 + ((3 * Math.random()) >> 0)));
boxes[i] = new Node(0, 0, w, h);
}
var bm : Bitmap = new Bitmap(dtf);
bm.opaqueBackground = 0x0;
addChild(bm);
stage.addEventListener(Event.ENTER_FRAME, oef);
}
private function oef(e : Event) : void//
{
fcnt++;
if ((fcnt & 63) == 1) {
graphics.clear();
graphics.beginFill(0x181410);
graphics.drawRect(0, dtf.height, 465, 465);
graphics.endFill();
}
if ((fcnt & 63) == 3) {
if (++curMethod > 4) curMethod = 0;
pack.reset(465, 465 - dtf.height, false);
/* process */
var startTime : int = getTimer();
for each (var box : Node in boxes) {
var node : Node = pack.insert(box.width, box.height, curMethod);
if ((node.width == 0) || (node.height == 0)) break;
}
var elapsed : int = getTimer() - startTime;
/* draw */
var len : uint = pack.usedRectangles.length;
var i : uint = len;
while (i-- != 0) {
node = pack.usedRectangles[i];
var lum : uint = 0x60 + (0x80 * (i / len));
var c : uint = ((lum + 2) << 16) | ((lum) << 8) | (lum - 2);
graphics.lineStyle(0, c, 1.0, false, 'none', 'none');
lum ^= 0xFF;
c = ((lum + 2) << 16) | ((lum) << 8) | (lum - 2);
graphics.beginFill(c);
graphics.drawRect(node.x + 1, node.y + 1 + dtf.height, node.width - 2, node.height - 2);
}
/* info */
msg[0] = 'METHOD | ' + METHOD_NAME[curMethod];
msg[1] = 'PACKED | ' + pack.usedRectangles.length + '/' + NUM_BOXES + ' | ' + (pack.usedRectangles.length / NUM_BOXES * 100).toPrecision(4) + '%';
msg[2] = 'ELAPSED | ' + elapsed + 'ms';
dtf.write(msg);
}
}
}
}
import flash.display.BitmapData;
internal class MaxRectsBinPack {
/* Best Short Side Fit: Positions the Rectangle against the short side of a free Rectangle into which it fits the best. */
private const BSSF : int = 0;
/* Best Long Side Fit: Positions the Rectangle against the long side of a free Rectangle into which it fits the best. */
private const BLSF : int = 1;
/* Best Area Fit: Positions the Rectangle into the smallest free Rectangle into which it fits. */
private const BAF : int = 2;
/* Bottom Left Rule: Does the Tetris placement. */
private const BL : int = 3;
/* Contact Point Rule: Choose the placement where the Rectangle touches other Rectangles as much as possible. */
private const CP : int = 4;
/* */
public var usedRectangles : Vector.<Node> = new Vector.<Node>();
/* */
private var binWidth : int = 0;
private var binHeight : int = 0;
private var allowRotations : Boolean = false;
private var freeRectangles : Vector.<Node> = new Vector.<Node>();
private var bestShortSideFit : int;
private var bestLongSideFit : int;
public function reset(width : int, height : int, rotations : Boolean) : void {
binWidth = width;
binHeight = height;
allowRotations = rotations;
usedRectangles.length = 0;
freeRectangles.length = 0;
freeRectangles.push(new Node(0, 0, width, height));
}
public function insert(width : int, height : int, method : int) : Node {
var node : Node = new Node();
switch(method) {
case BSSF:
node = insertBSSF(width, height);
break;
case BL:
node = insertBL(width, height);
break;
case CP:
node = insertCP(width, height);
break;
case BLSF:
node = insertBLSF(width, height);
break;
case BAF:
node = insertBAF(width, height);
break;
}
if ((node.width == 0) || (node.height == 0)) return node;
var len : int = freeRectangles.length;
for (var i : int = 0; i < len; i++) {
if (splitFreeNode(freeRectangles[i], node)) {
freeRectangles.splice(i, 1);
--i;
--len;
}
}
/* pruneFreeList(); */
prune:
for (i = 0; i < freeRectangles.length; i++) {
for (var j : int = i + 1; j < freeRectangles.length; j++) {
var a : Node = freeRectangles[i];
var b : Node = freeRectangles[j];
if (isContainedIn(a, b)) {
freeRectangles.splice(i, 1);
break prune;
} else if (isContainedIn(b, a)) {
freeRectangles.splice(j, 1);
}
}
}
usedRectangles.push(node);
return node;
}
private function isContainedIn(a : Node, b : Node) : Boolean {
return (a.x >= b.x) && (a.y >= b.y) && ((a.x + a.width) <= (b.x + b.width)) && ((a.y + a.height) <= (b.y + b.height));
}
private function insertBL(width : int, height : int) : Node {
var bestNode : Node = new Node();
var bestX : int;
var bestY : int = int.MAX_VALUE;
var rect : Node;
var topSideY : int;
for (var i : int = 0; i < freeRectangles.length; i++) {
rect = freeRectangles[i];
/* Try to place the Node in upright (non-flipped) orientation. */
if (rect.width >= width && rect.height >= height) {
topSideY = rect.y + height;
if (topSideY < bestY || (topSideY == bestY && rect.x < bestX)) {
bestNode.x = rect.x;
bestNode.y = rect.y;
bestNode.width = width;
bestNode.height = height;
bestY = topSideY;
bestX = rect.x;
}
}
if (allowRotations && rect.width >= height && rect.height >= width) {
topSideY = rect.y + width;
if (topSideY < bestY || (topSideY == bestY && rect.x < bestX)) {
bestNode.x = rect.x;
bestNode.y = rect.y;
bestNode.width = height;
bestNode.height = width;
bestY = topSideY;
bestX = rect.x;
}
}
}
return bestNode;
}
private function insertBSSF(width : int, height : int) : Node {
var bestNode : Node = new Node();
bestShortSideFit = int.MAX_VALUE;
var rect : Node;
var leftoverHoriz : int;
var leftoverVert : int;
var shortSideFit : int;
var longSideFit : int;
for (var i : int = 0; i < freeRectangles.length; i++) {
rect = freeRectangles[i];
/* Try to place the Node in upright (non-flipped) orientation. */
if (rect.width >= width && rect.height >= height) {
leftoverHoriz = Math.abs(rect.width - width);
leftoverVert = Math.abs(rect.height - height);
shortSideFit = Math.min(leftoverHoriz, leftoverVert);
longSideFit = Math.max(leftoverHoriz, leftoverVert);
if (shortSideFit < bestShortSideFit || (shortSideFit == bestShortSideFit && longSideFit < bestLongSideFit)) {
bestNode.x = rect.x;
bestNode.y = rect.y;
bestNode.width = width;
bestNode.height = height;
bestShortSideFit = shortSideFit;
bestLongSideFit = longSideFit;
}
}
var flippedLeftoverHoriz : int;
var flippedLeftoverVert : int;
var flippedShortSideFit : int;
var flippedLongSideFit : int;
if (allowRotations && rect.width >= height && rect.height >= width) {
flippedLeftoverHoriz = Math.abs(rect.width - height);
flippedLeftoverVert = Math.abs(rect.height - width);
flippedShortSideFit = Math.min(flippedLeftoverHoriz, flippedLeftoverVert);
flippedLongSideFit = Math.max(flippedLeftoverHoriz, flippedLeftoverVert);
if (flippedShortSideFit < bestShortSideFit || (flippedShortSideFit == bestShortSideFit && flippedLongSideFit < bestLongSideFit)) {
bestNode.x = rect.x;
bestNode.y = rect.y;
bestNode.width = height;
bestNode.height = width;
bestShortSideFit = flippedShortSideFit;
bestLongSideFit = flippedLongSideFit;
}
}
}
return bestNode;
}
private function insertBLSF(width : int, height : int) : Node {
var bestNode : Node = new Node();
var bestLongSideFit : int = int.MAX_VALUE;
var rect : Node;
var leftoverHoriz : int;
var leftoverVert : int;
var shortSideFit : int;
var longSideFit : int;
for (var i : int = 0; i < freeRectangles.length; i++) {
rect = freeRectangles[i];
/* Try to place the Node in upright (non-flipped) orientation. */
if (rect.width >= width && rect.height >= height) {
leftoverHoriz = Math.abs(rect.width - width);
leftoverVert = Math.abs(rect.height - height);
shortSideFit = Math.min(leftoverHoriz, leftoverVert);
longSideFit = Math.max(leftoverHoriz, leftoverVert);
if (longSideFit < bestLongSideFit || (longSideFit == bestLongSideFit && shortSideFit < bestShortSideFit)) {
bestNode.x = rect.x;
bestNode.y = rect.y;
bestNode.width = width;
bestNode.height = height;
bestShortSideFit = shortSideFit;
bestLongSideFit = longSideFit;
}
}
if (allowRotations && rect.width >= height && rect.height >= width) {
leftoverHoriz = Math.abs(rect.width - height);
leftoverVert = Math.abs(rect.height - width);
shortSideFit = Math.min(leftoverHoriz, leftoverVert);
longSideFit = Math.max(leftoverHoriz, leftoverVert);
if (longSideFit < bestLongSideFit || (longSideFit == bestLongSideFit && shortSideFit < bestShortSideFit)) {
bestNode.x = rect.x;
bestNode.y = rect.y;
bestNode.width = height;
bestNode.height = width;
bestShortSideFit = shortSideFit;
bestLongSideFit = longSideFit;
}
}
}
return bestNode;
}
private function insertBAF(width : int, height : int) : Node {
var bestNode : Node = new Node();
var bestAreaFit : int = int.MAX_VALUE;
var rect : Node;
var leftoverHoriz : int;
var leftoverVert : int;
var shortSideFit : int;
var areaFit : int;
for (var i : int = 0; i < freeRectangles.length; i++) {
rect = freeRectangles[i];
areaFit = rect.width * rect.height - width * height;
/* Try to place the Node in upright (non-flipped) orientation. */
if (rect.width >= width && rect.height >= height) {
leftoverHoriz = Math.abs(rect.width - width);
leftoverVert = Math.abs(rect.height - height);
shortSideFit = Math.min(leftoverHoriz, leftoverVert);
if (areaFit < bestAreaFit || (areaFit == bestAreaFit && shortSideFit < bestShortSideFit)) {
bestNode.x = rect.x;
bestNode.y = rect.y;
bestNode.width = width;
bestNode.height = height;
bestShortSideFit = shortSideFit;
bestAreaFit = areaFit;
}
}
if (allowRotations && rect.width >= height && rect.height >= width) {
leftoverHoriz = Math.abs(rect.width - height);
leftoverVert = Math.abs(rect.height - width);
shortSideFit = Math.min(leftoverHoriz, leftoverVert);
if (areaFit < bestAreaFit || (areaFit == bestAreaFit && shortSideFit < bestShortSideFit)) {
bestNode.x = rect.x;
bestNode.y = rect.y;
bestNode.width = height;
bestNode.height = width;
bestShortSideFit = shortSideFit;
bestAreaFit = areaFit;
}
}
}
return bestNode;
}
/* Returns 0 if the two intervals i1 and i2 are disjoint, or the length of their overlap otherwise. */
private function commonIntervalLength(i1start : int, i1end : int, i2start : int, i2end : int) : int {
if (i1end < i2start || i2end < i1start) return 0;
return Math.min(i1end, i2end) - Math.max(i1start, i2start);
}
private function contactPointScoreNode(x : int, y : int, width : int, height : int) : int {
var score : int = 0;
if (x == 0 || x + width == binWidth) score += height;
if (y == 0 || y + height == binHeight) score += width;
var rect : Node;
for (var i : int = 0; i < usedRectangles.length; i++) {
rect = usedRectangles[i];
if (rect.x == x + width || rect.x + rect.width == x)
score += commonIntervalLength(rect.y, rect.y + rect.height, y, y + height);
if (rect.y == y + height || rect.y + rect.height == y)
score += commonIntervalLength(rect.x, rect.x + rect.width, x, x + width);
}
return score;
}
private function insertCP(width : int, height : int) : Node {
var bestNode : Node = new Node();
var bestContactScore : int = -1;
var rect : Node;
var score : int;
for (var i : int = 0; i < freeRectangles.length; i++) {
rect = freeRectangles[i];
/* Try to place the Node in upright (non-flipped) orientation. */
if (rect.width >= width && rect.height >= height) {
score = contactPointScoreNode(rect.x, rect.y, width, height);
if (score > bestContactScore) {
bestNode.x = rect.x;
bestNode.y = rect.y;
bestNode.width = width;
bestNode.height = height;
bestContactScore = score;
}
}
if (allowRotations && rect.width >= height && rect.height >= width) {
score = contactPointScoreNode(rect.x, rect.y, height, width);
if (score > bestContactScore) {
bestNode.x = rect.x;
bestNode.y = rect.y;
bestNode.width = height;
bestNode.height = width;
bestContactScore = score;
}
}
}
return bestNode;
}
private function splitFreeNode(freeNode : Node, usedNode : Node) : Boolean {
/* Test with SAT if the Rectangles even intersect. */
if (usedNode.x >= freeNode.x + freeNode.width || usedNode.x + usedNode.width <= freeNode.x || usedNode.y >= freeNode.y + freeNode.height || usedNode.y + usedNode.height <= freeNode.y) {
return false;
}
var newNode : Node;
if (usedNode.x < freeNode.x + freeNode.width && usedNode.x + usedNode.width > freeNode.x) {
/* New node at the top side of the used node. */
if (usedNode.y > freeNode.y && usedNode.y < freeNode.y + freeNode.height) {
newNode = freeNode.clone();
newNode.height = usedNode.y - newNode.y;
freeRectangles.push(newNode);
}
/* New node at the bottom side of the used node. */
if (usedNode.y + usedNode.height < freeNode.y + freeNode.height) {
newNode = freeNode.clone();
newNode.y = usedNode.y + usedNode.height;
newNode.height = freeNode.y + freeNode.height - (usedNode.y + usedNode.height);
freeRectangles.push(newNode);
}
}
if (usedNode.y < freeNode.y + freeNode.height && usedNode.y + usedNode.height > freeNode.y) {
/* New node at the left side of the used node. */
if (usedNode.x > freeNode.x && usedNode.x < freeNode.x + freeNode.width) {
newNode = freeNode.clone();
newNode.width = usedNode.x - newNode.x;
freeRectangles.push(newNode);
}
/* New node at the right side of the used node. */
if (usedNode.x + usedNode.width < freeNode.x + freeNode.width) {
newNode = freeNode.clone();
newNode.x = usedNode.x + usedNode.width;
newNode.width = freeNode.x + freeNode.width - (usedNode.x + usedNode.width);
freeRectangles.push(newNode);
}
}
return true;
}
}
internal class Node {
public var x : int;
public var y : int;
public var width : int;
public var height : int;
function Node(x : int = 0, y : int = 0, width : int = 0, height : int = 0) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public function clone() : Node {
return new Node(x, y, width, height);
}
}
internal class DOSTxT extends BitmapData {
private var fmap : Vector.<int>;
private var c0 : uint;
private var c1 : uint;
private var buff : Vector.<uint>;
function DOSTxT(width : int, height : int, c0 : int, c1 : int) : void {
this.c0 = c0;
this.c1 = c1;
super(width, height, false, c0);
buff = new Vector.<uint>(width * height, true);
fmap = Vector.<int>([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E, 0x7E, 0xFF, 0x00, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E, 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x92, 0x10, 0x7C, 0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x7C, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF, 0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0, 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0, 0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99, 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00, 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, 0x7F, 0x00, 0x00, 0x7B, 0x1B, 0x1B, 0x1B, 0x00, 0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0x86, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x18, 0x7E, 0xC0, 0x7C, 0x06, 0xFC, 0x18, 0x00, 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00, 0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x7C, 0xCE, 0xDE, 0xF6, 0xE6, 0xC6, 0x7C, 0x00, 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00, 0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00, 0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00, 0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00, 0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00, 0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00, 0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30, 0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x3C, 0x66, 0x0C, 0x18, 0x18, 0x00, 0x18, 0x00, 0x7C, 0xC6, 0xDE, 0xDE, 0xDC, 0xC0, 0x7C, 0x00, 0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00, 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00, 0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00, 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00, 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00, 0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3A, 0x00, 0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00, 0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00, 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xD6, 0x7C, 0x0E, 0x00, 0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00, 0x7C, 0xC6, 0xE0, 0x78, 0x0E, 0xC6, 0x7C, 0x00, 0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0x6C, 0x00, 0xC6, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0xC6, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00, 0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, 0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00, 0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00, 0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00, 0x38, 0x6C, 0x64, 0xF0, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00, 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, 0x0C, 0x00, 0x1C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00, 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xD6, 0x00, 0x00, 0x00, 0xB8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E, 0x00, 0x00, 0xDC, 0x76, 0x62, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x7C, 0xC0, 0x70, 0x1C, 0xF8, 0x00, 0x10, 0x30, 0xFC, 0x30, 0x30, 0x34, 0x18, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xD6, 0xFE, 0x6C, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, 0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00, 0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, 0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00]);
fmap.fixed = true;
}
public function write(txt : Vector.<String>) : void {
var id : uint = buff.length;
while (id-- != 0) buff[id] = c0;
var w : uint = width;
var py : uint = txt.length;
while (py-- != 0) {
var line : String = txt[py];
var y0 : uint = (py >> 1) + (py << 3);
var px : uint = line.length;
while (px-- != 0) {
var x0 : uint = (px >> 1) + (px << 3);
id = line.charCodeAt(px) << 3;
var fy : uint = 8;
while (fy-- != 0) {
var ybits : int = fmap[id + fy];
var fx : int = 8;
while (fx-- != 0) {
if (((ybits << fx) & 0x80) == 0x80) {
buff[(x0 + fx) + ((y0 + fy) * w)] = c1;
}
}
}
}
}
setVector(rect, buff);
}
}