Beautifl - Flash Gallery

Thumbnail : OceanCurve
OceanCurve
imajuk 2010-05-07 MIT License

再生するにはFlash Playerが必要です。デスクトップのブラウザでご覧ください。

package  
{
    import flash.display.StageScaleMode;
    import flash.display.StageQuality;
    import flash.display.Sprite;
    import flash.display.Shape;
    import flash.display.BlendMode;
    import flash.display.IGraphicsFill;
    import flash.display.GradientType;
    import flash.geom.Matrix;
    import flash.display.GraphicsGradientFill;
    import flash.display.BitmapData;
    import flash.display.Bitmap;
    import org.libspark.thread.EnterFrameThreadExecutor;
    import org.libspark.thread.Thread;

    /**
     * @author imajuk
     */
    public class OceanCurve extends Sprite 
    {
        public function OceanCurve()
        {
            Wonderfl.capture_delay(21);
        		
        		Thread.initialize(new EnterFrameThreadExecutor());
        	
        		stage.quality = StageQuality.HIGH;
        		stage.scaleMode = StageScaleMode.NO_SCALE;
	        	stage.frameRate = 60;
 	       	start();
        }
        
        private function start() : void
        {
            var w : int = stage.stageWidth;
            var h : int = stage.stageHeight;

            //=================================
            // canvas
            //=================================
            var canvas : BitmapData = new BitmapData(w, h, true, 0xFFFFFFFF);
            var canvas2 : BitmapData = canvas.clone();
            
            var layer0:Shape = new Shape();
            
            var layer1 : Bitmap = new Bitmap(canvas2);
            layer1.blendMode = BlendMode.MULTIPLY;
            
            var layer2 : Bitmap = new Bitmap(canvas);
            layer2.blendMode = BlendMode.SCREEN;
            
            var layer3 : Bitmap = new Bitmap(canvas);
            layer3.blendMode = BlendMode.OVERLAY;
            
            
            addChild(layer0);
            addChild(layer1);
            addChild(layer2);
            addChild(layer3);
            
            //=================================
            // color
            //=================================
            var cl1 : int = 0x6264db;
            var cl2 : int = 0xcecee5;
            var cl3 : int = 0x32347f;
            var cl4 : int = 0x2b2edb;
            
            //=================================
            // background
            //=================================
            layer0.graphics.beginGradientFill(
                GradientType.LINEAR, 
                [0xFFFFFF, cl4], 
                [1, 1], 
                [100,255], 
                getGradMatrix(h, Math.PI * .5)
            );
            layer0.graphics.drawRect(0, 0, w, h);
            
            //=================================
            // fill
            //=================================
            var fill1 : IGraphicsFill = 
                new GraphicsGradientFill(
                    GradientType.LINEAR, 
                    [cl2, cl3], 
                    [1, 1], 
                    [0,255], 
                    getGradMatrix(h, Math.PI * .5)
                );
            var fill2 : IGraphicsFill = 
                new GraphicsGradientFill(
                    GradientType.LINEAR, 
                    [0xFFFFFF, cl1], 
                    [1, 1], 
                    [100,255], 
                    getGradMatrix2(h, Math.PI * .5)
                );
            var fill3 : IGraphicsFill = 
                new GraphicsGradientFill(
                    GradientType.LINEAR, 
                    [0xFFFFFF, cl1], 
                    [1, 1], 
                    [0,255], 
                    getGradMatrix(h, -Math.PI * .5)
                );
            
            //=================================
            // waves
            //=================================
            var wave1 : Wave = new Wave(w+50, h, null, fill1, 450, 38);
            var wave2 : Wave = new Wave(w+50, h, null, fill2, 450, 30);
            var wave3 : Wave = new Wave(w+50, h, null, fill3, 400, 50, WaveType.COS);
            wave2.opposite = true;
            wave2.rotation = 2;
            wave1.y = wave2.y = wave3.y = 340;
            
            //=================================
            // wave updater
            //=================================
            new WaveUpdateThread(wave1, Math.PI * .5, .02, .03, 100, 0, 1).start();
            new WaveUpdateThread(wave2, Math.PI,      .02, .03, 30, 0, 2).start();
            new WaveUpdateThread(wave3, -Math.PI,     .02, .05, 50, 0, .5).start();
            
            //=================================
            // draw waves in canvas
            //=================================
            new WaveRenderThread(Vector.<Wave>([wave3, wave1, wave2]), canvas, canvas2).start();
        };

        private function getGradMatrix(length : int, angle : Number) : Matrix 
        {
            var gradMatrix : Matrix = new Matrix();
            gradMatrix.createGradientBox(length, length, angle, 0, 0);
            return gradMatrix;
        }

        private function getGradMatrix2(length : int, angle : Number) : Matrix 
        {
            var gradMatrix : Matrix = new Matrix();
            gradMatrix.createGradientBox(length, length, angle, 0, -length);
            return gradMatrix;
        }
    }
}

