# Monthly Archives: July 2009

## 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...

Posted in 3D, BitmapData, Vector | 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...

Posted in 3D, Graphics, Vector | 2 Comments

## Recursive 2D Structure

Actionscript:
1. [SWF(width = 600, height = 700, frameRate=24)]
2. var canvas:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,false, 0xFFFFFF);
3. addChild(new Bitmap(canvas));
4.
5. var maxBranches:int = 600;
6. var branches:int = 0;
7. var startX:Number = 300
8. makeBranch(startX,690,30,-60, 60);
9.
10. function makeBranch(xp:Number, yp:Number, step:Number, min:Number, max:Number):void {
11.     var vectors:Shape = Shape(addChild(new Shape()));
12.     var cX:Number, cY:Number, eX:Number, eY:Number
13.     var dcX:Number=xp, dcY:Number=yp, deX:Number=xp, deY:Number=yp;
14.     var theta:Number = (min + Math.random()*(max-min) - 90) * Math.PI / 180;
15.     cX = xp + step * Math.cos(theta);
16.     cY = yp + step * Math.sin(theta);
17.     theta = (min + Math.random()*(max-min)-90) * Math.PI / 180;
18.     eX = cX + step * Math.cos(theta);
19.     eY = cY + step * Math.sin(theta);
20.     var run:Function = function():void{
21.          dcX +=  (cX - dcX) / 2;
22.          dcY +=  (cY - dcY) / 2;
23.          deX +=  (eX - deX) / 8;
24.          deY +=  (eY - deY) / 8;
25.          with(vectors.graphics){
26.               clear();
27.               beginFill(0xFFFFFF,0.8);
28.               lineStyle(0,0x000000,0.8);
29.               moveTo(startX, yp);
30.               lineTo(xp, yp);
31.               curveTo(dcX, dcY, deX, deY);
32.               lineTo(startX, deY);
33.          }
34.          if (Math.abs(dcX - cX) <1 && Math.abs(deX - eX) <1 && Math.abs(dcY - cY) <1 && Math.abs(deY - eY) <1){
35.              canvas.draw(vectors);
36.              removeChild(vectors);
37.              if (branches <maxBranches){
38.                  setTimeout(makeBranch, 10, deX, deY, step - Math.random(), -90, 90);
39.                  branches++;
40.                  if (int(Math.random()*2) == 1){
41.                     setTimeout(makeBranch, 10, deX, deY, step - Math.random()*3, -90, 90);
42.                     branches++;
43.                  }
44.              }
45.          }else{
46.              setTimeout(arguments.callee,  1000 / 24);
47.          }
48.     }();
49. }

This snippet uses a technique similar to what you might use to create a recursive tree. A bit of additional logic is added for bezier branches, filled shapes and animation.

WARNING: may run slow on older machines

Have a look at the swf...

Posted in BitmapData, bezier, functions, misc, motion | Tagged , , | 7 Comments

## Smudge Tool #1

Actionscript:
1. [SWF(backgroundColor = 0xCCCCCC)]
2. var canvas:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,true, 0xFFFFFFFF);
3. addChild(new Bitmap(canvas));
4.
5. var loader:Loader = new Loader();
6. loader.load(new URLRequest("http://actionsnippet.com/wp-content/chair.jpg"));
7. loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
8. function onComplete(evt:Event):void{
9.     canvas.draw(loader);
10. }
11.
12. var brush:Shape = new Shape();
13. var diameter:Number = 120;
14. var radius:Number = diameter / 2;
15. var matrix:Matrix = new Matrix();
16.
17. var brushAlpha:BitmapData = new BitmapData(diameter, diameter, true, 0x00000000);
18. drawRadial();
19. brushAlpha.draw(brush);
20.
21. var xp:Number = 0, yp:Number = 0, px:Number = 0, py:Number = 0;
22. var dx:Number, dy:Number;
23.
24. stage.addEventListener(MouseEvent.MOUSE_MOVE, onLoop);
25. function onLoop(evt:Event):void {
26.     xp = mouseX - radius;
27.     yp = mouseY - radius;
28.     dx = xp - px;
29.     dy = yp - py;
30.     canvas.copyPixels(canvas,
31.                     new Rectangle(px, py, diameter, diameter),
32.                     new Point(xp, yp), brushAlpha, new Point(0,0), true);
33.     px = xp;
34.     py = yp
35. }
36.
37. function drawRadial():void{
38.     matrix.createGradientBox(diameter, diameter, 0, 0, 0);
39.     with (brush.graphics){
40.         beginGradientFill(GradientType.RADIAL, [0xFFFFFF, 0xFFFFFF], [1,0], [0, 255], matrix, SpreadMethod.PAD);
41.         drawCircle(radius, radius, radius);
42.     }
43. }

This is a quick snippet I wrote while thinking about how to create a smudge tool using BitmapData... it isn't perfect, but it's a good first step. It still needs some linear interpolation and I may need to do some pixel pushing to prevent a strange alpha anomaly that causes the brush to get darker than expected....

Here is the swf...

Posted in BitmapData | Tagged , , | 1 Comment

• ActionSnippet is on Twitter