text: import { Vector3 } from '../math/Vector3';
  import { Vector2 } from '../math/Vector2';
  import { Sphere } from '../math/Sphere';
  import { Ray } from '../math/Ray';
  import { Matrix4 } from '../math/Matrix4';
  import { SceneNode } from '../core/SceneNode';
  import { Triangle } from '../math/Triangle';
  import { Face3 } from '../core/Face3';
  import { DoubleSide, BackSide, TrianglesDrawMode } from '../constants';
  import { Material } from '../core/Material';
  import { BufferGeometry } from '../core/BufferGeometry';
  
  /**
   * @author mrdoob / http://mrdoob.com/
   * @author alteredq / http://alteredqualia.com/
   * @author mikael emtinger / http://gomo.se/
   * @author jonobr1 / http://jonobr1.com/
   */
  
  function Mesh( geometry, material ) {
  
  	SceneNode.call( this );
  
  	this.type = 'Mesh';
  
  	this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
  	this.material = material !== undefined ? material : new Material();
  
  	this.drawMode = TrianglesDrawMode;
  
  	this.updateMorphTargets();
  
  }
  
  Mesh.prototype = Object.assign( Object.create( SceneNode.prototype ), {
  
  	constructor: Mesh,
  
  	isMesh: true,
  
  	setDrawMode: function ( value ) {
  
  		this.drawMode = value;
  
  	},
  
  	copy: function ( source ) {
  
  		SceneNode.prototype.copy.call( this, source );
  
  		this.drawMode = source.drawMode;
  
  		return this;
  
  	},
  
  	updateMorphTargets: function () {
  
  		var morphTargets = this.geometry.morphTargets;
  
  		if ( morphTargets !== undefined && morphTargets.length > 0 ) {
  
  			this.morphTargetInfluences = [];
  			this.morphTargetDictionary = {};
  
  			for ( var m = 0, ml = morphTargets.length; m < ml; m ++ ) {
  
  				this.morphTargetInfluences.push( 0 );
  				this.morphTargetDictionary[ morphTargets[ m ].name ] = m;
  
  			}
  
  		}
  
  	},
  
  	raycast: ( function () {
  
  		var inverseMatrix = new Matrix4();
  		var ray = new Ray();
  		var sphere = new Sphere();
  
  		var vA = new Vector3();
  		var vB = new Vector3();
  		var vC = new Vector3();
  
  		var tempA = new Vector3();
  		var tempB = new Vector3();
  		var tempC = new Vector3();
  
  		var uvA = new Vector2();
  		var uvB = new Vector2();
  		var uvC = new Vector2();
  
  		var barycoord = new Vector3();
  
  		var intersectionPoint = new Vector3();
  		var intersectionPointWorld = new Vector3();
  
  		function uvIntersection( point, p1, p2, p3, uv1, uv2, uv3 ) {
  
  			Triangle.barycoordFromPoint( point, p1, p2, p3, barycoord );
  
  			uv1.multiplyScalar( barycoord.x );
  			uv2.multiplyScalar( barycoord.y );
  			uv3.multiplyScalar( barycoord.z );
  
  			uv1.add( uv2 ).add( uv3 );
  
  			return uv1.clone();
  
  		}
  
  		function checkIntersection( object, raycaster, ray, pA, pB, pC, point ) {
  
  			var intersect;
  			var material = object.material;
  
  			if ( material.side === BackSide ) {
  
  				intersect = ray.intersectTriangle( pC, pB, pA, true, point );
  
  			} else {
  
  				intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point );
  
  			}
  
  			if ( intersect === null ) return null;
  
  			intersectionPointWorld.copy( point );
  			intersectionPointWorld.applyMatrix4( object.matrixWorld );
  
  			var distance = raycaster.ray.origin.distanceTo( intersectionPointWorld );
  
  			if ( distance < raycaster.near || distance > raycaster.far ) return null;
  
  			return {
  				distance: distance,
  				point: intersectionPointWorld.clone(),
  				object: object
  			};
  
  		}
  
  		function checkBufferGeometryIntersection( object, raycaster, ray, position, uv, a, b, c ) {
  
  			vA.fromBufferAttribute( position, a );
  			vB.fromBufferAttribute( position, b );
  			vC.fromBufferAttribute( position, c );
  
  			var intersection = checkIntersection( object, raycaster, ray, vA, vB, vC, intersectionPoint );
  
  			if ( intersection ) {
  
  				if ( uv ) {
  
  					uvA.fromBufferAttribute( uv, a );
  					uvB.fromBufferAttribute( uv, b );
  					uvC.fromBufferAttribute( uv, c );
  
  					intersection.uv = uvIntersection( intersectionPoint, vA, vB, vC, uvA, uvB, uvC );
  
  				}
  
  				intersection.face = new Face3( a, b, c, Triangle.normal( vA, vB, vC ) );
  				intersection.faceIndex = a;
  
  			}
  
  			return intersection;
  
  		}
  
  		return function raycast( raycaster, intersects ) {
  
  			var geometry = this.geometry;
  			var material = this.material;
  			var matrixWorld = this.matrixWorld;
  
  			if ( material === undefined ) return;
  
  			// Checking boundingSphere distance to ray
  
  			if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
  
  			sphere.copy( geometry.boundingSphere );
  			sphere.applyMatrix4( matrixWorld );
  
  			if ( raycaster.ray.intersectsSphere( sphere ) === false ) return;
  
  			//
  
  			inverseMatrix.getInverse( matrixWorld );
  			ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
  
  			// Check boundingBox before continuing
  
  			if ( geometry.boundingBox !== null ) {
  
  				if ( ray.intersectsBox( geometry.boundingBox ) === false ) return;
  
  			}
  
  			var intersection;
  
  			var a, b, c;
  			var index = geometry.index;
  			var position = geometry.attributes.position;
  			var uv = geometry.attributes.uv;
  			var i, l;
  
  			if ( index !== null ) {
  
  				// indexed buffer geometry
  
  				for ( i = 0, l = index.count; i < l; i += 3 ) {
  
  					a = index.getX( i );
  					b = index.getX( i + 1 );
  					c = index.getX( i + 2 );
  
  					intersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c );
  
  					if ( intersection ) {
  
  						intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indices buffer semantics
  						intersects.push( intersection );
  
  					}
  
  				}
  
  			} else {
  
  				// non-indexed buffer geometry
  
  				for ( i = 0, l = position.count; i < l; i += 3 ) {
  
  					a = i;
  					b = i + 1;
  					c = i + 2;
  
  					intersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c );
  
  					if ( intersection ) {
  
  						intersection.index = a; // triangle number in positions buffer semantics
  						intersects.push( intersection );
  
  					}
  
  				}
  
  			}
  
  		};
  
  	}() ),
  
  	clone: function () {
  
  		return new this.constructor( this.geometry, this.material ).copy( this );
  
  	}
  
  } );
  
  
  export { Mesh };
  