In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

flash on 2012-8-31

Get Adobe Flash player
by russ 30 Aug 2012

    Talk

    russ at 12 Jan 2013 19:38
    @Johannes - the timings in this test are disturbingly dependent on the version for the flash runtime you have running. drawPath on a LOW quality stage should *always* win... at least fundamentally (assuming a good underlying implementation). I recall a recent runtime update (don't recall which version) that caused havoc, resulting in EFLA actually beating drawPath (LOW). Scary.

    Tags

    Embed
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);
            }
        }
    }
}
}