class WaveType 
{
    public static const SIN:String = "SIN";
    public static const COS:String = "COS";
}

import flash.display.IGraphicsFill;
import flash.display.GraphicsPathCommand;
import flash.display.GraphicsPath;
import flash.display.GraphicsStroke;
import flash.display.IGraphicsData;
import flash.display.Graphics;
import flash.display.Shape;

class Wave extends Shape
{
    public var curveWidth:Number;
    public var curveHeight:Number;
    public var opposite:Boolean = false;
    private var stroke:GraphicsStroke;
    private var canvasWidth:Number;
    private var fill:IGraphicsFill;
    private var canvasHeight:int;
    private var curve:Function;

    /**
     * @param canvasWidth   キャンバスの横幅
     * @param canvasHeight  キャンバスの縦幅
     * @param stroke        波のスタイル(ストローク)
     * @param fill          波のスタイル(塗り)
     * @param curveWidth    波の最大幅
     * @param curveHeight   波の最大高
     * @param type          波のタイプ(WaveType.SIN or WaveType.COS)
     */
    public function Wave(
                        canvasWidth:int, 
                        canvasHeight:int, 
                        stroke:GraphicsStroke, 
                        fill:IGraphicsFill, 
                        curveWidth:Number,
                        curveHeight:Number,
                        type:String = WaveType.SIN
                        ) 
    {
        this.stroke = stroke;
        this.fill = fill;
        this.canvasWidth = canvasWidth;
        this.canvasHeight = canvasHeight;
        this.curveWidth = curveWidth;
        this.curveHeight = curveHeight;
        this.curve = (type == WaveType.COS) ? Math.cos : Math.sin;
    }

    public function draw(seed:Number, sx:Number, sy:Number):void 
    {
        //波の縦サイズ(-curveHeight ~ +curveHeight)
        var waveHeight:Number = Math.sin(seed) * curveHeight;
            
        var g:Graphics = graphics;
        g.clear();
        g.drawGraphicsData(Vector.<IGraphicsData>([ stroke, fill, getPath(sx, sy, curveWidth, waveHeight, seed) ]));
    }

    /**
     * @param px    描画のスタート位置
     * @param py    描画のスタート位置
     * @param w     波の最大横幅
     * @param h     波の最大縦幅
     * @param seed  上下の触れ幅(-Math.PI ~ Math.PI)
     */
    private function getPath(px:Number, py:Number, w:Number, h:Number, seed:Number):GraphicsPath
    {
        if (w <= 0) throw new Error("サイズが負の数値です");
            
        var path:GraphicsPath = new GraphicsPath();
        path.commands = Vector.<int>([ GraphicsPathCommand.MOVE_TO ]);
        path.data = Vector.<Number>([ px, py += Math.sin(seed) * h * .5 ]);
            
        //波一つ分をどのくらいの精度で描画するか(数値が大きいほど解像度が高い)
        var resolution:int = 30;
        var step:Number = 1 / resolution;
        var stepRad:Number = Math.PI * 2 / resolution;
            
        h *= .5;
            
        while(px < canvasWidth)
        {   
            seed += stepRad;
            px += w * step;
            py += curve(seed) * h * stepRad;
            path.commands.push(GraphicsPathCommand.LINE_TO);
            path.data.push(px, py);
        }
            
        path.commands.push(GraphicsPathCommand.LINE_TO);
        path.data.push(px, py += (opposite) ? -canvasHeight : canvasHeight);
        path.commands.push(GraphicsPathCommand.LINE_TO);
        path.data.push(0, py);
            
        return path;
    }
}

