forked from: INK BLEED
<p>Ink Bleed</p>
@author monoDreamer, aka ryo
@langversion ActionScript 3.0
@playerversion Flash 10.2+
@see
/**
* Copyright aobyrne ( http://wonderfl.net/user/aobyrne )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/1I9U
*/
package
{
import com.greensock.easing.Elastic;
import com.greensock.easing.Expo;
import com.greensock.TweenLite;
import flash.display.Graphics;
import net.hires.debug.Stats;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.filters.DisplacementMapFilter;
import flash.filters.DisplacementMapFilterMode;
import flash.geom.ColorTransform;
import flash.geom.Point;
import flash.utils.Timer;
[SWF(width=465, height=465, frameRate=30)]
/**
* <p>Ink Bleed</p>
* @author monoDreamer, aka ryo
* @langversion ActionScript 3.0
* @playerversion Flash 10.2+
* @see
*/
public class InkBleed extends Sprite
{
//----------------------------------------------------------------
// Properties
//----------------------------------------------------------------
//----------------------------------------------------------------
// Getter/Setter Method
//----------------------------------------------------------------
//----------------------------------------------------------------
// Public method
//----------------------------------------------------------------
//----------------------------------------------------------------
// Protected Method
//----------------------------------------------------------------
protected function timerHandler($e:TimerEvent):void
{
var i:int = _pnum;
while (--i>-1) {
_dots[i].diffuse();
}
}
protected function render($e:Event):void
{
var d:Dot, i:int, c:uint;
if (_isMouseDown) {
i = _px + _py*_cw;
_dots[i].cur += 0x2f0;
}
i = _pnum;
while (--i>-1) {
c = _dots[i].cur;
_canvasData[i] = (c > 0xff ? 0xff : c) << 24;
}
_canvas.setVector(_canvas.rect, _canvasData);
}
protected function downHandler($e:MouseEvent):void
{
var mx:int = stage.mouseX >> DX, my:int = stage.mouseY >> DY;
if (_canvas.rect.contains(mx, my)) {
_px = mx;
_py = my;
_isMouseDown = true;
stage.addEventListener(MouseEvent.MOUSE_MOVE, moveHandler);
}
}
protected function moveHandler($e:MouseEvent):void
{
trace( "----------------------------- " );
if(_isMouseDown) {
var mx:int = stage.mouseX >> DX;
var my:int = stage.mouseY >> DY;
mx = uint(leader.x) >> DX;
trace( "leader.x : " + leader.x );
trace( "mx : " + mx );
my = uint(leader.y) >> DY;
trace( "leader.y : " + leader.y );
trace( "my : " + my );
if (_canvas.rect.contains(mx, my))
{
t_efla(_px, _py, mx, my, 0x1ff);
_px = mx;
_py = my;
}
}
}
protected function upHandler($e:MouseEvent):void
{
_isMouseDown = false;
stage.removeEventListener(MouseEvent.MOUSE_MOVE, moveHandler);
}
protected function t_efla($sx:int, $sy:int, $ex:int, $ey:int, $color:uint):void
{
var shortLen:int = $ey - $sy;
var longLen:int = $ex - $sx;
if (!longLen) if (!shortLen) return;
var i:int, id:int, inc:int;
var multDiff:Number;
var idx:int;
// TODO: check for this above, swap x/y/len and optimize loops to ++ and -- (operators twice as fast, still only 2 loops)
if ((shortLen ^ (shortLen >> 31)) - (shortLen >> 31) > (longLen ^ (longLen >> 31)) - (longLen >> 31)) {
if (shortLen < 0) {
inc = -1;
id = -shortLen & 3;
} else {
inc = 1;
id = shortLen & 3;
}
multDiff = !shortLen ? longLen : longLen / shortLen;
if (id) {
idx = $sx + $sy*_cw;
_dots[idx].cur += $color;
i += inc;
if (--id) {
idx = roundPlus($sx + i * multDiff) + ($sy + i)*_cw;
_dots[idx].cur += $color;
i += inc;
if (--id) {
idx = roundPlus($sx + i * multDiff) + ($sy + i)*_cw;
_dots[idx].cur += $color;
i += inc;
}
}
}
while (i != shortLen) {
idx = roundPlus($sx + i * multDiff) + ($sy + i) * _cw;
_dots[idx].cur += $color;
i += inc;
idx = roundPlus($sx + i * multDiff) + ($sy + i) * _cw;
_dots[idx].cur += $color;
i += inc;
idx = roundPlus($sx + i * multDiff) + ($sy + i) * _cw;
_dots[idx].cur += $color;
i += inc;
idx = roundPlus($sx + i * multDiff) + ($sy + i) * _cw;
_dots[idx].cur += $color;
i += inc;
}
}
else {
if (longLen < 0) {
inc = -1;
id = -longLen & 3;
} else {
inc = 1;
id = longLen & 3;
}
multDiff = !longLen ? shortLen : shortLen / longLen;
if (id) {
idx = $sx + $sy * _cw;
_dots[idx].cur += $color;
i += inc;
if (--id) {
idx = $sx + i + roundPlus($sy + i * multDiff) * _cw;
_dots[idx].cur += $color;
i += inc;
if (--id) {
idx = $sx + i + roundPlus($sy + i * multDiff) * _cw;
_dots[idx].cur += $color;
i += inc;
}
}
}
while (i != longLen) {
idx = $sx + i + roundPlus($sy + i * multDiff) * _cw;
_dots[idx].cur += $color;
i += inc;
idx = $sx + i + roundPlus($sy + i * multDiff) * _cw;
_dots[idx].cur += $color;
i += inc;
idx = $sx + i + roundPlus($sy + i * multDiff) * _cw;
_dots[idx].cur += $color;
i += inc;
idx = $sx + i + roundPlus($sy + i * multDiff) * _cw;
_dots[idx].cur += $color;
i += inc;
}
}
}
protected function roundPlus($value:Number):int {
return ($value + BIG_ENOUGH_ROUND) - BIG_ENOUGH_INT;
}
//----------------------------------------------------------------
// Private Method
//----------------------------------------------------------------
/** Constructor */
public function InkBleed():void
{
super();
_cw = 200
_ch = 200;
_pnum = _cw * _ch;
leader = addChild(new Sprite) as Sprite;
var g:Graphics = leader.graphics;
g.lineStyle(0);
g.drawRect( -3, 3, 6, 6);
functions = Vector.<Function>([]);
functions[functions.length] = Elastic.easeIn;
functions[functions.length] = Elastic.easeInOut;
functions[functions.length] = Elastic.easeOut;
functions[functions.length] = Expo.easeIn;
functions[functions.length] = Expo.easeOut;
functions[functions.length] = Expo.easeInOut;
leader.x = 50;
_px = leader.x >> DX;
TweenLite.to(leader, 5, { y:300, onComplete:oc});
init();
addEventListener(Event.ENTER_FRAME, ef);
_isMouseDown = true;
}
private function ef(e:Event):void
{
moveHandler(null);
}
private function oc():void
{
trace('....................................');
_isMouseDown = false;
removeEventListener(Event.ENTER_FRAME, ef);
if (functionIndex<functions.length)
{
var currentFunction:Function = functions[functionIndex];
leader.x += 50;
_px = leader.x >> DX;
leader.y = 0;
_py = leader.y >> DY;
TweenLite.to(leader, 5, { y:300, ease:currentFunction, onComplete:oc } );
_isMouseDown = true;
addEventListener(Event.ENTER_FRAME, ef);
}
functionIndex++;
}
/** Initialize */
private function init():void
{
initTimer();
initDots();
initCanvas();
addListeners();
_timer.start();
}
private function initTimer():void
{
_timer = new Timer(100);
_timer.addEventListener(TimerEvent.TIMER, timerHandler);
}
private function initCanvas():void
{
_canvas = new BitmapData(_cw, _ch, true, 0);
_canvasData = _canvas.getVector(_canvas.rect);
_canvasData.fixed = true;
var map:BitmapData = new BitmapData(_cw * SCX, _ch *SCY);
map.perlinNoise(map.width * .4, map.height * .4, 8, Math.random()*100, true, true, 1, true);
var bmp:Bitmap = new Bitmap(_canvas);
bmp.smoothing = true;
bmp.scaleX = SCX;
bmp.scaleY = SCY;
bmp.filters = [new DisplacementMapFilter(map, new Point(), 1, 1, 32, 32, DisplacementMapFilterMode.CLAMP)];
addChild(bmp);
graphics.lineStyle(1);
graphics.drawRect(0, 0, _cw * SCX, _ch * SCY);
var stat:Stats = new Stats();
stat.x = 400;
addChild(stat);
}
private function addListeners():void
{
addEventListener(Event.ENTER_FRAME, render);
//stage.addEventListener(MouseEvent.MOUSE_DOWN, downHandler);
//stage.addEventListener(MouseEvent.MOUSE_UP, upHandler);
}
private function initDots():void
{
var absorbMap:BitmapData = new BitmapData(_cw, _ch, false, 0);
absorbMap.perlinNoise(_cw/2, _ch/2, 5, 100*Math.random(), true, true, 1, true);
absorbMap.colorTransform(absorbMap.rect, new ColorTransform(.2, .2, .2));
var maxCapMap:BitmapData = new BitmapData(_cw, _ch, false, 0xffffff);
maxCapMap.perlinNoise(_cw, _ch, 5, 100 * Math.random(), true, true, 1, true);
maxCapMap.colorTransform(maxCapMap.rect, new ColorTransform(1.8, 1.8, 1.8));
var d:Dot, i:int = _pnum;
_dots = new Vector.<Dot>(_pnum, true);
while(--i>-1) {
_dots[i] = new Dot();
}
var neighbors:Array;
for (var my:int=0; my<_ch; my++)
{
for (var mx:int=0; mx<_cw; mx++)
{
i = mx + my*_cw;
d = _dots[i];
neighbors = [];
d.abs = absorbMap.getPixel(mx, my) & 0xff;
d.max = maxCapMap.getPixel(mx, my) & 0xff;
if (mx>0) neighbors.push(_dots[i-1]);
if (mx<_cw-1) neighbors.push(_dots[i+1]);
if (my>0) neighbors.push(_dots[i-_cw]);
if (my<_ch-1) neighbors.push(_dots[i+_cw]);
d.setNeighbors(neighbors);
}
}
}
private const BIG_ENOUGH_INT:int = 16 * 1024;
private const BIG_ENOUGH_ROUND:Number = BIG_ENOUGH_INT + 0.5;
private const SCX:int = 2;
private const SCY:int = 2;
private var DX:int = 1;
private var DY:int = 1;
private var _canvasData:Vector.<uint>;
private var _canvas:BitmapData;
private var _pnum:int;
private var _dots:Vector.<Dot>;
private var _cw:int;
private var _ch:int;
private var _px:int;
private var _py:int;
private var _isMouseDown:Boolean;
private var _timer:Timer;
private var leader:Sprite;
private var functions:Vector.<Function>;
private var functionIndex:uint;
}
}
class Dot
{
public var max:uint;
public var cur:uint;
public var abs:uint;
public var isOver:Boolean;
public function setNeighbors($neighbors:Array):void
{
_neighbors = Vector.<Dot>($neighbors);
_neighbors.fixed = true;
_len = _neighbors.length;
}
public function diffuse():void
{
if (cur <= max) return;
isOver = true;
var d:Dot, l:int = _len;
while (--l > -1) {
d = _neighbors[l];
if (d.isOver|| cur<d.abs) continue;
d.cur += d.abs;
}
cur -= d.abs * .2;
}
private var _neighbors:Vector.<Dot>;
private var _len:int;
}