text: import { Matrix3 } from '../../math/Matrix3.js';
  import { Plane } from '../../math/Plane.js';
  
  function WebGLClipping( properties ) {
  
  	const scope = this;
  
  	let globalState = null,
  		numGlobalPlanes = 0,
  		localClippingEnabled = false,
  		renderingShadows = false;
  
  	const plane = new Plane(),
  		viewNormalMatrix = new Matrix3(),
  
  		uniform = { value: null, needsUpdate: false };
  
  	this.uniform = uniform;
  	this.numPlanes = 0;
  	this.numIntersection = 0;
  
  	this.init = function ( planes, enableLocalClipping, camera ) {
  
  		const enabled =
  			planes.length !== 0 ||
  			enableLocalClipping ||
  			// enable state of previous frame - the clipping code has to
  			// run another frame in order to reset the state:
  			numGlobalPlanes !== 0 ||
  			localClippingEnabled;
  
  		localClippingEnabled = enableLocalClipping;
  
  		globalState = projectPlanes( planes, camera, 0 );
  		numGlobalPlanes = planes.length;
  
  		return enabled;
  
  	};
  
  	this.beginShadows = function () {
  
  		renderingShadows = true;
  		projectPlanes( null );
  
  	};
  
  	this.endShadows = function () {
  
  		renderingShadows = false;
  		resetGlobalState();
  
  	};
  
  	this.setState = function ( material, camera, useCache ) {
  
  		const planes = material.clippingPlanes,
  			clipIntersection = material.clipIntersection,
  			clipShadows = material.clipShadows;
  
  		const materialProperties = properties.get( material );
  
  		if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) {
  
  			// there's no local clipping
  
  			if ( renderingShadows ) {
  
  				// there's no global clipping
  
  				projectPlanes( null );
  
  			} else {
  
  				resetGlobalState();
  
  			}
  
  		} else {
  
  			const nGlobal = renderingShadows ? 0 : numGlobalPlanes,
  				lGlobal = nGlobal * 4;
  
  			let dstArray = materialProperties.clippingState || null;
  
  			uniform.value = dstArray; // ensure unique state
  
  			dstArray = projectPlanes( planes, camera, lGlobal, useCache );
  
  			for ( let i = 0; i !== lGlobal; ++ i ) {
  
  				dstArray[ i ] = globalState[ i ];
  
  			}
  
  			materialProperties.clippingState = dstArray;
  			this.numIntersection = clipIntersection ? this.numPlanes : 0;
  			this.numPlanes += nGlobal;
  
  		}
  
  
  	};
  
  	function resetGlobalState() {
  
  		if ( uniform.value !== globalState ) {
  
  			uniform.value = globalState;
  			uniform.needsUpdate = numGlobalPlanes > 0;
  
  		}
  
  		scope.numPlanes = numGlobalPlanes;
  		scope.numIntersection = 0;
  
  	}
  
  	function projectPlanes( planes, camera, dstOffset, skipTransform ) {
  
  		const nPlanes = planes !== null ? planes.length : 0;
  		let dstArray = null;
  
  		if ( nPlanes !== 0 ) {
  
  			dstArray = uniform.value;
  
  			if ( skipTransform !== true || dstArray === null ) {
  
  				const flatSize = dstOffset + nPlanes * 4,
  					viewMatrix = camera.matrixWorldInverse;
  
  				viewNormalMatrix.getNormalMatrix( viewMatrix );
  
  				if ( dstArray === null || dstArray.length < flatSize ) {
  
  					dstArray = new Float32Array( flatSize );
  
  				}
  
  				for ( let i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) {
  
  					plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix );
  
  					plane.normal.toArray( dstArray, i4 );
  					dstArray[ i4 + 3 ] = plane.constant;
  
  				}
  
  			}
  
  			uniform.value = dstArray;
  			uniform.needsUpdate = true;
  
  		}
  
  		scope.numPlanes = nPlanes;
  		scope.numIntersection = 0;
  
  		return dstArray;
  
  	}
  
  }
  
  
  export { WebGLClipping };
  