Basic bitmap distortion using triangles and UVs (source)

This little class is sort of an offshoot of something I did for a professional project I'm working on.
Since it's completely bare-bones and targets the essentials (it's only 2 triangles and a texture) I think it's very useful for understanding the basics, that's why I decided to make it available.
I'm well aware that there are pretty robust and comprehensive solutions out there dealing with bitmap distortion - not to mention that with Flash 10 this issue is going to be completely trivialized - but the point here is simplicity.

Try dragging the corner handles around a little:

In this particular case the class was instantiated like this:

addChild (new BitmapDistorter (80,100, 420,100, 80,400, 420,400, new MyBitmapData(MyBitmapData.width,MyBitmapData.height)));

...where MyBitmapData is a bitmap I have in the Library.

The main class itself is as follows:

 
// BitmapDistorter (C) edvardtoth.com
 
package
{
	import flash.events.*;
	import flash.display.Sprite;
	import flash.display.BitmapData;
	import flash.display.Bitmap;
	import flash.geom.Point;
	import flash.geom.Matrix;
 
	public class BitmapDistorter extends Sprite
	{
		private var topLeftX:Number;
		private var topLeftY:Number;
		private var topRightX:Number;
		private var topRightY:Number;
		private var bottomLeftX:Number;
		private var bottomLeftY:Number;
		private var bottomRightX:Number;
		private var bottomRightY:Number;
 
		private var topLeftHandle:Handle;
		private var topRightHandle:Handle;
		private var bottomLeftHandle:Handle;
		private var bottomRightHandle:Handle;
 
		private var topLeft:Point;
		private var topRight:Point;
		private var bottomLeft:Point;
		private var bottomRight:Point;
 
		private var myBitmapData:BitmapData;
 
		private var matrix:Matrix = new Matrix();
 
		private var vtx01:Array;
		private var vtx02:Array;
		private var vtx03:Array;
		private var vtx04:Array;
 
		public function BitmapDistorter(inTopLeftX:Number, inTopLeftY:Number, inTopRightX:Number, inTopRightY:Number, inBottomLeftX:Number, inBottomLeftY:Number, inBottomRightX:Number,inBottomRightY:Number,inBitmapData:BitmapData)
		{
			myBitmapData = inBitmapData;
 
			topLeftX 	= inTopLeftX;
			topLeftY 	= inTopLeftY;
			topRightX 	= inTopRightX;
			topRightY 	= inTopRightY;
			bottomLeftX 	= inBottomLeftX;
			bottomLeftY 	= inBottomLeftY;
			bottomRightX 	= inBottomRightX;
			bottomRightY 	= inBottomRightY;
 
			topLeft 	= new Point (topLeftX, topRightY);
			topRight	= new Point (topRightX, topRightY);
			bottomLeft	= new Point (bottomLeftX, bottomLeftY);
			bottomRight = new Point (bottomRightX, bottomRightY);
 
			topLeftHandle = new Handle (topLeft.x, topLeft.y);
			topRightHandle = new Handle (topRight.x, topRight.y);
			bottomLeftHandle = new Handle (bottomLeft.x, bottomLeft.y);
			bottomRightHandle = new Handle (bottomRight.x, bottomRight.y);
 
			addChild (topLeftHandle);
			addChild (topRightHandle);
			addChild (bottomLeftHandle);
			addChild (bottomRightHandle);
 
			// vertices
			vtx01 = new Array (topLeft, 	new Point (0					,0));
			vtx02 = new Array (topRight, 	new Point (myBitmapData.width	,0));
			vtx03 = new Array (bottomLeft,	new Point (0					,myBitmapData.height));
			vtx04 = new Array (bottomRight,	new Point (myBitmapData.width	,myBitmapData.height));
 
			addEventListener (Event.ENTER_FRAME, updateFrame);
		}
 
		function updateFrame (event:Event):void
		{
			this.graphics.clear ();
 
			topLeft.x = topLeftHandle.x;
			topLeft.y = topLeftHandle.y;
 
			topRight.x = topRightHandle.x;
			topRight.y = topRightHandle.y;
 
			bottomLeft.x = bottomLeftHandle.x;
			bottomLeft.y = bottomLeftHandle.y;
 
			bottomRight.x = bottomRightHandle.x;
			bottomRight.y = bottomRightHandle.y;
 
			drawTriangle (vtx01, vtx02, vtx03);
			drawTriangle (vtx02, vtx04, vtx03);
		}
 
		function drawTriangle( p0In:Array, p1In:Array, p2In:Array ):void
		{
			var points:Array = calcUVs(p0In, p1In, p2In);
			var p0:Point = points[0];
			var p1:Point = points[1];
			var p2:Point = points[2];
 
			this.graphics.beginBitmapFill(myBitmapData, matrix);
 
			this.graphics.moveTo(p0.x, p0.y);
			this.graphics.lineTo(p1.x, p1.y);
			this.graphics.lineTo(p2.x, p2.y);
 
			this.graphics.endFill();
		}
 
		function calcUVs( p0In:Array, p1In:Array, p2In:Array):Array
		{
			var p0:Point = p0In[0];
			var uv0:Point = p0In[1];
			var p1:Point = p1In[0];
			var uv1:Point = p1In[1];
			var p2:Point = p2In[0];
			var uv2:Point = p2In[1];
 
			var du1:Number = uv1.x - uv0.x;
			var dv1:Number = uv1.y - uv0.y;
			var du2:Number = uv2.x - uv0.x;
			var dv2:Number = uv2.y - uv0.y;
			var dx1:Number = p1.x - p0.x;
			var dy1:Number = p1.y - p0.y;
			var dx2:Number = p2.x - p0.x;
			var dy2:Number = p2.y - p0.y;
			var det:Number = 1.0 / ((du1 * dv2) - (du2 * dv1));
			matrix.a = (( dv2 * dx1) + (-dv1 * dx2)) * det;
			matrix.b = (( dv2 * dy1) + (-dv1 * dy2)) * det;
			matrix.c = ((-du2 * dx1) + ( du1 * dx2)) * det;
			matrix.d = ((-du2 * dy1) + ( du1 * dy2)) * det;
			matrix.tx = p0.x - ( (uv0.x * matrix.a) + (uv0.y * matrix.c) );
			matrix.ty = p0.y - ( (uv0.x * matrix.b) + (uv0.y * matrix.d) );
 
			return(new Array( p0, p1, p2 ) );
		}
	}
}
 

