/**
* @author Pierre Lepers
* @author De'Angelo Richardson
* @author John Grden
* 
* NOTES:
* 	Special thanks to Blackpawn for this post:
*   http://www.blackpawn.com/texts/pointinpoly/default.html
* 
* 	And Pierre Lepers / Away3D for providing the foundational UVatPoint and getCoordAtPoint methods.  We're not sure who came out with them first, but wanted
* 	to thank them both just the same.
* 
* 	These rock!!
* @version 1.0
*/
package org.papervision3d.core.utils {
	import flash.display.BitmapData;
	
	import org.papervision3d.core.geom.renderables.Triangle3D;
	import org.papervision3d.core.geom.renderables.Vertex3D;
	import org.papervision3d.core.proto.MaterialObject3D;
	import org.papervision3d.materials.BitmapMaterial;
	import org.papervision3d.objects.DisplayObject3D;	

	/**
	 * InteractiveUtils are used in conjunction with the ISM to resolve a face's mouse interaction and coordinates back to 2D screen space
	 * 
	 * 
	 */	
	public class InteractiveUtils 
	{
		public static function UVatPoint( face3d:Triangle3D, x : Number, y : Number ) : Object 
		{	
			
			var v0:Vertex3D = face3d.v0;
			var v1:Vertex3D = face3d.v1;
			var v2:Vertex3D = face3d.v2;
			
			var v0Dx : Number = v0.vertex3DInstance.x;
			var v0Dy : Number = v0.vertex3DInstance.y;
			var v1Dx : Number = v1.vertex3DInstance.x;
			var v1Dy : Number = v1.vertex3DInstance.y;
			var v2Dx : Number = v2.vertex3DInstance.x;
			var v2Dy : Number = v2.vertex3DInstance.y;
			
			var v0_x : Number = v2Dx - v0Dx;
			var v0_y : Number = v2Dy - v0Dy;
			var v1_x : Number = v1Dx - v0Dx;
			var v1_y : Number = v1Dy - v0Dy;
			var v2_x : Number = x - v0Dx;
			var v2_y : Number = y - v0Dy;
				
			var dot00 : Number = v0_x * v0_x + v0_y * v0_y;
			var dot01 : Number = v0_x * v1_x + v0_y * v1_y;
			var dot02 : Number = v0_x * v2_x + v0_y * v2_y;
			var dot11 : Number = v1_x * v1_x + v1_y * v1_y;
			var dot12 : Number = v1_x * v2_x + v1_y * v2_y;
				
			var invDenom : Number = 1 / (dot00 * dot11 - dot01 * dot01);
			var u : Number = (dot11 * dot02 - dot01 * dot12) * invDenom;
			var v : Number = (dot00 * dot12 - dot01 * dot02) * invDenom;
		   
			return { u : u, v : v };
		}
		
		public static function getCoordAtPoint( face3d:Triangle3D, x : Number, y : Number ) : Vertex3D
		{	
			var rUV : Object = UVatPoint(face3d, x, y);
			
			var v0x : Number = face3d.v0.x;
			var v0y : Number = face3d.v0.y;
			var v0z : Number = face3d.v0.z;
			var v1x : Number = face3d.v1.x;
			var v1y : Number = face3d.v1.y;
			var v1z : Number = face3d.v1.z;
			var v2x : Number = face3d.v2.x;
			var v2y : Number = face3d.v2.y;
			var v2z : Number = face3d.v2.z;
			
			var u : Number = rUV.u;
			var v : Number = rUV.v;
				
			var rX : Number = v0x + ( v1x - v0x ) * v + ( v2x - v0x ) * u;
			var rY : Number = v0y + ( v1y - v0y ) * v + ( v2y - v0y ) * u;
			var rZ : Number = v0z + ( v1z - v0z ) * v + ( v2z - v0z ) * u;
				
			return Vertex3D( {x:rX, y:rY, z:rZ} );
		}
		
		public static function getMapCoordAtPointDO3D( displayObject:DisplayObject3D, x : Number, y : Number ):Object
		{
			var face:Triangle3D = displayObject.geometry.faces[0];
			return getMapCoordAtPoint(face, x, y);
		}
		
		public static function getMapCoordAtPoint( face3d:Triangle3D, x : Number, y : Number ) : Object 
		{
			
			var uv:Array = face3d.uv;
			
			var rUV : Object = UVatPoint(face3d, x, y);
			var u : Number = rUV.u;
			var v : Number = rUV.v;
			
			var u0 : Number = uv[0].u;
			var u1 : Number = uv[1].u;
			var u2 : Number = uv[2].u;
			var v0 : Number = uv[0].v;
			var v1 : Number = uv[1].v;
			var v2 : Number = uv[2].v;
				
			var v_x : Number = ( u1 - u0 ) * v +  ( u2 - u0 ) * u + u0;
			var v_y : Number = ( v1 - v0 ) * v +  ( v2 - v0 ) * u + v0;

			var material:MaterialObject3D = face3d.face3DInstance.instance.material;
			var bitmap:BitmapData = material.bitmap;
			var width:Number = 1;
			var height:Number = 1;
			if(bitmap)
			{
				width = BitmapMaterial.AUTO_MIP_MAPPING ? material.widthOffset : bitmap.width;
				height = BitmapMaterial.AUTO_MIP_MAPPING ? material.heightOffset : bitmap.height;
			}
				
			return { x:v_x * width, y:height - v_y * height };
		}
	}	
}