flash on 2012-8-31
package
{
import flash.display.*;
import flash.events.Event;
import flash.text.*;
import flash.utils.*;
import org.osmf.logging.Log;
public class LineDrawingTest extends Sprite {
private var _BMD:BitmapData;
private var _Logger:TextField = new TextField();
private const NUM_LINES_TO_DRAW:int = 30000;
private var _Result:Bitmap = new Bitmap();
public function LineDrawingTest()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
_Logger.autoSize = TextFieldAutoSize.LEFT;
addChild(_Logger);
_BMD = new BitmapData(1000, 1000, false, 0xffffff);
addChild(_Result);
_Result.x = 300;
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame1);
}
private function onEnterFrame1(e:Event):void {
_TestEFLA();
stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame1);
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame2);
}
private function onEnterFrame2(e:Event):void {
_TestLineTo(StageQuality.LOW, "(low) lineTo: ");
stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame2);
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame3);
}
private function onEnterFrame3(e:Event):void {
_TestLineTo(StageQuality.MEDIUM, "(medium) lineTo: ");
stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame3);
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame4);
}
private function onEnterFrame4(e:Event):void {
_TestLineTo(StageQuality.HIGH, "(high) lineTo: ");
stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame4);
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame5);
}
private function onEnterFrame5(e:Event):void {
_TestLineTo(StageQuality.BEST, "(best) lineTo: ");
stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame5);
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame6);
}
private function onEnterFrame6(e:Event):void {
_TestDrawPath(StageQuality.LOW, "(low) DrawPath: ");
stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame6);
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame7);
}
private function onEnterFrame7(e:Event):void {
_TestDrawPath(StageQuality.MEDIUM, "(medium) DrawPath: ");
stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame7);
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame8);
}
private function onEnterFrame8(e:Event):void {
_TestDrawPath(StageQuality.HIGH, "(high) DrawPath: ");
stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame8);
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame9);
}
private function onEnterFrame9(e:Event):void {
_TestDrawPath(StageQuality.BEST, "(best) DrawPath: ");
stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame9);
//stage.addEventListener(Event.ENTER_FRAME, onEnterFrame10);
}
private function _TestEFLA_OLD():void {
var beforeTime:uint;
var i:uint;
var bmd:BitmapData = _BMD;
var numIterations:uint = NUM_LINES_TO_DRAW; // local lookups much faster than global in loop below
beforeTime = getTimer();
for (i = 0; i < numIterations; ++i) {
efla(0, 0, 999, 999, 0x00ff00, bmd);
}
log("efla: " + (getTimer()-beforeTime));
}
private function _TestEFLA():void {
var beforeTime:uint;
var i:uint;
var bmd:BitmapData = new BitmapData(1000, 1000, false, 0xffffff);
var numIterations:uint = NUM_LINES_TO_DRAW; // local lookups much faster than global in loop below
var totalLines:uint = NUM_LINES_TO_DRAW;
var maxSize:uint = 500;
var numOrbits:uint = 100; // 4 lines per loop
var dx:uint = 0;
var dy:uint = 0;
var linesDrawn:uint = 0;
var lastX:uint;
var lastY:uint;
var lineColor:uint = 0x0000ff;
beforeTime = getTimer();
while (linesDrawn < totalLines) {
dx = dy = 0;
lastX = 0;
lastY = 0;
for (i = 0; i < numOrbits; ++i) {
efla(lastX, lastY, dx, dy, lineColor, bmd);
efla( dx, dy, maxSize - dx, dy, lineColor, bmd);
lastY = maxSize - dy;
efla( maxSize - dx, dy, maxSize - dx, lastY, lineColor, bmd);
dx += 2;
lastX = dx;
efla( maxSize - dx, lastY, lastX, lastY, lineColor, bmd);
dy += 2;
linesDrawn += 4;
if (linesDrawn >= totalLines) {
break;
}
}
}
log("efla: " + (getTimer()-beforeTime + "ms -- " + linesDrawn + " lines"));
_Result.bitmapData = bmd;
}
private function _TestLineTo(StageQuality:String, LogMsg:String):void {
var shape:Shape = new Shape();
var graphics:Graphics = shape.graphics;
var beforeTime:uint;
var i:uint;
var j:uint;
var bmd:BitmapData = new BitmapData(1000, 1000, false, 0xffffff);
var numIterations:uint = NUM_LINES_TO_DRAW; // local lookups much faster than global in loop below
stage.quality = StageQuality;
graphics.lineStyle(0, 0x00ff00, 1);
//THIS LOOP WAS THE ORIGINAL SIMPLE TEST...
// for (i = 0; i < numIterations; ++i) {
// graphics.moveTo(0, 0);
// graphics.lineTo(999, 999);
// }
var totalLines:uint = NUM_LINES_TO_DRAW;
var maxSize:uint = 500;
var numOrbits:uint = 100; // 4 lines per loop
var dx:uint = 0;
var dy:uint = 0;
var linesDrawn:uint = 0;
while (linesDrawn < totalLines) {
graphics.moveTo(0, 0);
dx = dy = 0;
for (i = 0; i < numOrbits; ++i) {
graphics.lineTo(dx, dy);
graphics.lineTo(maxSize - dx, dy);
graphics.lineTo(maxSize - dx, maxSize - dy);
dx += 2;
graphics.lineTo(dx, maxSize - dy);
dy += 2;
linesDrawn += 4;
if (linesDrawn >= totalLines) {
break;
}
}
}
beforeTime = getTimer();
bmd.draw(shape);
log(LogMsg + (getTimer() - beforeTime) + " ms -- " + linesDrawn + " lines");
_Result.bitmapData = bmd;
}
private function _TestDrawPath_OLD(StageQuality:String, LogMsg:String):void {
var shape:Shape = new Shape();
var graphics:Graphics = shape.graphics;
var beforeTime:uint;
var i:uint;
var bmd:BitmapData = _BMD;
var numIterations:uint = NUM_LINES_TO_DRAW; // local lookups much faster than global in loop below
// make the required drawPath vectors
var commands:Vector.<int> = new Vector.<int>();
var dataPts:Vector.<Number> = new Vector.<Number>();
stage.quality = StageQuality;
beforeTime = getTimer();
for(i = 0; i < numIterations; i++) {
commands.push(GraphicsPathCommand.MOVE_TO);
dataPts.push(0); // moveto x
dataPts.push(0); // moveto y
commands.push(GraphicsPathCommand.LINE_TO);
dataPts.push(999); // lineto x
dataPts.push(999); // lineto y
}
shape.graphics.drawPath(commands, dataPts);
log("full drawPath pt generation time: " + (getTimer() - beforeTime) + "ms");
beforeTime = getTimer();
bmd.draw(shape);
log(LogMsg + (getTimer() - beforeTime) + " ms");
}
private function _TestDrawPath(StageQuality:String, LogMsg:String):void {
var shape:Shape = new Shape();
var graphics:Graphics = shape.graphics;
var beforeTime:uint;
var i:uint;
var j:uint;
var bmd:BitmapData = new BitmapData(1000, 1000, false, 0xffffff);
var numIterations:uint = NUM_LINES_TO_DRAW; // local lookups much faster than global in loop below
// make the required drawPath vectors
var commands:Vector.<int> = new Vector.<int>();
var dataPts:Vector.<Number> = new Vector.<Number>();
stage.quality = StageQuality;
graphics.lineStyle(0, 0xff0000, 1);
beforeTime = getTimer();
var totalLines:uint = NUM_LINES_TO_DRAW;
var maxSize:uint = 500;
var numOrbits:uint = 100; // 4 lines per loop
var dx:uint = 0;
var dy:uint = 0;
var linesDrawn:uint = 0;
while (linesDrawn < totalLines) {
commands.push(GraphicsPathCommand.MOVE_TO);
dataPts.push(0); // moveto x
dataPts.push(0); // moveto y
dx = dy = 0;
for (i = 0; i < numOrbits; ++i) {
commands.push(GraphicsPathCommand.LINE_TO);
dataPts.push(dx); // lineto x
dataPts.push(dy); // lineto y
commands.push(GraphicsPathCommand.LINE_TO);
dataPts.push(maxSize - dx); // lineto x
dataPts.push(dy); // lineto y
commands.push(GraphicsPathCommand.LINE_TO);
dataPts.push(maxSize - dx); // lineto x
dataPts.push(maxSize - dy); // lineto y
dx += 2;
commands.push(GraphicsPathCommand.LINE_TO);
dataPts.push(dx); // lineto x
dataPts.push(maxSize - dy); // lineto y
dy += 2;
linesDrawn += 4;
if (linesDrawn >= totalLines) {
break;
}
}
}
shape.graphics.drawPath(commands, dataPts);
//log("full drawPath pt generation time: " + (getTimer() - beforeTime) + "ms");
beforeTime = getTimer();
bmd.draw(shape);
log(LogMsg + (getTimer() - beforeTime) + " ms -- " + linesDrawn + " lines");
_Result.bitmapData = bmd;
}
private function log(msg:*):void {
_Logger.appendText(msg + "\n");
}
// "Extremely Fast Line Algorithm"
private function efla(x:int, y:int, x2:int, y2:int, color:uint, bmd:BitmapData): void {
var shortLen:int = y2-y;
var longLen:int = x2-x;
if ((shortLen ^ (shortLen >> 31)) - (shortLen >> 31) > (longLen ^ (longLen >> 31)) - (longLen >> 31)) {
shortLen ^= longLen;
longLen ^= shortLen;
shortLen ^= longLen;
var yLonger:Boolean = true;
}
else {
yLonger = false;
}
var inc:int = longLen < 0 ? -1 : 1;
var multDiff:Number = longLen == 0 ? shortLen : shortLen / longLen;
if (yLonger) {
for (var i:int = 0; i != longLen; i += inc) {
bmd.setPixel(x + i*multDiff, y+i, color);
}
}
else {
for (i = 0; i != longLen; i += inc) {
bmd.setPixel(x+i, y+i*multDiff, color);
}
}
}
}
}