Category Archives: Vector

BitmapData Static

Actionscript:
  1. var canvas:BitmapData = new BitmapData(500,500,false, 0x000000);
  2. addChild(new Bitmap(canvas));
  3.  
  4. var pix:Vector.<uint> = new Vector.<uint>(canvas.width * canvas.height, true);
  5.  
  6. addEventListener(Event.ENTER_FRAME, onLoop);
  7. function onLoop(evt:Event):void {
  8.     canvas.lock();
  9.     var i:int = pix.length;
  10.     while(--i> -1){
  11.         var c:uint = uint(Math.random() * 255);
  12.         pix[i] = c <<16 | c <<8 | c;
  13.     }
  14.     canvas.setVector(canvas.rect, pix);
  15.     canvas.unlock();
  16. }

This is an easy way to fill a BitmapData Object up with a bunch of TV-style static....

This post is meant to serve as filler while I work to get a good solid SIMPLE fp10, drawing api z-sorting example going... There seem to be 3 main ways of doing z-sorting all of which don't seem right to me for some reason... they all work... but I have a gut feeling there is a faster way... The winner so far (unexpectedly) is using Array.sortOn

Also posted in BitmapData, misc | Tagged , , | 6 Comments

Sierpiński Glitch Texture #3

Actionscript:
  1. [SWF(frameRate=60, backgroundColor=0x000000, width=500, height=500)]
  2.  
  3. var canvas:BitmapData = new BitmapData(500,500,false, 0x000000);
  4. addChild(new Bitmap(canvas));
  5. var clone:BitmapData = new BitmapData(500,500,false, 0x000000);
  6. var canvasRect:Rectangle = canvas.rect;
  7. var w:int = canvas.width;
  8. var w2:Number = 1/w;
  9. var w10:Number = 1/(w * 80);
  10. var convert:Number = Math.PI/180;
  11. var size:int = canvas.width * canvas.height;
  12. var pix:Vector.<uint> = new Vector.<uint>(size, true);
  13. var m:Matrix = new Matrix();
  14. m.scale(1,-1);
  15. m.translate(0,canvas.height);
  16. var sin:Number = 0, cos:Number = 0;
  17. var dx:Number = 0, dy:Number = 0;
  18. var pnt:Point = new Point();
  19. var blur:BlurFilter = new BlurFilter(10,10,1);
  20. addEventListener(Event.ENTER_FRAME, onLoop);
  21. function onLoop(evt:Event):void {
  22.     canvas.lock();
  23.     dx +=  (mouseX * 10 - 3000 - dx) / 8;
  24.     dy +=  (mouseY * 4 - dy) / 8;
  25.     for (var i:int = 0; i<size; i++){
  26.         var xp:int = i % w;
  27.         var yp:int = int(i * w2);
  28.         var xp2:int = xp <<1;
  29.         var t:Number;
  30.         t = ((yp|(xp + yp * 0.1)) * (xp + dx) *w10) % 6.14687;
  31.         //compute sine
  32.         // technique from http://lab.polygonal.de/2007/07/18/fast-and-accurate-sinecosine-approximation/
  33.         // by Michael Baczynski
  34.         if (t<0) {
  35.             sin=1.27323954*t+.405284735*t*t;
  36.         } else {
  37.             sin=1.27323954*t-0.405284735*t*t;
  38.         }
  39.         // compute cosine
  40.         t = (xp2|(yp+xp*0.1) + dy) * convert % 6.28;
  41.         t+=1.57079632;
  42.         if (t>3.14159265) {
  43.             t-=6.28318531;
  44.         }
  45.         if (t<0) {
  46.             cos=1.27323954*t+0.405284735*t*t;
  47.         } else {
  48.             cos=1.27323954*t-0.405284735*t*t;
  49.         }
  50.         var c1:int = 31 * (sin - cos);
  51.         if (c1 <0) c1 = 256 - c1;
  52.         c1 = (c1 <<4 | c1) ;
  53.         pix[i] = c1 <<16 | c1 <<8 | c1;
  54.     }
  55.     canvas.setVector(canvasRect, pix);
  56.     clone.copyPixels(canvas, canvasRect, pnt);
  57.     canvas.draw(clone, m, null, BlendMode.SUBTRACT);
  58.     clone.copyPixels(canvas, canvasRect, pnt);
  59.     clone.applyFilter(clone, canvasRect, pnt, blur);
  60.     canvas.draw(clone, null, null, BlendMode.SCREEN);
  61.     canvas.unlock();
  62. }

