Source: projection-glsl.js

/**
    @module GLSL
*/

/**
    Project a longitude/latitude/elevation coordinate into mercator space.

    @function mercator_gl_lngLatToMercator
    @param {vec3} lngLatElevation Longitude/latitude/meter elevation coordinate.
    @param {vec2} lngLatPrecision "Low part" of 64-bit longitude/latitude coordinates.
    @return {vec4} Homegeneous representation of mercator position.
*/

/**
    Project a longitude/latitude/elevation coordinate into mercator space without
    enhanced precition. Equivalent to <code>mercator_gl_lngLatToMercator(lngLatElevation, vec2(0.0))</code>.

    @function mercator_gl_lngLatToMercator
    @param {vec3} lngLatElevation Longitude/latitude/meter elevation coordinate.
    @return {vec4} Homegeneous representation of mercator position.
*/

/**
    Project a longitude/latitude coordinate into mercator space. Equivalent
    to <code>mercator_gl_lngLatToMercator(vec3(lngLat, 0.0), lngLatPrecision)</code>.

    @function mercator_gl_lngLatToMercator
    @param {vec2} lngLat Longitude/latitude coordinate.
    @param {vec2} lngLatPrecision "Low part" of 64-bit longitude/latitude coordinates.
    @return {vec4} Homegeneous representation of mercator position.
*/

/**
    Project a longitude/latitude coordinate into mercator space without
    enhanced precition. Equivalent to <code>mercator_gl_lngLatToMercator(vec3(lngLat, 0.0), vec2(0.0))</code>.

    @function mercator_gl_lngLatToMercator
    @param {vec2} lngLat Longitude/latitude coordinate.
    @return {vec4} Homegeneous representation of mercator position.
*/

/**
    Project a longitude/latitude coordinate into mercator space without
    enhanced precition. Equivalent to <code>mercator_gl_lngLatToMercator(vec3(lngLat, 0.0), vec2(0.0))</code>.

    @function mercator_gl_lngLatToMercator
    @param {vec2} lngLat Longitude/latitude coordinate.
    @return {vec4} Homegeneous representation of mercator position.
*/

/**
    Project a homegeneous 4d mercator coordinate to clip space.

    @function mercator_gl_mercatorToClip
    @param {vec4} mercatorPosition x/y/<meter elevation/1 homegeneous mercator coordinate.
    @return {vec4} Clip space coordinate (can be passed to <code>gl_Position</code>).
*/

/**
    Project a longitude/latitude/elevation coordinate into clip space.

    @function mercator_gl_lngLatToClip
    @param {vec3} lngLatElevation Longitude/latitude/meter elevation coordinate.
    @param {vec2} lngLatPrecision "Low part" of 64-bit longitude/latitude coordinates.
    @return {vec4} Clip space coordinate (can be passed to <code>gl_Position</code>).
*/

/**
    Project a longitude/latitude/elevation coordinate into clip space without
    enhanced precition. Equivalent to <code>mercator_gl_lngLatToClip(lngLatElevation, vec2(0.0))</code>.

    @function mercator_gl_lngLatToClip
    @param {vec3} lngLatElevation Longitude/latitude/meter elevation coordinate.
    @return {vec4} Clip space coordinate (can be passed to <code>gl_Position</code>).
*/

/**
    Project a longitude/latitude coordinate into clip space. Equivalent
    to <code>mercator_gl_lngLatToClip(vec3(lngLat, 0.0), lngLatPrecision)</code>.

    @function mercator_gl_lngLatToClip
    @param {vec2} lngLat Longitude/latitude coordinate.
    @param {vec2} lngLatPrecision "Low part" of 64-bit longitude/latitude coordinates.
    @return {vec4} Clip space coordinate (can be passed to <code>gl_Position</code>).
*/

/**
    Project a longitude/latitude coordinate into clip space without
    enhanced precition. Equivalent to <code>mercator_gl_lngLatToClip(vec3(lngLat, 0.0), vec2(0.0))</code>.

    @function mercator_gl_lngLatToClip
    @param {vec2} lngLat Longitude/latitude coordinate.
    @return {vec4} Clip space coordinate (can be passed to <code>gl_Position</code>).
*/

