Beautifl - Flash Gallery

Thumbnail : Dolphin Play [Alternativa3D7.5 Sample]
Dolphin Play [Alternativa3D7.5 Sample]
narutohyper 2010-10-01 MIT License

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

package {
    import alternativ7.engine3d.animation.AnimationController;
    import alternativ7.engine3d.animation.AnimationGroup;
    import alternativ7.engine3d.animation.AnimationState;
    import alternativ7.engine3d.animation.AnimationTimer;
    import alternativ7.engine3d.animation.keys.MatrixKey;
    import alternativ7.engine3d.animation.MatrixAnimation;
    import alternativ7.engine3d.animation.Track;
    import alternativ7.engine3d.containers.ConflictContainer;
    import alternativ7.engine3d.controllers.SimpleObjectController;
    import alternativ7.engine3d.core.Camera3D;
    import alternativ7.engine3d.core.Object3DContainer;
    import alternativ7.engine3d.core.Sorting;
    import alternativ7.engine3d.core.View;
    import alternativ7.engine3d.loaders.MaterialLoader;
    import alternativ7.engine3d.loaders.ParserCollada;
    import alternativ7.engine3d.materials.FillMaterial;
    import alternativ7.engine3d.materials.TextureMaterial;
    import alternativ7.engine3d.objects.Joint;
    import alternativ7.engine3d.objects.Skin;
    import alternativ7.engine3d.primitives.Box;
    import flash.display.BitmapData;
    import flash.display.BlendMode;
    import flash.display.GradientType;
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageQuality;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.geom.Matrix;
    import flash.geom.Matrix3D;
    import flash.geom.Vector3D;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import flash.system.LoaderContext;
    import flash.text.TextField;
    import flash.text.TextFormat;
    import flash.ui.Keyboard;


    
    [SWF(backgroundColor="#000000", frameRate="60", width="800", height="600")]
    public class Main extends Sprite {
        
        private const modelURL:String = "http://marubayashi.net/archive/sample/alt3d7/dolphin.dae";
        private var loader:URLLoader;
        private var materialLoader:MaterialLoader;

        
        private var back:Sprite
        private var backMaterial:TextureMaterial;
        private var camera:Camera3D;

        private var cameraController:SimpleObjectController;
        private var moveController:dolphinController;
        private var animationController:AnimationController;

        private var animationTimer:AnimationTimer

        private var container:ConflictContainer;
        private var anim:Boolean = true;
        private var dolphinObject:ConflictContainer;
        private var frame:Sprite = new Sprite();
        private var textures:Vector.<TextureMaterial>
        
        private var nextX:Number=0
        private var nextY:Number=0
        private var nextZ:Number=0
        
        private var viewLength:Number
        private var focalLength:Number
        
        
        private var tField:TextField
        private var tFormat:TextFormat
        
        private var light:Sprite
        private var dolphin:Skin
        private var info:TextInfo
        
        private var scale:Number=0.5
        private var context :LoaderContext = new LoaderContext();

        public function Main() {
            
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;
            stage.quality = StageQuality.HIGH;
            //        Security.loadPolicyFile("http://marubayashi.net/crossdomain.xml");
            //    context.applicationDomain = ApplicationDomain.currentDomain;
            
            //---------------------------------
            // Root objectの作成
            //---------------------------------
            container = new ConflictContainer();
            
            //---------------------------------
            //背景の作成
            //---------------------------------
            //Caustics(水面、底面)Materialの作成
            back = new water()
            back.visible=false

            addChild(back)
            backMaterial = new TextureMaterial(new BitmapData(260, 860, false, 0x000033));
            backMaterial.texture.draw(back)
            //backMaterial.mipMapping = MipMapping.PER_PIXEL;
            //backMaterial.smooth = true;

            var blackMaterial:FillMaterial = new FillMaterial(0x0,0);
            
            // Box
            var box:Box = new Box(6000, 8000, 1400, 1, 1, 1, true,false,blackMaterial,blackMaterial,blackMaterial,blackMaterial,backMaterial,backMaterial);
            //box.setMaterialToAllFaces(backMaterial);
            container.addChild(box);
            box.y=2000
            box.blendMode=BlendMode.SCREEN
            box.rotationZ = 180 * Math.PI / 180
            box.sorting = Sorting.AVERAGE_Z;


            //---------------------------------
            //手前光の描画
            //---------------------------------
            light = new Sunlight()
            addChild(light)


            //---------------------------------
            //cameraの作成
            //---------------------------------
            camera = new Camera3D();
            camera.view = new View(800, 600);
            addChild(camera.view);

            camera.rotationX = -90*Math.PI/180;
            //camera.rotationZ = -10*Math.PI/180;
            camera.x = -0;
            camera.y = -500;
            camera.z = -0;

            container.addChild(camera);

            addChild(frame);

            
            loader = new URLLoader();
            loader.addEventListener(Event.COMPLETE, onModelLoad);
            loader.load(new URLRequest(modelURL));
            
            // Info
            info = new TextInfo();
            info.x = 3;
            info.y = 3;

            addChild(info);
            
            
            onResize();
        }
        

        private function onModelLoad(e:Event):void {

            //イルカを格納するContainer
            dolphinObject = new ConflictContainer();
            dolphinObject.resolveByAABB = true;
            dolphinObject.resolveByOOBB = true;
            dolphinObject.scaleX=scale
            dolphinObject.scaleY=scale
            dolphinObject.scaleZ=scale
            container.addChild(dolphinObject)
            
            //----------------------------------------------------
            //Blenderが吐き出すDaeファイルでは、以下の置換が必要
            //----------------------------------------------------
            var myPattern:RegExp = /IDREF/g;
            loader.data=loader.data.replace(myPattern, "Name");

            //----------------------------------------------------
            //パース
            //----------------------------------------------------
            var collada:ParserCollada = new ParserCollada();
            //collada.parse(XML(loader.data), modelURL);
            collada.parseForAnimation(XML(loader.data),  modelURL);
            //collada.parseForStatic(XML(loader.data),    modelURL);
            
            var objects:* = collada.objects;

            //----------------------------------------------------
            //objectのadd
            //----------------------------------------------------
            var bones:Object3DContainer
            var boneY:Number=0
            var count:int = objects.length;
            for (var o:int = 0;  o < count; o++) {
                if (objects[o].name == 'Camera') {
                    //trace(objects[o].name,o)
                } else {
                    dolphinObject.addChild(objects[o]);
                    dolphin = objects[o] as Skin
                    dolphin.sorting = Sorting.AVERAGE_Z;
                    dolphin.rotationZ = -90 * Math.PI / 180
                    dolphin.y=100
                }
            }
            
            //----------------------------------------------------
            //どうもボーンの回転が、基点軸回転ではない(Translation後Rotationしてる?)
            //ようなのでアニメも自作する。また、逆行列の扱いがblenderが吐き出す物と違うため、
            //ボーンの始点を動かすと、スキンが伸びてしまう。
            //なので、ボーンの再配置からやり直す。
            //Dae側で、ルートボーン以下を並列で配置しておく
            //(つなげていると呼び出すのがめんどくさい)
            //----------------------------------------------------
            var joint:Joint
            joint = dolphin.getJointAt(0);

            //アニメシーケンスの作成
            var matrixAnimations:Vector.<MatrixAnimation> = new Vector.<MatrixAnimation>()
            matrixAnimations[0] = new MatrixAnimation(joint.getJointAt(0))
            matrixAnimations[1] = new MatrixAnimation(joint.getJointAt(1))
            matrixAnimations[2] = new MatrixAnimation(joint.getJointAt(2))
            
            //Trackはコンストラクタで初期化されていないので、自前で作成
            var track1:Track = new Track();
            var track2:Track = new Track();
            var track3:Track = new Track();
            
            matrixAnimations[0].matrix = track1
            matrixAnimations[1].matrix = track2
            matrixAnimations[2].matrix = track3

            var keyTime:Vector.<Number> = Vector.<Number>([0.04000, 0.44000, 0.84000, 1.24000, 1.64000]);
            var boneXs:Vector.<Number> = Vector.<Number>([120,200,280]);
            var rounds:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>()
            var rot1:Number=5
            var rot2:Number=10
            var rot3:Number=40
            rounds[0] = Vector.<Number>([0, rot1, 0, -rot1, 0]);
            rounds[1] = Vector.<Number>([0, rot2, 0, -rot2, 0]);
            rounds[2] = Vector.<Number>([0, rot3, 0, -rot3, 0]);
            
            var trans:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>()
            trans[0] = Vector.<Number>([0, 0, 0, 0, 0]);
            trans[1] = Vector.<Number>([0, Math.sin(rot1*Math.PI/180)*120, 0, -Math.sin(rot1*Math.PI/180)*120, 0]);
            trans[2] = Vector.<Number>([0, Math.sin(rot2*Math.PI/180)*80+Math.sin(rot1*Math.PI/180)*120, 0, -Math.sin(rot2*Math.PI/180)*80-Math.sin(rot1*Math.PI/180)*120, 0]);

            for (var m:int = 0; m < 3 ;m++ ) {
                for (var t:int = 4; t >=0 ;t-- ) {
                    var animeMatrix:Matrix3D = new Matrix3D()
                    animeMatrix.prependTranslation(boneXs[m],0,0);
                    animeMatrix.prependRotation(rounds[m][t], Vector3D.Z_AXIS);
                    animeMatrix.prependTranslation(-boneXs[m], trans[m][t],0);
                    matrixAnimations[m].matrix.addKey(new MatrixKey(keyTime[t], animeMatrix))
                }
                //ループする時間を設定(これがないと動かない)
                matrixAnimations[m].length = 1.64
            }
            
            
            //出来たアニメはAnimationグループへ
            var animations:AnimationGroup = new AnimationGroup(dolphin);
            animations.addAnimation(matrixAnimations[0]);
            animations.addAnimation(matrixAnimations[1]);
            animations.addAnimation(matrixAnimations[2]);
            //ループする時間を設定(これがないと動かない)
            //animations.length=1.64
            
            
            animationController = new AnimationController()
            //var animation:Animation = collada.getAnimationByObject(objects[0]);
            animationController.addAnimation('tail',animations, true);
            
            animationController.playAll()
            animationTimer = new AnimationTimer()
            animationTimer.addController(animationController)
            animationTimer.start()
            

            //----------------------------------------------------
            // Camera controller
            //----------------------------------------------------
            cameraController = new SimpleObjectController(stage, camera, 200);
            cameraController.mouseSensitivity = 0
            cameraController.unbindAll()

            camera.debug = true;
            //camera.farClipping=2
            addChild(camera.diagram);
            //camera.addToDebug(Debug.BONES,objects[0])
            //camera.addToDebug(Debug.EDGES,objects[0])


            //----------------------------------------------------
            //イルカコントローラー
            //----------------------------------------------------
            moveController = new dolphinController(stage, dolphinObject, 400*scale, 5);
            //moveController.mouseSensitivity=0
            moveController.unbindAll()
            moveController.bindKey(87,        SimpleObjectController.ACTION_FORWARD);
            moveController.bindKey(Keyboard.UP,        SimpleObjectController.ACTION_PITCH_DOWN);
            moveController.bindKey(90,        SimpleObjectController.ACTION_BACK);
            moveController.bindKey(Keyboard.DOWN,    SimpleObjectController.ACTION_PITCH_UP);
            moveController.bindKey(65,        SimpleObjectController.ACTION_YAW_LEFT);
            moveController.bindKey(Keyboard.LEFT,    SimpleObjectController.ACTION_YAW_LEFT);
            moveController.bindKey(68,        SimpleObjectController.ACTION_YAW_RIGHT    );
            moveController.bindKey(Keyboard.RIGHT, SimpleObjectController.ACTION_YAW_RIGHT);
            dolphinObject.rotationZ = 90 * Math.PI / 180
            
            moveController.bindKey(Keyboard.SHIFT,SimpleObjectController.ACTION_ACCELERATE);
            moveController.bindKey(Keyboard.ENTER,SimpleObjectController.ACTION_ACCELERATE);

            //----------------------------------------------------
            //Texture作成
            //----------------------------------------------------
            //materialLoaderへはVectorで渡す
            //Loadが終わると勝手に貼り付けてくれる。
            textures = new Vector.<TextureMaterial>(1);
            textures[0] = new TextureMaterial();
            textures[0] = new TextureMaterial();
            textures[0].diffuseMapURL='http://marubayashi.net/archive/sample/alt3d7/texture.jpg'
            
            dolphin.setMaterialToAllFaces(textures[0])

            materialLoader = new MaterialLoader();
            materialLoader.addEventListener(Event.COMPLETE, onMaterialsLoad);
            materialLoader.load(textures);


        }
        
        private var state:AnimationState
        
        private function onMaterialsLoad(e:Event):void {
            //MaterialのLoad処理終了
            addEventListener(Event.ENTER_FRAME, onEnterFrame);
            stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
            stage.addEventListener(Event.RESIZE, onResize);
        }
        
        
        public function onEnterFrame(e:Event = null):void {
            if (dolphinObject != null) {
                var ty:Number = dolphinObject.z / (dolphinObject.y + focalLength) * focalLength
                var tx:Number = dolphinObject.x / (dolphinObject.y + focalLength) * focalLength
                var size:Number = 400*scale / (dolphinObject.y + focalLength) * focalLength
                
                if (dolphinObject.y < -2000 || Math.abs(tx) > camera.view.width / 2 + size || Math.abs(ty) > camera.view.height / 2 + size ) {
                    moveController.lookAtXYZ(0, 2000, 0)
                    moveController.onKeyUp();
                }
                if (anim) {
                    moveController.moveForward(true);
                } else {
                    moveController.moveForward(false);
                }
            } else {
                
            }
            moveController.update();

            animationTimer.update()
            animationController.update(0.005);
            cameraController.update();

            camera.render();
            backMaterial.texture.draw(back)
        }
        
        private function onKeyDown(e:KeyboardEvent):void {
            switch (e.keyCode) {
                case Keyboard.TAB:
                    camera.debug = !camera.debug;
                    break;
                case Keyboard.ENTER:
                    moveController.lookAtXYZ(0, 0, 0)
                    
                    break;
                case Keyboard.SPACE:
                    anim = !anim;
                    break;
                case 81: // Q
                    if (stage.quality == "HIGH") {
                        stage.quality = StageQuality.LOW;
                    } else {
                        stage.quality = StageQuality.HIGH;
                    }
                    break;
            }
        }

        
        public function onResize(e:Event = null):void {
            var pd:Number = 80;
            camera.view.width = stage.stageWidth// - pd*2;
            camera.view.height = stage.stageHeight// - pd*2;
            camera.view.x = 0//pd;
            camera.view.y = 0//pd;
            
            var colors:Array=new Array(0xDDEEFF,0x003366,0x000000,0x000000,0x002266,0x9999FF)
            var alphas:Array=new Array(1,1,1,1,1,1)
            var ratios:Array=new Array(0,100,140,150,180,255)
            var matrix:Matrix=new Matrix()
            matrix.createGradientBox(stage.stageWidth, stage.stageHeight, Math.PI / 2, 0, 0)
            graphics.clear()
            graphics.beginGradientFill(GradientType.LINEAR,colors, alphas, ratios, matrix)
            graphics.drawRect(0,0,stage.stageWidth,stage.stageHeight)
            
            //cameraからイルカまでの距離
            var d:Vector3D=new Vector3D(dolphinObject.x,dolphinObject.y,dolphinObject.z)
            var c:Vector3D=new Vector3D(0,-500,0)            
            var distance:Number = Vector3D.distance(c,d);            
            camera.fov = 2 * Math.atan2(Math.sqrt(camera.view.width * camera.view.width +camera.view.height * camera.view.height) / 2,distance);



        }
        
    }
}