Decided to do a grayscale version ... also rendered it out large and posted it on flickr...

Check out the swf...


Check out the large flickr version...

Also posted in BitmapData, Operators, pixel manipulation | Tagged , , | 2 Comments

Sierpiński Glitch Texture #2

Actionscript:
  1. [SWF(frameRate=60, backgroundColor=0x000000, width=500, height=500)]
  2. var canvas:BitmapData = new BitmapData(500,500,false, 0x000000);
  3. addChild(new Bitmap(canvas));
  4. var clone:BitmapData = new BitmapData(500,500,false, 0x000000);
  5. var canvasRect:Rectangle = canvas.rect;
  6. var w:int = canvas.width;
  7. var w2:Number = 1/w;
  8. var w10:Number = 1/(w * 80);
  9. var convert:Number = Math.PI/180;
  10. var size:int = canvas.width * canvas.height;
  11. var pix:Vector.<uint> = new Vector.<uint>(size, true);
  12. var gray:ColorMatrixFilter = new ColorMatrixFilter([1, 0.55, 0.55, 0,0,0.55, 0.9, 0.55, 0,0,0.55, 0.55, 0.550,0, 0,0,0,1,0]);
  13. var m:Matrix = new Matrix();
  14. m.scale(1,-1);
  15. m.translate(0,canvas.height);
  16. var sin:Number = 0, cos:Number = 0;
  17. var dx:Number = 0, dy:Number = 0;
  18. var pnt:Point = new Point();
  19. var blur:BlurFilter = new BlurFilter(10,10,1);
  20. addEventListener(Event.ENTER_FRAME, onLoop);
  21. function onLoop(evt:Event):void {
  22.     canvas.lock();
  23.     dx += (mouseX * 10 - 3000 - dx) / 8;
  24.     dy += (mouseY * 4 - dy) / 8;
  25.     for (var i:int = 0; i<size; i++){
  26.         var xp:int = i % w;
  27.         var yp:int = int(i * w2);
  28.         var xp2:int = xp <<1;
  29.         var t:Number;
  30.         t = ((yp|(xp + yp)) * (xp + dx) *w10) % 6.14687;
  31.         //compute sine
  32.         // technique from http://lab.polygonal.de/2007/07/18/fast-and-accurate-sinecosine-approximation/
  33.         // by Michael Baczynski
  34.         if (t<0) {
  35.             sin=1.27323954*t+.405284735*t*t;
  36.         } else {
  37.             sin=1.27323954*t-0.405284735*t*t;
  38.         }
  39.         // compute cosine
  40.         t = (xp2|(yp+xp/dx) + dy) * convert % 6.28;
  41.         t+=1.57079632;
  42.         if (t>3.14159265) {
  43.             t-=6.28318531;
  44.         }
  45.         if (t<0) {
  46.             cos=1.27323954*t+0.405284735*t*t;
  47.         } else {
  48.             cos=1.27323954*t-0.405284735*t*t;
  49.         }
  50.         var c1:int = 31 * (sin - cos);
  51.         if (c1 <0) c1 = 256 - c1;
  52.         c1 = (c1>>1  | c1) ;
  53.         pix[i] = c1 <<17 | c1 <<8 | c1;
  54.     }
  55.     canvas.setVector(canvasRect, pix);
  56.     clone.copyPixels(canvas, canvasRect, pnt);
  57.     canvas.draw(clone, m, null, BlendMode.SUBTRACT);
  58.     clone.copyPixels(canvas, canvasRect, pnt);
  59.     clone.applyFilter(clone, canvasRect, pnt, blur);
  60.    
  61.     canvas.draw(clone, null, null, BlendMode.LIGHTEN);
  62.     canvas.applyFilter(canvas, canvasRect, pnt, gray);
  63.     canvas.unlock();
  64. }

