Senoculars 'Perlin Flag Wave' to AS2 Class

I’ve been trying to encapsulate Senoculars brilliant PerlinNoise Flag Wave example into a self contained AS2 class.

The original Fla example is here:

http://www.senocular.com/flash/source.php?id=0.188

I’ve tried to remove the need for having displacement Maps and bounding boxes in the target movieClip, by dynamically drawing them within the class itself.

I have so far succeeded and the effect works almost perfectly. However, the original example uses the alpha values of the displacement map to determine where, and how much displacement should take place. In my version though, I can’t seem to tie the alpha values to the displacement. The noise happens uniformly across the displacement map, no matter how much alpha there is. (Should be none from the left edge where there is 100% alpha).

My Class is contained below, and still needs a lot of refactoring and openness to dynamic values, but if anyone can help me figure out why the displacement seems uniform, I’d very much appreciate it.

[AS]
/**

  • @author d.robert hall
    */

import com.bourre.commands.Delegate;
import com.bourre.log.PixlibStringifier;
import com.bourre.transitions.FPSBeacon;
import com.bourre.transitions.IFrameListener;

import flash.display.BitmapData;
import flash.filters.DisplacementMapFilter;
import flash.geom.Matrix;
import flash.geom.Point;

class com.skivecreative.effects.FlagRipple
implements IFrameListener
{
private var speed:Number;
private var channel:Number;
private var baseX:Number;
private var baseY:Number;
private var octs:Number;
private var seed:Number;
private var stitch:Boolean;
private var fractal:Boolean;
private var gray:Boolean;
private var flapX:Number;
private var flapY:Number;
private var mode:String;
private var offset:Point;
private var displaceBitmap:BitmapData;
private var displaceFilter:DisplacementMapFilter;
private var ramp:MovieClip;
private var noiseBitmap:BitmapData;
private var shift:Matrix;
private var onEnterFrameHandler:Function;
private var target:MovieClip;
private var displace:MovieClip;
private var perlin:MovieClip;
private var ripple:MovieClip;
private var maxWidth:Number;
private var maxHeight:Number;
private var clampBox:MovieClip;

/* CONSTRUCTOR ********************************************************************************/
public function FlagRipple( target:MovieClip, maxWidth:Number, maxHeight:Number ) {
    this.target = target;
    this.maxWidth = maxWidth;
    this.maxHeight = maxHeight;

    speed = 3; // speed at which noise is shifted (causes flap)
    channel = 1; // red - red used to displace pixels along 
    baseX = 80; // size of noise in x axis
    baseY = 0; // size of noise in y axis
    octs = 1; // noise functions for noise (smaller = faster)
    seed = 20; // random seed for noise
    stitch = true; // stitching makes the noise wrap making it easy to repeat
    fractal = true; // use fractal noise
    gray = false; // grayscale is not used because the red channel is
    flapX = 0; // power of pixel displacement along x axis
    flapY = 20; // power of pixel displacement along y axis
    mode = "clamp"; // clamp the image so none of the original is seen
    offset = new Point( 0, 0 ); // displacment map offset
    
    init();
}

/* PUBLIC METHODS *****************************************************************************/
public function init()
{
    ripple = target.ripple_mc;
    
    drawDisplacementMap();
    setClampBox();

    displaceFilter = new DisplacementMapFilter( 
        displaceBitmap, offset, channel, channel, flapX, flapY, mode );
        
    shift = new Matrix();
    
    noiseBitmap = new BitmapData( 500, 1 );
    noiseBitmap.perlinNoise( baseX, baseY, octs, seed, stitch, fractal, channel, gray );
    
    FPSBeacon.getInstance().addFrameListener( this );
    onEnterFrameHandler = Delegate.create( this, update );
}

public function onEnterFrame () : Void
{
    onEnterFrameHandler();    
}

public function flush () : Void
{
    ripple.removeMovieClip();
    ripple = target.ripple_mc;
    ripple.swapDepths( target.getNextHighestDepth() );
    setClampBox();
}

/* PRIVATE METHODS ****************************************************************************/
private function setClampBox () : Void
{
    clampBox = ripple.createEmptyMovieClip( "clampBox", ripple.getNextHighestDepth() );
    clampBox._x = -( maxWidth / 2 );
    clampBox._y = -( maxHeight / 2 );
    clampBox.moveTo( 0, 0 );
    clampBox.lineStyle( 1, 0xFF0000, 0 );
    clampBox.lineTo( 0, maxHeight );
    clampBox.lineTo( maxWidth, maxHeight );
}

private function drawDisplacementMap () : Void
{
    displace = target.createEmptyMovieClip( "displace_mc", target.getNextHighestDepth() );
    ramp = displace.createEmptyMovieClip( "ramp", displace.getNextHighestDepth() );
    displace._x = -60;
    displace._y = -25;
    
    var dFillType:String = "linear";
    var dColors:Array = [0x800000, 0x800000];
    var dAlphas:Array = [100, 0];
    var dRatios:Array = [255, 0];
    var dMatrix:Object = {matrixType:"box", x:0, y:0, w:180, h:50, r:0/180*Math.PI};
    ramp.lineStyle(1, 0x000000, 0);
    ramp.beginGradientFill( dFillType, dColors, dAlphas, dRatios, dMatrix );
    ramp.moveTo( 0, 0 );
    ramp.lineTo( 180, 0 );
    ramp.lineTo( 180, 50 );
    ramp.lineTo( 0, 50 );
    ramp.lineTo( 0, 0 );
    ramp.endFill();
    
    perlin = displace.createEmptyMovieClip( "perlin", 1 );
    displaceBitmap = new BitmapData( ramp._width, ramp._height );    
    
    displace._visible = false;
}

private function update () : Void
{
    shift.translate( speed, 0 );
    perlin.clear();
    perlin.beginBitmapFill( noiseBitmap, shift );
    perlin.moveTo( 0, 0 );
    perlin.lineTo( ramp._width, 0 );
    perlin.lineTo( ramp._width, ramp._height );
    perlin.lineTo( 0, ramp._height );
    perlin.lineTo( 0, 0 );
    perlin.endFill();
    displaceBitmap.draw( displace );
    ripple.filters = [displaceFilter];
}

/* DEFAULT ************************************************************************************/
public function toString() : String
{
    return PixlibStringifier.stringify( this );
}

public function destroy()  : Void
{
    FPSBeacon.getInstance().removeFrameListener( this );
}

}
[/AS]