Category Archives: BitmapData

drawTriangles() 2D Textured Plane

Actionscript:
  1. [SWF(width = 700, height = 700)]
  2.  
  3. var loader:Loader = new Loader();
  4. loader.load(new URLRequest("http://actionsnippet.com/wp-content/chair.jpg"));
  5. loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaded);
  6. var tex:BitmapData;
  7. function onLoaded(evt:Event):void{
  8.     tex = Bitmap(loader.content).bitmapData;
  9.     addEventListener(Event.ENTER_FRAME, onLoop);
  10. }
  11.  
  12. var plane:Shape = Shape(addChild(new Shape()));
  13. plane.x = plane.y = 50;
  14.  
  15. var verts:Vector.<Number> = new Vector.<Number>();
  16. var uvs:Vector.<Number> = new Vector.<Number>();
  17. var indices:Vector.<int> = new Vector.<int>();
  18. var rows:int = 30;
  19. var size:Number = rows + 1;
  20. var vertNum:Number = size * size;
  21. var polySize:Number = 20;
  22. var vIndex:int = 0;
  23. var uvIndex:int = 0;
  24. var gridSize:Number = rows * polySize;
  25. for (var i:Number = 0; i<vertNum; i++){
  26.     var xp:Number = i % size * polySize;
  27.     var yp:Number =  int(i / size) * polySize;
  28.     verts[vIndex++] = xp
  29.     verts[vIndex++] = yp;
  30.     uvs[uvIndex++] = xp / gridSize;
  31.     uvs[uvIndex++] = yp / gridSize;
  32.     if (i % size != rows){
  33.           indices.push(i, i+1, i+size, i+size, i+size+1, i+1);
  34.     }
  35. }
  36.  
  37. // render and show that the verts can be changed around
  38. function onLoop(evt:Event):void {
  39.     // shake the verts
  40.     for (var i:int = 0; i<verts.length; i++){
  41.         verts[i] += Math.random() - 0.5;
  42.     }
  43.     with(plane.graphics){
  44.         clear();
  45.         beginBitmapFill(tex,null, false, true);
  46.         drawTriangles(verts, indices,uvs);
  47.     }
  48. }

This snippet is shows how to draw a textured 2D plane using drawTriangles(). This is similar to the wireframe 2D plane post from yesterday... the main difference is that you need to calculate UV coordinates if you want to use a bitmap fill with drawTriangles().

Here is a still of this snippet:

Also posted in Graphics, Vector | Tagged , , | 2 Comments

drawTriangles() Terrain