More texture experimentation...

Have a look at the swf over at wonderfl.net...

Also posted in BitmapData, Operators, pixel manipulation | Tagged , , | Leave a comment

Interesting Texture #3 (animated)

Actionscript:
  1. [SWF(frameRate=60, backgroundColor=0x000000, width=500, height=500)]
  2. var canvas:BitmapData = new BitmapData(500,500,false, 0x000000);
  3. addChild(new Bitmap(canvas));
  4. var clone:BitmapData = new BitmapData(500,500,false, 0x000000);
  5. var canvasRect:Rectangle = canvas.rect;
  6. var w:int = canvas.width;
  7. var w2:Number = 1/w;
  8. var w10:Number = 1/(w * 80);
  9. var convert:Number = Math.PI/180;
  10. var size:int = canvas.width * canvas.height;
  11. var pix:Vector.<uint> = new Vector.<uint>(size, true);
  12. var gray:ColorMatrixFilter = new ColorMatrixFilter([1, 0.55, 0.55, 0,0,0.55, 0.9, 0.55, 0,0,0.55, 0.55, 0.550,0, 0,0,0,1,0]);
  13. var m:Matrix = new Matrix();
  14. m.scale(1,-1);
  15. m.translate(0,canvas.height);
  16. var sin:Number = 0, cos:Number = 0;
  17. var dx:Number = 0, dy:Number = 0;
  18. var pnt:Point = new Point();
  19. var blur:BlurFilter = new BlurFilter(10,10,1);
  20. addEventListener(Event.ENTER_FRAME, onLoop);
  21. function onLoop(evt:Event):void {
  22.     canvas.lock();
  23.     dx += (mouseX * 10 - 3000 - dx) / 8;
  24.     dy += (mouseY * 4 - dy) / 8;
  25.     for (var i:int = 0; i<size; i++){
  26.         var xp:int = i % w;
  27.         var yp:int = int(i * w2);
  28.         var xp2:int = xp <<1;
  29.         var t:Number = (yp * (xp2 + dx) * w10) % 3.14687;
  30.         //compute sine
  31.         // technique from http://lab.polygonal.de/2007/07/18/fast-and-accurate-sinecosine-approximation/
  32.         // by Michael Baczynski
  33.         if (t<0) {
  34.             sin=1.27323954*t+.405284735*t*t;
  35.         } else {
  36.             sin=1.27323954*t-0.405284735*t*t;
  37.         }
  38.         // compute cosine
  39.         t = (xp2 + dy) * convert % 6.28;
  40.         t+=1.57079632;
  41.         if (t>3.14159265) {
  42.             t-=6.28318531;
  43.         }
  44.         if (t<0) {
  45.             cos=1.27323954*t+0.405284735*t*t;
  46.         } else {
  47.             cos=1.27323954*t-0.405284735*t*t;
  48.         }
  49.         var c1:int = 31 * (cos - sin);
  50.         if (c1 <0) c1 = 256 - c1;
  51.         c1 = (c1 <<2 | c1) ;
  52.         pix[i] = c1 <<15 | c1 <<9 | c1;
  53.     }
  54.     canvas.setVector(canvasRect, pix);
  55.     clone.copyPixels(canvas, canvasRect, pnt);
  56.     canvas.draw(clone, m, null, BlendMode.SUBTRACT);
  57.     clone.copyPixels(canvas, canvasRect, pnt);
  58.     clone.applyFilter(clone, canvasRect, pnt, blur);
  59.     canvas.draw(clone, null, null, BlendMode.ADD);
  60.     canvas.applyFilter(canvas, canvas.rect, new Point(0,0), gray);
  61.     canvas.unlock();
  62. }

This snippet creates an interactive animated texture. Originally this texture wasn an unoptimized messy code snippet (see the original post here) - I went through and did a few optimizations to get it running in real-time and this is the result:

Check out the swf over at wonderfl.net...

Also posted in BitmapData, color, pixel manipulation | Tagged , , | Leave a comment

Perlin Outlines

