forked from: forked from: 直線描画高速化テスト

by yotsu42keisuke forked from forked from: 直線描画高速化テスト (diff: 155)
♥0 | Line 116 | Modified 2010-11-17 14:50:40 | MIT License
play

ActionScript3 source code

/**
 * Copyright yotsu42keisuke ( http://wonderfl.net/user/yotsu42keisuke )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/rdEF
 */

// forked from tail_y's forked from: 直線描画高速化テスト
// forked from tail_y's 直線描画高速化テスト
package {
 
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Graphics;
    import flash.display.Sprite;
    import flash.display.StageQuality;
    import flash.events.Event;
    import flash.geom.Matrix;
    import flash.geom.Rectangle;
    import flash.text.TextField;
    import flash.utils.getTimer;

    public class DrawLineTest extends Sprite
    {
        /*
         マリモのための、直線描画高速化テスト。 
         Flashの線描画は重いって有名だから、オリジナルの手法で勝つる!って思って頑張ったけど
         微妙な結果に・・・orz
         setPixel使えば軽く(約0.7倍)なるんだけど、その場合太さが表現できない。
         あと、なんかマイナス方向への描画が汚い。
         誰かアイデアをください。
         
         アンチエイリアスはひとまず無視して、2px以上の線を高速に描画できればとりあえず成功。マリモに応用できるはず。

         一応、僕の環境では45%くらい高速化しているんだけど、どうかな。
                */
        
        public static const TEST_LINE_NUM:uint = 10000;    // テストする回数
        public static const DISPLAY_LINE_NUM:uint = 100;    // 見た目も確認したいから表示用に、少ない回数の描画もするよ~。
        
        public static const BITMAP_SIZE:uint = 232;    // 描画サイズ
        public static const BITMAP_CENTER:uint = BITMAP_SIZE/2;    // 描画の中央
        public static const LINE_LENGTH:uint = 100;    // 線の長さ
        public static const LINE_COLOR:uint = 0x33aa22;
        
        public static const LINE_THICNESS:Number = 2;
        
        public function DrawLineTest()
        {
            addEventListener(Event.ADDED_TO_STAGE, init);    // flexBuilderとの互換性。
        }

        private function init(e:Event):void {
            // SWF設定
            stage.frameRate = 24
            stage.quality = StageQuality.LOW;
            
            // 変数
            var timeCount0:Number, timeCount1:Number;    // 時間計測用
            var xList:Array, yList:Array;    // sinとcosをあらかじめ計算しておくリスト
            var infoDisplay:TextField = new TextField();    // 時間表示TF
            
            // 計測をなるべく純粋にするために、座標位置は計算しておく。
            xList = calcXList(TEST_LINE_NUM);
            yList = calcYList(TEST_LINE_NUM);
            
            // 通常の描画をするよ。
            timeCount0 = getTimer();
            drawLine_normal(TEST_LINE_NUM, xList, yList);
            timeCount1 = getTimer();
            infoDisplay.appendText("normal:" + (timeCount1 - timeCount0) + "\n");
            
            // fillRectによる描画をするよ。
            timeCount0 = getTimer();
            drawLine_rect(TEST_LINE_NUM, xList, yList);
            timeCount1 = getTimer();
            infoDisplay.appendText("rect:" + (timeCount1 - timeCount0) + "\n");
            
            // 表示用の描画をするよ(時間は計らない)
            xList = calcXList(DISPLAY_LINE_NUM);
            yList = calcYList(DISPLAY_LINE_NUM);
            var normalBitmapData:BitmapData = drawLine_normal(DISPLAY_LINE_NUM, xList, yList);
            var rectBitmapData:BitmapData = drawLine_rect(DISPLAY_LINE_NUM, xList, yList);
            
            // まとめて表示
            var normalBitmap:Bitmap = new Bitmap(normalBitmapData);
            var rectBitmap:Bitmap = new Bitmap(rectBitmapData);
            normalBitmap.x = 0;
            normalBitmap.y = 0;
            rectBitmap.x = BITMAP_SIZE;
            rectBitmap.y = 0;
            addChild(normalBitmap);
            addChild(rectBitmap);
            addChild(infoDisplay);
            
            // 縮小表示もしておく。
            stage.quality = StageQuality.HIGH;
            
            var normalBitmapSmall:Bitmap = new Bitmap();
            var rectBitmapSmall:Bitmap = new Bitmap();
            normalBitmapSmall.bitmapData = new BitmapData(BITMAP_SIZE/2, BITMAP_SIZE/2, false);
            rectBitmapSmall.bitmapData = new BitmapData(BITMAP_SIZE/2, BITMAP_SIZE/2, false);
            var smallMatrix:Matrix = new Matrix();
            smallMatrix.scale(0.5, 0.5);
            normalBitmapSmall.bitmapData.draw(normalBitmapData, smallMatrix, null, null, null, true);
            rectBitmapSmall.bitmapData.draw(rectBitmapData, smallMatrix, null, null, null, true);
            normalBitmapSmall.x = 0;
            normalBitmapSmall.y = BITMAP_SIZE
            rectBitmapSmall.x = BITMAP_SIZE;
            rectBitmapSmall.y = BITMAP_SIZE;
            addChild(normalBitmapSmall);
            addChild(rectBitmapSmall);
        }
        
        // Graphicを使った描画をする。
        private function drawLine_normal(num:int, xList:Array, yList:Array):BitmapData{
            var sprite:Sprite = new Sprite();
            var graphics:Graphics = sprite.graphics;
            var i:int
            
            graphics.lineStyle(LINE_THICNESS, LINE_COLOR, 1);
            for (i = 0; i < num; i++){
                graphics.moveTo(BITMAP_CENTER, BITMAP_CENTER);
                graphics.lineTo(xList[i], yList[i]);
            }
            var bitmapData:BitmapData = new BitmapData(BITMAP_SIZE, BITMAP_SIZE, false, 0xffffff);
            bitmapData.draw(sprite);
            return bitmapData;
        }
        
        // BitmapへのfillRectを使った描画をする
        private function drawLine_rect(num:int, xList:Array, yList:Array):BitmapData{
            var bitmapData:BitmapData = new BitmapData(BITMAP_SIZE, BITMAP_SIZE, false, 0xffffff);
            var rectNum:int;
            var rect:Rectangle = new Rectangle(0, 0, LINE_THICNESS, LINE_THICNESS);        // 予め作って使いまわす。
            var i:int, j:int;
            var stepX:Number, stepY:Number;
            
            for (i = 0; i < num; i++){
                rectNum = Math.max(Math.abs(xList[i] - BITMAP_CENTER), Math.abs(yList[i] - BITMAP_CENTER));    // 多いほうの座標の数だけ四角が必要。
                stepX = (xList[i] - BITMAP_CENTER) / rectNum;
                stepY = (yList[i] - BITMAP_CENTER) / rectNum;
                for (j = 0; j < rectNum; j++){
                    rect.x = BITMAP_CENTER + j*stepX;
                    rect.y = BITMAP_CENTER + j*stepY;
                    bitmapData.fillRect(rect, LINE_COLOR)
                    /* 上の3行の処理を、↓1行にすると、Flashの描画より軽くなるんだけど、太さに対応できない・・・。
                    bitmapData.setPixel(int(BITMAP_CENTER + j*stepX), int(BITMAP_CENTER + j*stepY), LINE_COLOR);
                    */
                }
            }
            return bitmapData;
        }
        
        private function calcXList(num:int):Array{
            var ans:Array = [];
            for (var i:int = 0; i < num; i++){
                ans.push(BITMAP_CENTER + Math.cos(i * 2 * Math.PI / num) * LINE_LENGTH);
            }
            return ans;
        }
        private function calcYList(num:int):Array{
            var ans:Array = [];
            for (var i:int = 0; i < num; i++){
                ans.push(BITMAP_CENTER + Math.sin(i * 2 * Math.PI / num) * LINE_LENGTH);
            }
            return ans;
        }
    }
}