// Petri Leskinen // leskinen[dot]petri[at]luukku[dot]com // August 2008 // Espoo, Finland package { import flash.display.Shader; import flash.display.ShaderData; import flash.filters.ShaderFilter; import flash.events.Event; import flash.events.EventDispatcher; import flash.geom.Point; import flash.net.URLLoader; import flash.net.URLLoaderDataFormat; import flash.net.URLRequest; public class LinearBlurFilter extends EventDispatcher { private var _lineEquation:Array; private var _uScale:Number; private var _vScale:Number; private var _quality:int; public var shaders:Array = []; public var filters:Array = []; private var ratios:Array = []; public var isLoaded:Boolean = false; private var shaderLoader:URLLoader; function LinearBlurFilter( lineEquation:Array, // = [1.0, 0.0, -100.0], uScale:Number = 12.0, vScale:Number = 12.0, quality:int = 3 ):void { this._lineEquation = lineEquation; this._uScale = uScale; this._vScale = vScale; // 'quality' means the numbers of blurring shaders in the array of filters // quality = 1, one shader, takes samples from 4 points // quality = 2, samples 4x4 = 16 points, // quality = 3, samples 4x4x4 = 64 points, increases exponentally // maximum value 5 this._quality = Math.min(5,quality); shaders = new Array(_quality); filters = new Array(_quality); ratios = countRatios(_quality); // loading pixel bender -bytecode shaderLoader = new URLLoader(); shaderLoader.dataFormat = URLLoaderDataFormat.BINARY; shaderLoader.addEventListener(Event.COMPLETE, shaderLoaded); // url for bytecode, in this case the same folder shaderLoader.load(new URLRequest("FocusingLinearBlur.pbj")); } function shaderLoaded(event:Event):void { // Create new array of shaders and filters for (var i:int=_quality-1; i>-1; i--) { shaders[i] = new Shader(shaderLoader.data); shaders[i].data.lineEquation.value = _lineEquation; filters[i] = new ShaderFilter(); filters[i].shader = shaders[i]; } // lineEquation is same for all shaders // uScale and vScale are geometric series of the radii, like 1.0,2.0,4.0 etc uScale=_uScale; vScale=_vScale; // tell possible listeners we're ready isLoaded=true; this.dispatchEvent(new Event(Event.COMPLETE)); } public function get uScale():Number { return this._uScale; } public function set uScale(value:Number):void { // see comments on function countRatios for more info _uScale= value; for (var i:int =0; i_quality) { shaders.shift(); filters.shift(); } } } public function horizontalLine(y0:Number):void { // sets lineEquation to y=y0 lineEquation = [ 0.0,1.0,-y0 ]; } public function verticalLine(x0:Number):void { // sets lineEquation to x=x0 lineEquation = [ 1.0,0.0,-x0 ]; } public function equationByPoints(point:Point, point2:Point):void { // line's equation Ax+By+C = 0 // solved with two points var A:Number = point2.y-point.y; var B:Number = point.x-point2.x; // normalizing A and B var L:Number = Math.max(Math.sqrt(A*A+B*B),0.00000001); A /= L; B /= L; // C solved by 1st point's coordinates lineEquation = [ A,B,-A*point.x - B*point.y ]; } private function countRatios(quality:int=3):Array { // uScale and vScale -ratios for each shader // // quality = 1: ratios = [1.0]; // quality = 2: ratios = [1/3,2/3]; sum = 1.0 // quality = 3: ratios = [1/7,2/7,4/7]; sum = 1.0 // quality = n: ratios = [1/(2^n-1),2/(2^n-1), ... ,2^(n-1)/(2^n-1)]; var ratios:Array = []; var j:int=1; var s:Number=0; // array of 2's powers ... for (var i:int =0; i