title: Optimising AS3 draw speed of line waves. Ready to run files and performance analyser included
body: <p>I have attached a zip with an FLA that you can run in CS 5.5. The animation contains a performance analyser and sliders to control various parameters.</p>
  
  <p>Demo:
  <a href="http://sephardi.ehclients.com/alivetest/index.html" rel="nofollow">http://sephardi.ehclients.com/alivetest/index.html</a>
  Click anywhere to start the animation</p>
  
  <p>Files:
  <a href="https://www.dropbox.com/s/4rcpvzo1h7br8fh/alivesource.zip" rel="nofollow">https://www.dropbox.com/s/4rcpvzo1h7br8fh/alivesource.zip</a></p>
  
  <p>I have written a program that draws lines pixel by pixel and animates them in a wave-like manner, and displaces certain pixels using a displacement map.</p>
  
  <p>This is what happens on each loop:</p>
  
  <ol>
  <li>Display objects and variables from previous loop are cleared</li>
  <li>Displacement map is stored in a bitmap data object </li>
  <li>A line is drawn pixel by pixel by reading the y coordinates stored in an array. It's value is also altered using corresponding displacement map and sine wave data.</li>
  </ol>
  
  <p>I have setup sliders with which you can control how many lines are drawn (linecount), the width of each line (canvaswidth), and the resolution of each line (res). </p>
  
  <p>The performance is pretty poor, and I would like your help in optimising it. Maybe there is nothing I can do to optimise my code, please let me know.</p>
  
  <p>I don't think caching as bitmap data is possible because the lines are in permanent motion</p>
  
  <p>Keep in mind, I would really like to preserve 35 lines and a resolution of 1 pixel per iteration</p>
  
  <p>Many thanks</p>
  
  <p>UPDATE:
  I am now using drawPath to draw the line rather than drawing pixel by pixel.</p>
  
  <pre><code>/*
  Click anywhere on the stage to start anim
  */
  
  
  import flash.display.BitmapData;
  import com.greensock.*;
  import flash.display.Shape;
  import uk.co.soulwire.*;
  import net.hires.debug.Stats;
  import uk.co.soulwire.gui.SimpleGUI;
  import flash.display.MovieClip;
  import flash.display.Sprite;
  
  
  /*
  Performance analyser and variable sliders
  */
  var stats:Stats;
  var gui:SimpleGUI;
  var guiholder:MovieClip;
  stats=new Stats();
  stats.x = 1200;
  stats.y = 0;
  addChild(stats);
  gui = new SimpleGUI(this,"Parameters","h",1000,0);
  gui.show();
  
  /*
  Stores the base coordinates
  */
  var c:Coordinates;
  c=new Coordinates();
  
  /*
  Holds the lines
  */
  var holder:MovieClip = new MovieClip  ;
  addChild(holder);
  
  
  /*
  Generic variables
  */
  var i:uint;
  var j:uint;
  var line:Sprite;
  var lines:Array = [];
  var bmd:BitmapData;
  var brightness = 0;
  var sinus = 0;
  
  
  
  
  
  
  /**
  *
  Parameters used to control the animaitons and extrusions
  *
  **/
  
  
  /*
  How many pixels do we draw in each loop?
  */
  var scaleFactor:Number=2
  var canvasWidth:Number = 999;
  var lineCount:Number = 35;
  var res = 1;//Skip res-1 pixels per loop to lower the resolution
  
  /*
  Displacement map properties
  */
  var extrusion:Number = 1;
  var extrusiontarget:Number = .1;
  var tolerance:Number = 1;
  var smoothness = 10;
  
  //Sinewave 
  var lasti = 0;
  var sinedirection = -1;
  var sineamplitude:Number = 3;
  var sinespeed = 0.5;
  var sinedensity = 100;
  
  /*
  Breathing animation
  */
  var inhale:Number = 2;
  var exhale:Number = 2;
  var beforeInhale:Number = 0;
  var beforeExhale:Number = 0;
  
  /*
  Add sliders to control the above variables
  */
  gui.addGroup("Pixels being drawn");
  gui.addSlider("lineCount", 5, 35);
  gui.addSlider("canvasWidth",30,999);
  gui.addSlider("res",1,10);
  
  gui.addGroup("Displacement Map");
  gui.addSlider("smoothness", 1, 100,{callback:setBlur});
  gui.addSlider("tolerance", 1, 255);
  gui.addSlider("extrusiontarget", 0.1, 3);
  
  gui.addGroup("Sinwave");
  gui.addSlider("sinedirection",-1,1);
  gui.addSlider("sineamplitude",0,30);
  gui.addSlider("sinespeed",0,10);
  
  gui.addGroup("Breathing");
  gui.addSlider("beforeInhale",0,5);
  gui.addSlider("inhale",0,5);
  gui.addSlider("beforeExhale",0,5);
  gui.addSlider("exhale",0,5);
  
  
  
  
  /**
  Loop
  **/
  function myEnterFrame(event:Event):void {
      /*
      Start a new iteration of line drawing, triggered when you click anywhere ons tage
      */
      drawLines();
  }
  
  
  
  
  
  function drawLines():void {
  
  
      for (i=0; i&lt;lines.length; i++) {
          holder.removeChild(lines[i]);
          lines[i] = null;
      }
      lines = [];
      for (i=0; i&lt;lineCount; i++) {
          drawLine(i);
      }
  
  }
  
  
  function resetBitmapData(){
      bmd = null;
      bmd = new BitmapData(canvasWidth,1000);
      bmd.draw(mc);
      mc.visible = false;
  }
  
  
  /**
  plot the cordinates of each point absed on sin data and bmp brihgtness
  **/
  
  
  var targety:Number;
  var myPath:GraphicsPath;
  var myStroke:GraphicsStroke;
  var myDrawing:Vector.&lt;IGraphicsData &gt; ;
  var myFill:GraphicsSolidFill;
  myFill= new GraphicsSolidFill();
  myFill.color = 0x000000;
  
  function drawLine(linenumber):void {
      line=new Sprite();
      holder.addChild(line);
      myPath= new GraphicsPath(new Vector.&lt;int&gt;(), new Vector.&lt;Number&gt;());
      myStroke = new GraphicsStroke(res);
      myStroke.fill = new GraphicsSolidFill(0xff0000);// solid stroke
      for (j=0; j&lt;canvasWidth; j+=res) {
          brightness = Math.ceil(getbrightness(getcolor(j,c.coords[linenumber][j]))/tolerance) ;
          sinus= Math.sin((j + (lasti * sinespeed)) / sinedensity) * sineamplitude;
          targety=c.coords[linenumber][j]-(sinus*0)-(brightness*extrusion)-(sinus*(linenumber-15)*1);
          myPath.commands.push(2);
          myPath.data.push(j,targety);
      }
      myPath.commands.push(2);
      myPath.data.push(0,1000);
      myDrawing = new Vector.&lt;IGraphicsData&gt;();
      myDrawing.push(myStroke,myFill, myPath);
      line.graphics.drawGraphicsData(myDrawing);
      lines.push(line);
      lasti -=  sinedirection;
  }
  
  
  /*
  Functions to retrieve brightness of displacement map
  */
  
  function getcolor(xx,targety):uint {
      var pixelValue:uint = bmd.getPixel(xx,targety);
      return pixelValue;
  }
  
  
  function getbrightness(colour):Number {
      var R:Number = 0;
      var G:Number = 0;
      var B:Number = 0;
      R +=  colour &gt;&gt; 16 &amp; 0xFF;
      G +=  colour &gt;&gt; 8 &amp; 0xFF;
      B +=  colour &amp; 0xFF;
      var br = Math.sqrt(R * R * .241 + G * G * .691 + B * B * .068);
      return br;
  }
  
  /*
  Makes the displacment map "breathe"
  */
  
  function grow():void {
      TweenLite.to(this,inhale,{extrusion:extrusiontarget,onComplete:shrink,delay:beforeInhale});
  }
  
  function shrink():void {
      TweenLite.to(this,exhale,{extrusion:0,onComplete:grow,delay:beforeExhale});
  }
  
  
  
  
  /*
  Smoothness of displacement map
  */
  var blur:BlurFilter = new BlurFilter();
  
  function setBlur():void {
      trace("sb");
      blur.blurX = smoothness;
      blur.blurY = smoothness;
      blur.quality = BitmapFilterQuality.HIGH;
      mc.word.filters = [blur];
      //reset the bitmap data
      resetBitmapData()
  }
  
  function mouseDownHandler(e) {
      grow();
      addEventListener(Event.ENTER_FRAME,myEnterFrame);
  }
  stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
  
  //Draws lines;
  setBlur();
  drawLines();
  </code></pre>
  
  <p>OLD CODE:</p>
  
  <pre><code>/*
  Click anywhere on the stage to start anim
  */
  
  
  import flash.display.BitmapData;
  import com.greensock.*;
  import flash.display.Shape;
  import uk.co.soulwire.*;
  import net.hires.debug.Stats;
  import uk.co.soulwire.gui.SimpleGUI;
  import flash.display.MovieClip;
  
  
  /*
  Performance analyser and variable sliders
  */
  var stats:Stats;
  var gui:SimpleGUI;
  var guiholder:MovieClip;
  stats=new Stats();
  stats.x = 1200
  stats.y = 0;
  addChild(stats);
  gui = new SimpleGUI(this,"Parameters","h",1000,0);
  gui.show();
  
  /*
  Stores the base coordinates
  */
  var c:Coordinates;
  c=new Coordinates();
  
  /*
  Holds the lines
  */
  var holder:MovieClip=new MovieClip
  addChild(holder)
  
  
  /*
  Generic variables
  */
  var i:uint;
  var j:uint;
  var line:Shape;
  var lines:Array = [];
  var bmd:BitmapData;
  var brightness = 0;
  var sinus=0;
  
  
  
  
  
  
  /**
  *
  Parameters used to control the animaitons and extrusions
  *
  **/
  
  
  /*
  How many pixels do we draw in each loop?
  */
  var canvaswidth:Number = 999;
  var linecount:Number=35
  var res=2//Skip res-1 pixels per loop to lower the resolution
  
  /*
  Displacement map properties
  */
  var extrusion:Number = 1;
  var extrusiontarget:Number = .1;
  var tolerance:Number = 1;
  var smoothness = 10;
  
  //Sinewave 
  var lasti = 0;
  var sinedirection = -1;
  var sineamplitude:Number = 3;
  var sinespeed = 0.5;
  var sinedensity = 100;
  
  /*
  Breathing animation
  */
  var inhale:Number = 2;
  var exhale:Number = 2;
  var beforeInhale:Number = 0;
  var beforeExhale:Number = 0;
  
  /*
  Add sliders to control the above variables
  */
  gui.addGroup("Pixels being drawn")
  gui.addSlider("linecount", 5, 35);
  gui.addSlider("canvaswidth",30,999);
  gui.addSlider("res",1,10);
  
  gui.addGroup("Displacement Map")
  gui.addSlider("smoothness", 1, 100,{callback:setblur});
  gui.addSlider("tolerance", 1, 255);
  gui.addSlider("extrusiontarget", 0.1, 3);
  
  gui.addGroup("Sinwave")
  gui.addSlider("sinedirection",-1,1);
  gui.addSlider("sineamplitude",0,30);
  gui.addSlider("sinespeed",0,10);
  
  gui.addGroup("Breathing")
  gui.addSlider("beforeInhale",0,5);
  gui.addSlider("inhale",0,5);
  gui.addSlider("beforeExhale",0,5);
  gui.addSlider("exhale",0,5);
  
  
  
  
  /**
  Loop
  **/
  function myEnterFrame(event:Event):void {
      /*
      Start a new iteration of line drawing, triggered when you click anywhere ons tage
      */
      initdraw();
  }
  
  
  
  
  /**
  Clear the lines
  Clear the bmp data
  Redraw the bitmpa data
  Redraw the lines
  **/
  
  function initdraw():void {
      /*
      Clear previous lines and displacement map data
      Lance drawing of 35 lines
      */
      for (i=0; i&lt;lines.length; i++) {
          holder.removeChild(lines[i]);
          lines[i] = null;
      }
      bmd = null;
      bmd = new BitmapData(canvaswidth,400);
      bmd.draw(mc);
      lines = [];
      for (i=0; i&lt;35; i++) {
  //  for (i=0; i&lt;c.coords.length; i++) {
          drawlines(i);
      }
  
  }
  
  
  /**
  plot the cordinates of each point absed on sin data and bmp brihgtness
  **/
  
  function drawlines(linenumber):void {
      /*
      Start to draw a line
      */
      line =new Shape();
      line.graphics.lineStyle(1, 0xdddddd);
      line.graphics.beginFill(0x000000);
      line.graphics.moveTo(-1,0);
      /*
      Increase length by 1 * times resolution and 
      Adjust y values based on displacement map and sinewave data
      */
      for (j=0; j&lt;canvaswidth; j+=res) {
          if (c.coords[linenumber][j] ==1100) {
              line.graphics.lineStyle(1, 0x000000);
          } else {
              line.graphics.lineStyle(1, 0xFFffff);
          }
          brightness = Math.ceil(getbrightness(getcolor(j,c.coords[linenumber][j]))/tolerance) ;
          sinus= Math.sin((j + (lasti * sinespeed)) / sinedensity) * sineamplitude;
          line.graphics.lineTo(j,c.coords[linenumber][j]-sinus-(brightness*extrusion));
  
      }
      /*
      Close the path that the line is drawing
      */
  
      lasti -=  sinedirection;
      line.graphics.lineTo(500,1100);
      line.graphics.lineTo(-1,1100);
      line.graphics.endFill();
      lines.push(line);
      holder.addChild(line);
  
  }
  
  
  
  
  
  
  /*
  Smoothness of displacement map
  */
  var blur:BlurFilter = new BlurFilter();
  
  function setblur():void {
      trace("sb");
      blur.blurX = smoothness;
      blur.blurY = smoothness;
      blur.quality = BitmapFilterQuality.HIGH;
      mc.word.filters = [blur];
  }
  
  
  /*
  Functions to retrieve brightness of displacement map
  */
  
  function getcolor(xx,yy):uint {
      var pixelValue:uint = bmd.getPixel(xx,yy);
      return pixelValue;
  }
  
  
  function getbrightness(colour):Number {
      var R:Number = 0;
      var G:Number = 0;
      var B:Number = 0;
      R +=  colour &gt;&gt; 16 &amp; 0xFF;
      G +=  colour &gt;&gt; 8 &amp; 0xFF;
      B +=  colour &amp; 0xFF;
      var br = Math.sqrt(R * R * .241 + G * G * .691 + B * B * .068);
      return br;
  }
  
  /*
  Makes the displacment map stringer then weaker
  */
  
  function grow():void {
      TweenLite.to(this,inhale,{extrusion:extrusiontarget,onComplete:shrink,delay:beforeInhale});
  }
  
  function shrink():void {
      TweenLite.to(this,exhale,{extrusion:0,onComplete:grow,delay:beforeExhale});
  }
  
  function mouseDownHandler(e){
      grow();
      addEventListener(Event.ENTER_FRAME,myEnterFrame);
  }
  
  
  stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
  
  //Draws lines
  initdraw();
  setblur()
  </code></pre>