Actionscript:
  1. [SWF(width=500,height=500,backgroundColor=0x333333, frameRate=40)]
  2. var terrain:Shape = Shape(addChild(new Shape()));
  3. terrain.x = terrain.y = 250;
  4. var rows:int = 60;
  5. var size:int = rows + 1;
  6. var vertNum:int = size * size;
  7. var polySize:Number = 5;
  8. var gridWidth:Number = polySize * rows;
  9. var halfWidth:Number = gridWidth / 2;
  10. var verts:Vector.<Number> = new Vector.<Number>();
  11. var pVerts:Vector.<Number> = new Vector.<Number>();
  12. var indices:Vector.<int> = new Vector.<int>();
  13. var uvs:Vector.<Number> = new Vector.<Number>();
  14. var uvts:Vector.<Number> = new Vector.<Number>();
  15. var tex:BitmapData = new BitmapData(gridWidth, gridWidth, false, 0x000000);
  16. var pix:int = gridWidth * gridWidth;
  17. var perlin:BitmapData = new BitmapData(gridWidth, gridWidth, false, 0x000000);
  18. // generate the texture and the terrain
  19. function generate():void{
  20.     tex.fillRect(tex.rect, 0x000000);
  21.     var i:Number, xp:Number, yp:Number;
  22.     for (i = 0; i<pix; i++){
  23.         xp = i % gridWidth;
  24.         yp= int(i / gridWidth);
  25.         var dx:Number = xp - gridWidth / 2;
  26.         var dy:Number = yp - gridWidth / 2;
  27.         var d:Number = 255 - Math.sqrt(dx * dx + dy * dy) / halfWidth* 255;
  28.         if (d <0) d = 0;
  29.         if (d> 255) d = 255;
  30.         var c:uint = uint(d);
  31.         tex.setPixel(xp, yp, c <<16 | c <<8 | c);
  32.     }
  33.     perlin.perlinNoise(100,100,3,Math.random()*100,false,false,7,true);
  34.     perlin.draw(perlin, null, null, BlendMode.SCREEN);
  35.     tex.draw(perlin, null, null, BlendMode.MULTIPLY);
  36.     // calculate verts, uvs and indices
  37.     var vIndex:int = 0;
  38.     var uvIndex:int = 0;
  39.     indices = new Vector.<int>();
  40.     for (i = 0; i<vertNum; i++){
  41.         var xMod:Number = i % size;
  42.         xp = xMod * polySize;
  43.         yp = int(i / size) * polySize;
  44.         verts[vIndex++] = xp - halfWidth;
  45.         verts[vIndex++] = yp - halfWidth;
  46.         verts[vIndex++] = tex.getPixel(xp, yp) & 0xFF;
  47.         uvs[uvIndex++] = xp /  gridWidth;
  48.         uvs[uvIndex++] = yp / gridWidth;
  49.         if (xMod != rows){
  50.               indices.push(i, i+1, i+size, i+1, i+size+1, i+size);
  51.         }
  52.     }
  53. }
  54. generate();
  55. stage.addEventListener(MouseEvent.MOUSE_DOWN, onGenerate);
  56. function onGenerate(evt:MouseEvent):void{ generate() };
  57. var m:Matrix3D = new Matrix3D();
  58. var rot:Number = 0;
  59. addEventListener(Event.ENTER_FRAME, onLoop);
  60. function onLoop(evt:Event):void {
  61.         m.identity();
  62.         var destRot:Number = mouseX / stage.stageWidth * 90;
  63.         if (destRot <0) destRot = 0;
  64.         if (destRot> 90) destRot = 90;
  65.         rot += (destRot - rot) * 0.2;
  66.         m.appendRotation(rot,Vector3D.Z_AXIS);
  67.         m.appendRotation(60,Vector3D.X_AXIS);
  68.         Utils3D.projectVectors(m, verts, pVerts, uvts);
  69.         with(terrain.graphics){
  70.             clear();
  71.             beginBitmapFill(tex, null, false, true);
  72.             drawTriangles(pVerts, indices, uvs, TriangleCulling.NEGATIVE);
  73.         }
  74. }

This snippet draws a pretty simple isometric terrain using fp10 graphics stuff and perlin noise.


Have a look at the swf here...

Also posted in Graphics, Vector, pixel manipulation, setPixel | Tagged , , | 4 Comments

Utils3D.projectVectors() Lathe

