In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Cubic Bezier Segment with Bitmap Blurry Brush

[EDIT: Just a slight update to get rid of an unneeded function, and also make it so you can change the background colour easily if you choose to play around.]

Instructions:
-play around with the control points to change the curve
-tap or hold hold " ^ "arrow key to increase the number of steps along the curve
-tap or hold " v " arrow key to decrease the number of steps along the curve
-tap " x " to make the control points disappear

This is really just building on what I did yesterday; however, it's a little different. I again, had some time while doing an illustration for school, because Adobe Illustrator was lagging, so I decided to go cubic instead of Quadratic.

I tried to comment a little, but if you have issues, let me know. I can be messaged using Facebook. https://www.facebook.com/arpace
Get Adobe Flash player
by NME 12 Mar 2016
package {
    import flash.ui.Keyboard;
    import flash.display.Graphics;
    import flash.display.Shape;
    import flash.events.MouseEvent;
    import flash.events.KeyboardEvent;
    import flash.geom.Matrix;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    
    [SWF(width=465, height=465, backgroundColor=0x00, frameRate=30)]
    public class FlashTest extends Sprite {
        public function FlashTest() {
            //Cubic Bezier Curve this time
            var n:uint = 200; //number of steps
            var bgColour:uint = 0x00;
            
            //this is a path which is essentially just a storage of control pts
            var ctrlPtVec:Vector.<Pt> = new Vector.<Pt>;
            //doing it by hand for now
            ctrlPtVec[0] = new Pt(100,200);//special control point
            ctrlPtVec[1] = new Pt(180,280);
            ctrlPtVec[2] = new Pt(300,180);
            ctrlPtVec[3] = new Pt(380,300);//special control point
            
            
            var cpl:Sprite = new Sprite();//control points layer
            
            var lineLayer:Shape = new Shape();
            cpl.addChild(lineLayer);
            
            var ctrlBoxVec:Vector.<CtrlPtBox> = new Vector.<CtrlPtBox>;
            for(var i:uint=0;i!=ctrlPtVec.length;++i){
               ctrlBoxVec[i]= new CtrlPtBox();
               ctrlBoxVec[i].x = ctrlPtVec[i].x;
               ctrlBoxVec[i].y = ctrlPtVec[i].y;
               ctrlBoxVec[i].ptData = ctrlPtVec[i];
               cpl.addChild(ctrlBoxVec[i]);
            }
            
            var brush:BMDBrush1 = new BMDBrush1(); 
            //making a bitmap canvas the size of the stage
            var bmd:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,false,0x00);//the colour needs to be 0 in order to be transparent
            var bmp:Bitmap = new Bitmap(bmd,'never',true);
            
            stage.addChild(bmp);//add the bitmap to the stage
            stage.addChild(cpl);//add the control layer... this will be added and removed for simplicity when the user taps x
            
            //start up the image
            drawCtrlLines(ctrlPtVec,lineLayer);
            drawPts(bmp,findCubicBezPts(ctrlPtVec[0],ctrlPtVec[1],ctrlPtVec[2],ctrlPtVec[3],n),brush,bgColour);
            
            //stuff to help with dragging when we roll out of the object we are trying to drag
            var isDragging:Boolean = false,
            instanceOfDraggedObject:Object; 
           //setting up the listeners using anonymous funtions for now to make things easier on me
           //this may be familiar to someone that knows Javascript
        
           cpl.addEventListener(MouseEvent.MOUSE_DOWN,
               function(me:MouseEvent):void{
                   isDragging=true;
                   instanceOfDraggedObject = me.target;
               }); 
           stage.addEventListener(MouseEvent.MOUSE_UP,
               function(me:MouseEvent):void{
                   isDragging=false;
               });
           stage.addEventListener(MouseEvent.MOUSE_MOVE,
               function(me:MouseEvent):void{
                   if(me.buttonDown && isDragging){
                           instanceOfDraggedObject.ptData.x = me.stageX;
                           instanceOfDraggedObject.ptData.y = me.stageY;
                           instanceOfDraggedObject.x = me.stageX;
                           instanceOfDraggedObject.y = me.stageY;
                           drawPts(bmp,findCubicBezPts(ctrlPtVec[0],ctrlPtVec[1],ctrlPtVec[2],ctrlPtVec[3],n),brush,bgColour);
                           drawCtrlLines(ctrlPtVec,lineLayer);
                   }
                   me.updateAfterEvent();
               });
               
           var ctrlLayerIsVisible:Boolean = true;//this is an easy way to track if the control layer visible
           stage.addEventListener(KeyboardEvent.KEY_UP,
               function(ke:KeyboardEvent):void{
                   if(ke.keyCode == 88){
                      if(ctrlLayerIsVisible){
                          ctrlLayerIsVisible = false;
                          stage.removeChild(cpl);
                      }else {
                          ctrlLayerIsVisible = true;
                          stage.addChild(cpl);
                      }
                   }
                   
                 });
            stage.addEventListener(KeyboardEvent.KEY_DOWN,
               function(ke:KeyboardEvent):void{
                  if(ke.keyCode==40){
                       if(n>1){
                           n--;
                           drawPts(bmp,findCubicBezPts(ctrlPtVec[0],ctrlPtVec[1],ctrlPtVec[2],ctrlPtVec[3],n),brush,bgColour);
                           drawCtrlLines(ctrlPtVec,lineLayer);
                       }
                   }else if(ke.keyCode==38){
                       if(n<0xffffff){
                           n++;
                           drawPts(bmp,findCubicBezPts(ctrlPtVec[0],ctrlPtVec[1],ctrlPtVec[2],ctrlPtVec[3],n),brush,bgColour);
                           drawCtrlLines(ctrlPtVec,lineLayer);
                       }
                   }
                 });
        }
        public function drawCtrlLines(ctrlPts:Vector.<Pt>,container:Shape):void{
                var ctrlPtsLen:uint = ctrlPts.length;
                var g:Graphics = container.graphics;
                g.clear();
                g.moveTo(ctrlPts[0].x,ctrlPts[0].y);
                for(var i:uint = 1; i!=ctrlPtsLen;++i){
                    if((i+1)%3==0){
                        g.lineStyle(1,0x888888,1);
                    }else{
                        g.lineStyle(1,0x666666,1);
                    }
                    g.lineTo(ctrlPts[i].x,ctrlPts[i].y);
                }
        }
        public function drawPts(bmp:Bitmap,pts:Vector.<Pt>,brush:BitmapData,bgColour:uint):void{
            var bmd:BitmapData = new BitmapData(bmp.width,bmp.height,false,bgColour),
            lenPts:uint = pts.length,
            offsetX:Number = brush.rect.width*0.5,
            offsetY:Number = brush.height*0.5,
            m:Matrix = new Matrix(1,0,
                                  0,1,  0,0); // we ignore/set the identity matrix, and just edit the translation variables, tx,ty
            for (var i:uint = 0;i!=lenPts;++i){
                m.tx = pts[i].x - offsetX;
                m.ty = pts[i].y - offsetY;
                bmd.draw(brush,m);
            }
            bmp.bitmapData=bmd;
        }
        public function findCubicBezPts(cp0:Pt,cp1:Pt,cp2:Pt,cp3:Pt,steps:uint=2):Vector.<Pt>{
            //this will also include the end pts in the resulting Locus Vector Array
            
            /*
            //you could actually get rid of this, but you may want to keep it in later
            //but you need this here if you want to prevent issues when step number is less than 1 
            if(steps<1){
                steps==1;
            }*/
            var locus:Vector.<Pt> = new Vector.<Pt>;
            //just in case we need to modify the original Pt at some point
            locus[0] = new Pt(cp0.x,cp0.y);
            var t:Number=0; //current percent from 1 to 100
            var inc:Number=1/steps;//ammount that t will increment by
            
            //stored math to help find x positions
            var cp1x_neg_cp0x:Number = cp1.x-cp0.x,
            cp2x_neg_cp1x:Number = cp2.x-cp1.x,
            cp3x_neg_cp2x:Number = cp3.x-cp2.x;
            
            //stored math to help find y positions
            var cp1y_neg_cp0y:Number = cp1.y-cp0.y,
            cp2y_neg_cp1y:Number = cp2.y-cp1.y,
            cp3y_neg_cp2y:Number = cp3.y-cp2.y;
            
            var m0:Number,
                m1:Number,
                m2:Number,
                mm0:Number,
                mm1:Number,
                x:Number,
                y:Number;
            
            for(var i:uint = 1; i!=steps; ++i){
                t+=inc;
                m0 = cp0.x + (cp1x_neg_cp0x)*t;
                m1 = cp1.x + (cp2x_neg_cp1x)*t;
                m2 = cp2.x + (cp3x_neg_cp2x)*t
            
                mm0 = m0+(m1-m0)*t;
                mm1 = m1+(m2-m1)*t;
            
                x = mm0+(mm1-mm0)*t;
                
                m0 = cp0.y + (cp1y_neg_cp0y)*t;
                m1 = cp1.y + (cp2y_neg_cp1y)*t;
                m2 = cp2.y + (cp3y_neg_cp2y)*t
            
                mm0 = m0+(m1-m0)*t;
                mm1 = m1+(m2-m1)*t;
            
                y = mm0+(mm1-mm0)*t;
                
               locus[i] = new Pt(x,y);
            }
            locus[i] = new Pt(cp3.x,cp3.y);
            return locus;
        }
    }
}