//-----------------------------------------------------------------
//イルカController
//なんちゃって当たり判定付き
//-----------------------------------------------------------------

import alternativ7.engine3d.controllers.SimpleObjectController;
import alternativ7.engine3d.core.Object3D;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.display.BlendMode;
import flash.display.GradientType;
import flash.display.Graphics;
import flash.display.InteractiveObject;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.TimerEvent;
import flash.filters.BlurFilter;
import flash.filters.DisplacementMapFilter;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.geom.Vector3D;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.utils.Timer;

class dolphinController extends SimpleObjectController{

    public var _target:Object3D
    private var _yawSpeed:Number= 1.5
    private var _pitchSpeed:Number = 2
    public var _pitchDown:Boolean
    public var _pitchUp:Boolean
    public var _yawLeft:Boolean
    public var _yawRight:Boolean

    public var _yawNear:Boolean=false
    public var _yawNearAngle:Number

    public var _pitchNear:Boolean=false
    public var _pitchNearAngle:Number
    
    
    public function dolphinController(param0:InteractiveObject, param1:Object3D, param2:Number, param3:Number = 3, param4:Number = 1) {
        _target=param1
        super(param0, param1, param2, param3, param4);
        
        param0.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
        param0.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
    }
    
    public function onKeyDown(e:KeyboardEvent):void {
        
        for (var key:String in keyBindings) {
            if (String(e.keyCode)==key) {
                keyBindings[key](true)
            }
        }
    }
    
