package { import flash.display.BitmapData; import flash.display.Shape; import flash.display.BlendMode; import flash.display.GradientType; import flash.geom.Rectangle; import flash.geom.Point; import flash.geom.Matrix; import flash.filters.BitmapFilter; public class Noise { static public var colors:Array = [ 0xFFFFFF, 0x000000 ]; static public var alphas:Array = [ 1, 1 ]; static public var repartition:Array = [ 0,255 ]; static public var blendModes:Array = [ BlendMode.DIFFERENCE ]; /* PRNG function found on: http://www.firstpr.com.au/dsp/rand31/#History-implementation via: http://lab.polygonal.de/2007/04/21/a-good-pseudo-random-number-generator-prng/ and screwed up a bit to suit my needs. */ /* * PRNG * * the point of using a custom PRNG instead of the Math.random() method is to be able to store settings * the multiplier and randomnum variables are the most important thingsfor the algorithm * */ static public var multiplier:int = 255; static private var _m:uint = 0xFFFFFFFF; static private var randomnum:Number = 1; // static private function nextRandom( seed:int ):int { var lo:int; var hi:int; lo = multiplier * ( seed & 0xFFFF ); hi = multiplier * ( seed >> 16 ); lo += ( hi & 0xFFFF ) << 16; if( lo > _m ) { lo &= _m; ++lo; } lo += hi >> 16; if (lo > _m) { lo &= _m; ++lo; } return lo; } static public function random():Number { randomnum = nextRandom( randomnum ); return randomnum / 0xFFFFFFFF; } /** * performs a black and white noise on a bitmapData * @param bd the bitmapData to perform the noise on * @param octaves the complexity of the noise * @param multi the multiplier of the noise * @param scale scaling factor * @param filter filter that will be applied to each layer * @param randomSize should the size of the spots be randomized also * @return */ /* a pretty nice result can be achieved using this technique check this out : http://blog.oaxoa.com/2008/11/03/actionscript-3-better-perlinnoise-perlinnoise-complexification/ */ static public function process( bd:BitmapData, octaves:int = 10, multi:int = 255, scale:Number = 1, filter:BitmapFilter = null, randomSize:Boolean = false ):BitmapData { //resets the noises's seed randomnum = 1; //skips powers of 2 multiplier = ( ( multi & ( multi-1 ) ) == 0 ) ? ( multi + 1 ) : multi; //bounding the scale scale = ( scale < 1 ) ? 1 : scale; var W:int = bd.width * scale; var H:int = bd.height * scale; //creates a shape and draws a gradient var mat:Matrix = new Matrix(); mat.createGradientBox( W, H, 0, 0, 0 ); var sp:Shape = new Shape(); sp.graphics.beginGradientFill( GradientType.RADIAL, colors, alphas, repartition, mat ); sp.graphics.drawRect( 0,0,W,H ); //blendMode var bm:String; var i:int = 0; bd.lock(); bd.fillRect( bd.rect, 0xFF000000 ); for ( i = 0; i < octaves; i++ ) { mat.identity(); //size if( randomSize ) { mat.a *= 1 + random(); mat.d *= 1 + random(); }else{ mat.a = scale; mat.d = scale; } //posiiton mat.tx = ( random() * W ); mat.ty = ( random() * H ); if( scale > 1 ) { mat.tx -= ( W * ( scale - 1 ) ); mat.ty -= ( H * ( scale - 1 ) ); } //allows alterning BlendModes bm = blendModes[ i % blendModes.length ]; if ( filter != null ) { bd.draw( sp, mat, null, bm ); bd.applyFilter( bd, bd.rect, new Point(0, 0), filter ); } else { bd.draw( sp, mat, null, bm ); } } bd.unlock(); return bd; } } }