SwingingLight forked from: Fluid on the Video
Copyright alumican_net ( http://wonderfl.net/user/alumican_net )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/wM1h
Fluid on the Video
*
* @author http://alumican.net
*
* 動画はこちらからお借りしています
* http://www.nicovideo.jp/watch/sm3605606
/**
* Copyright HaraMakoto ( http://wonderfl.net/user/HaraMakoto )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/sFXf
*/
/**
* Copyright alumican_net ( http://wonderfl.net/user/alumican_net )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/wM1h
*/
/**
* Fluid on the Video
*
* @author http://alumican.net
*
* 動画はこちらからお借りしています
* http://www.nicovideo.jp/watch/sm3605606
*/
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BlendMode;
import flash.display.Graphics;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.NetStatusEvent;
import flash.filters.BlurFilter;
import flash.filters.ColorMatrixFilter;
import flash.filters.DisplacementMapFilter;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.media.SoundTransform;
import flash.media.Video;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
// import net.hires.debug.Stats;
[SWF(width="465", height="465", backgroundColor="0x000000", frameRate="30")]
public class LiquidVideo extends Sprite
{
//CLASS CONSTANTS
private const MAP_WIDTH:Number = 465;
private const MAP_HEIGHT:Number = 465;
private const MAP_GRID_SIZE:Number = 20;
private const MAP_FLOW_SIZE:Number = 2;
private const MAP_INTENSITY:Number = 0.25;
private const MAP_SCALE:Number = 150;
private const MAP_USE_DECAY:Boolean = true;
private const MAP_BLUR_INTENSITY:uint = 32;
private const MAP_BLUR_QUALITY:uint = 2;
private const ZERO_POINT:Point = new Point(0,0);
//VARIABLES
private var _container:Sprite;
private var _canvas:BitmapData;
private var _canvasTone:ColorMatrixFilter;
private var _fluidMap:FluidMap;
private var _fluidBmp:Bitmap;
private var _mapBmd:BitmapData;
private var _mapFilter:DisplacementMapFilter;
private var _oldX:Number = 0;
private var _oldY:Number = 0;
private var _isMouseMove:Boolean = false;
private var _ns:NetStream;
private var _nc:NetConnection;
private var _video:Video;
private var _videoMatrix:Matrix;
private var _background:Sprite;
// private var _stats:Stats;
private var _usage:TextField;
/////////particle
private var _mirrorBmp:Bitmap = new Bitmap();
private var _mirrorBmd:BitmapData = new BitmapData(465,465,false,0);
private var _mirrorMtx:Matrix;
private var _transPoint:Point = new Point(465/2, 465/2);
private var _particleLayer:Sprite = new Sprite();
private var _particles:Array = [];
private var _emitter:Emitter;
// 1フレーム間に発生させる Particle 数
private const PARTICLE_NUM:uint = 1;
private var _blustLayer:Sprite = new Sprite();
private var _mixPoint:Sprite = new Sprite();
private var _mixcounter:int = 0;
//CONSTRUCTOR
public function LiquidVideo():void
{
// Wonderfl.disable_capture();
addEventListener(Event.ADDED_TO_STAGE, _initialize);
}
//METHODS
private function _initialize(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, _initialize);
addChild(_blustLayer);
_background = new Sprite();
addChild(_background);
_container = new Sprite();
addChild(_container);
_canvas = new BitmapData(MAP_WIDTH, MAP_HEIGHT, false, 0xffffff);
_fluidMap = new FluidMap(MAP_WIDTH, MAP_HEIGHT, MAP_GRID_SIZE, MAP_FLOW_SIZE, MAP_INTENSITY, MAP_USE_DECAY, MAP_SCALE, MAP_BLUR_INTENSITY, MAP_BLUR_QUALITY);
_container.addChild(new Bitmap(_canvas));
// _container.addChild(new Bitmap(_fluidMap._mapBmd));
_mapFilter = _fluidMap.mapFilter;
_canvasTone = new ColorMatrixFilter([
1, 0, 0, 0, 5,
0, 1, 0, 0, 5,
0, 0, 1, 0, 5,
0, 0, 0, 0, 0
]);
// _stats = new Stats( {
// bg:0xffffff,
// fps:0x333333,
// ms:0x333333,
// mem:0x333333,
// memmax:0x333333
// });
// _stats.blendMode = BlendMode.DARKEN;
// addChild(_stats);
_usage = new TextField();
_usage.defaultTextFormat = new TextFormat("MS Gothic", 11, 0x0);
_usage.text = "Move mouse on movie";
_usage.autoSize = TextFieldAutoSize.RIGHT;
_usage.selectable = false;
_usage.blendMode = BlendMode.INVERT;
_usage.visible = false;
_container.addChild(_usage);
stage.addEventListener(Event.RESIZE, _resizeHandler);
_resizeHandler();
setup();
addEventListener(Event.ENTER_FRAME, _update);
// addChild(_blustLayer);
}
//--------------------------------------------------------------------------------//
// パーティクル
//--------------------------------------------------------------------------------//
private function setup():void
{
_mirrorBmp.bitmapData = _mirrorBmd;
_blustLayer.addChild(_mirrorBmp);
_emitter = new Emitter();
_blustLayer.addChild(_particleLayer);
_particleLayer.addChild(_emitter);
for (var i:uint = 0; i < 100; i++) {
_particles.push(new Particle());
}
addEventListener(Event.ENTER_FRAME, draw);
stage.addEventListener(MouseEvent.MOUSE_MOVE, _mouseMoveHandler);
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
}
private function draw(event:Event):void
{
_emitter.update();
for each (var p:Particle in _particles) {
if (!p.destroy) {
if (p.y >= 10) {
// p.vy *= -0.9;
// p.vx *= -0.9
}
p.update();
}
}
//拡大反射
_mirrorMtx = new Matrix();
var ram:Number = 10+2*Math.random();
_mirrorMtx.translate(-_transPoint.x, -_transPoint.y);
_mirrorMtx.scale(ram,ram);
_mirrorMtx.translate(_transPoint.x, _transPoint.y);
_mirrorBmd.fillRect(_mirrorBmd.rect, 0x00000000);
_mirrorBmd.draw( _particleLayer, _mirrorMtx);
}
private function mouseDown(event:MouseEvent):void
{
addEventListener(Event.ENTER_FRAME, createParticle);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
_transPoint.x = mouseX;
_transPoint.y = mouseY;
}
private function mouseUp(event:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUp);
removeEventListener(Event.ENTER_FRAME, createParticle);
Wonderfl.disable_capture();
}
private function createParticle(event:Event):void
{
var count:uint = 0;
for each (var p:Particle in _particles) {
// 停止している Particle を探す
if (p.destroy) {
p.x = _emitter.x;
p.y = _emitter.y;
p.init();
_particleLayer.addChild(p);
count++;
}
if (count > PARTICLE_NUM) break;
}
}
//--------------------------------------------------------------------------------//
// 流体
//--------------------------------------------------------------------------------//
private function _drawCanvas():void
{
_canvas.lock();
_canvas.applyFilter(_canvas, _canvas.rect, ZERO_POINT, _canvasTone);
_canvas.draw(_blustLayer);
_canvas.applyFilter(_canvas, _canvas.rect, ZERO_POINT, _mapFilter);
_canvas.unlock();
}
private function _refillBackground():void
{
var sw:int = stage.stageWidth;
var sh:int = stage.stageHeight;
var g:Graphics = _background.graphics;
g.clear();
g.beginFill(0xffffff);
g.moveTo(0 , 0 );
g.lineTo(sw, 0 );
g.lineTo(sw, sh);
g.lineTo(0 , sh);
g.lineTo(0 , 0 );
g.endFill();
}
private function _update(e:Event):void
{
var speedX:Number = _mixPoint.x - _oldX;
var speedY:Number = _mixPoint.y - _oldY;
_fluidMap.addOrientedForce(_mixPoint.x, _mixPoint.y, speedX, speedY);
_mixPoint.x = 466/2 + 20 * Math.cos(_mixcounter * Math.PI/180)
_mixPoint.y = 466/2 + 10*Math.random() + 100 * Math.sin(_mixcounter * Math.PI/180)
_fluidMap.updateMap();
_drawCanvas();
_oldX = _mixPoint.x;
_oldY = _mixPoint.y;
_mixcounter+=1+20*Math.random();
}
private function _mouseMoveHandler(e:MouseEvent):void
{
_isMouseMove = true;
}
private function _resizeHandler(e:Event = null):void
{
_refillBackground();
_container.x = uint((stage.stageWidth - MAP_WIDTH ) / 2);
_container.y = uint((stage.stageHeight - MAP_HEIGHT) / 2);
// _stats.x = 2;
// _stats.y = stage.stageHeight - 45;
}
}
}
//--------------------------------------------------------------------------------//
// パーティクル関連クラス
//--------------------------------------------------------------------------------//
import flash.display.Sprite;
import flash.display.GradientType;
class Emitter extends Sprite
{
public var vx:Number = 0;
public var vy:Number = 0;
public function Emitter(){}
public function update():void
{
var dx:Number = root.mouseX - x;
var dy:Number = root.mouseY - y;
var d:Number = Math.sqrt(dx*dx+dy*dy) * 0.2;
var rad:Number = Math.atan2(dy, dx);
vx += Math.cos(rad)*d;
vy += Math.sin(rad)*d;
vx *= 0.7;
vy *= 0.7;
x += vx;
y += vy;
}
}
import flash.filters.BlurFilter;
import flash.geom.Matrix;
import flash.display.SpreadMethod;
class Particle extends Sprite
{
public var vx:Number;
public var vy:Number;
public var life:Number;
public var size:Number;
private var _count:uint;
private var _destroy:Boolean;
/**
* ブラウン運動関連
*/
private var friction:Number = 0.99;
private var vectx:Number = -0.4;
private var vecty:Number = -0.8;
private var xrandom:Number = 0.8;
private var yrandom:Number = 0.3;
public function Particle()
{
size = Math.random() * 30;
//白版
// var red:uint = Math.floor(Math.random()*10+246);
// var blue:uint = Math.floor(Math.random()*10+240);
// var green:uint = Math.floor(Math.random()*10+246);
//七色版
var red:uint = Math.floor(Math.random()*100+126);
var blue:uint = Math.floor(Math.random()*100+124);
var green:uint = Math.floor(Math.random()*246+10);
var color:Number = (red << 16) | (green << 8) | (blue);
var fillType:String = GradientType.RADIAL;
var colors:Array = [color , 0x000000];
var alphas:Array = [100, 100];
var ratios:Array = [0x00, 0xFF];
var mat:Matrix = new Matrix();
mat.createGradientBox(size * 2, size * 2, 0, -size, -size);
var spreadMethod:String = SpreadMethod.PAD;
graphics.clear();
graphics.beginGradientFill(fillType, colors, alphas, ratios, mat, spreadMethod);
graphics.drawCircle(0, 0, size);
graphics.endFill();
// 大量のオブジェクトを重ねるとおかしくなる
blendMode = "add";
_destroy = true;
}
public function init():void
{
vx = Math.random() * 20 - 10;
vy = Math.random() * 20 - 10;
life = Math.random() * 20 + 10;
_count = 0;
_destroy = false;
}
public function update():void
{
vx += Math.random()*xrandom + vectx;
vy += Math.random()*yrandom + vecty;
vx *= friction;
vy *= friction;
x += vx;
y += vy;
_count++;
// 死亡フラグ
if (life < _count) {
_destroy = true;
parent.removeChild(this);
}
}
public function get destroy():Boolean
{
return _destroy;
}
}
//--------------------------------------------------------------------------------//
// 流体関連クラス
//--------------------------------------------------------------------------------//
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.filters.BlurFilter;
import flash.filters.DisplacementMapFilter;
import flash.filters.DisplacementMapFilterMode;
import flash.geom.Point;
import flash.geom.Rectangle;
internal class FluidMap
{
//CLASS CONSTANTS
private static const ZERO_POINT:Point = new Point(0, 0);
//VARIABLES
private var _cells:Array;
private var _cellCount:uint;
private var _allCells:Array;
private var _allCellCount:uint;
private var _width:uint;
private var _height:uint;
private var _widthCount:uint;
private var _heightCount:uint;
private var _gridSize:uint;
private var _flowSize:Number;
private var _intensity:Number;
private var _useDecay:Boolean;
public var _mapBmd:BitmapData;
private var _mapFilter:DisplacementMapFilter;
private var _mapScale:Number;
private var _mapBlurIntensity:uint;
private var _mapBlurQuality:uint;
private var _blurFilter:BlurFilter;
private var _calculator:FluidCalculator;
private var _colorAdjust:Number;
private var _distMin2:Number;
private var _flowSize2:Number;
public function get mapFilter():DisplacementMapFilter { return _mapFilter; }
//CONSTRUCTOR
public function FluidMap(
width:uint,
height:uint,
gridSize:uint = 10,
flowSize:Number = 2,
intensity:Number = 0.25,
useDecay:Boolean = true,
mapScale:Number = 100,
mapBlurIntensity:uint = 32,
mapBlurQuality:uint = 2
):void
{
_width = width;
_height = height;
_gridSize = gridSize;
_flowSize = flowSize;
_useDecay = useDecay;
_intensity = intensity;
_mapScale = mapScale;
_mapBlurIntensity = mapBlurIntensity;
_mapBlurQuality = mapBlurQuality;
_widthCount = uint( Math.ceil(width / gridSize) );
_heightCount = uint( Math.ceil(height / gridSize) );
_allCellCount = _widthCount * _heightCount;
_allCells = new Array(_allCellCount);
var p:uint = 0;
var i:uint;
var j:uint;
var data:FluidMapData;
var cells2d:Array = new Array(_widthCount);
for (i = 0; i < _widthCount; ++i)
{
cells2d[i] = new Array(_heightCount);
for (j = 0; j < _heightCount; ++j)
{
data = new FluidMapData(i, j);
cells2d[i][j] = data;
_allCells[p] = data;
++p;
}
}
_cells = new Array();
var w:uint = _widthCount - 1;
var h:uint = _heightCount - 1;
var pi:uint = 0;
var pj:uint = 0;
for (i = 1; i < w; ++i)
{
for (j = 1; j < h; ++j)
{
data = cells2d[i][j] as FluidMapData;
data.n00 = cells2d[i - 1][j - 1] as FluidMapData;
data.n10 = cells2d[i ][j - 1] as FluidMapData;
data.n20 = cells2d[i + 1][j - 1] as FluidMapData;
data.n01 = cells2d[i - 1][j ] as FluidMapData;
data.n21 = cells2d[i + 1][j ] as FluidMapData;
data.n02 = cells2d[i - 1][j + 1] as FluidMapData;
data.n12 = cells2d[i ][j + 1] as FluidMapData;
data.n22 = cells2d[i + 1][j + 1] as FluidMapData;
if (pi != 0)
{
data.prev = cells2d[pi][pj] as FluidMapData;
data.prev.next = data;
}
_cells.push(data);
pi = i;
pj = j;
}
}
_cellCount = _cells.length;
_mapBmd = new BitmapData(_width, _height, false, 0x008080);
_mapFilter = new DisplacementMapFilter();
_mapFilter.mapBitmap = _mapBmd;
_mapFilter.mapPoint = ZERO_POINT;
_mapFilter.componentX = BitmapDataChannel.GREEN;
_mapFilter.componentY = BitmapDataChannel.BLUE;
_mapFilter.mode = DisplacementMapFilterMode.CLAMP;
_mapFilter.scaleX = _mapScale;
_mapFilter.scaleY = _mapScale;
_blurFilter = new BlurFilter(_mapBlurIntensity, _mapBlurIntensity, _mapBlurQuality);
_colorAdjust = -128 * _intensity;
_distMin2 = 4 * _gridSize * _gridSize;
_flowSize2 = _flowSize * _flowSize;
_calculator = new FluidCalculator();
}
//METHODS
public function addOrientedForce(x:uint, y:uint, forceX:Number = 0, forceY:Number = 0):void
{
var s:uint = _gridSize;
var n:uint = _cellCount;
var cell:FluidMapData = _cells[0] as FluidMapData;
for (var i:uint = 0; i < n; ++i)
{
_calcOrientedForce(cell, x / s, y / s, forceX, forceY);
cell = cell.next;
}
}
public function updateMap():BitmapData
{
var s:uint = _gridSize;
var n:uint = _cellCount;
var cell:FluidMapData = _cells[0] as FluidMapData;
var map:BitmapData = _mapBmd;
_decay();
_updatePressure();
_updateVelocity();
map.lock();
map.fillRect(map.rect, 0x008080);
for (var i:uint = 0; i < n; ++i)
{
map.fillRect(
new Rectangle(cell.x * s, cell.y * s, s, s),
_calcMapColor(cell)
);
cell = cell.next;
}
map.applyFilter(map, map.rect, ZERO_POINT, _blurFilter);
map.unlock();
return map;
}
private function _decay():void
{
if (_useDecay)
{
var n:uint = _allCellCount;
var cell:FluidMapData = _allCells[0] as FluidMapData;
for (var i:uint = 0; i < n; ++i)
{
_calcDecay(_allCells[i]);
//cell = cell.next;
}
}
}
private function _updatePressure():void
{
var n:uint = _cellCount;
var cell:FluidMapData = _cells[0] as FluidMapData;
for (var i:uint = 0; i < n; ++i)
{
_calcPressure(cell);
cell = cell.next;
}
}
private function _updateVelocity():void
{
var n:uint = _cellCount;
var cell:FluidMapData = _cells[0] as FluidMapData;
for (var i:uint = 0; i < n; ++i)
{
_calcVelocity(cell);
cell = cell.next;
}
}
private function _calcDecay(data:FluidMapData):void
{
var r:Number = data.colorX;
var b:Number = data.colorY;
if (r != 128) data.colorX += (r < 128) ? 1 : -1;
if (b != 128) data.colorY += (b < 128) ? 1 : -1;
}
private function _calcPressure(data:FluidMapData):void
{
data.pressure += _calculator.calcPressure(data);
data.pressure *= 0.7;
}
private function _calcVelocity(data:FluidMapData):void
{
data.vx += _calculator.calcVelocityX(data);
data.vy += _calculator.calcVelocityY(data);
data.vx *= 0.7;
data.vy *= 0.7;
}
private function _calcOrientedForce(data:FluidMapData, x:uint, y:uint, forceX:Number = 0, forceY:Number = 0):void
{
var dx:int = data.x - x;
var dy:int = data.y - y;
var dist2:Number = dx * dx + dy * dy;
if (dist2 < _flowSize2)
{
var f:Number = (dist2 < _distMin2) ? 1.0 : (_flowSize / Math.sqrt(dist2));
// data.vx += forceX * f;
// data.vy += forceY * f;
data.vx += 20*dx * f;
data.vy += 20*dy * f;
}
}
private function _calcMapColor(data:FluidMapData):uint
{
var vx:Number = data.vx;
var vy:Number = data.vy;
var g:int = data.colorX;
var b:int = data.colorY;
g = Math.round( _colorAdjust * vx + g );
b = Math.round( _colorAdjust * vy + b );
g = (g < 0) ? 0 : (g > 255) ? 255 : g;
b = (b < 0) ? 0 : (b > 255) ? 255 : b;
data.colorX = g;
data.colorY = b;
return data.color = g << 8 | b;
}
}
internal class FluidCalculator
{
//CONSTRUCTOR
public function FluidCalculator():void
{
}
//METHODS
public function calcVelocityX(data:FluidMapData):Number
{
return ( data.n00.pressure * 0.5
+ data.n01.pressure
+ data.n02.pressure * 0.5
- data.n20.pressure * 0.5
- data.n21.pressure
- data.n22.pressure * 0.5
) * 0.25;
}
public function calcVelocityY(data:FluidMapData):Number
{
return ( data.n00.pressure * 0.5
+ data.n10.pressure
+ data.n20.pressure * 0.5
- data.n02.pressure * 0.5
- data.n12.pressure
- data.n22.pressure * 0.5
) * 0.25;
}
public function calcPressure(data:FluidMapData):Number
{
return ( data.n00.vx * 0.5
+ data.n01.vx
+ data.n02.vx * 0.5
- data.n20.vx * 0.5
- data.n21.vx
- data.n22.vx * 0.5
+ data.n00.vy * 0.5
+ data.n10.vy
+ data.n20.vy * 0.5
- data.n02.vy * 0.5
- data.n12.vy
- data.n22.vy * 0.5
) * 0.20;
}
}
internal class FluidMapData
{
//VARIABLES
public function get x():uint { return _x; }
public function set x(value:uint):void { _x = value; }
private var _x:uint;
public function get y():uint { return _y; }
public function set y(value:uint):void { _y = value; }
private var _y:uint;
public function get vx():Number { return _vx; }
public function set vx(value:Number):void { _vx = value; }
private var _vx:Number;
public function get vy():Number { return _vy; }
public function set vy(value:Number):void { _vy = value; }
private var _vy:Number;
public function get pressure():Number { return _pressure; }
public function set pressure(value:Number):void { _pressure = value; }
private var _pressure:Number;
public function get color():uint { return _color; }
public function set color(value:uint):void { _color = value; }
private var _color:uint;
public function get colorX():uint { return _colorX; }
public function set colorX(value:uint):void { _colorX = value; }
private var _colorX:uint;
public function get colorY():uint { return _colorY; }
public function set colorY(value:uint):void { _colorY = value; }
private var _colorY:uint;
public function get next():FluidMapData { return _next; }
public function set next(value:FluidMapData):void { _next = value; }
private var _next:FluidMapData;
public function get prev():FluidMapData { return _prev; }
public function set prev(value:FluidMapData):void { _prev = value; }
private var _prev:FluidMapData;
private var _n00:FluidMapData;
private var _n01:FluidMapData;
private var _n02:FluidMapData;
private var _n10:FluidMapData;
private var _n12:FluidMapData;
private var _n20:FluidMapData;
private var _n21:FluidMapData;
private var _n22:FluidMapData;
public function get n00():FluidMapData { return _n00; }
public function get n01():FluidMapData { return _n01; }
public function get n02():FluidMapData { return _n02; }
public function get n10():FluidMapData { return _n10; }
public function get n12():FluidMapData { return _n12; }
public function get n20():FluidMapData { return _n20; }
public function get n21():FluidMapData { return _n21; }
public function get n22():FluidMapData { return _n22; }
public function set n00(value:FluidMapData):void { _n00 = value; }
public function set n01(value:FluidMapData):void { _n01 = value; }
public function set n02(value:FluidMapData):void { _n02 = value; }
public function set n10(value:FluidMapData):void { _n10 = value; }
public function set n12(value:FluidMapData):void { _n12 = value; }
public function set n20(value:FluidMapData):void { _n20 = value; }
public function set n21(value:FluidMapData):void { _n21 = value; }
public function set n22(value:FluidMapData):void { _n22 = value; }
//CONSTRUCTOR
public function FluidMapData(x:uint, y:uint):void
{
_x = x;
_y = y;
_vx = 0;
_vy = 0;
_pressure = 0;
_color = 0x008080;
_colorX = 128;
_colorY = 128;
}
}