text: import { UniformsUtils, Vector2 } from '//unpkg.com/three@0.114.0/build/three.module.js';
  import { sampleFunctions } from './mipSampleFunctions.js';
  
  export function clone( shader ) {
  
  	const newShader = { ...shader };
  	if ( 'defines' in shader ) {
  
  		newShader.defines = { ...shader.defines };
  
  	}
  
  	if ( 'uniforms' in shader ) {
  
  		newShader.uniforms = UniformsUtils.clone( shader.uniforms );
  
  	}
  
  	return newShader;
  
  }
  
  // Non Power of Two mip map generation
  // https://www.nvidia.com/en-us/drivers/np2-mipmapping/
  export const MipGenerationShader = {
  
  	defines: {
  
  		X_IS_EVEN: 1,
  		Y_IS_EVEN: 1,
  
  	},
  
  	uniforms: {
  
  		map: { value: null },
  		originalMapSize: { value: new Vector2() },
  		parentMapSize: { value: new Vector2() },
  		parentLevel: { value: 0 },
  
  	},
  
  	vertexShader: /* glsl */`
  		varying vec2 vUv;
  		void main() {
  
  			#include <begin_vertex>
  			#include <project_vertex>
  			vUv = uv;
  
  		}
  	`,
  
  	fragmentShader: /* glsl */`
  		varying vec2 vUv;
  		uniform sampler2D map;
  		uniform int parentLevel;
  		uniform vec2 parentMapSize;
  		uniform vec2 originalMapSize;
  
  		${ sampleFunctions }
  
  		#if X_IS_EVEN && Y_IS_EVEN
  
  		#define SAMPLES 4
  		#define WIDTH 2
  		#define HEIGHT 2
  
  		#elif X_IS_EVEN
  
  		#define SAMPLES 6
  		#define WIDTH 2
  		#define HEIGHT 3
  
  		#elif Y_IS_EVEN
  
  		#define SAMPLES 6
  		#define WIDTH 3
  		#define HEIGHT 2
  
  		#else
  
  		#define SAMPLES 9
  		#define WIDTH 3
  		#define HEIGHT 3
  
  		#endif
  
  		vec4 sampleAt( vec2 uv ) {
  
  			return packedTexture2DLOD( map, uv, parentLevel, originalMapSize );
  
  		}
  
  		void main() {
  
  			vec2 childMapSize = parentMapSize / 2.0;
  			// vec2 childPixelSize = 1.0 / childMapSize;
  			// vec2 halfChildPixelSize = childPixelSize / 2.0;
  			vec2 childPixelPos = floor( vUv * childMapSize );
  
  			vec2 parentPixelSize = 1.0 / parentMapSize;
  			vec2 halfParentPixelSize = parentPixelSize / 2.0;
  			vec2 parentPixelPos = childPixelPos * 2.0;
  
  			vec2 baseUv = ( parentPixelPos / parentMapSize ) + halfParentPixelSize;
  
  			vec4 samples[ SAMPLES ];
  			float weights[ SAMPLES ];
  
  			#if X_IS_EVEN && Y_IS_EVEN
  
  			samples[ 0 ] = sampleAt( baseUv );
  			samples[ 1 ] = sampleAt( baseUv + vec2( parentPixelSize.x, 0.0 ) );
  			samples[ 2 ] = sampleAt( baseUv + vec2( 0.0, parentPixelSize.y ) );
  			samples[ 3 ] = sampleAt( baseUv + vec2( parentPixelSize.x, parentPixelSize.y ) );
  
  			weights[ 0 ] = 0.25;
  			weights[ 1 ] = 0.25;
  			weights[ 2 ] = 0.25;
  			weights[ 3 ] = 0.25;
  
  			#elif X_IS_EVEN
  
  			float wx0 = 0.5;
  			float wx1 = 0.5;
  
  			float yden = 2.0 * parentMapSize.y + 1.0;
  			float wy0 = ( parentMapSize.y - parentPixelPos.y ) / yden;
  			float wy1 = ( parentMapSize.y ) / yden;
  			float wy2 = ( parentPixelPos.y + 1.0 ) / yden;
  
  			samples[ 0 ] = sampleAt( baseUv );
  			samples[ 1 ] = sampleAt( baseUv + vec2( parentPixelSize.x, 0.0 ) );
  
  			samples[ 2 ] = sampleAt( baseUv + vec2( 0.0, parentPixelSize.y ) );
  			samples[ 3 ] = sampleAt( baseUv + vec2( parentPixelSize.x, parentPixelSize.y ) );
  
  			samples[ 4 ] = sampleAt( baseUv + vec2( 0.0, 2.0 * parentPixelSize.y ) );
  			samples[ 5 ] = sampleAt( baseUv + vec2( parentPixelSize.x, 2.0 * parentPixelSize.y ) );
  
  			weights[ 0 ] = wx0 * wy0;
  			weights[ 1 ] = wx1 * wy0;
  
  			weights[ 2 ] = wx0 * wy1;
  			weights[ 3 ] = wx1 * wy1;
  
  			weights[ 4 ] = wx0 * wy2;
  			weights[ 5 ] = wx1 * wy2;
  
  			#elif Y_IS_EVEN
  
  			float xden = 2.0 * parentMapSize.x + 1.0;
  			float wx0 = ( parentMapSize.x - parentPixelPos.x ) / xden;
  			float wx1 = ( parentMapSize.x ) / xden;
  			float wx2 = ( parentPixelPos.x + 1.0 ) / xden;
  
  			float wy0 = 0.5;
  			float wy1 = 0.5;
  
  			samples[ 0 ] = sampleAt( baseUv );
  			samples[ 1 ] = sampleAt( baseUv + vec2( parentPixelSize.x, 0.0 ) );
  			samples[ 2 ] = sampleAt( baseUv + vec2( 2.0 * parentPixelSize.x, 0.0 ) );
  
  			samples[ 3 ] = sampleAt( baseUv + vec2( 0.0, parentPixelSize.y ) );
  			samples[ 4 ] = sampleAt( baseUv + vec2( parentPixelSize.x, parentPixelSize.y ) );
  			samples[ 5 ] = sampleAt( baseUv + vec2( 2.0 * parentPixelSize.x, parentPixelSize.y ) );
  
  			weights[ 0 ] = wx0 * wy0;
  			weights[ 1 ] = wx1 * wy0;
  			weights[ 2 ] = wx2 * wy0;
  
  			weights[ 3 ] = wx0 * wy1;
  			weights[ 4 ] = wx1 * wy1;
  			weights[ 5 ] = wx2 * wy1;
  
  			#else
  
  			float xden = 2.0 * parentMapSize.x + 1.0;
  			float wx0 = ( parentMapSize.x - parentPixelPos.x ) / xden;
  			float wx1 = ( parentMapSize.x ) / xden;
  			float wx2 = ( parentPixelPos.x + 1.0 ) / xden;
  
  			float yden = 2.0 * parentMapSize.y + 1.0;
  			float wy0 = ( parentMapSize.y - parentPixelPos.y ) / yden;
  			float wy1 = ( parentMapSize.y ) / yden;
  			float wy2 = ( parentPixelPos.y + 1.0 ) / yden;
  
  			samples[ 0 ] = sampleAt( baseUv );
  			samples[ 1 ] = sampleAt( baseUv + vec2( parentPixelSize.x, 0.0 ) );
  			samples[ 2 ] = sampleAt( baseUv + vec2( 2.0 * parentPixelSize.x, 0.0 ) );
  
  			samples[ 3 ] = sampleAt( baseUv + vec2( 0.0, parentPixelSize.y ) );
  			samples[ 4 ] = sampleAt( baseUv + vec2( parentPixelSize.x, parentPixelSize.y ) );
  			samples[ 5 ] = sampleAt( baseUv + vec2( 2.0 * parentPixelSize.x, parentPixelSize.y ) );
  
  			samples[ 6 ] = sampleAt( baseUv + vec2( 0.0, 2.0 * parentPixelSize.y ) );
  			samples[ 7 ] = sampleAt( baseUv + vec2( parentPixelSize.x, 2.0 * parentPixelSize.y ) );
  			samples[ 8 ] = sampleAt( baseUv + vec2( 2.0 * parentPixelSize.x, 2.0 * parentPixelSize.y ) );
  
  			weights[ 0 ] = wx0 * wy0;
  			weights[ 1 ] = wx1 * wy0;
  			weights[ 2 ] = wx2 * wy0;
  
  			weights[ 3 ] = wx0 * wy1;
  			weights[ 4 ] = wx1 * wy1;
  			weights[ 5 ] = wx2 * wy1;
  
  			weights[ 6 ] = wx0 * wy2;
  			weights[ 7 ] = wx1 * wy2;
  			weights[ 8 ] = wx2 * wy2;
  
  			#endif
  
  			<mipmap_logic>
  
  		}
  	`
  
  };
  
  