And for the sake of completeness the ridiculously simple Handle class (which generates the draggable handle-sprites) is this:

 
package
{
	import flash.display.Sprite;
	import flash.events.*;
 
	public class Handle extends Sprite
	{
		public function Handle (inX:Number, inY:Number)
		{
			this.x = inX;
			this.y = inY;
 
			this.graphics.lineStyle (3, 0x572025, 1, false, "normal");
			this.graphics.beginFill (0xEBE27D, 1);
			this.graphics.drawCircle (0, 0, 10);
			this.graphics.endFill();
 
			addEventListener (MouseEvent.MOUSE_DOWN, onDown);
			addEventListener (MouseEvent.MOUSE_UP, onUp);
		}
 
		private function onDown (event:MouseEvent):void
		{
			this.startDrag();
		}
		private function onUp (event:MouseEvent):void
		{
			this.stopDrag();
		}
	}
}
 
  • Digg
  • Technorati
  • del.icio.us
  • StumbleUpon
  • LinkedIn
  • Facebook
  • TwitThis
  • Reddit
  • Google
  • YahooMyWeb
  • Slashdot
  • Propeller
  • blogmarks
  • blinkbits
  • BlinkList
  • Furl
  • Ma.gnolia
  • NewsVine
  • Fark
  • Netvouz
  • MisterWong
  • Live
  • description
  • TailRank
  • Simpy

0 comments

There are no comments yet...Kick things off by filling out the form below.

Leave a Comment