I bet you can't fill the canvas with paint using the bad painting algorithm below (keep an eye on the frame rate counter). Now check out your paint skills using the good paint algorithm. What's the difference? Check out the answer after the examples.

Bad Paint:

Alternate Page.

Get Adobe Flash player

(pretend your cursor is a paint brush, click and drag around)

Good Paint:

Alternate Page.

Get Adobe Flash player

(notice the fps counter in the top left)

I would like to start by pointing out that every Flash 'paint' example I found online uses lineTo. That's fine if your just playing around but what if you want to use a more advanced painting algorithm? It looks MUCH better. Drawing a circle using the 'lineTo' method has noticeable rigid corners. Using a good painting algorithm allows for much smoother edges and more control: Safe from the Losing Fight - How to implement a basic bitmap brush.

Well my first implementation of a simple painting algorithm turned out really bad (bad paint above). Why? Two reasons. I was creating a new sprite and BitmapAsset for every circle added (thousands of circles eating up memory). In addition to that I was using my own painting algorithm which was just barely a step up from lineTo.

The fix? First I converted a nice painting algorithm from C (CProgramming.com - Line Drawing Algorithm) into ActionScript. Second I took another look at the circle creation method.

My bad code:

Actionscript:
  1. override public function paint(point:Point):void
  2. {
  3.  
  4.     _wrapper = new Sprite();
  5.     _stroke = new Sprite();
  6.     _stroke.addChild(_particle);
  7.     _stroke.width = _stroke.height = 20;
  8.    
  9.     _wrapper.addChild(_stroke);
  10.    
  11.     while(Math.abs(_point.y - point.y)> _travel || Math.abs(_point.x - point.x)> _travel){
  12.         var bitmapData:BitmapData = new BitmapData(_wrapper.width, _wrapper.height, true, 0x00000000);
  13.         bitmapData.draw(_wrapper);
  14.        
  15.         // Creating a new BitmapAsset every time a particle is added: BAD!!!
  16.         var bitmap:BitmapAsset = new BitmapAsset(bitmapData);
  17.         bitmap.x = _point.x - (bitmap.width / 2);
  18.         bitmap.y = _point.y - (bitmap.height / 2);
  19.         this.addChild(bitmap);
  20.        
  21.         // Average painting algorithm
  22.         if(_point.x <point.x){
  23.             _point.x = _point.x + _travel;
  24.         }else if(_point.x> point.x){
  25.             _point.x = _point.x - _travel;
  26.         }else{
  27.             _point.x = point.x;
  28.         }
  29.        
  30.         if(_point.y <point.y){
  31.             _point.y = _point.y + _travel;
  32.         }else if(_point.y> point.y){
  33.             _point.y = _point.y - _travel;
  34.         }else{
  35.             _point.y = point.y;
  36.         }
  37.     }
  38. }

My good code:

Actionscript:
  1. public function PaintPngStroke(color:uint, start :P oint)
  2. {
  3.     super(color, start);
  4.    
  5.     _stroke = new Sprite();
  6.     _stroke.addChild(_particle);
  7.     _stroke.width = _stroke.height = 20;
  8.  
  9.     var colorTransform:ColorTransform = _stroke.transform.colorTransform;
  10.     colorTransform.color = _color;
  11.     _stroke.transform.colorTransform = colorTransform;
  12.    
  13.     // Only create ONE particle
  14.     _wrapper = new Sprite();
  15.     _wrapper.addChild(_stroke);
  16.  
  17.     _bitmapData = new BitmapData(SimplePaint.CANVAS_WIDTH, SimplePaint.CANVAS_HEIGHT, true, 0x00FF3300);
  18.    
  19.     // Only create ONE BitmapAsset
  20.     _bitmap = new BitmapAsset(_bitmapData);
  21.     this.addChild(_bitmap);
  22. }
  23.  
  24. override protected function wp(startx:int, starty:int):void
  25. {
  26.     // Move particle
  27.     _wrapper.x = startx - (_wrapper.width / 2);
  28.     _wrapper.y = starty - (_wrapper.height / 2);
  29.    
  30.     var matrix:Matrix = new Matrix();
  31.     matrix.tx = _wrapper.x;
  32.     matrix.ty = _wrapper.y;
  33.    
  34.     // GOOD paint: reuse the BitmapData
  35.     _bitmapData.draw(_wrapper, matrix);
  36. }

The good code runs much faster, is more efficient, looks better, and so on. Check out the source files to get a copy of the GOOD paint algorithm.

Enjoy!

Resources:
CProgramming.com - Line Drawing Algorithm
Safe from the Losing Fight - How to implement a basic bitmap brush

Tags: , ,