/**
 * @author erichlof /  http://github.com/erichlof
 *
 * A shadow Mesh that follows a shadow-casting Mesh in the scene, but is confined to a single plane.
 */

THREE.ShadowMesh = function ( mesh ) {

	var shadowMaterial = new THREE.MeshBasicMaterial( {

		color: 0x000000,
		transparent: true,
		opacity: 0.2,
		depthWrite: false

	} );

	THREE.Mesh.call( this, mesh.geometry, shadowMaterial );

	this.meshMatrix = mesh.matrixWorld;

	this.frustumCulled = false;
	this.matrixAutoUpdate = false;

};

THREE.ShadowMesh.prototype = Object.create( THREE.Mesh.prototype );
THREE.ShadowMesh.prototype.constructor = THREE.ShadowMesh;

THREE.ShadowMesh.prototype.update = function () {

	var shadowMatrix = new THREE.Matrix4();

	return function ( plane, lightPosition4D ) {

		// based on https://www.opengl.org/archives/resources/features/StencilTalk/tsld021.htm

		var dot = plane.normal.x * lightPosition4D.x +
			  plane.normal.y * lightPosition4D.y +
			  plane.normal.z * lightPosition4D.z +
			  - plane.constant * lightPosition4D.w;

		var sme = shadowMatrix.elements;

		sme[ 0 ]  = dot - lightPosition4D.x * plane.normal.x;
		sme[ 4 ]  = - lightPosition4D.x * plane.normal.y;
		sme[ 8 ]  = - lightPosition4D.x * plane.normal.z;
		sme[ 12 ] = - lightPosition4D.x * - plane.constant;

		sme[ 1 ]  = - lightPosition4D.y * plane.normal.x;
		sme[ 5 ]  = dot - lightPosition4D.y * plane.normal.y;
		sme[ 9 ]  = - lightPosition4D.y * plane.normal.z;
		sme[ 13 ] = - lightPosition4D.y * - plane.constant;

		sme[ 2 ]  = - lightPosition4D.z * plane.normal.x;
		sme[ 6 ]  = - lightPosition4D.z * plane.normal.y;
		sme[ 10 ] = dot - lightPosition4D.z * plane.normal.z;
		sme[ 14 ] = - lightPosition4D.z * - plane.constant;

		sme[ 3 ]  = - lightPosition4D.w * plane.normal.x;
		sme[ 7 ]  = - lightPosition4D.w * plane.normal.y;
		sme[ 11 ] = - lightPosition4D.w * plane.normal.z;
		sme[ 15 ] = dot - lightPosition4D.w * - plane.constant;

		this.matrix.multiplyMatrices( shadowMatrix, this.meshMatrix );

	};

}();