    public function onKeyUp(e:KeyboardEvent = null):void {
        for (var key:String in keyBindings) {
            /*
            if (e) {
                if (String(e.keyCode)==key) {
                    keyBindings[key](false)
                }
            } else {
            }*/
            keyBindings[key](false)
        }
        _yawNear = false
        _pitchNear = false;
    }

    
    override public function bindKey(param0:uint, param1:String): void {
        switch (param1) {
            case ACTION_YAW_LEFT:
                keyBindings[param0]=yawLeft
            break
            case ACTION_YAW_RIGHT:
                keyBindings[param0]=yawRight
            break
            case ACTION_PITCH_DOWN:
                keyBindings[param0]=pitchDown
            break
            case ACTION_PITCH_UP:
                keyBindings[param0]=pitchUp
            break
        }
        super.bindKey(param0, param1)
    }
    

    public function pitchDown(value:Boolean):void {
        _pitchDown=value
    }
    public function pitchUp(value:Boolean):void {
        _pitchUp=value
    }
    public function yawLeft(value:Boolean,near:Boolean=false):void {
        _yawLeft = value
        if (near) {
            _yawNear = true
        }
    }
    public function yawRight(value:Boolean,near:Boolean=false):void {
        _yawRight = value
        if (near) {
            _yawNear = true
        }
    }
    
    
    override public function update(): void {
        //現在のVector3D
        var nowVector:Vector3D=new Vector3D(_target.x,_target.y,_target.z)
        
        if (_yawLeft) {
            _target.rotationZ = (((_target.rotationZ / Math.PI * 180) - _yawSpeed) % 360) *    Math.PI/180
        } else if (_yawRight) {
            _target.rotationZ = (((_target.rotationZ / Math.PI * 180) + _yawSpeed) % 360) *    Math.PI/180
        }
        
        if (_pitchDown) {
            _target.rotationX=(((_target.rotationX / Math.PI * 180) + _pitchSpeed) % 360) *    Math.PI/180
        }
        if (_pitchUp) {
            _target.rotationX=(((_target.rotationX / Math.PI * 180) - _pitchSpeed) % 360) *    Math.PI/180
        }
        
        updateObjectTransform()
        super.update()

        //Colsion関係がまだ実装されてないので、Controller内で無理やり対応
        //Vector3Dで処理せんといかん
        //現在の進行方向をVector3Dに記憶
        
        var nextVector:Vector3D = new Vector3D(_target.x, _target.y, _target.z)
        //現在の進行方向
        var velocity:Vector3D = nextVector.subtract(nowVector);
        var normalVelocity:Vector3D
        if (_target.y > 30000) {
            normalVelocity = collision(velocity, new Vector3D(0, 1, 0))
            lookAt(nextVector.add(normalVelocity))
            _target.y = 29999
        }
        if (_target.z > 10000) {
            //上なので、下向きベクトル
            //normalVelocity = collision(velocity, new Vector3D(0, 0, -1))
            //lookAt(nextVector.add(normalVelocity))
            _target.rotationX=(((_target.rotationX / Math.PI * 180) - _pitchSpeed) % 360) *    Math.PI/180
            _target.z=9999
        } else if (_target.z < -1000) {
            //normalVelocity = collision(velocity, new Vector3D(0, 0, 1))
            //lookAt(nextVector.add(normalVelocity))
            _target.rotationX=(((_target.rotationX / Math.PI * 180) + _pitchSpeed) % 360) *    Math.PI/180
            _target.z = -999

        }
        
        
        
        
    }
    
    
    
