const float Values_16Bit = exp2(16) - 1.0;

float Pack2x8(vec2 x) {
	return dot(floor(255.0 * x + 0.5), vec2(1.0 / 65535.0, 256.0 / 65535.0));
} 
float Pack2x8(float x, float y) { return Pack2x8(vec2(x, y)); }
float Pack2x8Dithered(vec2 x, float pattern) {
	return dot(floor(255.0 * x + pattern), vec2(1.0 / 65535.0, 256.0 / 65535.0));
} float Pack2x8Dithered(float x, float y, float pattern) { return Pack2x8Dithered(vec2(x, y), pattern); }

vec2 Unpack2x8(float pack) {
	pack *= 65535.0 / 256.0;
	vec2 xy; xy.y = floor(pack); xy.x = pack - xy.y;
	return vec2(256.0 / 255.0, 1.0 / 255.0) * xy;
}
void Unpack2x8(float pack, out float x, out float y) {
	vec2 xy = Unpack2x8(pack);
	x = xy.x; y = xy.y;
}
float Unpack2x8X(float x) { return (256.0 / 255.0) * fract(x * (65535.0 / 256.0)); }
float Unpack2x8Y(float x) { return floor(x * (65535.0 / 256.0)) / 255.0; }

float Pack2x4(vec2 x) {
	return dot(floor(15.0 * x + 0.5), vec2(1.0 / 255.0, 16.0 / 255.0));
}
vec2 Unpack2x4(float pack) {
	pack *= 255.0 / 16.0;
	vec2 xy; xy.y = floor(pack); xy.x = pack - xy.y;
	return vec2(16.0 / 15.0, 1.0 / 15.0) * xy;
}

float encode2x16(vec2 a){
    ivec2 bf = ivec2(a*255.);
    return float( bf.x|(bf.y<<8) ) / 65535.;
}

vec2 decode2x16(float a){
    int bf = int(a*65535.);
    return vec2(bf%256, bf>>8) / 255.;
}

float encode3x16(vec3 a){
    vec3 m = vec3(31,63,31);
    a = clamp(a,0.0,1.0);
    ivec3 b = ivec3(a*m);
    return float( b.r|(b.g<<5)|(b.b<<11) ) / 65535.;
}

vec3 decode3x16(float a){
    int bf = int(a*65535.);
    return vec3(bf%32, (bf>>5)%64, bf>>11) / vec3(31,63,31);
}

float encodeNormal3x16(vec3 normal){
    // Scale down to octahedron, project onto XY plane
    normal.xy /= abs(normal.x) + abs(normal.y) + abs(normal.z);
    // Reflect -Z hemisphere folds over the diagonals
    vec2 encoded = (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;
    return Pack2x8(encoded);
}

vec3 decodeNormal3x16(float a){
    vec2 encoded = Unpack2x8(a) * 2.0 - 1.0;
    // Exctract Z component
    vec3 normal = vec3(encoded, 1.0 - abs(encoded.x) - abs(encoded.y));
    // Reflect -Z hemisphere folds over the diagonals
    float t = max(-normal.z, 0.0);
    normal.xy += vec2(normal.x >= 0.0 ? -t : t, normal.y >= 0.0 ? -t : t);
    // Normalize and return
    return normalize(normal);
}


// vec2 encodeNormal2 (vec3 n)
// {
//     float p = sqrt(n.z*8+8);
//     return n.xy/p + 0.5;
// }
// vec3 reconstructNormal (vec2 enc)
// {
//     vec2 fenc = enc*4-2;
//     float f = dot(fenc,fenc);
//     float g = sqrt(1-f/4);
//     vec3 n;
//     n.xy = fenc*g;
//     n.z = 1-f/2;
//     return n;
// }

// vec2 encodeNormal2 (vec3 n)
// {
//     const float scale = 1.7777;
//     vec2 enc = n.xy / (n.z+1);
//     enc /= scale;
//     enc = enc*0.5+0.5;
//     return enc;
// }
// vec3 reconstructNormal (vec2 enc)
// {
//     float scale = 1.7777;
//     vec3 nn =
//         vec3(enc*2*scale, 0.0) +
//         vec3(-scale,-scale,1);
//     float g = 2.0 / dot(nn,nn);
//     vec3 n;
//     n.xy = g*nn.xy;
//     n.z = g-1;
//     return n;
// }

#define kPI 3.1415926536f
vec2 encodeNormal2 (vec3 n)
{
    return (vec2(atan(n.y,n.x)/kPI, n.z)+1.0)*0.5;
}
vec3 reconstructNormal (vec2 enc)
{
    vec2 ang = enc*2-1;
    vec2 scth = vec2(sin(ang.x * kPI), cos(ang.x * kPI));
    vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y);
    return vec3(scth.y*scphi.x, scth.x*scphi.x, scphi.y);
}

vec4 getTangentNormals(sampler2D tex, vec2 coord) {
    vec4 normal = texture2D(tex,  coord) * 2.0 - 1.0;
    return vec4(normal.xyz, normal.w);
}

vec4 getTangentNormals(sampler2D tex, vec2 coord, out float ao) {
    vec4 normal = texture2D(tex,  coord);
    ao = normal.b;
    normal = normal * 2.0 - 1.0;
    return vec4((vec3(normal.x, normal.y, sqrt(1.0 - dot(normal.xy, normal.xy)))), normal.a);
}
// vec2 encodeNormal2 (vec3 n) {
//     vec2 enc = normalize(n.xy) * (sqrt(-n.z*0.5+0.5));
//     enc = enc*0.5+0.5;
//     return enc;
// }
// vec3 reconstructNormal (vec2 enc)
// {
//     vec4 nn = vec4(2*enc.x,2*enc.y,0,0) + vec4(-1,-1,1,-1);
//     float l = dot(nn.xyz,-nn.xyw);
//     nn.z = l;
//     nn.xy *= sqrt(l);
//     return nn.xyz * 2 + vec3(0,0,-1);
// }

// float encodeNormal3x16(vec3 a){
//     vec3 b  = abs(a);
//     vec2 p  = a.xy / (b.x + b.y + b.z);
//     vec2 sp = vec2(greaterThanEqual(p, vec2(0.0))) * 2.0 - 1.0;

//     vec2 encoded = a.z <= 0.0 ? (1.0 - abs(p.yx)) * sp : p;

//     encoded = encoded * 0.5 + 0.5;

//     return encode2x16(encoded);
// }

// vec3 decodeNormal3x16(float encoded){
//     vec2 a = decode2x16(encoded);

//     a = a * 2.0 - 1.0;
//     vec2 b = abs(a);
//     float z = 1.0 - b.x - b.y;
//     vec2 sa = vec2(greaterThanEqual(a, vec2(0.0))) * 2.0 - 1.0;

//     vec3 decoded = normalize(vec3(
//         z < 0.0 ? (1.0 - b.yx) * sa : a.xy,
//         z
//     ));

//     return decoded;
// }