PageRenderTime 507ms CodeModel.GetById 201ms app.highlight 104ms RepoModel.GetById 198ms app.codeStats 0ms

/src/away3d/entities/Mesh.as

http://github.com/away3d/away3d-core-fp11
ActionScript | 368 lines | 231 code | 53 blank | 84 comment | 28 complexity | b8a4fac8df88acbd62805e76970d2f71 MD5 | raw file
  1package away3d.entities
  2{
  3	import away3d.materials.utils.DefaultMaterialManager;
  4	import away3d.animators.IAnimator;
  5	import away3d.arcane;
  6	import away3d.containers.*;
  7	import away3d.core.base.*;
  8	import away3d.core.partition.*;
  9	import away3d.events.*;
 10	import away3d.library.assets.*;
 11	import away3d.materials.*;
 12	
 13	use namespace arcane;
 14	
 15	/**
 16	 * Mesh is an instance of a Geometry, augmenting it with a presence in the scene graph, a material, and an animation
 17	 * state. It consists out of SubMeshes, which in turn correspond to SubGeometries. SubMeshes allow different parts
 18	 * of the geometry to be assigned different materials.
 19	 */
 20	public class Mesh extends Entity implements IMaterialOwner, IAsset
 21	{
 22		private var _subMeshes:Vector.<SubMesh>;
 23		protected var _geometry:Geometry;
 24		private var _material:MaterialBase;
 25		private var _animator:IAnimator;
 26		private var _castsShadows:Boolean = true;
 27		private var _shareAnimationGeometry:Boolean = true;
 28		
 29		/**
 30		 * Create a new Mesh object.
 31		 *
 32		 * @param geometry                    The geometry used by the mesh that provides it with its shape.
 33		 * @param material    [optional]        The material with which to render the Mesh.
 34		 */
 35		public function Mesh(geometry:Geometry, material:MaterialBase = null)
 36		{
 37			super();
 38			_subMeshes = new Vector.<SubMesh>();
 39			
 40			this.geometry = geometry || new Geometry(); //this should never happen, but if people insist on trying to create their meshes before they have geometry to fill it, it becomes necessary
 41			
 42			this.material = material || DefaultMaterialManager.getDefaultMaterial(this);
 43		}
 44		
 45		public function bakeTransformations():void
 46		{
 47			geometry.applyTransformation(transform);
 48			transform.identity();
 49		}
 50		
 51		public override function get assetType():String
 52		{
 53			return AssetType.MESH;
 54		}
 55		
 56		private function onGeometryBoundsInvalid(event:GeometryEvent):void
 57		{
 58			invalidateBounds();
 59		}
 60		
 61		/**
 62		 * Indicates whether or not the Mesh can cast shadows. Default value is <code>true</code>.
 63		 */
 64		public function get castsShadows():Boolean
 65		{
 66			return _castsShadows;
 67		}
 68		
 69		public function set castsShadows(value:Boolean):void
 70		{
 71			_castsShadows = value;
 72		}
 73		
 74		/**
 75		 * Defines the animator of the mesh. Act on the mesh's geometry. Default value is <code>null</code>.
 76		 */
 77		public function get animator():IAnimator
 78		{
 79			return _animator;
 80		}
 81		
 82		public function set animator(value:IAnimator):void
 83		{
 84			if (_animator)
 85				_animator.removeOwner(this);
 86			
 87			_animator = value;
 88			
 89			// cause material to be unregistered and registered again to work with the new animation type (if possible)
 90			var oldMaterial:MaterialBase = material;
 91			material = null;
 92			material = oldMaterial;
 93			
 94			var len:uint = _subMeshes.length;
 95			var subMesh:SubMesh;
 96			
 97			// reassign for each SubMesh
 98			for (var i:int = 0; i < len; ++i) {
 99				subMesh = _subMeshes[i];
100				oldMaterial = subMesh._material;
101				if (oldMaterial) {
102					subMesh.material = null;
103					subMesh.material = oldMaterial;
104				}
105			}
106			
107			if (_animator)
108				_animator.addOwner(this);
109		}
110		
111		/**
112		 * The geometry used by the mesh that provides it with its shape.
113		 */
114		public function get geometry():Geometry
115		{
116			return _geometry;
117		}
118		
119		public function set geometry(value:Geometry):void
120		{
121			var i:uint;
122			
123			if (_geometry) {
124				_geometry.removeEventListener(GeometryEvent.BOUNDS_INVALID, onGeometryBoundsInvalid);
125				_geometry.removeEventListener(GeometryEvent.SUB_GEOMETRY_ADDED, onSubGeometryAdded);
126				_geometry.removeEventListener(GeometryEvent.SUB_GEOMETRY_REMOVED, onSubGeometryRemoved);
127				
128				for (i = 0; i < _subMeshes.length; ++i)
129					_subMeshes[i].dispose();
130				_subMeshes.length = 0;
131			}
132			
133			_geometry = value;
134			if (_geometry) {
135				_geometry.addEventListener(GeometryEvent.BOUNDS_INVALID, onGeometryBoundsInvalid);
136				_geometry.addEventListener(GeometryEvent.SUB_GEOMETRY_ADDED, onSubGeometryAdded);
137				_geometry.addEventListener(GeometryEvent.SUB_GEOMETRY_REMOVED, onSubGeometryRemoved);
138				
139				var subGeoms:Vector.<ISubGeometry> = _geometry.subGeometries;
140				
141				for (i = 0; i < subGeoms.length; ++i)
142					addSubMesh(subGeoms[i]);
143			}
144			
145			if (_material) {
146				// reregister material in case geometry has a different animation
147				_material.removeOwner(this);
148				_material.addOwner(this);
149			}
150		}
151		
152		/**
153		 * The material with which to render the Mesh.
154		 */
155		public function get material():MaterialBase
156		{
157			return _material;
158		}
159		
160		public function set material(value:MaterialBase):void
161		{
162			if (value == _material)
163				return;
164			if (_material)
165				_material.removeOwner(this);
166			_material = value;
167			if (_material)
168				_material.addOwner(this);
169		}
170		
171		/**
172		 * The SubMeshes out of which the Mesh consists. Every SubMesh can be assigned a material to override the Mesh's
173		 * material.
174		 */
175		public function get subMeshes():Vector.<SubMesh>
176		{
177			// Since this getter is invoked every iteration of the render loop, and
178			// the geometry construct could affect the sub-meshes, the geometry is
179			// validated here to give it a chance to rebuild.
180			_geometry.validate();
181			
182			return _subMeshes;
183		}
184		
185		/**
186		 * Indicates whether or not the mesh share the same animation geometry.
187		 */
188		public function get shareAnimationGeometry():Boolean
189		{
190			return _shareAnimationGeometry;
191		}
192		
193		public function set shareAnimationGeometry(value:Boolean):void
194		{
195			_shareAnimationGeometry = value;
196		}
197		
198		/**
199		 * Clears the animation geometry of this mesh. It will cause animation to generate a new animation geometry. Work only when shareAnimationGeometry is false.
200		 */
201		public function clearAnimationGeometry():void
202		{
203			var len:int = _subMeshes.length;
204			for (var i:int = 0; i < len; ++i)
205				_subMeshes[i].animationSubGeometry = null;
206		}
207		
208		/**
209		 * @inheritDoc
210		 */
211		override public function dispose():void
212		{
213			super.dispose();
214			
215			material = null;
216			geometry = null;
217		}
218		
219		/**
220		 * Disposes mesh including the animator and children. This is a merely a convenience method.
221		 * @return
222		 */
223		public function disposeWithAnimatorAndChildren():void
224		{
225			disposeWithChildren();
226			
227			if (_animator)
228				_animator.dispose();
229		}
230		
231		/**
232		 * Clones this Mesh instance along with all it's children, while re-using the same
233		 * material, geometry and animation set. The returned result will be a copy of this mesh,
234		 * containing copies of all of it's children.
235		 *
236		 * Properties that are re-used (i.e. not cloned) by the new copy include name,
237		 * geometry, and material. Properties that are cloned or created anew for the copy
238		 * include subMeshes, children of the mesh, and the animator.
239		 *
240		 * If you want to copy just the mesh, reusing it's geometry and material while not
241		 * cloning it's children, the simplest way is to create a new mesh manually:
242		 *
243		 * <code>
244		 * var clone : Mesh = new Mesh(original.geometry, original.material);
245		 * </code>
246		 */
247		override public function clone():Object3D
248		{
249			var clone:Mesh = new Mesh(_geometry, _material);
250			clone.transform = transform;
251			clone.pivotPoint = pivotPoint;
252			clone.partition = partition;
253			clone.bounds = _bounds.clone();
254			clone.name = name;
255			clone.castsShadows = castsShadows;
256			clone.shareAnimationGeometry = shareAnimationGeometry;
257			clone.mouseEnabled = this.mouseEnabled;
258			clone.mouseChildren = this.mouseChildren;
259			//this is of course no proper cloning
260			//maybe use this instead?: http://blog.another-d-mention.ro/programming/how-to-clone-duplicate-an-object-in-actionscript-3/
261			clone.extra = this.extra;
262			
263			var len:int = _subMeshes.length;
264			for (var i:int = 0; i < len; ++i)
265				clone._subMeshes[i]._material = _subMeshes[i]._material;
266			
267			len = numChildren;
268			for (i = 0; i < len; ++i)
269				clone.addChild(ObjectContainer3D(getChildAt(i).clone()));
270			
271			if (_animator)
272				clone.animator = _animator.clone();
273			
274			return clone;
275		}
276		
277		/**
278		 * @inheritDoc
279		 */
280		override protected function updateBounds():void
281		{
282			_bounds.fromGeometry(_geometry);
283			_boundsInvalid = false;
284		}
285		
286		/**
287		 * @inheritDoc
288		 */
289		override protected function createEntityPartitionNode():EntityNode
290		{
291			return new MeshNode(this);
292		}
293		
294		/**
295		 * Called when a SubGeometry was added to the Geometry.
296		 */
297		private function onSubGeometryAdded(event:GeometryEvent):void
298		{
299			addSubMesh(event.subGeometry);
300		}
301		
302		/**
303		 * Called when a SubGeometry was removed from the Geometry.
304		 */
305		private function onSubGeometryRemoved(event:GeometryEvent):void
306		{
307			var subMesh:SubMesh;
308			var subGeom:ISubGeometry = event.subGeometry;
309			var len:int = _subMeshes.length;
310			var i:uint;
311			
312			// Important! This has to be done here, and not delayed until the
313			// next render loop, since this may be caused by the geometry being
314			// rebuilt IN THE RENDER LOOP. Invalidating and waiting will delay
315			// it until the NEXT RENDER FRAME which is probably not desirable.
316			
317			for (i = 0; i < len; ++i) {
318				subMesh = _subMeshes[i];
319				if (subMesh.subGeometry == subGeom) {
320					subMesh.dispose();
321					_subMeshes.splice(i, 1);
322					break;
323				}
324			}
325			
326			--len;
327			for (; i < len; ++i)
328				_subMeshes[i]._index = i;
329		}
330		
331		/**
332		 * Adds a SubMesh wrapping a SubGeometry.
333		 */
334		private function addSubMesh(subGeometry:ISubGeometry):void
335		{
336			var subMesh:SubMesh = new SubMesh(subGeometry, this, null);
337			var len:uint = _subMeshes.length;
338			subMesh._index = len;
339			_subMeshes[len] = subMesh;
340			invalidateBounds();
341		}
342		
343		public function getSubMeshForSubGeometry(subGeometry:ISubGeometry):SubMesh
344		{
345			return _subMeshes[_geometry.subGeometries.indexOf(subGeometry)];
346		}
347		
348		override arcane function collidesBefore(shortestCollisionDistance:Number, findClosest:Boolean):Boolean
349		{
350			_pickingCollider.setLocalRay(_pickingCollisionVO.localRayPosition, _pickingCollisionVO.localRayDirection);
351			_pickingCollisionVO.renderable = null;
352			var len:int = _subMeshes.length;
353			for (var i:int = 0; i < len; ++i) {
354				var subMesh:SubMesh = _subMeshes[i];
355				
356				//var ignoreFacesLookingAway:Boolean = _material ? !_material.bothSides : true;
357				if (_pickingCollider.testSubMeshCollision(subMesh, _pickingCollisionVO, shortestCollisionDistance)) {
358					shortestCollisionDistance = _pickingCollisionVO.rayEntryDistance;
359					_pickingCollisionVO.renderable = subMesh;
360					if (!findClosest)
361						return true;
362				}
363			}
364			
365			return _pickingCollisionVO.renderable != null;
366		}
367	}
368}