package {
    
    import com.gskinner.utils.PerformanceTest;
    
    import flash.display.Sprite;

    [SWF(width=1024, height=512, backgroundColor=0xffffff, frameRate=30)]

    public class Benchmark extends Sprite {
        
        public function Benchmark() {
            var p:PerformanceTest = PerformanceTest.getInstance();
            p.testSuite(new TestSuite(this.stage));
        }
    }
}



import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Stage;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.filters.DisplacementMapFilter;
import flash.display.BitmapDataChannel;
import flash.filters.DisplacementMapFilterMode;
    
class TestSuite {
    
    public var iterations:int = 20;
    
    [Embed(source='test.png')]
    private var TestImageClass:Class;
    
    private var RECT:Rectangle = new Rectangle(0, 0, 512, 512);
    private var ZERO_POINT:Point = new Point(0, 0);
    
    private var P:Array = [
        new Point(134, 153), new Point(390, 73), new Point(442, 435), new Point(55, 391)
    ];

    private var _stage:Stage;
    private var _source:BitmapData;
    private var _dest:BitmapData;
    
    private var _hmFilt:HomographyTransformFilter;
    private var _hmFilt2:HomographyTransformFilter;
    
    private var _mapFilt:DisplacementMapFilter;
    
    public function TestSuite(stage:Stage) {
        this._stage = stage;
        var b:Bitmap = this._stage.addChild(new TestImageClass()) as Bitmap;
        this._source = b.bitmapData;
        this._dest = new BitmapData(512, 512, false, 0x0);
        b = this._stage.addChild(new Bitmap(this._dest)) as Bitmap;
        b.x = 512;
        this._hmFilt = new HomographyTransformFilter(512, 512, P[0], P[1], P[2], P[3], false);
        this._hmFilt2 = new HomographyTransformFilter(512, 512, P[0], P[1], P[2], P[3], true);
        this._mapFilt = new DisplacementMapFilter(this._createDisplacementMap(P), ZERO_POINT, BitmapDataChannel.GREEN, BitmapDataChannel.BLUE, 512, 512);
    }
    
    public function Test1_setPixel():void {
        Homography.setTransform(this._source, this._dest, P[0], P[1], P[2], P[3]);
    }
    
    public function Test2a_PixelBender():void {
        this._dest.applyFilter(this._source, RECT, ZERO_POINT, this._hmFilt);
    }

    public function Test2b_PixelBender_Smoothed():void {
        this._dest.applyFilter(this._source, RECT, ZERO_POINT, this._hmFilt2);
    }

    public function Test3_DisplacementMap():void {
        this._dest.applyFilter(this._source, RECT, ZERO_POINT, this._mapFilt);
    }



    private function _createDisplacementMap(points:Array):BitmapData {
        const w:int = 512;
        const h:int = 512;
        var map:BitmapData = new BitmapData(w, h, false, 0x808080);
        var param:Array = this.getSystem(points);
        
        for (var y:int = 0; y < h; y++) {
            for (var x:int = 0; x < w; x++) {
                var u:Number = x / w;
                var v:Number = y / h;
                var ox:Number = (param[0] * u + param[1] * v + param[2]) / (param[6] * u + param[7] * v + 1);
                var oy:Number = (param[3] * u + param[4] * v + param[5]) / (param[6] * u + param[7] * v + 1);
                var dx:int = 128 + (ox - x) / 2;
                var dy:int = 128 + (oy - y) / 2;
                map.setPixel(x, y, (dx << 8) | dy);
            }
        }
        
        return map; 
    }

    private function getSystem( P:Array ):Array {
        var system:Array = new Array( 8 );
        var sx:Number = (P[0].x-P[1].x)+(P[2].x-P[3].x);
        var sy:Number = (P[0].y-P[1].y)+(P[2].y-P[3].y);
        
        var dx1:Number = P[1].x-P[2].x;
        var dx2:Number = P[3].x-P[2].x;
        var dy1:Number = P[1].y-P[2].y;
        var dy2:Number = P[3].y-P[2].y;
     
        var z:Number = (dx1*dy2)-(dy1*dx2);
        var g:Number = ((sx*dy2)-(sy*dx2))/z;
        var h:Number = ((sy*dx1)-(sx*dy1))/z;
     
        system[0]=P[1].x-P[0].x+g*P[1].x;
        system[1]=P[3].x-P[0].x+h*P[3].x;
        system[2]=P[0].x;
        system[3]=P[1].y-P[0].y+g*P[1].y;
        system[4]=P[3].y-P[0].y+h*P[3].y;
        system[5]=P[0].y;
        system[6]=g;
        system[7]=h;
     
        return system;
    }
}