package org.papervision3d.core.controller{	import org.papervision3d.core.geom.TriangleMesh3D;	import org.papervision3d.core.geom.renderables.Vertex3D;	import org.papervision3d.core.log.PaperLogger;		/**	 * The MorphController class controls a mesh's vertices by applying a morph.	 * 	 * Each possible mesh that can be blended (a morph target) must be specified.	 * Each morph target is assigned a blend weight. The result is obtained via two methods :	 * 	 * <ol>	 * <li>NORMALIZED  (Target1, Target2, ...)*(w1, w2, ...) = (1-w1-w2-...)*BaseMesh + w1*Target1 + w2*Target2 + ...</li>	 * <li>RELATIVE    (Target1, Target2, ...) + (w1, w2, ...) = BaseMesh + w1*Target1 + w2*Target2 + ...</li>	 * </ol>	 * 	 * @author Tim Knip / floorplanner.com	 */	public class MorphController implements IObjectController	{		/** */		public var active :Boolean;				/** */		public var target :TriangleMesh3D;				/** */		public var targets :Array;				/** */		public var weights :Array;				/** */		public var normalized :Boolean;				/** */		private var cached :Array;				/**		 * Constructor.		 */ 		public function MorphController(target:TriangleMesh3D, normalized:Boolean=true)		{			this.target = target;			this.active = true;			this.targets = new Array();			this.normalized = normalized;			this.weights = new Array();			this.cached = new Array(target.geometry.vertices.length);						var v :Vertex3D;			for(var i:int = 0; i < cached.length; i++)			{				v = target.geometry.vertices[i];				cached[i] = v.clone();			}		}		/**		 * 		 */		public function addMorphTarget(mesh:TriangleMesh3D, weight:Number):void		{			if(mesh.geometry.vertices.length != this.target.geometry.vertices.length)			{				PaperLogger.warning("Invalid morph target! " +					"Number of specified vertices (" + mesh.geometry.vertices.length + ")" +					" not equal to number of base vertices (" +					+this.target.geometry.vertices.length + ").");				return;			}						this.targets.push(mesh);			this.weights.push(weight);		}				/**		 * 		 */ 		public function update():void		{			var orig :Array = this.target.geometry.vertices;			var cached :Array = this.cached;			var mesh :TriangleMesh3D;			var c :Vertex3D, v :Vertex3D, t :Vertex3D;			var num :int = orig.length;			var totalWeight :Number = 0;			var restWeight :Number, weight :Number;			var i :int, j :int;						if(!this.active)			{				return;			}						if(normalized)			{				for(i = 0; i < weights.length; i++)				{					totalWeight += weights[i];				}				restWeight = 1 - totalWeight;			}						for(i = 0; i < num; i++)			{				v = orig[i];				c = cached[i];								v.x = normalized ? restWeight * c.x : c.x;				v.y = normalized ? restWeight * c.y : c.y;				v.z = normalized ? restWeight * c.z : c.z;								for(j = 0; j < targets.length; j++)				{					mesh = targets[j];					t = mesh.geometry.vertices[i];					weight = weights[j];										v.x += weight * t.x;					v.y += weight * t.y;					v.z += weight * t.z;				}			}		}	}}