 }
 params;
 
-vec4 decode_abgr_2_10_10_10(uint base) {
-	uvec4 abgr_2_10_10_10 = (uvec4(base) >> uvec4(0, 10, 20, 30)) & uvec4(0x3FF, 0x3FF, 0x3FF, 0x3);
-	return vec4(abgr_2_10_10_10) / vec4(1023.0, 1023.0, 1023.0, 3.0) * 2.0 - 1.0;
-}
-
-uint encode_abgr_2_10_10_10(vec4 base) {
-	uvec4 abgr_2_10_10_10 = uvec4(clamp(ivec4((base * 0.5 + 0.5) * vec4(1023.0, 1023.0, 1023.0, 3.0)), ivec4(0), ivec4(0x3FF, 0x3FF, 0x3FF, 0x3))) << uvec4(0, 10, 20, 30);
-	return abgr_2_10_10_10.x | abgr_2_10_10_10.y | abgr_2_10_10_10.z | abgr_2_10_10_10.w;
+vec2 uint_to_vec2(uint base) {
+	uvec2 decode = (uvec2(base) >> uvec2(0, 16)) & uvec2(0xFFFF, 0xFFFF);
+	return vec2(decode) / vec2(65535.0, 65535.0) * 2.0 - 1.0;
+}
+
+vec3 oct_to_vec3(vec2 oct) {
+	vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));
+	float t = max(-v.z, 0.0);
+	v.xy += t * -sign(v.xy);
+	return v;
+}
+
+vec3 decode_uint_oct_to_norm(uint base) {
+	return oct_to_vec3(uint_to_vec2(base));
+}
+
+vec4 decode_uint_oct_to_tang(uint base) {
+	vec2 oct_sign_encoded = uint_to_vec2(base);
+	// Binormal sign encoded in y component
+	vec2 oct = vec2(oct_sign_encoded.x, abs(oct_sign_encoded.y) * 2.0 - 1.0);
+	return vec4(oct_to_vec3(oct), sign(oct_sign_encoded.y));
+}
+
+vec2 signNotZero(vec2 v) {
+	return mix(vec2(-1.0), vec2(1.0), greaterThanEqual(v.xy, vec2(0.0)));
+}
+
+uint vec2_to_uint(vec2 base) {
+	uvec2 enc = uvec2(clamp(ivec2(base * vec2(65535, 65535)), ivec2(0), ivec2(0xFFFF, 0xFFFF))) << uvec2(0, 16);
+	return enc.x | enc.y;
+}
+
+vec2 vec3_to_oct(vec3 e) {
+	e /= abs(e.x) + abs(e.y) + abs(e.z);
+	vec2 oct = e.z >= 0.0f ? e.xy : (vec2(1.0f) - abs(e.yx)) * signNotZero(e.xy);
+	return oct * 0.5f + 0.5f;
+}
+
+uint encode_norm_to_uint_oct(vec3 base) {
+	return vec2_to_uint(vec3_to_oct(base));
+}
+
+uint encode_tang_to_uint_oct(vec4 base) {
+	vec2 oct = vec3_to_oct(base.xyz);
+	// Encode binormal sign in y component
+	oct.y = oct.y * 0.5f + 0.5f;
+	oct.y = base.w >= 0.0f ? oct.y : 1 - oct.y;
+	return vec2_to_uint(oct);
 }
 
 void main() {

				base_offset += 3;

				if (params.has_normal) {
					blend_normal += decode_abgr_2_10_10_10(src_blend_shapes.data[base_offset]).rgb * w;
					base_offset++;
				}

				if (params.has_tangent) {
					blend_tangent += decode_abgr_2_10_10_10(src_blend_shapes.data[base_offset]).rgb * w;
				}

				blend_total += w;

	src_offset += 3;

	if (params.has_normal) {
		normal = decode_uint_oct_to_norm(src_vertices.data[src_offset]);
		src_offset++;
	}

	if (params.has_tangent) {
		tangent = decode_uint_oct_to_tang(src_vertices.data[src_offset]);
	}

	if (params.has_blend_shape) {
