package { /** * @author Joel May * www.connectedpixel.com * All original source code listed here is licensed under a Creative Commons License. */ import flash.display.BitmapData; import flash.geom.Rectangle; import flash.geom.Point; import flash.geom.Matrix; import flash.filters.BlurFilter; import flash.filters.BitmapFilter; import flash.filters.ColorMatrixFilter; import flash.geom.ColorTransform; ////////////////////////////////////////////////////////////////////////// // Renders a wood texture to a bitmap. Uses perlin noise and the folumula // pixval = fraction(nTreeRings * perlin(x,y)) ////////////////////////////////////////////////////////////////////////// class filter_wood { private var _baseX :Number = 400; private var _baseY :Number = 120; private var _nOctaves :Number = 1; private var _randomSeed :Number = 128; private var _bTile :Boolean = false; private var _bFractalNoise :Boolean = false; private var _nGrainLayers :Number = 15; private var _blurX :Number = 5; private var _blurY :Number = 5; private var _rgb0:Number = 0xaa5522; private var _rgb1:Number = 0xee9922; private var _identityMatrix:Matrix; private var _identityColorTrans:ColorTransform; private var _woodColorFilter:ColorMatrixFilter; private var _blurFilter:BlurFilter; private function invalidateWoodColorFilter():Void { delete _woodColorFilter; _woodColorFilter = undefined; } private function invalidateBlurFilter():Void { delete _blurFilter; _blurFilter = undefined; } ////////////////////////////////////////////////////////////////////// // Properties. public function set perlinBaseX(bx:Number):Void { if (isNaN(bx)) return; if (bx < 3) bx = 3; if (bx > 1000) bx = 1000; _baseX = bx; } public function get perlinBaseX():Number { return _baseX; } public function set perlinBaseY(by:Number):Void { if (isNaN(by)) return; if (by < 3) by = 3; if (by > 1000) by = 1000; _baseY = by; } public function get perlinBaseY():Number { return _baseY; } public function set octaves(nOct:Number):Void { _nOctaves = nOct; } public function get octaves():Number { return _nOctaves; } public function set grainLayers(nLayers:Number):Void { _nGrainLayers = nLayers; } public function get grainLayers():Number { return _nGrainLayers; } public function set rgb0(rgb:Number):Void { _rgb0 = rgb; invalidateWoodColorFilter(); } public function get rgb0():Number { return _rgb0; } public function set rgb1(rgb:Number):Void { _rgb1 = rgb; invalidateWoodColorFilter(); } public function get rgb1():Number { return _rgb1; } public function set seed(s:Number):Void { _randomSeed = s; } public function get seed():Number { return _randomSeed; } public function set tileable(bTile:Boolean):Void { _bTile = bTile; } public function get tileable():Boolean { return _bTile; } public function set fractalNoise(bFractal:Boolean):Void { _bFractalNoise = bFractal; } public function get fractalNoise():Boolean { return _bFractalNoise; } public function filter_wood() { _identityMatrix = new Matrix(); _identityColorTrans = new ColorTransform(); } //////////////////////////////////////////////////////////////////////// // Convenience function. Returns a bitmap of the desired // size using the current wood settings. /////////////////////////////////////////////////////////////////////// public function createBitmap(w:Number,h:Number):BitmapData { var wood_bmp:BitmapData = new BitmapData(w, h, false, 0x000000); render(wood_bmp); return wood_bmp; } //////////////////////////////////////////////////////////////////////// // Render the wood grain onto the bitmap using the current property // values. // buffer0_bmp and buffer1_bmp are optional. If they are not supplied // temporary bitmaps will be created. They MUST have the same // width and height as the destination bmp. /////////////////////////////////////////////////////////////////////// public function render(bmp:BitmapData, buffer0_bmp:BitmapData, buffer1_bmp:BitmapData):Void { var w:Number = bmp.width; var h:Number = bmp.height; // Will hold perlin noise. var srcNoise_bmp:BitmapData = (buffer0_bmp != undefined) ? buffer0_bmp : new BitmapData(w, h, false, 0xffffffff); var tmp_bmp:BitmapData = (buffer1_bmp != undefined) ? buffer1_bmp : new BitmapData(w, h, false, 0xffffffff); // channelOptions - 1 - Red only // grayscale - false srcNoise_bmp.perlinNoise(_baseX,_baseY,_nOctaves,_randomSeed,_bTile,_bFractalNoise,1,false); // Needed in some of the following flash api calls. var rect:Rectangle = new Rectangle(0,0,w,h); var origin:Point = new Point(0,0); // For each tree ring. for (var iLayer:Number = 0 ; iLayer < _nGrainLayers ; iLayer++){ // After multiplying, the signal needs to be shifted into the // 0 to 255 range. var offset:Number = - iLayer * 256; // Amplify and shift the pixels. var matrix:Array = [_nGrainLayers, 0, 0, 0, offset, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 ]; var filter:BitmapFilter = new ColorMatrixFilter(matrix); tmp_bmp.applyFilter(srcNoise_bmp,rect,origin,filter); // Set the brightest to be black. Following layers will write // only on the black. tmp_bmp.threshold(tmp_bmp, rect, origin, "==", 0x00ff0000, 0xff000000, 0x00ff0000, false); // Copy the tmp on to the dest bitmap. var blend:Object = 5; //lighten bmp.draw(tmp_bmp, _identityMatrix, _identityColorTrans, blend); } // Don't need the temporary bitmaps anymore if (buffer1_bmp == undefined){ tmp_bmp.dispose(); } if (buffer0_bmp == undefined){ srcNoise_bmp.dispose(); } // Change it from black and red to the desired colors. bmp.applyFilter(bmp,rect, origin, getWoodColorFilter()); // Blur it to remove the jaggies. bmp.applyFilter(bmp,rect,origin,getBlurFilter()); } /////////////////////////////////////////////////////////////////////// // Create a filter that will lessen the jaggies. The threshold() call // creates jaggies that are pretty bad. This basically solves the // problem. /////////////////////////////////////////////////////////////////////// private function getBlurFilter():BlurFilter { if (_blurFilter != undefined){ return _blurFilter; } _blurFilter = new BlurFilter(_blurX,_blurY,1); return _blurFilter; } /////////////////////////////////////////////////////////////////////// // Map the black to red colors to the desired wood colors. /////////////////////////////////////////////////////////////////////// private function getWoodColorFilter():ColorMatrixFilter { if (_woodColorFilter != undefined){ return _woodColorFilter; } // Apply the desired colors to the bitmap. var r0:Number = (_rgb0 >> 16) & 0xff; var g0:Number = (_rgb0 >> 8 ) & 0xff; var b0:Number = _rgb0 & 0xff; var r1:Number = (_rgb1 >> 16) & 0xff; var g1:Number = (_rgb1 >> 8 ) & 0xff; var b1:Number = _rgb1 & 0xff; var woodColor:Array = [(r1-r0)/255, 0, 0, 0, r0, (g1-g0)/255, 0, 0, 0, g0, (b1-b0)/255, 0, 0, 0, b0, 0 , 0, 0, 1, 0 ]; _woodColorFilter= new ColorMatrixFilter(woodColor); return _woodColorFilter; } } }