/*
* Blowing Hair effect
* P.Leskinen 12 January MMIX
* Hairy Text Blowing in a Perlin Wind
*/
package {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.display.BlendMode;
import flash.display.Sprite;
import flash.events.Event;
import flash.filters.BlurFilter;
import flash.filters.ConvolutionFilter;
import flash.filters.DisplacementMapFilter;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.text.*;
public class BlowingInTheHair extends Sprite
{
public var source:*;
public var margin:int = 40; // white space around
// controls the hair length
public var hairLength:Number = 8.0;
// density:
// 0.0 = solid
// 0.99 = just a few hair
public var density:Number = 0.85;
public var contrast:Number = 1.5;
protected var bmd:BitmapData;
protected var perlinMap:BitmapData;
protected var canvas:BitmapData;
protected var offsets:Array;
internal var i:int, j:int;
internal const NEWMATRIX:Matrix= new Matrix();
internal const NEWPOINT:Point= new Point();
internal const NEWCOLORTRANSFORM:ColorTransform = new ColorTransform();
internal const BLUR:BlurFilter = new BlurFilter(2,2); // or try (1,8);
public function BlowingInTheHair ()
{
// create a text element
with( source= new TextField() ) {
defaultTextFormat= new TextFormat(
"Arial",
70,
0x654321 );
htmlText="Hello world";
multiline = true;
width= 360.0;
}
initStage();
}
// init bitmapdatas and listeners:
private function initStage():void {
var w:int, h:int;
bmd= new BitmapData(
w= source.width+2*margin,
h= source.height+2*margin,
true, 0x00);
perlinMap = new BitmapData(w,h, false);
offsets= [new Point(), new Point(), new Point()];
canvas = new BitmapData(w,h, true,0x00);
addChild(new Bitmap(canvas));
addEventListener(Event.ENTER_FRAME, generate);
}
private function generate(e:Event =null):void {
// creating the 'blowing'
offsets[0].x -= 8.0;
offsets[1].x += 5.2;
offsets[2].x += 2.8;
offsets[0].y += 2.0;
offsets[1].y -= 1.6;
offsets[2].y -= 0.4;
perlinMap.perlinNoise(perlinMap.width/2,perlinMap.height/2, 3,11,true,true,
BitmapDataChannel.BLUE + BitmapDataChannel.GREEN, false, offsets);
// creating the effect:
var displacer:DisplacementMapFilter = new DisplacementMapFilter(perlinMap,
NEWPOINT,
BitmapDataChannel.BLUE,BitmapDataChannel.GREEN,
hairLength,hairLength);
canvas.lock();
canvas.fillRect(canvas.rect, 0x00);
canvas.draw(source, new Matrix(1,0,0,1,margin,margin));
// pixelDissolve to set some pixels to completely transparent
// , without this would be a 'solid mass'
canvas.pixelDissolve(canvas, canvas.rect, NEWPOINT, 11,
density*canvas.width*canvas.height,
0x000000);
canvas.applyFilter(canvas, canvas.rect, NEWPOINT, BLUR);
canvas.applyFilter(canvas, canvas.rect, NEWPOINT,
new ConvolutionFilter(3,3,[0, 1, 1.5,
-1, contrast, 1,
-1.5, -1, 0],contrast, 0, true) );
// repeat a serie of displacements to achieve a hair effect
// number of iterations, bigger value for smoother hair, but slows down
for (i=0; i!=5; i++) {
displacer.scaleX = displacer.scaleY *= 1.4;
bmd.applyFilter(canvas, bmd.rect, NEWPOINT, displacer);
canvas.draw(bmd,NEWMATRIX ,
// modify to change the color:
new ColorTransform(1.22,1.2,0.95,1.0),
BlendMode.LIGHTEN);
}
canvas.unlock();
}
}
}