    public function collision(velocity:Vector3D, faceNormal:Vector3D):Vector3D {
        //衝突面のnormalと進行方向の内積で新たな方向を出す

        //進行方向を反転させる
        var reverse:Vector3D
        //Faceの法線を正規化
        var tempVector:Vector3D=faceNormal.clone()
        tempVector.normalize()
        //進行スピードを反転する
        reverse = velocity.clone()
        reverse.negate()
        //投影の長さを計算
        //投影の長さに面法線ベクトル*衝突後の速度をかける
        //tempVector.scaleBy(2*tempVector.dotProduct(reverse))
        tempVector.scaleBy(2*tempVector.dotProduct(reverse)/10)
            
        return velocity.add(tempVector);
    }
    
    

    
    public function set yawSpeed(value:Number):void {
        _yawSpeed = value*Math.PI/180;
    }
    
    public function set pitchSpeed(value:Number):void
    {
        _pitchSpeed = value*Math.PI/180;
    }
    
}





class TextInfo extends TextField {

    public function TextInfo() {
        autoSize = TextFieldAutoSize.LEFT;
        selectable = false;
        defaultTextFormat = new TextFormat("Tahoma", 10, 0x7F7F7F);
    }
    
    public function write(value:String):void {
        appendText(value + "\n");
    }
    
    public function clear():void {
        text = "";
    }
}








/**
 * 海面から射す光
 *
 * @author narutohyper
 */