Actionscript:
  1. [SWF(width = 600, height=600, backgroundColor=0xCCCCCC, frameRate=24)]
  2. var canvas:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight, false, 0x000000);
  3. var blur:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight, false, 0x000000);
  4. addChild(new Bitmap(canvas, "auto", true));
  5.  
  6. var w:int = canvas.width
  7. var hw:int = w / 2;
  8. var size:int = w * w;
  9. var seed:Number = Math.random()*100;
  10. var pnt:Point = new Point();
  11. var dy:Number = 0, dx:Number = 0;
  12. var blr:BlurFilter = new BlurFilter(10,10,1);
  13. addEventListener(Event.ENTER_FRAME, onLoop);
  14. function onLoop(evt:Event):void {
  15.    
  16.     dx += (mouseX - dx) / 4;
  17.     dy += (mouseY - dy) / 4;
  18.     canvas.lock();
  19.     canvas.perlinNoise(hw,hw,2,seed,false, false, 1, true, [new Point(dx, dy), new Point(-dx, -dy)]);
  20.     var pix:Vector.<uint> = canvas.getVector(canvas.rect);
  21.     for (var i:int = 0; i<size; i++){
  22.         var col:uint = 255 - pix[i] <<4 & 0x00FF00;
  23.         pix[i] = col <<8 | col | col>> 8;
  24.     }
  25.     canvas.setVector(canvas.rect, pix);
  26.     blur.copyPixels(canvas, canvas.rect, pnt);
  27.     blur.applyFilter(blur, blur.rect, pnt, blr);
  28.     canvas.draw(blur, null, null, BlendMode.DIFFERENCE);
  29.     canvas.draw(canvas, null, null, BlendMode.INVERT);
  30.     canvas.unlock();
  31. }

This is actually an optimized variation on some recent posts that made use of perlin noise. You can get a wide range of effects by changing just the BlendMode values alone.... I particularly like this combination of BlendModes because it reminds me a bit of a terrain map...

Have a look at the swf...

Also posted in BitmapData, pixel manipulation | Tagged , , | Leave a comment

Wave Trick

Actionscript:
  1. [SWF(width=800, height=600)]
  2. var dupes:int = 5
  3. var pntNum:int = 180;
  4.  
  5. var hh:Number = stage.stageHeight / 2;
  6. var points:Vector.<Number> = new Vector.<Number>();
  7. var vel:Vector.<Number> = new Vector.<Number>();
  8. var cmds:Vector.<int> = new Vector.<int>();
  9. var vectors:Vector.<Shape> = new Vector.<Shape>();
  10.  
  11. for (var i:int = 0; i<dupes; i++){
  12.     vectors[i] = Shape(addChildAt(new Shape(),0));
  13.     vectors[i].x = 10 * i;
  14.     vectors[i].y = -10 * i;
  15. }
  16. var index:int = 0;
  17. for (i = 0; i<pntNum; i++){
  18.     points[index++] = 10 + i * 4;
  19.     points[index++] = hh;
  20.     cmds[i] = 2;
  21.     vel[i] = 0;
  22. }
  23. cmds[0] = 1;
  24. addEventListener(Event.ENTER_FRAME, onLoop);
  25. function onLoop(evt:Event):void {  
  26.    index = 1;
  27.    points[index] += (mouseY - points[index]) / 12;
  28.    for (var i:int = 3; i<points.length; i+=2){
  29.          points[i] += vel[index];
  30.          vel[index] += ((points[i] - points[i - 2]) * -0.16 - vel[index]) / 4;
  31.          index++;
  32.    }
  33.    for (i = 0; i<dupes; i++){
  34.        var c:uint =  255 - 255 / i;
  35.        with (vectors[i].graphics){
  36.            clear();
  37.            lineStyle(0,c <<16 | c <<8 | c);
  38.            drawPath(cmds, points);
  39.        }
  40.    }
  41. }

This snippet uses elasticity to create an interesting wave effect. I first stumbled upon this technique back in my director days...


Have a look at the swf here...

Also posted in Graphics, motion | Tagged , , | Leave a comment

Sphere of Squares

