import {
    DataTexture,
    LinearMipMapLinearFilter,
    NearestFilter,
    NormalBlending,
    RGBAFormat,
    ShaderMaterial,
    Vector2 as ThreeVector2
} from "three";

/**
 *
 * @return {ShaderMaterial}
 */
export function buildMaterial() {
    function vertexShader() {
        return `
            attribute float size;
            attribute vec4 aPatch;
            
			varying vec4 vPatch;
			
			uniform vec2 resolution;
			
			vec2 extractScale2D(mat4 matrix){
			    float sx = length(matrix[0].xy);
			    float sz = length(matrix[2].xy);
			
			    return vec2(sx, sz);
			}
			
			void main() {
			    vPatch = aPatch;
				vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
				
				//extract scale
				vec2 scale =  extractScale2D(projectionMatrix);

                float radius = size / 2.0;
							
				gl_Position = projectionMatrix * mvPosition;
				gl_PointSize = resolution.y * radius * max(scale.x, scale.y);
			}`;
    }

    function fragmentShader() {
        return `
            uniform sampler2D atlas;
            
			varying vec4 vPatch;
			void main() {
			    vec2 uv = gl_PointCoord*vPatch.zw + vPatch.xy;
			    vec4 texel = texture2D( atlas, uv );
			    
			    if(texel.a == 0.0){
			        discard;
			    }
			    
				gl_FragColor = texel;
			}`;
    }


    const dataTexture = new DataTexture(new Uint8Array(4), 1, 1, RGBAFormat);
    dataTexture.flipY = false;
    dataTexture.generateMipmaps = true;
    dataTexture.minFilter = LinearMipMapLinearFilter;
    dataTexture.magFilter = NearestFilter;

    const uniforms = {
        atlas: {
            type: 't',
            value: dataTexture
        },
        resolution: {
            type: 'v2',
            value: new ThreeVector2()
        }
    };

    const material = new ShaderMaterial({
        uniforms,
        vertexShader: vertexShader(),
        fragmentShader: fragmentShader(),
        blending: NormalBlending,
        lights: false,
        fog: false,
        depthTest: false,
        transparent: true,
        vertexColors: false
    });

    return material;
}
