/** * ... * @author Default * @version 0.1 */ package org.papervision3d.core.effects { import flash.display.BitmapData; import flash.display.DisplayObject; import flash.display.Sprite; import flash.filters.BlurFilter; import flash.filters.ColorMatrixFilter; import flash.filters.DisplacementMapFilter; import flash.geom.ColorTransform; import flash.geom.Matrix; import flash.geom.Point; import org.papervision3d.view.layer.BitmapEffectLayer; public class BitmapFireEffect extends AbstractEffect{ private var layer:BitmapEffectLayer; private var _fadeRate:Number=0.4; private var _distortionScale:Number=0.4; private var _distortion:Number=0.5; private var _flameHeight:Number=0.3; private var _flameSpread:Number=0.3; private var _blueFlame:Boolean = false; private var _smoke:Number = 0; // private properties: // display elements: private var displayBmp:BitmapData; private var scratchBmp:BitmapData; private var perlinBmp:BitmapData; // geom: private var mtx:Matrix; private var pnt:Point; private var drawColorTransform:ColorTransform; // filters: private var fireCMF:ColorMatrixFilter; private var dispMapF:DisplacementMapFilter; private var blurF:BlurFilter; // other private var endCount:Number; private var bmpsValid:Boolean=false; private var perlinValid:Boolean=false; private var filtersValid:Boolean=false; private var _target:DisplayObject; public function BitmapFireEffect(r:Number = 1, g:Number = 1, b:Number = 1, a:Number= 1){ mtx = new Matrix(); pnt = new Point(); } public override function attachEffect(layer:BitmapEffectLayer):void{ this.layer = BitmapEffectLayer(layer); target = layer.drawLayer; } public override function postRender():void{ doFire(); //layer.canvas.applyFilter(layer.canvas, layer.canvas.rect, new Point(), fade); } public function set width(value:Number):void { //layer.canvas.width; } public function get width():Number { return layer.canvas.width; } public function set height(value:Number):void { ; } public function get height():Number { return layer.canvas.height; } [Inspectable(defaultValue=0.4,name='fadeRate (0-1)')] /** * Sets the rate that flames fade as they move up. 0 is slowest, 1 is fastest. * * @default 0.4 */ public function set fadeRate(value:Number):void { filtersValid &&= (value == _fadeRate); _fadeRate = value; } public function get fadeRate():Number { return _fadeRate; } [Inspectable(defaultValue=0.4,name='distortionScale (0-1)')] /** * Sets the scale of flame distortion. 0.1 is tiny and chaotic, 1 is large and smooth. * * @default 0.4 */ public function set distortionScale(value:Number):void { perlinValid &&= (value == _distortionScale); _distortionScale = value; } public function get distortionScale():Number { return _distortionScale; } [Inspectable(defaultValue=0.4,name='distortion (0-1)')] /** * Sets the amount of distortion. 0.1 is little, 1 is chaotic. * * @default 0.4 */ public function set distortion(value:Number):void { filtersValid &&= (value == _fadeRate); _distortion = value; } public function get distortion():Number { return _distortion; } [Inspectable(defaultValue=0.3,name='flameHeight (0-1)')] /** * Sets the how high the flame will burn. 0 is zero gravity, 1 is a bonfire. * * @default 0.3 */ public function set flameHeight(value:Number):void { perlinValid &&= (value == _flameHeight); _flameHeight = value; } public function get flameHeight():Number { return _flameHeight; } [Inspectable(defaultValue=0.3,name='flameSpread (0-1)')] /** * Sets the how much the fire will spread out around the target. 0 is no spread, 1 is a lot. * * @default 0.3 */ public function set flameSpread(value:Number):void { filtersValid &&= (value == _flameSpread); _flameSpread = value; } public function get flameSpread():Number { return _flameSpread; } [Inspectable(defaultValue=false,name='blueFlame')] /** * Indicates whether it should use a blue or red flame. * * @default false */ public function set blueFlame(value:Boolean):void { filtersValid &&= (value == _blueFlame); _blueFlame = value; } public function get blueFlame():Boolean { return _blueFlame; } [Inspectable(defaultValue=0,name='smoke (0-1)')] /** * Sets the amount of smoke. 0 little, 1 lots. * * @default 0 */ public function set smoke(value:Number):void { filtersValid &&= (value == _smoke); _smoke = value; } public function get smoke():Number { return _smoke; } [Inspectable(defaultValue='',name='target')] /** * Sets the amount of smoke. 0 little, 1 lots. * * @default */ public function set targetName(value:String):void { } /** * Defines the shape of the fire. The fire will burn upwards, so it should be near the bottom, and centered in the FireFX component. * * @default */ public function set target(value:DisplayObject):void { _target = value; clear(); } public function get target():DisplayObject { return _target; } /** * Clears the fire. */ public function clear():void { if (displayBmp) { displayBmp.fillRect(displayBmp.rect,0); } } public function stopFire():void { // let the fire burn down for 20 frames: if (endCount == 0) { endCount = 20; } } private function updateBitmaps():void { if (displayBmp) { displayBmp.dispose(); displayBmp = null; scratchBmp.dispose(); scratchBmp = null; perlinBmp.dispose(); perlinBmp = null; } displayBmp = layer.canvas; scratchBmp = displayBmp.clone(); perlinBmp = new BitmapData(width*3, height*3, false, 0); updatePerlin(); updateFilters(); bmpsValid = true; } private function updatePerlin():void { perlinBmp.perlinNoise(30*_distortionScale,20*_distortionScale,1,-Math.random()*1000|0,false,true,1|2,false); perlinBmp.colorTransform(perlinBmp.rect,new ColorTransform(1, 1-_flameHeight*0.5 ,1,1,0,0,0,0)); perlinValid = true; } private function updateFilters():void { if (_blueFlame) { fireCMF = new ColorMatrixFilter([0.8-0.55*_fadeRate,0,0,0,0, 0,0.93-0.48*_fadeRate,0,0,0, 0,0.1,0.96-0.35*_fadeRate,0,0, 0,0.1,0,1,-25+_smoke*24]); drawColorTransform = new ColorTransform(0,0,0,1,210,240,255,0); } else { fireCMF = new ColorMatrixFilter([0.96-0.35*_fadeRate,0.1,0,0,-1, 0,0.9-0.45*_fadeRate,0,0,0, 0,0,0.8-0.55*_fadeRate,0,0, 0,0.1,0,1,-25+_smoke*24]); drawColorTransform = new ColorTransform(0,0,0,1,255,255,210,0); } dispMapF = new DisplacementMapFilter(perlinBmp,pnt,1,2,14*_distortion,-30,"clamp"); blurF = new BlurFilter(32*_flameSpread,32*_flameSpread,1); filtersValid = true; } private function startFire():void { endCount = 0; } private function doFire():void { if (_target == null) { return; } if (!bmpsValid) { updateBitmaps(); } if (!perlinValid) { updatePerlin(); } if (!filtersValid) { updateFilters(); } if (endCount == 0) { var drawMtx:Matrix = _target.transform.matrix; scratchBmp.fillRect(scratchBmp.rect,0); drawColorTransform.alphaOffset = -Math.random()*200|0; scratchBmp.draw(_target,drawMtx,drawColorTransform,"add"); scratchBmp.applyFilter(scratchBmp,scratchBmp.rect,pnt,blurF); displayBmp.draw(scratchBmp,mtx,null,"add"); } dispMapF.mapPoint = new Point( -Math.random()*(perlinBmp.width-displayBmp.width)|0, -Math.random()*(perlinBmp.height-displayBmp.height)|0 ); displayBmp.applyFilter(displayBmp,displayBmp.rect,pnt,dispMapF); displayBmp.applyFilter(displayBmp,displayBmp.rect,pnt,fireCMF); //if (endCount != 0 && --endCount == 0) { // removeEventListener(Event.ENTER_FRAME,doFire); } } }