class Sunlight extends Sprite
{
    private var angle:uint = 0
    private var light:Sprite=new Sprite()
    private var yuragi:BitmapData;
    
    public function Sunlight()
    {
        makelight()
        addEventListener(Event.ADDED_TO_STAGE, init);
    }

    private function init(event : Event) : void {
        stage.addEventListener(Event.RESIZE, onResize);
        onResize()
    }
    
    private function makelight():void {
        var angleArray:Array = new Array()
        var lightArray:Array = new Array()
        while (angle < 360) {
            angle += Math.floor(Math.random() * 5)
            angleArray.push(angle)
        }


        var rx1:Number
        var ry1:Number
        var rx2:Number
        var ry2:Number
        var colors:Array=new Array(0xFFFFFF,0xFFFFFF)
        var alphas:Array=new Array(1,0)
        var ratios:Array=new Array(100,255)
        var matrix:Matrix = new Matrix();
        matrix.createGradientBox(400,400,0,-200,-200)
        light.graphics.beginGradientFill(GradientType.RADIAL,colors, alphas, ratios, matrix)
        for (var i:uint = 0; i < angleArray.length - 3; i += 3) {
            if (angleArray[i]>0 && angleArray[i]<90) {
                rx1=Math.sin(angleArray[i]*Math.PI/180)
                ry1=Math.cos(angleArray[i]*Math.PI/180)
                rx2=Math.sin(angleArray[i+1]*Math.PI/180)
                ry2=Math.cos(angleArray[i+1]*Math.PI/180)
                light.graphics.moveTo(rx1*10,ry1*10)
                light.graphics.lineTo(rx2*10,ry2*10)
                light.graphics.lineTo(rx2*200,ry2*200)
                light.graphics.lineTo(rx1 * 200, ry1 * 200)
            }
        }
        light.graphics.endFill()
        light.x=0
        light.y=0
        var f1:BlurFilter = new BlurFilter(20, 20, 1);

        light.blendMode=BlendMode.ADD
        light.alpha = 0.2
        addChild(light)


        light.filters = [f1];
    }
    
    
    private function createMap(width:int, height:int):BitmapData{
            var bmp:BitmapData = new BitmapData(width, height, false, 0xffffff);
            for(var j:int = 0; j < height; j++){
                    for(var i:int = 0; i < width; i++){
                            bmp.setPixel(i, j, 32*Math.sin(Math.PI*3/height*j)+128+64);
                    }
            }
            return bmp;
    }
    
    public function onResize(e:Event = null):void {
        height=stage.stageHeight*1.5
        width=stage.stageHeight*1.5
        //light.x = 400
        //light.y= 300
        y=stage.stageHeight/-2
    }
    
}













/**
 * 以下は、
 * Caustics(水面、底面)Materialの作成
 *
 *
 * 超速ボロノイ図(Fortune's algorithm)
 * http://wonderfl.net/c/3TKq
 *
 * を使用させていただいてます。
 *
 * 正直、なにやってるかわかりませんw
 *
 *
 */

/**
 * 超速ボロノイアルゴリズム
 * 元ネタ
 * Fortune's algorithm - Wikipedia, the free encyclopedia
 * http://en.wikipedia.org/wiki/Fortune's_algorithm
 * Controul > Speedy Voronoi diagrams in as3/flash
 * http://blog.controul.com/2009/05/speedy-voronoi-diagrams-in-as3flash/
 * 上記blogのasそのままです(Fortuneクラス)。
 * 全然ロジックわからないので誰か解説してほしいです。
 *
 * 母点を800程度にしてますがもう少し多くてもいけそう。
 * fullscreenでもお楽しみいただけます(重いけど)
 *
 * 日本語の資料(PDF)
 * http://atom.is.ocha.ac.jp/~kanenko/KOUGI/CompGeo/cpgeob.pdf
 * http://i-health.u-aizu.ac.jp/CompuGeo/2008/handouts/chapter4/Chapter4H.pdf
 */


//import com.flashdynamix.utils.SWFProfiler;

class water extends Sprite {
        //キャンパス
        private var _gradation : Sprite;
        private var _canvas : Sprite;
        //background
        private var _background:BitmapData;
        //voronoi母点数
        private const Q : uint = 200;
        //voronoi作図用のクラス
        private var fortune : Fortune;
        //voronoi母点(パーティクル的な?)
        private var points : Vector.<Number2>;
        private var _first : Number2;

        private var stageWidth : int=300;
        private var stageHeight : int=300;
        private var yuragi:BitmapData;
        private var bmd:BitmapData;
        private var bm:Bitmap;
        private var bmd2:BitmapData;
        private var bm2:Bitmap;
        public function water() {
            addEventListener(Event.ADDED_TO_STAGE, _initialize);
        }