Actionscript:
  1. [SWF(width = 600, height = 600, backgroundColor=0x000000)]
  2. var squareNum:int  = 1000;
  3. var hw:Number = stage.stageWidth / 2;
  4. var hh:Number = stage.stageHeight / 2;
  5. // verts defines a single square
  6. var verts:Vector.<Number> = Vector.<Number>([-20, 0, 0, 20, 0, 0, 20, 0, 40, -20, 0, 40, -20, 0, 0]);
  7. var cmds:Vector.<int> = Vector.<int>([1,2,2,2,2]);
  8. var tempVerts:Vector.<Number> = new Vector.<Number>();
  9. var newVerts:Vector.<Number> = new Vector.<Number>();
  10. var pVerts:Vector.<Number> = new Vector.<Number>(10 * squareNum);
  11. var uv:Vector.<Number> = new Vector.<Number>(15 * squareNum);
  12. var vectors:Shape = new Shape();
  13. var canvas:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,false, 0x000000);
  14. addChild(new Bitmap(canvas));
  15. var blurred:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,false, 0x000000);
  16. var blur:BlurFilter = new BlurFilter(20,20,1);
  17.  
  18. var m:Matrix3D = new Matrix3D();
  19.  
  20. var radius:Number = 200;
  21. // duplicate the verts array a bunch of times
  22. // each time moving the square to a random place on the
  23. // circumference of a sphere
  24. for (var i:int = 0; i<squareNum; i++){
  25.     m.identity();
  26.     var s:Number = Math.random()*.5 + .5;
  27.     m.appendScale(s, s, s);
  28.     m.appendRotation(90,Vector3D.X_AXIS);
  29.     m.appendTranslation(0, 0, radius);
  30.     m.appendRotation(Math.random()*360,Vector3D.X_AXIS);
  31.     m.appendRotation(Math.random()*360,Vector3D.Y_AXIS);
  32.     m.appendRotation(Math.random()*360,Vector3D.Z_AXIS);
  33.     m.transformVectors(verts,tempVerts);
  34.     newVerts = newVerts.concat(tempVerts);
  35.     cmds = cmds.concat(Vector.<int>([1,2,2,2,2]));
  36. }
  37. newVerts.fixed = pVerts.fixed = uv.fixed = true;
  38. var dx:Number = 0, dy:Number = 0;
  39. var pnt:Point = new Point();
  40. addEventListener(Event.ENTER_FRAME, onLoop);
  41. function onLoop(evt:Event):void {
  42.        dx += (mouseX - dx) / 4;
  43.        dy += (mouseY - dy) / 4;
  44.        m.identity();
  45.        m.appendRotation(dx,Vector3D.Z_AXIS);
  46.        m.appendRotation(dy,Vector3D.X_AXIS);
  47.        m.appendTranslation(hw,hh, 0);
  48.        Utils3D.projectVectors(m, newVerts, pVerts, uv);
  49.        with(vectors.graphics){
  50.            clear();
  51.            beginFill(0xFFFFFF);
  52.            drawCircle(hw, hh, radius+10);
  53.            beginFill(0x000000);
  54.            drawPath(cmds, pVerts, GraphicsPathWinding.NON_ZERO);
  55.        }
  56.        canvas.fillRect(canvas.rect, 0x000000);
  57.        canvas.draw(vectors);
  58.        blurred.copyPixels(canvas, canvas.rect, pnt);
  59.        blurred.applyFilter(blurred,blurred.rect, pnt, blur);
  60.        canvas.draw(blurred, null, null, BlendMode.SCREEN);
  61. }

This snippet is similar to yesterdays post but the visual result is rather different. This one does a little more Matrix3D stuff resulting in a sphere made up entirely of squares. This is obscured by the size of the squares and the fact that they overlap and cut each other up. BitmapData a BlurFilter and a BlendMode give the entire thing a slight glow...


Have a look at the swf here...

Also posted in 3D, BitmapData | Tagged , , , | 12 Comments

transformVectors() and drawPath()