import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.Shape;
import flash.display.Graphics;
import flash.filters.BlurFilter;
import flash.geom.Matrix;


// I wish I could call this a struct, but w/e
internal class Pt{
   public var x:Number;
   public var y:Number;
   public function Pt(x:Number=0,y:Number=0){  
       this.x=x;
       this.y=y;  
   }
}

internal class CtrlPtBox extends Sprite{
   public var ptData:Pt;
    
    public function CtrlPtBox(w:uint = 10,h:uint=10,colour:uint=0x000000){
        
        this.buttonMode = true;
        drawBox(w,h,colour);
    }
    public function drawBox(w:uint=10,h:uint=10,colour:uint= 0x000000):void{
        
        var g:Graphics = this.graphics;
        g.lineStyle(1,0x0000ff);
        g.beginFill(colour,1); //
        g.drawRect(-w/2,-h/2,w,h);
    }
    
}
internal class BMDBrush1 extends BitmapData{
    //this is just an example of a brush that you would put in a set of bitmap brushes
    
    //you could make things editable
    //but for now I just wanted to be able to call it as the CircleBrush
    public function BMDBrush1(lineColour:uint=0xff0000,blurAmount:uint=8,radius:uint=10){  
          //making the sprite that will be used as a brush
          if(radius<10){
              radius=10;
          }
          var brushContainer:Sprite= new Sprite();
          var ldot:Shape = new Shape();
          var g:Graphics = ldot.graphics;
          var rpb:uint = radius+blurAmount;
          g.lineStyle(1,lineColour,1);
          g.drawCircle(rpb,rpb,radius);
          ldot.filters = [new BlurFilter(blurAmount,blurAmount,3)];
          
          var dot:Shape = new Shape();
          g = dot.graphics;
          //g.lineStyle(1,0xff600)
          g.beginFill(0xfeff00,1);
          g.drawCircle(rpb,rpb,radius-5);
          dot.filters = [new BlurFilter(blurAmount,blurAmount,3)];
          
          //workaround to be sure we get the all the bitmap data including the blurred areas
          
          brushContainer.addChild(dot);
          brushContainer.addChild(ldot);
          
          g = brushContainer.graphics;
          g.lineStyle(1,0x000000,0);
          g.drawRect(0,0,rpb*2,rpb*2);
          
          //turning the brush into bitmap data
          super(brushContainer.width,brushContainer.height,true,0);
          this.draw(brushContainer,new Matrix(1,0,0,1,0,0));        
         
    }
    
}