function vertex() {
    return `
    precision mediump float;
    precision mediump int;
    
    uniform mat4 modelViewMatrix;
    uniform mat4 projectionMatrix;
    
    in vec2 uv;
    in vec3 position;
    
    out vec2 vUv;
    void main()
    {
        vUv = uv;
        
        vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
        gl_Position = projectionMatrix * mvPosition;
    }
`
}

function fragment() {
    return `
    precision highp float;
    precision highp int;
    
    uniform uvec4 u_mt_tex; // [ width, height, tileSize, id ]
    uniform vec2 u_mt_params; // [ bias, maxLevel ]
    uniform vec2 u_mt_viewport_scale;
    in vec2 vUv;
    
    out uvec4 out_decoded;
    
    float MTCalculateMipLevel( const in vec2 uv, const in float bias ) {
        
        float scale_x = float(u_mt_tex.x) ;
        float scale_y = float(u_mt_tex.y) ;
        
        vec2 dx = dFdx( uv * scale_x ) * u_mt_viewport_scale.x;
        vec2 dy = dFdy( uv * scale_y ) * u_mt_viewport_scale.y;
        
        float d = max( dot( dx, dx ), dot( dy, dy ) );
        
        return log2( d ) * 0.5 + bias;
    }
    
    uvec4 MTCalculateTileKeyRGBA( const in vec2 uv ) {
       uint level = clamp(  uint( floor( MTCalculateMipLevel( uv, u_mt_params.x ) ) ), 0u, uint(u_mt_params.y) );
       
       uint mip_resolution_in_tiles = 1u << level;
       
       uint mip_resolution_in_texels = mip_resolution_in_tiles * u_mt_tex.z;
              
       vec2 texel_position = fract(uv.xy) * vec2(u_mt_tex.xy);
            
       uvec2 tile_position = uvec2( texel_position / float(mip_resolution_in_texels)  );
           
       // [ level, tileX, tileY, texId ] -> RGBA
       return uvec4( uint(u_mt_params.y) - level, tile_position, u_mt_tex.w );
    }
    
        
    void main(){
        out_decoded =  MTCalculateTileKeyRGBA(vUv);
    }
`;
}

export {
    vertex,
    fragment
};
