forked from: Water Color
@author imajuk
/**
* Copyright hacker_dj7nuxk3 ( http://wonderfl.net/user/hacker_dj7nuxk3 )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/nhUK
*/
// forked from imajuk's Water Color
package
{
/**
* @author imajuk
*/
import com.bit101.components.PushButton;
import flash.system.LoaderContext;
import flash.display.StageScaleMode;
import flash.display.StageAlign;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.geom.ColorTransform;
import flash.filters.BlurFilter;
import flash.utils.Dictionary;
import flash.net.URLRequest;
import flash.display.Loader;
import flash.display.BlendMode;
import flash.display.BitmapData;
import flash.events.Event;
import flash.display.Sprite;
import flash.display.Bitmap;
public class WaterColorsMain_wonderfl extends Sprite
{
private static const POINT : Point = new Point();
//=================================
// view
//=================================
private var artBoard : Sprite;
private var canvas : BitmapData;
private var canvas2 : BitmapData;
private var canvas3 : BitmapData;
//=================================
// drawing
//=================================
public var drawingMaterial : Brush;
private var brushes : Array;
private var cursor : Point = new Point();
//=================================
// coloring
//=================================
private var hue : Number = 0;
private var tone : String;
private var time : Number = 0;
private var bIndex : int = 0;
private var tIndex : Dictionary = new Dictionary(true);
private var palette : Dictionary;
private var palette1 : Array = [ ColorTone.LIGHT, ColorTone.SOFT ];
private var palette2 : Array = [ ColorTone.PALE, ColorTone.LIGHT ];
//=================================
// effect
//=================================
private var stencil : BitmapData;
private var rect : Rectangle;
private var transparent : ColorTransform = new ColorTransform(1, 1, 1, 1, 0, 0, 0, -240);
private var transparent2 : ColorTransform = new ColorTransform(1, 1, 1, 1, 1, 1, 1, -1);
private var blur : BlurFilter = new BlurFilter(1, 2);
private var resetTone : Function;
public function WaterColorsMain_wonderfl()
{
Wonderfl.capture_delay(90);
//=================================
// stage setting
//=================================
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.frameRate = 60;
var sw:int = stage.stageWidth;
var sh:int = stage.stageHeight;
//=================================
// background
//=================================
var loader : Loader = addChild(new Loader()) as Loader;
loader.load(new URLRequest("http://www.imajuk.com/images/paper.png"), new LoaderContext(true));
//=================================
// canvas
//=================================
canvas = new BitmapData(sw, sh, true, 0);
canvas2 = canvas.clone();
canvas3 = canvas.clone();
rect = canvas.rect;
artBoard = addChild(new Sprite()) as Sprite;
artBoard.addChild(new Bitmap(canvas)).blendMode = BlendMode.MULTIPLY;
//=================================
// stencil
//=================================
stencil = canvas.clone();
stencil.copyPixels(Stencil.getStencil(stencil, sw, sh), rect, POINT);
//=================================
// drawing materials
//=================================
var spray : Brush = new Brush(3, 5, .95, BlendMode.NORMAL, null, "spray");
var crayon : Brush = new Brush(20, 30, .3, BlendMode.NORMAL, null, "crayon");
brushes = [ crayon, spray ];
//=================================
// palette
//=================================
palette = new Dictionary(true);
palette[spray] = palette1;
palette[crayon] = palette2;
resetTone = function():void
{
tIndex[spray] = 0;
tIndex[crayon] = 0;
};
resetTone();
//=================================
// drawing material
//=================================
var me : WaterColorsMain_wonderfl = this;
drawingMaterial = spray;
drawingMaterial.addEventListener(Event.INIT, function():void
{
drawingMaterial = brushes[0];
new CanvasInteraction(artBoard, me, cursor);
var clear:PushButton = addChild(new PushButton(stage, sw - 55, sh-25, "clear", clearCanvas)) as PushButton;
clear.setSize(50, 20);
});
//=================================
// main loop
//=================================
addEventListener(Event.ENTER_FRAME, function():void
{
if (!drawingMaterial || !drawingMaterial.initialized)
return;
changeColor();
moveCursor();
drawBrush();
effectCanvas();
});
}
private function drawBrush() : void
{
drawingMaterial.drawTo( canvas, cursor.x, cursor.y, true);
drawingMaterial.drawTo(canvas3, cursor.x, cursor.y, true);
}
private function clearCanvas(...param) : void
{
canvas.fillRect(rect, 0);
canvas2.fillRect(rect, 0);
canvas3.fillRect(rect, 0);
resetTone();
bIndex = 0;
}
private function effectCanvas() : void
{
//顔料の流れ
canvas3.scroll(0, 1);
//アートボードの湿り気を調整
var wet : Number = .9;
if (Math.random() > wet)
canvas3.colorTransform(rect, transparent2);
//ステンシルで抜く
canvas2.copyPixels(canvas3, rect, POINT, stencil, POINT, true);
//エッジのにじみ
canvas2.applyFilter(canvas2, rect, POINT, blur);
//キャンバスに描画
canvas.draw(canvas2, null, transparent, BlendMode.SCREEN);
}
public function changeDrawingMaterial() : void
{
bIndex++;
if (bIndex >= brushes.length)
bIndex = 0;
drawingMaterial = brushes[bIndex];
drawingMaterial.changeBrushSizeTo(MathUtil.random(drawingMaterial.minBrushSize, drawingMaterial.maxBlushSize), 2);
}
public function changeTone() : void
{
var tones : Array = palette[drawingMaterial];
tIndex[drawingMaterial] ++;
if (tIndex[drawingMaterial] >= tones.length)
tIndex[drawingMaterial] = 0;
tone = tones[tIndex[drawingMaterial]];
}
private function changeColor() : void
{
if (!tone)
return;
time += .001;
drawingMaterial.color = ColorTone.getToneAs2(tone, hue += .2, Math.sin(time));
if (hue >= 360)
hue -= 360;
}
private function moveCursor() : void
{
var vx : Number = mouseX - cursor.x;
var vy : Number = mouseY - cursor.y;
cursor.x += vx * .1;
cursor.y += vy * .1;
}
}
}
import org.libspark.thread.Monitor;
import org.libspark.thread.EnterFrameThreadExecutor;
import org.libspark.thread.Thread;
import com.flashdynamix.motion.TweensyTimeline;
import com.flashdynamix.motion.Tweensy;
import flash.events.MouseEvent;
import flash.display.Sprite;
import flash.geom.Matrix;
import flash.geom.Rectangle;
import flash.events.Event;
import flash.utils.clearInterval;
import flash.utils.setInterval;
import flash.display.BlendMode;
import flash.geom.ColorTransform;
import flash.filters.BlurFilter;
import flash.display.BitmapData;
import flash.geom.Point;
import flash.events.EventDispatcher;
import fl.motion.easing.Exponential;
import fl.motion.easing.Linear;
import frocessing.color.ColorHSV;
class CanvasInteraction
{
private var canvas : Sprite;
private var cursor : Point;
private var sample : WaterColorsMain_wonderfl;
public function CanvasInteraction(
canvas : Sprite,
sample : WaterColorsMain_wonderfl,
cursor : Point
)
{
this.sample = sample;
this.canvas = canvas;
this.cursor = cursor;
canvas.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
canvas.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
}
private function mouseUpHandler(event : MouseEvent) : void
{
sample.drawingMaterial.changeBrushSizeTo(0);
}
private function mouseDownHandler(event : MouseEvent) : void
{
cursor.x = event.localX;
cursor.y = event.localY;
sample.changeDrawingMaterial();
sample.changeTone();
}
public function interrpt() : void
{
canvas.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
canvas.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
}
}
class Stencil
{
private static var data : String = "082004400fe01bb03ff82fe8282806c0";
public static function getStencil(b : BitmapData, width : int, height : int) : BitmapData
{
var data2 : String = MathUtil.hexToBinary(data);
var b2 : BitmapData = new BitmapData(b.width, b.height, true, 0);
var w:int = 16;
var h:int = 8;
var size : int = 18;
var px : int = 0;
var py : int = 0;
var sx : int = (b.width - size * w) * .5;
var sy : int = (b.height - size * h) * .5;
b2.fillRect(new Rectangle(0, 0, sx, height), 0xFF000000);
b2.fillRect(new Rectangle(width - sx, 0, sx, height), 0xFF000000);
b2.fillRect(new Rectangle(0, 0, width, sy), 0xFF000000);
b2.fillRect(new Rectangle(0, height - sy, width, sy), 0xFF000000);
var c : int = 0;
while(py < h)
{
while(px < w)
{
var cl : uint;
switch(data2.charAt(c++))
{
case "0" :
cl = int(MathUtil.random(0xEE, 0xAA)) << 24;
break;
case "1" :
cl = int(Math.random() * 0x15) << 24;
break;
}
b2.fillRect(new Rectangle(sx + px * size, sy + py * size, size, size), cl);
px++;
}
px = 0;
py++;
}
b2.applyFilter(b2, b2.rect, new Point(), new BlurFilter(8, 8));
return b2;
}
}
class Brush extends EventDispatcher
{
private static const POINT : Point = new Point();
public var initialized : Boolean = false;
private var name : String = "unnamed";
private var mat : Vector.<BitmapData>;
private var materialCanvas : BitmapData;
private var growBrushSize : TweensyThread;
private var spread : Number;
private var blend : String;
private var blur : BlurFilter;
private var _minBrushSize : int;
public function get minBrushSize() : int
{
return _minBrushSize;
}
private var _maxBlushSize : int;
public function get maxBlushSize() : int
{
return _maxBlushSize;
}
private var _blushSize : Number = 0;
public function get blushSize() : Number
{
return _blushSize;
}
public function set blushSize(value : Number) : void
{
if (value > _maxBlushSize)
return;
_blushSize = value;
}
private var _color : ColorTransform = new ColorTransform();
public function set color(value : uint) : void
{
_color.color = value;
}
public function Brush(
minBrushSize : int,
maxBlushSize : int,
spread : Number = .9, //顔料の広がり (値が大きいほど広い .1 ~ .9)
blend : String = BlendMode.NORMAL,
blur : BlurFilter = null,
name : String = ""
)
{
if (maxBlushSize <= 0)
throw new Error("the max size of brush should be more than 1");
this._minBrushSize = minBrushSize;
this._maxBlushSize = maxBlushSize;
this.spread = spread;
this.blend = blend;
this.blur = blur;
this.name = (name == "") ? this.name : name;
if (!Thread.isReady)
Thread.initialize(new EnterFrameThreadExecutor());
build();
}
override public function toString() : String
{
return "Brush[" + name + "(" + spread + ")]";
}
private function build() : void
{
materialCanvas = new BitmapData(400, 400);
if (mat)
return;
//preare material
mat = Vector.<BitmapData>([ new BitmapData(1, 1, true, 0) ]);
var bs : int = 1;
var intval : uint =
setInterval(
function():void
{
var material : BitmapData = getBrushMaterial(bs);
mat.push(material);
if (++bs > _maxBlushSize)
{
initialized = true;
clearInterval(intval);
dispatchEvent(new Event(Event.INIT));
}
}, 10);
}
private function getBrushMaterial(size : int) : BitmapData
{
var rad : Number = 0;
var dis : Number = 0;
//center of Bitmap
var cx : Number = materialCanvas.width * .5;
var cy : Number = materialCanvas.height * .5;
//密度
var density : Number = Exponential.easeIn(spread, 0.01, .1, 1);
materialCanvas.lock();
materialCanvas.fillRect(materialCanvas.rect, 0);
while(dis < size)
{
rad += MathUtil.random(.05, .35);
dis += (size / maxBlushSize) * density;
var alp : Number = MathUtil.random(0x22, 0xCC);
var t : Number = 0;
while(alp > .3)
{
t += .8;
drawPixel(materialCanvas, rad, dis + t, cx, cy, alp << 24);
alp *= spread;
}
}
materialCanvas.unlock();
if (blur)
materialCanvas.applyFilter(materialCanvas, materialCanvas.rect, POINT, blur);
var bounce : Rectangle = materialCanvas.getColorBoundsRect(0xFF000000, 0x00000000, false);
var trimed : BitmapData = new BitmapData(bounce.width, bounce.height, true, 0);
trimed.copyPixels(materialCanvas, bounce, POINT);
return trimed;
}
private function drawPixel(
target : BitmapData,
rad : Number,
dis : Number,
x : int,
y : int,
cl : uint
) : void
{
x += Math.cos(rad) * dis;
y += Math.sin(rad) * dis;
target.setPixel32(x, y, cl);
}
/**
* draw spray effect
* @param cx center x
* @param cy center y
* @param instability instability brush size (never be bigger than max brush size)
*/
public function drawTo(
canvas : BitmapData,
cx : int,
cy : int,
instable : Boolean = true
) : void
{
if (!initialized)
throw new Error("not initialized still.");
if (_blushSize <= 1)
return;
if (mat.length <= _blushSize)
return;
var brushMaterial : BitmapData = (instable) ? mat[int(Math.random() * _blushSize)] : mat[mat.length - 1];
var m : Matrix = new Matrix();
m.translate(-brushMaterial.width * .5, -brushMaterial.height * .5);
m.rotate(MathUtil.random(-Math.PI, Math.PI));
m.translate(brushMaterial.width * .5, brushMaterial.height * .5);
m.translate(cx - brushMaterial.width * .5, cy - brushMaterial.height * .5);
canvas.draw(brushMaterial, m, _color, blend);
}
public function changeBrushSizeTo(size : Number, duration:Number = .4, easing : Function = null) : void
{
if (easing == null)
easing = Exponential.easeOut;
if (growBrushSize)
growBrushSize.interrupt();
growBrushSize = new TweensyThread(this, 0, duration, easing, null, {blushSize:size});
growBrushSize.start();
}
}
class ColorTone
{
//=================================
// all kind of Color Tone
//=================================
public static const PALE : String = "PALE";
public static const LIGHT_GRAYISH : String = "LIGHT_GRAYISH";
public static const GRAYISH : String = "GRAYISH";
public static const DARK_GRAYISH : String = "DARK_GRAYISH";
public static const LIGHT : String = "LIGHT";
public static const SOFT : String = "SOFT";
public static const DULL : String = "DULL";
public static const DARK : String = "DARK";
public static const BRIGHT : String = "BRIGHT";
public static const STRONG : String = "STRONG";
public static const DEEP : String = "DEEP";
public static const VIVID : String = "VIVID";
//=================================
// defination of Color Tone
// [彩度min, 彩度max, 明度min, 明度max]
//=================================
internal static const DEF_PALE : Array = [7, 20, 100, 100];
internal static const DEF_LIGHT_GRAYISH : Array = [5, 20, 70, 90];
internal static const DEF_GRAYISH : Array = [5, 20, 40, 50];
internal static const DEF_DARK_GRAYISH : Array = [5, 10, 7, 32];
internal static const DEF_LIGHT : Array = [30, 68, 100, 100];
internal static const DEF_SOFT : Array = [30, 68, 80, 90];
internal static const DEF_DULL : Array = [30, 50, 40, 70];
internal static const DEF_DARK : Array = [50, 65, 10, 30];
internal static const DEF_BRIGHT : Array = [90, 100, 77, 90];
internal static const DEF_STRONG : Array = [100, 100, 47, 67];
internal static const DEF_DEEP : Array = [100, 100, 40, 45];
internal static const DEF_VIVID : Array = [100, 100, 100, 100];
/**
* 任意のトーンのカラーを返します
* @param n 明度と彩度の微調整
*/
public static function getToneAs2(toneKind : String, hue : Number, n:Number = 0) : uint
{
var tone:Array = ColorTone["DEF_" + toneKind];
var satiation : Number = Linear.easeNone(n, tone[0], tone[1] - tone[0], 1);
var value : Number = Linear.easeNone(n, tone[2], tone[3] - tone[2], 1);
return new ColorHSV(hue, satiation*.01, value*.01, .1).value32;
}
public static function getAll() : Array
{
return [PALE, LIGHT_GRAYISH, GRAYISH, DARK_GRAYISH, LIGHT, SOFT, DULL, DARK, BRIGHT, STRONG, DEEP, VIVID];
}
public var label : String;
public var value : Number;
/**
* コンストラクタ
* @param kind トーンの種類. すべてのトーンの種類はColorToneに定義されています.
* @param value 全体に占めるこのトーンの割合
*/
public function ColorTone(kind : String, value : Number)
{
this.label = kind;
this.value = value;
}
public function toString() : String
{
return label + " : " + int(value) + "%";
}
public function clone() : ColorTone
{
return new ColorTone(label, value);
}
}
class MathUtil
{
/**
* 任意の範囲からランダムな数値を返す
*/
public static function random(min:Number, max:Number):Number
{
return Math.random() * (max - min) + min;
}
public static function hexToBinary(hex : String) : String
{
var bin : String = "";
for (var i : int = 0;i < hex.length;i++)
{
var buff : String = hex.substr(i, 1);
var temp : String = parseInt(buff, 16).toString(2);
while(temp.length < 4)
{
temp = "0" + temp;
}
bin += temp;
}
return bin;
}
}
class TweensyThread extends Thread
{
private var target:*;
private var optionalProp:*;
private var _monitor:Monitor;
private var delay:Number;
private var duration:Number;
private var to:Object;
private var from:Object;
private var easing:Function;
private var tt:TweensyTimeline;
public function TweensyThread(
target:*,
delay:Number,
duration:Number,
easing:Function,
from:Object=null,
to:Object=null,
optionalProp:* = null)
{
super();
this.target = target;
this.delay = delay;
this.duration = duration;
this.easing = easing;
this.to = to;
this.from = from;
this.optionalProp = optionalProp;
_monitor = new Monitor();
}
override protected function run():void
{
if (isInterrupted)
return;
interrupted(function():void
{
if (tt)
Tweensy.remove(tt);
});
error(Error, function(e:Error):void
{
throw new Error("TweensyThreadエラー", e);
interrupt();
});
_monitor.wait();
var mainTarget:*;
var subTarget:*;
if (optionalProp)
{
mainTarget = optionalProp;
subTarget = target;
}
else
{
mainTarget = target;
subTarget = optionalProp;
}
try
{
if (from != null && to != null)
tt = Tweensy.fromTo(mainTarget, from, to, duration, easing, delay, subTarget, _monitor.notifyAll);
else if(from != null)
tt = Tweensy.from(mainTarget, to, duration, easing, delay, subTarget, _monitor.notifyAll);
else if(to != null)
tt = Tweensy.to(mainTarget, to, duration, easing, delay, subTarget, _monitor.notifyAll);
}
catch(e:Error)
{
trace("$$$$", e.message);
}
}
override protected function finalize() : void
{
target = null;
optionalProp = null;
_monitor = null;
to = null;
from = null;
easing = null;
tt = null;
}
}