Actionscript:
  1. [SWF(width = 500, height = 500, backgroundColor = 0x000000)]
  2. var halfWidth:Number = stage.stageWidth / 2;
  3. var halfHeight:Number = stage.stageHeight / 2;
  4. var loc:Vector.<Number>;
  5.  
  6. graphics.lineStyle(0, 0xFF0000);
  7. graphics.moveTo(halfWidth, 0);
  8. graphics.lineTo(halfWidth, stage.stageHeight);
  9. graphics.moveTo(0, halfHeight);
  10. graphics.lineTo(stage.stageWidth, halfHeight);
  11.  
  12. var line:Shape = Shape(addChild(new Shape()));
  13. line.x = halfWidth;
  14.  
  15. var idle:Function = function(){};
  16. var currentMode:Function = idle;
  17. stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
  18. stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
  19. addEventListener(Event.ENTER_FRAME, onLoop);
  20. function onDown(evt:MouseEvent):void{
  21.     if (contains(frame)){
  22.         removeChild(frame);
  23.         currentMode = idle;
  24.         line.graphics.clear();
  25.         return;
  26.     }
  27.     loc = new Vector.<Number>();
  28.     line.graphics.lineStyle(0,0xFFFFFF);
  29.     line.x = halfWidth
  30.     line.y = halfHeight;
  31.     line.graphics.moveTo(line.mouseX, line.mouseY);
  32.     currentMode = captureLocs;
  33.     canvas.fillRect(canvas.rect, 0x000000);
  34. }
  35. function onUp(evt:MouseEvent):void{
  36.     if (currentMode == idle) return;
  37.     setupLathe();
  38.     currentMode = showLathe;
  39. }
  40.  
  41. function onLoop(evt:Event):void{
  42.     currentMode();
  43. }
  44. function captureLocs():void{
  45.     loc.push(line.mouseX);
  46.     loc.push(line.mouseY);
  47.     loc.push(0);
  48.     line.graphics.lineTo(line.mouseX, line.mouseY);
  49. }
  50. /**
  51.  -- Lathe Stuff:
  52. */
  53. var canvas:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight,false, 0x000000);
  54. var frame:Bitmap = new Bitmap(canvas);
  55. var dx:Number=0;
  56. var dy:Number=0;
  57.  var matrix:Matrix3D = new Matrix3D();
  58. var pVerts:Vector.<Number>;
  59. var uvts:Vector.<Number>;
  60. function setupLathe():void{
  61.     addChild(frame);
  62.     pVerts =  new Vector.<Number>();
  63.     uvts = new Vector.<Number>();
  64.     var nVerts:Vector.<Number> = new Vector.<Number>();
  65.     var tVerts:Vector.<Number> = new Vector.<Number>();
  66.     matrix.identity();
  67.     var step:Number = 2;
  68.     for (var i:int = 0; i <360; i+=step){
  69.         matrix.appendRotation(step,Vector3D.Y_AXIS);
  70.         matrix.transformVectors(loc, tVerts);
  71.         nVerts = nVerts.concat(tVerts);
  72.     }
  73.     loc = nVerts.concat();
  74. }
  75. function showLathe():void{
  76.     dx += (mouseX - dx)/4;
  77.     dy += (mouseY - dy)/4;
  78.     matrix.identity();
  79.     matrix.appendRotation(dy,Vector3D.X_AXIS);
  80.     matrix.appendRotation(dx,Vector3D.Y_AXIS);
  81.     matrix.appendTranslation(halfWidth, halfHeight, 0);
  82.     Utils3D.projectVectors(matrix, loc, pVerts, uvts);
  83.     canvas.lock();
  84.     canvas.fillRect(canvas.rect, 0x000000);
  85.     var leng:int = pVerts.length;
  86.     for (var i:int = 0; i<leng; i+=2){
  87.         canvas.setPixel( pVerts[i], pVerts[i + 1], 0xFFFFFF);
  88.     }
  89.     canvas.unlock();
  90. }

This snippet allows you to create 3D lathe shapes by drawing a 2D line. This is done using Utils3D.projectVectors() and Matrix.transformVectors().

Have a look at the swf here...

Also posted in 3D, Math, Vector, graphics algorithms, matrix, setPixel | Tagged , , | 3 Comments

Better BitmapData Brush

Actionscript:
  1. var canvas:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,false, 0xCCCCCC);
  2. addChild(new Bitmap(canvas));
  3. var prevX:Number;
  4. var prevY:Number;
  5. var brush:Shape = new Shape();
  6.  
  7. stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
  8. stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
  9. function onDown(evt:MouseEvent):void{
  10.     prevX = mouseX;
  11.     prevY = mouseY;
  12.     addEventListener(Event.ENTER_FRAME, onLoop);
  13. }
  14.  
  15. function onUp(evt:MouseEvent):void{
  16.     removeEventListener(Event.ENTER_FRAME, onLoop);
  17. }
  18.  
  19. function onLoop(evt:Event):void {
  20.       brush.x = mouseX;
  21.       brush.y = mouseY;
  22.       with (brush.graphics){
  23.           clear();
  24.           lineStyle(3, 0x000000);
  25.           lineTo(prevX-mouseX, prevY-mouseY);
  26.       }
  27.       canvas.draw(brush, brush.transform.matrix);
  28.       prevX = mouseX;
  29.       prevY = mouseY;
  30. }

If you write a drawing program with the Graphics class alone, you'll notice that eventually the flash player will start to slow down. This could take quite some time, but it will eventually happen. Because the Graphics class is entirely vector based, the flash player needs to keep track of every single point that makes up any line in your drawing. If you draw something and then erase it by drawing white vector lines over it, flash still needs to know about that thing that you erased.

The snippet I wrote yesterday reminded me of the technique used in the above snippet. In yesterdays post every line is drawn using the graphics class. As a result, eventually the flash player begins to choke.

Today's snippet draws a vector between the previous mouse location and the current mouse location - this vector is then drawn onto a BitmapData object and the vector is cleared. So rather than creating vector graphics that are continuously increasing in complexity, your just changing the color of pixels around on a BitmapData.

To see a visual explanation take a look at the below swf. I slowed it down to 5fps, I tinted the vector red and scaled up the stage so you can differentiate between what's vector and what's bitmap:


Click to see the swf...

Also posted in Graphics | Tagged , , | 1 Comment