topical media & game development

talk show tell print

#filter-wood.ax

#filter-wood.ax [swf] flex


  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 @ax-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 @ax-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; } } }


(C) Æliens 27/08/2009

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.