Actionscript:
  1. var squareNum:int  = 100;
  2. // verts defines a single square
  3. var verts:Vector.<Number> = Vector.<Number>([-20, 0, 0, 20, 0, 0, 20, 0, 40, -20, 0, 40, -20, 0, 0]);
  4. var cmds:Vector.<int> = Vector.<int>([1,2,2,2,2]);
  5. var tempVerts:Vector.<Number> = new Vector.<Number>();
  6. var newVerts:Vector.<Number> = new Vector.<Number>();
  7. var pVerts:Vector.<Number> = new Vector.<Number>(10 * squareNum);
  8. var uv:Vector.<Number> = new Vector.<Number>(15 * squareNum);
  9.  
  10. var m:Matrix3D = new Matrix3D();
  11.  
  12. // duplicate the verts array a bunch of times
  13. // each time randomly rotating, scaling and translating it
  14. for (var i:int = 0; i<squareNum; i++){
  15.     m.identity();
  16.     m.appendRotation(Math.random()*360,Vector3D.X_AXIS);
  17.     m.appendRotation(Math.random()*360,Vector3D.Y_AXIS);
  18.     m.appendRotation(Math.random()*360,Vector3D.Z_AXIS);
  19.     var s:Number = Math.random()*2 + .1;
  20.     m.appendScale(s, s, s);
  21.     m.appendTranslation(Math.random()*400 - 200, Math.random()*400 - 200, Math.random()*400 - 200);
  22.     m.transformVectors(verts,tempVerts);
  23.     newVerts = newVerts.concat(tempVerts);
  24.     cmds = cmds.concat(Vector.<int>([1,2,2,2,2]));
  25. }
  26. newVerts.fixed = pVerts.fixed = uv.fixed = true;
  27.  
  28. var dx:Number = 0, dy:Number = 0;
  29. addEventListener(Event.ENTER_FRAME, onLoop);
  30. function onLoop(evt:Event):void {
  31.        dx += (mouseX - dx) / 4;
  32.        dy += (mouseY - dy) / 4;
  33.        
  34.        m.identity();
  35.        m.appendRotation(dx,Vector3D.Z_AXIS);
  36.        m.appendRotation(dy,Vector3D.X_AXIS);
  37.        m.appendTranslation(stage.stageWidth / 2,stage.stageHeight / 2, 0);
  38.  
  39.        Utils3D.projectVectors(m, newVerts, pVerts, uv);
  40.        
  41.        graphics.clear();
  42.        graphics.lineStyle(0,0x000000);
  43.        graphics.drawPath(cmds, pVerts);
  44. }

This is a demo showing how to use transformVectors() and drawPath() together. It creates 100 wireframe squares in 3D:


Have a look at the swf...

Also posted in 3D, Graphics | 2 Comments

setVector vs copyPixels