        /**
         * 初期化
         */
        private function _initialize(event : Event) : void {
                var i : uint,old : Number2,point : Number2;
                removeEventListener(Event.ADDED_TO_STAGE, _initialize);
                //SWFProfiler.init(this);

                //背景カラー
                bmd = new BitmapData(stageWidth , 900, false, 0x0);
                bm=new Bitmap(bmd)
                bmd2 = new BitmapData(stageWidth-40 , 860, false, 0x0);
                yuragi = createMap3(stageWidth , 900)
                
                //bm2=new Bitmap(yuragi)
                bm2=new Bitmap(bmd2)
                addChild(bm2);
                //キャンパス設定
                _canvas = new Sprite();
                _gradation = new Sprite()
                addChild(_gradation);
                
                var colors:Array=new Array(0xFFFFFF,0x000000)
                var alphas:Array=new Array(1,1)
                var ratios:Array=new Array(0,160)
                var matrix:Matrix=new Matrix()
                matrix.createGradientBox(stageWidth-40, 860, Math.PI / 2, 0, 0)
                _gradation.graphics.clear()
                _gradation.graphics.beginGradientFill(GradientType.LINEAR,colors, alphas, ratios, matrix)
                _gradation.graphics.drawRect(0,0,stageWidth-40,860)
                _gradation.blendMode=BlendMode.MULTIPLY
                
                
                
                //voronoi母点生成
                points = new Vector.<Number2>();
                for(i = 0;i < Q;i++) {
                        point = new Number2();
                        point.x = stageWidth * Math.random();
                        point.y = stageHeight * Math.random();
                        //各母点の速度

                        point.vx = (Math.random()*2-1)*0.5;
                        point.vy = (Math.random()*2-1)*0.5;
                        points.push(point);
                }
                //voronoi母点リンクリスト生成
                for(i = 0;i < Q;i++) {
                        point = points[i];
                        if (_first == null) {
                                old = _first = point;
                        } else {
                                old.next = point;
                                old = point;
                        }
                }

                //ボロノイ作図用クラス
                fortune = new Fortune();

                //addEventListener(Event.ENTER_FRAME, _updateHandler);
                
                var timer:Timer = new Timer(60, 0)
                timer.addEventListener(TimerEvent.TIMER, _updateHandler);
                timer.start()
                
        }

        
        
        
        private function createMap3(width:int, height:int):BitmapData{
                var bmp:BitmapData = new BitmapData(width, height, false, 0xffffff);
                for(var j:int = 0; j < height; j++){
                        for(var i:int = 0; i < width; i++){
                                bmp.setPixel(i, j, 128*Math.sin(Math.PI*10/height*j));
                        }
                }
                return bmp;
        }

        
        
        
        //アップデート
        private function _updateHandler(event : Event) : void {
            _interaction();
            _draw();
            //removeEventListener(Event.ENTER_FRAME, _updateHandler);

            var f1:DisplacementMapFilter = new DisplacementMapFilter(yuragi, new Point(0,0),
                        BitmapDataChannel.BLUE, BitmapDataChannel.BLUE, 100, 0, "color", 0x0);
            var f2:BlurFilter = new BlurFilter(6, 6, 1);
            bmd.fillRect(new Rectangle(0, 0, 300, 900), 0x000000);
            bmd.draw(_canvas,new Matrix(1, 0, 0, 1, 0, 250), null, null, new Rectangle(0, 250, 300, 650));
            bm.filters = [f1,f2];
            bmd2.draw(bm, new Matrix(1, 0, 0, 1, -20, -20), null, null, new Rectangle(0, 0, 260, 880));
            
        }

        //インタラクション
        private function _interaction() : void {
                var point : Number2 = _first;

                do {
                        //母点の位置を更新
                        point.x += point.vx;
                        point.y += point.vy;
                        if(point.x > stageWidth) {
                                point.x -= stageWidth;
                        }else if(point.x < 0) {
                                point.x += stageWidth;
                        }
                        if(point.y > stageHeight) {
                                point.y -= stageHeight;
                        }else if(point.y < 0) {
                                point.y += stageHeight;
                        }
                } while (point = point.next);

                //更新した母点をvoronoi作図用クラスに入れる
                fortune.points = points;
        }

        //描画
        private function _draw() : void {
                //ボロノイ頂点
                var segments : Vector.<Number2> = fortune.compute(),
                        i : uint,start : Number2,end : Number2,
                        point : Number2 = _first,
                        g : Graphics = _canvas.graphics;

                //ボロノイ辺の描画
                g.clear();
                g.beginFill(0x000000)
                g.drawRect(0,0,300,300)
                g.lineStyle(5, 0xFFFFFF, 1);
                for(i = 0;i < segments.length;i += 2) {
                        start = segments[i];
                        end = segments[i + 1];
                        g.moveTo(start.x, start.y);
                        g.lineTo(end.x, end.y);
                }

        }
}






/*
 * Fortune's algorithm
 * http://blog.controul.com/2009/05/speedy-voronoi-diagrams-in-as3flash/
 * オリジナルは上記blogからダウンロードして見てください!
 * はっきりいって全然わからないのでなにやってるのかどなたか解説を!
 */

class Fortune {

        //        voronoi図の母点となる点群
        public var points : Vector.<Number2>;

        //        Bounding box.
        private var x0 : Number;

        //        Root of the frontline and next arc to be removed.
        private var root : Arc;
        private var next : Arc;

        //        Reusable objects and pools.
        private var o : Number2 = new Number2;
        private static var arcPoolD : Arc;



        /**
         * 与えられた母点からvoronoi頂点群を返します.
         * @return A vector or vertices in pairs, describing segments ready for drawing.
         */