import fl.motion.easing.Quadratic;

import org.libspark.thread.Thread;

class WaveUpdateThread extends Thread 
{
    private var wave:Wave;
    private var time:Number = 0;
    private var seed:Number;
    private var easings:Array = [ Quadratic.easeOut, Quadratic.easeIn ];
    private var easing:Function = easings[0];
    private var step:Number;
    private var direction:int = 1;
    private var begin:Number;
    private var end:Number;
    private var speedH:Number;
    private var stX:Number = 0;

    /**
     * @param wave      ターゲットになるウェーブ
     * @param seed      ウェーブの初期値(-Math.PI ~ Math.PI)
     * @param minSpeed  縦揺れの最低スピード
     * @param maxSpeed  縦揺れの最高スピード
     * @param duration  縦揺れのスピードが変化する時間
     * @param time      縦揺れスピードの初期値(0 ~ 1)
     * @param speedH    横移動のスピード
     */
    public function WaveUpdateThread(
                            wave:Wave, 
                            seed:Number = NaN, 
                            minSpeed:Number = .01, 
                            maxSpeed:Number = .03, 
                            duration:int = 300, 
                            time:Number = NaN, 
                            speedH:Number = 1
                        )
    {
        super();
        this.wave = wave;
        this.begin = minSpeed; 
        this.end = maxSpeed - minSpeed;
        this.seed = isNaN(seed) ? Math.random() * Math.PI * 2 - Math.PI : seed;
        this.time = isNaN(time) ? Math.random() : time;
        this.step = 1 / duration;
        this.speedH = speedH;
    }

    override protected function run():void
    {
        next(run);
            
        time += step * direction;
        seed += easing(time, begin, end, 1);
        if (time > 1) 
        {
            time = 1;
            direction *= -1;
            easing = easings[1];
        }
        else if(time < 0)
        {
            time = 0;
            direction *= -1;
            easing = easings[1];
        }
            
        //スタートの描画位置(x=0, y=+-10)
        stX -= speedH % wave.curveWidth;
        var sx:Number = stX;
        var sy:Number = Math.cos(seed) * 10;
            
        wave.draw(seed, sx, sy);
    }
}

import flash.geom.Rectangle;
import flash.filters.BlurFilter;
import flash.geom.Point;
import flash.geom.ColorTransform;
import flash.display.BitmapData;

class WaveRenderThread extends Thread 
{
    private static const POINT:Point = new Point();
    private var waves:Vector.<Wave>;
    private var canvas:BitmapData;
    private var delay:BitmapData;
    private var transparent:ColorTransform;
    private var histroy:Vector.<BitmapData> = new Vector.<BitmapData>();
    private var blur:BlurFilter = new BlurFilter(2, 2);
    private var clear:BitmapData;
    private var rect:Rectangle;

    public function WaveRenderThread(waves:Vector.<Wave>, canvas:BitmapData, delay:BitmapData)
    {
        super();
        this.waves = waves;
        this.canvas = canvas;
        this.delay = delay;
            
        rect = canvas.rect; 
        clear = new BitmapData(canvas.width, canvas.height, true, 0x00FFFFFF);
        transparent = new ColorTransform(1, 1, 1, .5, 0, 0, 0, 0);
        histroy.push(canvas.clone());
    }

    override protected function run():void
    {
        next(run);
            
        canvas.lock();
        canvas.copyPixels(clear, rect, POINT);
        waves.forEach(function(wave:Wave, ...param):void
        {
            canvas.draw(wave, wave.transform.matrix, transparent);
        });
        canvas.unlock();
            
        delay.lock();
        delay.copyPixels(clear, rect, POINT);
        delay.draw(histroy[0]);
        delay.unlock();
                
        if (histroy.length > 5) histroy.shift().dispose();
                    
        var b:BitmapData = canvas.clone(); 
        b.applyFilter(b, b.rect, POINT, blur);
        histroy.push(b);
    }
}