Actionscript:
  1. var brushNum:int = 10000;
  2. var canvas:BitmapData = new BitmapData(800,600,false, 0x000000);
  3. addChild(new Bitmap(canvas));
  4.  
  5. var shape:Shape = new Shape();
  6. with(shape.graphics) beginFill(0xFF0000), drawCircle(10,10,5);
  7. shape.filters = [new BlurFilter(6, 6, 4)];
  8.  
  9. var brush:BitmapData = new BitmapData(20, 20, false, 0x000000);
  10. brush.draw(shape, shape.transform.matrix);
  11.  
  12.  
  13.  
  14. // make sure brushVect is fixed length
  15. var brushVect:Vector.<uint> = new Vector.<uint>(brush.width * brush.height, true);
  16. var tempVect:Vector.<uint> =  brush.getVector(brush.rect);
  17. var i:int = 0;
  18. // quick hack to retain fixed length
  19. for (i = 0; i<brushVect.length; i++){
  20.     brushVect[i] = tempVect[i];
  21. }
  22.  
  23. canvas.setVector(brush.rect, brushVect);
  24.  
  25. var pnt:Point = new Point();
  26. var brushRect:Rectangle = brush.rect;
  27. var destRect:Rectangle = brushRect.clone();
  28. var locX:Vector.<Number> = new Vector.<Number>(brushNum, true);
  29. var locY:Vector.<Number> = new Vector.<Number>(brushNum, true);
  30. for (i= 0; i<brushNum; i++){
  31.     locX[i] = Math.random() * stage.stageWidth - 10;
  32.     locY[i] = Math.random() * stage.stageHeight - 10;
  33. }
  34.  
  35. var iterations:int = 50;
  36. var timer:Number;
  37. var avg:Vector.<Number> = new Vector.<Number>();
  38. trace("copyPixels");
  39. addEventListener(Event.ENTER_FRAME, onLoop);
  40. function onLoop(evt:Event):void {
  41.        canvas.fillRect(canvas.rect, 0x000000);
  42.        var i:int = brushNum;
  43.        if (drawMode == "copyPixels"){
  44.            timer = getTimer();
  45.            canvas.lock();
  46.            while(--i> -1){
  47.                 pnt.x = locX[i];
  48.                 pnt.y = locY[i];
  49.                 // copyPixels can easily do alpha manipulation, setVector cannot (see comment below);
  50.                 canvas.copyPixels(brush, brushRect, pnt);//, null, null, true);
  51.            }
  52.            canvas.unlock();
  53.            avg.push(getTimer() - timer);
  54.        }else{
  55.            timer = getTimer();
  56.            canvas.lock();
  57.            while(--i> -1){
  58.                destRect.x = locX[i];
  59.                destRect.y = locY[i];
  60.                canvas.setVector(destRect, brushVect);
  61.            }
  62.            canvas.unlock();
  63.            avg.push(getTimer() - timer);
  64.        }
  65.        // take an average of iterations iterations
  66.        if (avg.length == iterations){
  67.            var average:Number = 0;
  68.            for (i = 0; i<iterations; i++){
  69.                  average += avg[i];
  70.            }
  71.            trace(average / iterations);
  72.            avg = new Vector.<Number>();
  73.        }
  74. }
  75.  
  76. var drawMode:String = "copyPixels";
  77. stage.addEventListener(KeyboardEvent.KEY_UP, onKeyReleased);
  78. function onKeyReleased(evt:Event):void{
  79.     avg = new Vector.<Number>();
  80.     drawMode = (drawMode == "copyPixels") ? "setVector" : "copyPixels"
  81.     trace(drawMode);
  82. }

In the comments of a post from a few days back, Piergiorgio Niero mentioned that setVector may be faster than copyPixels. To see if this was true, Piergiorgio and I each tried a few things and while Piergiorgio seemed to reach some conclusions... I wasn't sure we had properly tested to see which one was actually faster.

I created the above snippet to help test to see which is indeed faster. This snippet draws 10,000 small 20x20 pixel graphics to the stage. There is no animation because I wanted to try and isolate the speed of the setVector and copyPixels calls. These are the results on my macbook pro 2.4 ghz duo:

// average speed of 50 iterations of drawing
copyPixels
15.1
15.68
15.44
15.46
15.62
15.74
15.68
setVector
32.6
32.6
31.1
32.1
32.82
32.54
copyPixels
15.48
15.62
15.74
15.46
15.42
15.44
15.64
setVector
32.62
32.8
33.08
32.48
32.74
32.32

If you interested in this, post your results in the comments along with the type of computer you're using. I have a feeling there will be a wide variety of results... just make sure you're not using the flash debug player, as that can act significantly different than the release version of the player.

setVector() and copyPixels() Usage

Something to note here is that setVector and copyPixels aren't normally suitable for the same thing. copyPixels is used to move a rectangle of pixels from one BitmapData to another - you can easily do advanced alpha channel manipulation and scaling with it and you don't have to do pixel by pixel logic. setVector is used to do pixel by pixel manipulation - it is a sort of mature/advanced setPixel function that allows you to do logic on a Vector of uints and then set the pixels of a rectangular region of a BitmapData object equal to the data within that Vector. So if you need to do alpha manipulation or image scaling with setVector you'll find yourself running into some more advanced programming than copyPixels requires... and if you tried to do pixel by pixel manipulation with copyPixels... well, that just isn't what it was meant to be used for...

I'm always wary of these kind of speed tests... if anyone has suggestions about how to improve this test, please feel free to comment.

UPDATE katopz pointed out I should use fixed length Vectors... so I changed the brushVect instantiation code slightly. I didn't do it for the avg vector because it only has 50 values and it doesn't help improve the speed of setVector and copyPixels in any way and complicates the code slightly... it's hard to decide which optimization techniques you should choose to make habbit and which ones you should only whip out when you need speed...