        public function compute() : Vector.<Number2> {
                //        Clear the output.
                var out : Vector.<Number2> = new Vector.<Number2>,
                                len : int = 0;

                //        Clear the state.
                root = null;
                next = null;

                //        Read the pools.
                var key : * ,
                                arcPool : Arc = arcPoolD;

                //        Vars:
                var i : int,
                                j : int,
                                w : Number,
                                x : Number,

                                a : Arc,
                                b : Arc,

                                z : Number2,

                                p : Number2 = points[ 0 ],
                                points : Vector.<Number2> = points,
                                n : int = points.length,

                        //        Circle events check inlined.
                                circle : Boolean,
                                eventX : Number,

                                c : Arc,
                                d : Arc,

                                aa : Number2,
                                bb : Number2,
                                cc : Number2,

                                A : Number,
                                B : Number,
                                C : Number,
                                D : Number,
                                E : Number,
                                F : Number,
                                G : Number;


                //        与えられた母点をx軸でソート
                /////      Currently insertion sort. Quicksort?
                w = points[ 0 ].x;

                for ( i = 1;i < n;i++ ) {
                        p = points[ i ];

                        //        Insertion sort.
                        x = p.x;
                        if ( x < w ) {
                                j = i;
                                while ( ( j > 0 ) && ( points[ int(j - 1) ].x > x ) ) {
                                        points[ j ] = points[ int(j - 1) ];
                                        j--;
                                }
                                points[ j ] = p;
                        }
                                else
                                        w = x;
                }

                //        Get x bounds.
                x0 = points[ 0 ].x;

                //        Process.
                i = 0;
                p = points[ 0 ];
                x = p.x;

                //多分母点群でループ
                for ( ;; ) {

                        //        Check circle events. /////////////////////////
                        if ( a ) {
                                //        Check for arc a.
                                circle = false;

                                if ( a.prev && a.next ) {
                                        aa = a.prev.p,
                                        bb = a.p,
                                        cc = a.next.p;

                                        //        Algorithm from O'Rourke 2ed p. 189.
                                        A = bb.x - aa.x,
                                        B = bb.y - aa.y,
                                        C = cc.x - aa.x,
                                        D = cc.y - aa.y;

                                        //        Check that bc is a "right turn" from ab.
                                        if ( A * D - C * B <= 0 ) {
                                                E = A * ( aa.x + bb.x ) + B * ( aa.y + bb.y ),
                                                F = C * ( aa.x + cc.x ) + D * ( aa.y + cc.y ),
                                                G = 2 * ( A * ( cc.y - bb.y ) - B * ( cc.x - bb.x ) );

                                                //        Check for colinearity.
                                                //        if ( G > 0.000000001 || G < -0.000000001 )
                                                if ( G ) {
                                                        //        Point o is the center of the circle.
                                                        o.x = ( D * E - B * F ) / G;
                                                        o.y = ( A * F - C * E ) / G;

                                                        //        o.x plus radius equals max x coordinate.
                                                        A = aa.x - o.x;
                                                        B = aa.y - o.y;
                                                        eventX = o.x + Math.sqrt(A * A + B * B);

                                                        if ( eventX >= w ) circle = true;
                                                }
                                        }
                                }

                                //        Remove from queue.
                                if ( a.right )
                                                a.right.left = a.left;
                                if ( a.left )
                                                a.left.right = a.right;
                                if ( a == next )
                                                next = a.right;

                                //        Record event.
                                if ( circle ) {
                                        a.endX = eventX;
                                        if ( a.endP ) {
                                                a.endP.x = o.x;
                                                a.endP.y = o.y;
                                        } else {
                                                a.endP = o;
                                                o = new Number2;
                                        }

                                        d = next;
                                        if ( !d ) {
                                                next = a;
                                        }
                                                else for ( ;; ) {
                                                if ( d.endX >= eventX ) {
                                                        a.left = d.left;
                                                        if ( d.left ) d.left.right = a;
                                                        if ( next == d ) next = a;
                                                        a.right = d;
                                                        d.left = a;
                                                        break;
                                                }
                                                if ( !d.right ) {
                                                        d.right = a;
                                                        a.left = d;
                                                        a.right = null;
                                                        break;
                                                }
                                                d = d.right;
                                        }
                                } else {
                                        a.endX = NaN;
                                        a.endP = null;
                                        a.left = null;
                                        a.right = null;
                                }

                                //        Push next arc to check.
                                if ( b ) {
                                        a = b;
                                        b = null;
                                        continue;
                                }
                                if ( c ) {
                                        a = c;
                                        c = null;
                                        continue;
                                }
                                a = null;
                        }

                        //////////////////////////////////////////////////
                        //
                        if ( next && next.endX <= x ) {
                                //
                                //        Handle next circle event.

                                //        Get the next event from the queue. ///////////
                                a = next;
                                next = a.right;
                                if ( next )
                                                next.left = null;
                                a.right = null;

                                //        Remove the associated arc from the front.
                                if ( a.prev ) {
                                        a.prev.next = a.next;
                                        a.prev.v1 = a.endP;
                                }
                                if ( a.next ) {
                                        a.next.prev = a.prev;
                                        a.next.v0 = a.endP;
                                }

                                if ( a.v0 ) {
                                        out[ len++ ] = a.v0;
                                        a.v0 = null;
                                        out[ len++ ] = a.endP;
                                }
                                if ( a.v1 ) {
                                        out[ len++ ] = a.v1;
                                        a.v1 = null;
                                        out[ len++ ] = a.endP;
                                }

                                //        Keep a ref for collection.
                                d = a;

                                //        Recheck circle events on either side of p:
                                w = a.endX;
                                if ( a.prev ) {
                                        b = a.prev;
                                        a = a.next;
                                } else {
                                        a = a.next;
                                        b = null;
                                }
                                c = null;

                                //        Collect.
                                d.v0 = null;
                                d.v1 = null;
                                d.p = null;
                                d.prev = null;
                                d.endX = NaN;
                                d.endP = null;
                                d.next = arcPool;
                                arcPool = d;

                                        //////////////////////////////////////////////////
                                        //
                        } else {
                                if ( !p ) break;

                                //
                                //        Handle next site event. //////////////////////

                                if ( !root ) {
                                        if ( arcPool ) {
                                                root = arcPool;
                                                arcPool = arcPool.next;
                                                root.next = null;
                                        }
                                                else
                                                        root = new Arc;
                                        root.p = p;
                                } else {

                                        z = new Number2;

                                        //        Find the first arc with a point below p,
                                        //        and start searching for the intersection around it.
                                        a = root.next;
                                        if ( a ) {
                                                        while ( a.next ) {
                                                                a = a.next;
                                                                if ( a.p.y >= p.y ) break;
                                                        }

                                                        //        Find the intersecting curve.
                                                        intersection(a.prev.p, a.p, p.x, z);
                                                        if ( z.y <= p.y ) {

                                                                //        Search for the intersection to the south of i.
                                                                while ( a.next ) {
                                                                        a = a.next;
                                                                        intersection(a.prev.p, a.p, p.x, z);
                                                                        if ( z.y >= p.y ) {
                                                                                a = a.prev;
                                                                                break;
                                                                        }
                                                                }
                                                        } else {
                                                                //        Search for the intersection above i.
                                                                a = a.prev;
                                                                while ( a.prev ) {
                                                                        a = a.prev;
                                                                        intersection(a.p, a.next.p, p.x, z);
                                                                        if ( z.y <= p.y ) {
                                                                                a = a.next;
                                                                                break;
                                                                        }
                                                                }
                                                        }
                                                }
                                                else
                                                        a = root;

                                        //        New parabola will intersect arc a. Duplicate a.
                                        if ( a.next ) {
                                                        if ( arcPool ) {
                                                                b = arcPool;
                                                                arcPool = arcPool.next;
                                                                b.next = null;
                                                        }
                                                        else
                                                                b = new Arc;
                                                        b.p = a.p;
                                                        b.prev = a;
                                                        b.next = a.next;
                                                        a.next.prev = b;
                                                        a.next = b;
                                                } else {
                                                        if ( arcPool ) {
                                                                b = arcPool;
                                                                arcPool = arcPool.next;
                                                                b.next = null;
                                                        }
                                                        else
                                                                b = new Arc;
                                                        b.p = a.p;
                                                        b.prev = a;
                                                        a.next = b;
                                                }
                                        a.next.v1 = a.v1;

                                        //        Find the point of intersection.
                                        z.y = p.y;
                                        z.x = ( a.p.x * a.p.x + ( a.p.y - p.y ) * ( a.p.y - p.y ) - p.x * p.x ) / ( 2 * a.p.x - 2 * p.x );

                                        //        Add p between i and i->next.
                                        if ( arcPool ) {
                                                        b = arcPool;
                                                        arcPool = arcPool.next;
                                                        b.next = null;
                                                }
                                                else
                                                        b = new Arc;

                                        b.p = p;
                                        b.prev = a;
                                        b.next = a.next;

                                        a.next.prev = b;
                                        a.next = b;

                                        a = a.next;      //      Now a points to the new arc.

                                        a.prev.v1 = z;
                                                a.next.v0 = z;
                                                a.v0 = z;
                                                a.v1 = z;

                                                //        Check for new circle events around the new arc:
                                                b = a.next;
                                                a = a.prev;
                                                c = null;
                                                w = p.x;
                                }

                                //////////////////////////////////////////////////
                                //

                                i++;
                                if ( i >= n ) {
                                                p = null;
                                                x = Number.MAX_VALUE;
                                        } else {
                                                p = points[ i ];
                                                x = p.x;
                                        }
                        }
                }

                //        Store the pools.
                arcPoolD = arcPool;

                //
                //
                //        Return the result ready for drawing.
                return out;
        }



