varying vec3 vNormal;
varying vec2 vUv;

uniform float scale;
uniform float fold;

float sign_not_zero(float x) {
    return x >= 0.0 ? 1.0 : -1.0;
}

vec2 sign_not_zero(vec2 x) {
    return vec2(
        sign_not_zero(x.x),
        sign_not_zero(x.y)
    );
}

vec3 sign_not_zero(vec3 x) {
    return vec3(
        sign_not_zero(x.x),
        sign_not_zero(x.y),
        sign_not_zero(x.z)
    );
}
vec3 OctaSphereEnc(vec2 coord)
{
    coord = (coord - 0.5) * 2.0;
    vec3 position = vec3(coord.x, 0.0, coord.y);
    vec2 absolute = abs(position.xz);
    position.y = 1.0 - absolute.x - absolute.y;

    if (position.y < 0.0)
    {
        position.xz = sign(position.xz) * vec2(1.0 - absolute.y, 1.0 - absolute.x);
    }

    return position;
}

vec2 VecToSphereOct(vec3 v)
{
    float l1norm = abs(v.x) + abs(v.y) + abs(v.z);

    vec2 result = v.xz / l1norm;

    if (v.y < 0.0) {
        result = (1.0 - abs(result.yx)) * sign_not_zero(result.xy);
    }

    return result;
}

void main() {

    vNormal = normalize(normalMatrix * normal);
    vUv = uv;

    vec3 position_grid = vec3(uv.x, 0.0, uv.y);
    vec3 position_octa = normalize(OctaSphereEnc(uv));

    vec3 position_morphed = mix(position_grid, position_octa, fold) * scale;

    gl_Position = projectionMatrix * modelViewMatrix * vec4(position_morphed, 1.0);

}