Also posted in BitmapData | 7 Comments

Cut Image into Squares (copyPixels)

Actionscript:
  1. [SWF(width=650, height=650)]
  2. var loader:Loader = new Loader();
  3. loader.load(new URLRequest("http://actionsnippet.com/wp-content/chair.jpg"));
  4. loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaded);
  5.  
  6. var w:Number;
  7. var h:Number;
  8. var rows:Number = 20;
  9. var cols:Number = 20;
  10. var tiles:Vector.<BitmapData> = new Vector.<BitmapData>();
  11. var locX:Vector.<Number> = new Vector.<Number>();
  12. var locY:Vector.<Number> = new Vector.<Number>();
  13. var rX:Vector.<Number> = new Vector.<Number>();
  14. var rY:Vector.<Number> = new Vector.<Number>();
  15. var sX:Vector.<Number> = new Vector.<Number>();
  16. var sY:Vector.<Number> = new Vector.<Number>();
  17. function onLoaded(evt:Event):void{
  18.     w = evt.target.width;
  19.     h = evt.target.height;
  20.     var image:BitmapData = Bitmap(evt.target.content).bitmapData;
  21.     var tileWidth:Number = w / cols;
  22.     var tileHeight:Number = h / rows;
  23.     var inc:int = 0;
  24.     var pnt:Point = new Point();
  25.     var rect:Rectangle = new Rectangle(0,0,tileWidth,tileHeight);
  26.     for (var i:int = 0; i<rows; i++){
  27.         for (var j:int = 0; j<cols; j ++){
  28.              var currTile:BitmapData= new BitmapData(tileWidth, tileHeight, true, 0x00000000);
  29.              rect.x = j * tileWidth;
  30.              rect.y = i * tileHeight;
  31.              currTile.copyPixels(image, rect, pnt, null, null, true);
  32.              tiles[inc] = currTile;
  33.              rect.x += 25;
  34.              rect.y += 25;
  35.              sX[inc] = rect.x;
  36.              sY[inc] = rect.y;
  37.              locX[inc] = rX[inc] = -rect.width * 2
  38.              locY[inc] = rY[inc] =  Math.random() * stage.stageHeight;
  39.              setTimeout(startAnimation, inc *4 + 100, inc, rect.x, rect.y);
  40.              inc++;
  41.         }
  42.     }
  43. }
  44.  
  45. function startAnimation(index:int, dx:Number, dy:Number):void{
  46.     var interval:Number;
  47.     var animate:Function = function(index:int):void{
  48.         locX[index] += (dx - locX[index]) / 4;
  49.         locY[index] += (dy - locY[index]) / 4;
  50.         if (Math.abs(locX[index] - dx) <1 && Math.abs(locY[index] - dy)<1){
  51.             locX[index] = dx;
  52.             locY[index] = dy;
  53.             clearInterval(interval);
  54.         }
  55.     }
  56.    interval = setInterval(animate, 32, index);
  57. }
  58.  
  59. var canvas:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,false, 0xFFFFFF);
  60. addChild(new Bitmap(canvas));
  61.  
  62. var loc:Point = new Point();
  63. addEventListener(Event.ENTER_FRAME, onLoop);
  64. function onLoop(evt:Event):void {
  65.       canvas.fillRect(canvas.rect, 0xFFFFFF);
  66.       for (var i:int = 0; i<tiles.length; i++){
  67.             var tile:BitmapData= tiles[i];
  68.             loc.x = locX[i];
  69.             loc.y = locY[i];
  70.             canvas.copyPixels(tile, tile.rect, loc, null, null, true);
  71.       }
  72. }

This snippet cuts a dynamically loaded image into a series of smaller BitmapData instances. These BitmapData instances are then drawn to a canvas BitmapData using copyPixels. The BitmapData.copyPixels() method is extremely fast - so this has some advantages over yesterdays post (which did basically the same thing with Sprites). I used setInterval and setTimeout to do a simple demo animation, but I recommend using TweenLite on a real project.

Also posted in BitmapData | Tagged , , | 10 Comments