/**
    Project a longitude/latitude coordinate into clip space without
    enhanced precition. Equivalent to <code>mercator_gl_lngLatToClip(vec3(lngLat, 0.0), vec2(0.0))</code>.

    @function mercator_gl_lngLatToClip
    @param {vec2} lngLat Longitude/latitude coordinate.
    @return {vec4} Clip space coordinate (can be passed to <code>gl_Position</code>).
*/

export const PROJECTION_GLSL = `
#define MERCATOR_GL_TILE_SIZE 512.0
#define MERCATOR_GL_PI 3.1415926536
#define MERCATOR_GL_TILE_SCALE (MERCATOR_GL_TILE_SIZE / (MERCATOR_GL_PI * 2.0))
#define MERCATOR_GL_OFFSET_THRESHOLD 4096.0

uniform vec2 mercator_gl_lngLatCenter;
uniform vec3 mercator_gl_angleDerivatives;
uniform float mercator_gl_scale;
uniform vec4 mercator_gl_clipCenter;
uniform mat4 mercator_gl_viewProjectionMatrix;

vec4 mercator_gl_lngLatToMercator(vec3 lngLatElevation, vec2 lngLatPrecision) {
    vec3 mercatorPosition;
    if (mercator_gl_scale < MERCATOR_GL_OFFSET_THRESHOLD) {
        mercatorPosition.xy = vec2(
            (radians(lngLatElevation.x) + MERCATOR_GL_PI) * MERCATOR_GL_TILE_SCALE,
            (MERCATOR_GL_PI - log(tan(MERCATOR_GL_PI * 0.25 + radians(lngLatElevation.y) * 0.5))) * MERCATOR_GL_TILE_SCALE
        ) * mercator_gl_scale;
        mercatorPosition.z = lngLatElevation.z;
    } else {
        mercatorPosition.xy = (lngLatElevation.xy - mercator_gl_lngLatCenter) + lngLatPrecision;
        float dy = mercatorPosition.y;
        mercatorPosition = vec3(
            mercatorPosition.x * mercator_gl_angleDerivatives.x,
            -mercatorPosition.y * (mercator_gl_angleDerivatives.y - dy * mercator_gl_angleDerivatives.z),
            lngLatElevation.z
        );
    }

    return vec4(mercatorPosition, 1.0);
}

vec4 mercator_gl_lngLatToMercator(vec3 lngLatElevation) {
    return mercator_gl_lngLatToMercator(lngLatElevation, vec2(0.0));
}

vec4 mercator_gl_lngLatToMercator(vec2 lngLat, vec2 lngLatPrecision) {
    return mercator_gl_lngLatToMercator(vec3(lngLat, 0.0), lngLatPrecision);
}

vec4 mercator_gl_lngLatToMercator(vec2 lngLat) {
    return mercator_gl_lngLatToMercator(vec3(lngLat, 0.0));
}

vec4 mercator_gl_mercatorToClip(vec4 mercatorPosition) {
    if (mercator_gl_scale >= MERCATOR_GL_OFFSET_THRESHOLD) {
        mercatorPosition.w = 0.0;
    }
    vec4 clipPosition = mercator_gl_viewProjectionMatrix * mercatorPosition;
    if (mercator_gl_scale >= MERCATOR_GL_OFFSET_THRESHOLD) {
        clipPosition += mercator_gl_clipCenter;
    }

    return clipPosition;
}

vec4 mercator_gl_lngLatToClip(vec3 lngLatElevation, vec2 lngLatPrecision) {
    return mercator_gl_mercatorToClip(mercator_gl_lngLatToMercator(lngLatElevation, lngLatPrecision));
}

vec4 mercator_gl_lngLatToClip(vec3 lngLatElevation) {
    return mercator_gl_lngLatToClip(lngLatElevation, vec2(0.0));
}

vec4 mercator_gl_lngLatToClip(vec2 lngLat, vec2 lngLatPrecision) {
    return mercator_gl_lngLatToClip(vec3(lngLat, 0.0), lngLatPrecision);
}

vec4 mercator_gl_lngLatToClip(vec2 lngLat) {
    return mercator_gl_lngLatToClip(vec3(lngLat, 0.0));
}

`;