


///////

//////////////////////////////////////////////////////////

vec3 spherical_surface(vec2 uv)
{

    // Adjust phi to range from 0 to 2PI for a full rotation around the sphere
    float phi = (TWO_PI * uv.x - 1.5708); // Azimuthal angle
    // theta remains as is, ranging from 0 to PI to cover from pole to pole
    float theta = PI * uv.y; // Polar angle

    // Compute spherical coordinates
    float phi_s = sin(phi);

    float phi_c = cos(phi);
    float theta_s = sin(theta);

    float theta_c = cos(theta);

    // Convert to Cartesian coordinates
    return vec3(theta_s * phi_c, theta_s * phi_s, theta_c);
}

vec2 spherical_coordinates(vec3 xyz)
{
    // Cartesian coordinates
    float x = xyz.x;
    float y = xyz.y;
    float z = xyz.z;

    // Compute spherical coordinates
    float theta = acos(z / length(xyz)); // Polar angle
    float phi = (atan(y, x) + 1.5708);   // Azimuthal angle

    // Normalize to [0, 1] for UV mapping
    float u = phi / TWO_PI;
    if (u < 0.0)
        u += 1.0;
    float v = theta / PI;

    return vec2(u, v);
}

vec3 mapUVToSphere(vec2 uv)
{

    return spherical_surface(uv);

    float lon = (uv.x - 0.5) * TWO_PI;

    float lat = uv.y * PI;

    float x = sin(lat) * cos(lon);
    float y = cos(lat);
    float z = sin(lat) * sin(lon);

    return normalize(vec3(x, y, z));
}

vec4 skyFromTex2(vec3 pos, sampler2D sampler)
{
    vec2 p = spherical_coordinates(normalize(pos));

    return texture2D(sampler, p);
}

float PackUnorm2x8(vec2 xy)
{
    return dot(floor(255.0 * xy + 0.5), vec2(1.0 / 65535.0, 256.0 / 65535.0));
}
vec2 UnpackUnorm2x8(float pack)
{
    vec2 xy;
    xy.x = modf(pack * 255.996094, xy.y);

    return xy * vec2(1.003922, 0.00392156862);
}
float UnpackUnorm2x8X(float pack)
{
    return fract(pack * 65535.0 * 0.00390625) * 256.0 * recip;
}
float UnpackUnorm2x8Y(float pack)
{
    return floor(pack * 65535.0 * 0.00390625) * recip;
}

uint packSnorm4x8(vec4 x)
{
    x = clamp(x, -1.0, 1.0) * 127.0;
    uvec4 sig = uvec4(mix(vec4(0), vec4(1), greaterThanEqual(sign(x), vec4(0))));
    uvec4 mag = uvec4(abs(x));
    uvec4 r = sig << 7 | mag;
    return r.x << 24 | r.y << 16 | r.z << 8 | r.w;
}

vec4 unpackSnorm4x8(uint x)
{
    uvec4 r = (uvec4(x) >> uvec4(24, 16, 8, 0)) & uvec4(0xFF);
    uvec4 sig = r >> 7;
    uvec4 mag = r & uvec4(0x7F);
    vec4 fsig = mix(vec4(-1), vec4(1), greaterThanEqual(sig, uvec4(1)));
    vec4 fmag = vec4(mag) / 127.0;
    return fsig * fmag;
}
uint packSnorm3x10(vec3 x)
{
    x = clamp(x, -1., 1.) * 511.;
    uvec3 sig = uvec3(mix(vec3(0), vec3(1), greaterThanEqual(sign(x), vec3(0))));
    uvec3 mag = uvec3(abs(x));
    uvec3 r = sig.xyz << 9 | mag.xyz;
    return r.x << 22 | r.y << 12 | r.z << 2;
}

vec3 unpackSnorm3x10(uint x)
{
    uvec3 r = (uvec3(x) >> uvec3(22, 12, 2)) & uvec3(0x3FF);
    uvec3 sig = r >> 9;
    uvec3 mag = r & uvec3(0x1FF);
    vec3 fsig = mix(vec3(-1), vec3(1), greaterThanEqual(sig, uvec3(1)));
    vec3 fmag = vec3(mag) / 511.;
    return fsig * fmag;
}

#define unpack(x) unpackSnorm4x8(floatBitsToUint(x))
#define pack(x) uintBitsToFloat(packSnorm4x8(x))
#define pack2(x) uintBitsToFloat(packSnorm3x10(x))
#define unpack2(x) unpackSnorm3x10(floatBitsToUint(x))

//////////
/*
    Normals encoding and decoding based on Spectrum by Zombye
*/
vec2 encodeNormal(in vec3 normal)
{
    normal.xy /= abs(normal.x) + abs(normal.y) + abs(normal.z);
    return (normal.z <= 0.0 ? (1.0 - abs(normal.yx)) * vec2(normal.x >= 0.0 ? 1.0 : -1.0, normal.y >= 0.0 ? 1.0 : -1.0)
                            : normal.xy) *
               0.5 +
           0.5;
}
vec3 decodeNormal(in vec2 encodedNormal)
{
    encodedNormal = encodedNormal * 2.0 - 1.0;
    vec3 normal = vec3(encodedNormal, 1.0 - abs(encodedNormal.x) - abs(encodedNormal.y));
    float t = max(-normal.z, 0.0);
    normal.xy += vec2(normal.x >= 0.0 ? -t : t, normal.y >= 0.0 ? -t : t);
    return normalize(normal);
}
float encodeVec2(vec2 a)
{
    const vec2 constant1 = vec2(1., 256.0) / 65535.0;
    vec2 temp = floor(a * 255.0);
    return temp.x * constant1.x + temp.y * constant1.y;
}
float encodeVec2(float x, float y)
{
    return encodeVec2(vec2(x, y));
}
vec2 decodeVec2(float a)
{
    const vec2 constant1 = 65535.0 / vec2(256.0, 65536.0);
    const float constant2 = 256.0 / 255.;
    return fract(a * constant1) * constant2;
}