                /**
                 * Where do two parabolas intersect?
                 * @param      p0 A Number2 object describing the site for the first parabola.
                 * @param      p1 A Number2 object describing the site for the second parabola.
                 * @param      l The location of the sweep line.
                 * @param      res A Number2 object in which to store the intersection.
                 * @return The point of intersection.
                 */
                public function intersection( p0 : Number2, p1 : Number2, l : Number, res : Number2 ) : Number2 {
                        var p : Number2 = p0,
                                ll : Number = l * l;

                        if ( p0.x == p1.x )
                                res.y = ( p0.y + p1.y ) / 2;
                        else if ( p1.x == l )
                                res.y = p1.y;
                        else if ( p0.x == l ) {
                                res.y = p0.y;
                                p = p1;
                        } else {
                                //        Use the quadratic formula.
                                var z0 : Number = 0.5 / ( p0.x - l ); // 1 / ( 2*(p0.x - l) )
                                var z1 : Number = 0.5 / ( p1.x - l ); // 1 / ( 2*(p1.x - l) )

                                var a : Number = z0 - z1;
                                var b : Number = -2 * ( p0.y * z0 - p1.y * z1 );
                                var c : Number = ( p0.y * p0.y + p0.x * p0.x - ll ) * z0 - ( p1.y * p1.y + p1.x * p1.x - ll ) * z1;

                                res.y = ( -b - Math.sqrt(b * b - 4 * a * c) ) / ( 2 * a );
                        }

                        //        Plug back into one of the parabola equations.
                        res.x = ( p.x * p.x + ( p.y - res.y ) * ( p.y - res.y ) - ll ) / ( 2 * p.x - 2 * l );
                        return res;
                }
}

class Arc {

        public var p : Number2;
        public var next : Arc;
        public var prev : Arc;
        public var v0 : Number2;
        public var v1 : Number2;

        //        Circle event data :
        public var left : Arc;
        public var right : Arc;
        public var endX : Number;
        public var endP : Number2;
}

class Number2 {
        public var x : Number;
        public var y : Number;
        //速度
        public var vx : Number;
        public var vy : Number;

        public var next : Number2;
}