gputex 0.3.4 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +173 -93
- package/dist/index.d.ts +198 -67
- package/dist/index.js +1406 -672
- package/dist/testing.d.ts +52 -15
- package/dist/testing.js +935 -109
- package/dist/three.d.ts +80 -21
- package/dist/three.js +1740 -719
- package/package.json +1 -1
package/dist/testing.js
CHANGED
|
@@ -679,12 +679,239 @@ function decodeBC7Mode6Block(block) {
|
|
|
679
679
|
}
|
|
680
680
|
return out;
|
|
681
681
|
}
|
|
682
|
+
var BC7_PARTITION2 = [
|
|
683
|
+
52428,
|
|
684
|
+
34952,
|
|
685
|
+
61166,
|
|
686
|
+
60616,
|
|
687
|
+
51328,
|
|
688
|
+
65260,
|
|
689
|
+
65224,
|
|
690
|
+
60544,
|
|
691
|
+
51200,
|
|
692
|
+
65516,
|
|
693
|
+
65152,
|
|
694
|
+
59392,
|
|
695
|
+
65512,
|
|
696
|
+
65280,
|
|
697
|
+
65520,
|
|
698
|
+
61440,
|
|
699
|
+
63248,
|
|
700
|
+
142,
|
|
701
|
+
28928,
|
|
702
|
+
2254,
|
|
703
|
+
140,
|
|
704
|
+
29456,
|
|
705
|
+
12544,
|
|
706
|
+
36046,
|
|
707
|
+
2188,
|
|
708
|
+
12560,
|
|
709
|
+
26214,
|
|
710
|
+
13932,
|
|
711
|
+
6120,
|
|
712
|
+
4080,
|
|
713
|
+
29070,
|
|
714
|
+
14748,
|
|
715
|
+
43690,
|
|
716
|
+
61680,
|
|
717
|
+
23130,
|
|
718
|
+
13260,
|
|
719
|
+
15420,
|
|
720
|
+
21930,
|
|
721
|
+
38550,
|
|
722
|
+
42330,
|
|
723
|
+
29646,
|
|
724
|
+
5064,
|
|
725
|
+
12876,
|
|
726
|
+
15324,
|
|
727
|
+
27030,
|
|
728
|
+
49980,
|
|
729
|
+
39270,
|
|
730
|
+
1632,
|
|
731
|
+
626,
|
|
732
|
+
1252,
|
|
733
|
+
20032,
|
|
734
|
+
10016,
|
|
735
|
+
51510,
|
|
736
|
+
37740,
|
|
737
|
+
14790,
|
|
738
|
+
25500,
|
|
739
|
+
37686,
|
|
740
|
+
40134,
|
|
741
|
+
33150,
|
|
742
|
+
59160,
|
|
743
|
+
52464,
|
|
744
|
+
4044,
|
|
745
|
+
30532,
|
|
746
|
+
60962
|
|
747
|
+
];
|
|
748
|
+
var BC7_ANCHOR2 = [
|
|
749
|
+
15,
|
|
750
|
+
15,
|
|
751
|
+
15,
|
|
752
|
+
15,
|
|
753
|
+
15,
|
|
754
|
+
15,
|
|
755
|
+
15,
|
|
756
|
+
15,
|
|
757
|
+
15,
|
|
758
|
+
15,
|
|
759
|
+
15,
|
|
760
|
+
15,
|
|
761
|
+
15,
|
|
762
|
+
15,
|
|
763
|
+
15,
|
|
764
|
+
15,
|
|
765
|
+
15,
|
|
766
|
+
2,
|
|
767
|
+
8,
|
|
768
|
+
2,
|
|
769
|
+
2,
|
|
770
|
+
8,
|
|
771
|
+
8,
|
|
772
|
+
15,
|
|
773
|
+
2,
|
|
774
|
+
8,
|
|
775
|
+
2,
|
|
776
|
+
2,
|
|
777
|
+
8,
|
|
778
|
+
8,
|
|
779
|
+
2,
|
|
780
|
+
2,
|
|
781
|
+
15,
|
|
782
|
+
15,
|
|
783
|
+
6,
|
|
784
|
+
8,
|
|
785
|
+
2,
|
|
786
|
+
8,
|
|
787
|
+
15,
|
|
788
|
+
15,
|
|
789
|
+
2,
|
|
790
|
+
8,
|
|
791
|
+
2,
|
|
792
|
+
2,
|
|
793
|
+
2,
|
|
794
|
+
15,
|
|
795
|
+
15,
|
|
796
|
+
6,
|
|
797
|
+
6,
|
|
798
|
+
2,
|
|
799
|
+
6,
|
|
800
|
+
8,
|
|
801
|
+
15,
|
|
802
|
+
15,
|
|
803
|
+
2,
|
|
804
|
+
2,
|
|
805
|
+
15,
|
|
806
|
+
15,
|
|
807
|
+
15,
|
|
808
|
+
15,
|
|
809
|
+
15,
|
|
810
|
+
2,
|
|
811
|
+
2,
|
|
812
|
+
15
|
|
813
|
+
];
|
|
814
|
+
var W3 = [0, 9, 18, 27, 37, 46, 55, 64];
|
|
815
|
+
function decodeBC7Mode1Block(block) {
|
|
816
|
+
if (block.length !== 16) {
|
|
817
|
+
throw new Error(`decodeBC7Mode1Block: expected 16 bytes, got ${block.length}`);
|
|
818
|
+
}
|
|
819
|
+
const mode = readBC7Mode(block);
|
|
820
|
+
if (mode !== 1) {
|
|
821
|
+
throw new Error(`decodeBC7Mode1Block: expected mode 1, got mode ${mode}`);
|
|
822
|
+
}
|
|
823
|
+
const br = new BitReader128(block);
|
|
824
|
+
br.read(2);
|
|
825
|
+
const part = br.read(6);
|
|
826
|
+
const ep = [[], [], [], []];
|
|
827
|
+
for (let c = 0; c < 3; c++) {
|
|
828
|
+
for (let e = 0; e < 4; e++) ep[e].push(br.read(6));
|
|
829
|
+
}
|
|
830
|
+
const p0 = br.read(1);
|
|
831
|
+
const p1 = br.read(1);
|
|
832
|
+
const pbits = [p0, p0, p1, p1];
|
|
833
|
+
const e8 = ep.map(
|
|
834
|
+
(rgb, e) => rgb.map((v6) => {
|
|
835
|
+
const v7 = v6 << 1 | pbits[e];
|
|
836
|
+
return v7 << 1 | v7 >> 6;
|
|
837
|
+
})
|
|
838
|
+
);
|
|
839
|
+
const pal = [0, 1].map((s) => {
|
|
840
|
+
const lo = e8[s * 2];
|
|
841
|
+
const hi = e8[s * 2 + 1];
|
|
842
|
+
return W3.map((w) => [0, 1, 2].map((c) => ((64 - w) * lo[c] + w * hi[c] + 32 >> 6) / 255));
|
|
843
|
+
});
|
|
844
|
+
const anchor2 = BC7_ANCHOR2[part];
|
|
845
|
+
const mask = BC7_PARTITION2[part];
|
|
846
|
+
const out = new Float32Array(64);
|
|
847
|
+
for (let k = 0; k < 16; k++) {
|
|
848
|
+
const w = br.read(k === 0 || k === anchor2 ? 2 : 3);
|
|
849
|
+
const subset = mask >> k & 1;
|
|
850
|
+
const rgb = pal[subset][w];
|
|
851
|
+
out[k * 4] = rgb[0];
|
|
852
|
+
out[k * 4 + 1] = rgb[1];
|
|
853
|
+
out[k * 4 + 2] = rgb[2];
|
|
854
|
+
out[k * 4 + 3] = 1;
|
|
855
|
+
}
|
|
856
|
+
return out;
|
|
857
|
+
}
|
|
858
|
+
var W2 = [0, 21, 43, 64];
|
|
859
|
+
function decodeBC7Mode4Block(block) {
|
|
860
|
+
if (block.length !== 16) {
|
|
861
|
+
throw new Error(`decodeBC7Mode4Block: expected 16 bytes, got ${block.length}`);
|
|
862
|
+
}
|
|
863
|
+
const mode = readBC7Mode(block);
|
|
864
|
+
if (mode !== 4) {
|
|
865
|
+
throw new Error(`decodeBC7Mode4Block: expected mode 4, got mode ${mode}`);
|
|
866
|
+
}
|
|
867
|
+
const br = new BitReader128(block);
|
|
868
|
+
br.read(5);
|
|
869
|
+
const rotation = br.read(2);
|
|
870
|
+
const idxMode = br.read(1);
|
|
871
|
+
const c5 = [];
|
|
872
|
+
for (let i = 0; i < 6; i++) c5.push(br.read(5));
|
|
873
|
+
const a6 = [br.read(6), br.read(6)];
|
|
874
|
+
const c8 = c5.map((v) => v << 3 | v >> 2);
|
|
875
|
+
const a8 = a6.map((v) => v << 2 | v >> 4);
|
|
876
|
+
const e0 = [c8[0], c8[2], c8[4]];
|
|
877
|
+
const e1 = [c8[1], c8[3], c8[5]];
|
|
878
|
+
const w2idx = new Uint8Array(16);
|
|
879
|
+
for (let k = 0; k < 16; k++) w2idx[k] = br.read(k === 0 ? 1 : 2);
|
|
880
|
+
const w3idx = new Uint8Array(16);
|
|
881
|
+
for (let k = 0; k < 16; k++) w3idx[k] = br.read(k === 0 ? 2 : 3);
|
|
882
|
+
const out = new Float32Array(64);
|
|
883
|
+
for (let k = 0; k < 16; k++) {
|
|
884
|
+
const cw = idxMode === 0 ? W2[w2idx[k]] : W3[w3idx[k]];
|
|
885
|
+
const aw = idxMode === 0 ? W3[w3idx[k]] : W2[w2idx[k]];
|
|
886
|
+
const px = [
|
|
887
|
+
interp8(e0[0], e1[0], cw),
|
|
888
|
+
interp8(e0[1], e1[1], cw),
|
|
889
|
+
interp8(e0[2], e1[2], cw),
|
|
890
|
+
interp8(a8[0], a8[1], aw)
|
|
891
|
+
];
|
|
892
|
+
if (rotation > 0) {
|
|
893
|
+
const c = rotation - 1;
|
|
894
|
+
const t = px[3];
|
|
895
|
+
px[3] = px[c];
|
|
896
|
+
px[c] = t;
|
|
897
|
+
}
|
|
898
|
+
out[k * 4] = px[0] / 255;
|
|
899
|
+
out[k * 4 + 1] = px[1] / 255;
|
|
900
|
+
out[k * 4 + 2] = px[2] / 255;
|
|
901
|
+
out[k * 4 + 3] = px[3] / 255;
|
|
902
|
+
}
|
|
903
|
+
return out;
|
|
904
|
+
}
|
|
682
905
|
function encodeBC7Block(pixels) {
|
|
683
906
|
return encodeBC7Mode6Block(pixels);
|
|
684
907
|
}
|
|
685
908
|
function decodeBC7Block(block) {
|
|
686
909
|
const mode = readBC7Mode(block);
|
|
687
910
|
switch (mode) {
|
|
911
|
+
case 1:
|
|
912
|
+
return decodeBC7Mode1Block(block);
|
|
913
|
+
case 4:
|
|
914
|
+
return decodeBC7Mode4Block(block);
|
|
688
915
|
case 6:
|
|
689
916
|
return decodeBC7Mode6Block(block);
|
|
690
917
|
default:
|
|
@@ -694,16 +921,43 @@ function decodeBC7Block(block) {
|
|
|
694
921
|
|
|
695
922
|
// src/astc4x4_ref.ts
|
|
696
923
|
var BLOCK_MODE_4x4_2BIT = 66;
|
|
924
|
+
var BLOCK_MODE_4x4_3BIT = 83;
|
|
925
|
+
var BLOCK_MODE_4x4_5BIT = 595;
|
|
926
|
+
var CEM_LUM_DIRECT = 0;
|
|
927
|
+
var CEM_RGB_DIRECT = 8;
|
|
697
928
|
var CEM_RGBA_DIRECT = 12;
|
|
698
929
|
var WEIGHT_UNQ_4 = [0, 21, 43, 64];
|
|
930
|
+
var WEIGHT_UNQ_8 = [0, 9, 18, 27, 37, 46, 55, 64];
|
|
931
|
+
var WEIGHT_UNQ_32 = Array.from({ length: 32 }, (_, w) => w <= 15 ? 2 * w : 2 * w + 2);
|
|
932
|
+
var CLASS_LUM = {
|
|
933
|
+
cem: CEM_LUM_DIRECT,
|
|
934
|
+
blockMode: BLOCK_MODE_4x4_5BIT,
|
|
935
|
+
channels: [0],
|
|
936
|
+
weightBits: 5,
|
|
937
|
+
unq: WEIGHT_UNQ_32
|
|
938
|
+
};
|
|
939
|
+
var CLASS_RGB = {
|
|
940
|
+
cem: CEM_RGB_DIRECT,
|
|
941
|
+
blockMode: BLOCK_MODE_4x4_3BIT,
|
|
942
|
+
channels: [0, 1, 2],
|
|
943
|
+
weightBits: 3,
|
|
944
|
+
unq: WEIGHT_UNQ_8
|
|
945
|
+
};
|
|
946
|
+
var CLASS_RGBA = {
|
|
947
|
+
cem: CEM_RGBA_DIRECT,
|
|
948
|
+
blockMode: BLOCK_MODE_4x4_2BIT,
|
|
949
|
+
channels: [0, 1, 2, 3],
|
|
950
|
+
weightBits: 2,
|
|
951
|
+
unq: WEIGHT_UNQ_4
|
|
952
|
+
};
|
|
699
953
|
function clamp2(v, lo, hi) {
|
|
700
954
|
return v < lo ? lo : v > hi ? hi : v;
|
|
701
955
|
}
|
|
702
956
|
function to82(v) {
|
|
703
957
|
return clamp2(Math.round(v * 255), 0, 255);
|
|
704
958
|
}
|
|
705
|
-
function
|
|
706
|
-
return (64 - w) * e0 + w * e1 + 32 >> 6;
|
|
959
|
+
function interp16(e0, e1, w) {
|
|
960
|
+
return (64 - w) * e0 * 257 + w * e1 * 257 + 32 >> 6;
|
|
707
961
|
}
|
|
708
962
|
var BitWriter1282 = class {
|
|
709
963
|
bits = 0n;
|
|
@@ -737,18 +991,16 @@ var BitReader1282 = class {
|
|
|
737
991
|
return Number(this.bits >> BigInt(pos) & mask);
|
|
738
992
|
}
|
|
739
993
|
};
|
|
740
|
-
function farthestPair2(
|
|
994
|
+
function farthestPair2(vals, C) {
|
|
741
995
|
let best = -1;
|
|
742
996
|
let bi0 = 0, bi1 = 1;
|
|
743
997
|
for (let i = 0; i < 16; i++) {
|
|
744
|
-
const bi = i * 4;
|
|
745
998
|
for (let j = i + 1; j < 16; j++) {
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
const d = dr * dr + dg * dg + db * db + da * da;
|
|
999
|
+
let d = 0;
|
|
1000
|
+
for (let c = 0; c < C; c++) {
|
|
1001
|
+
const t = vals[i * C + c] - vals[j * C + c];
|
|
1002
|
+
d += t * t;
|
|
1003
|
+
}
|
|
752
1004
|
if (d > best) {
|
|
753
1005
|
best = d;
|
|
754
1006
|
bi0 = i;
|
|
@@ -758,68 +1010,61 @@ function farthestPair2(pixels8) {
|
|
|
758
1010
|
}
|
|
759
1011
|
return { i0: bi0, i1: bi1 };
|
|
760
1012
|
}
|
|
761
|
-
function buildPalette(e0, e1) {
|
|
762
|
-
const
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
pal[base + c] = interp82(e0[c], e1[c], w);
|
|
1013
|
+
function buildPalette(e0, e1, unq) {
|
|
1014
|
+
const C = e0.length;
|
|
1015
|
+
const pal = new Float64Array(unq.length * C);
|
|
1016
|
+
for (let i = 0; i < unq.length; i++) {
|
|
1017
|
+
for (let c = 0; c < C; c++) {
|
|
1018
|
+
pal[i * C + c] = interp16(e0[c], e1[c], unq[i]) / 257;
|
|
768
1019
|
}
|
|
769
1020
|
}
|
|
770
1021
|
return pal;
|
|
771
1022
|
}
|
|
772
|
-
function
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
for (let i = 0; i < 4; i++) {
|
|
776
|
-
const base = i * 4;
|
|
777
|
-
const dr = palette[base] - pixel[0];
|
|
778
|
-
const dg = palette[base + 1] - pixel[1];
|
|
779
|
-
const db = palette[base + 2] - pixel[2];
|
|
780
|
-
const da = palette[base + 3] - pixel[3];
|
|
781
|
-
const d = dr * dr + dg * dg + db * db + da * da;
|
|
782
|
-
if (d < bestD) {
|
|
783
|
-
bestD = d;
|
|
784
|
-
bestIdx = i;
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
return { idx: bestIdx, err: bestD };
|
|
788
|
-
}
|
|
789
|
-
function totalSqError(pixels8, e0, e1) {
|
|
790
|
-
const pal = buildPalette(e0, e1);
|
|
1023
|
+
function totalSqError(vals, C, e0, e1, unq) {
|
|
1024
|
+
const pal = buildPalette(e0, e1, unq);
|
|
1025
|
+
const levels = unq.length;
|
|
791
1026
|
const indices = new Uint8Array(16);
|
|
792
1027
|
let err = 0;
|
|
793
1028
|
for (let k = 0; k < 16; k++) {
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
1029
|
+
let bestIdx = 0;
|
|
1030
|
+
let bestD = Infinity;
|
|
1031
|
+
for (let i = 0; i < levels; i++) {
|
|
1032
|
+
let d = 0;
|
|
1033
|
+
for (let c = 0; c < C; c++) {
|
|
1034
|
+
const t = pal[i * C + c] - vals[k * C + c];
|
|
1035
|
+
d += t * t;
|
|
1036
|
+
}
|
|
1037
|
+
if (d < bestD) {
|
|
1038
|
+
bestD = d;
|
|
1039
|
+
bestIdx = i;
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
indices[k] = bestIdx;
|
|
1043
|
+
err += bestD;
|
|
798
1044
|
}
|
|
799
1045
|
return { indices, err };
|
|
800
1046
|
}
|
|
801
|
-
function refitEndpoints2(
|
|
1047
|
+
function refitEndpoints2(vals, C, indices, unq) {
|
|
802
1048
|
let sAA = 0, sBB = 0, sAB = 0;
|
|
803
|
-
const sAV =
|
|
804
|
-
const sBV =
|
|
1049
|
+
const sAV = new Float64Array(C);
|
|
1050
|
+
const sBV = new Float64Array(C);
|
|
805
1051
|
for (let k = 0; k < 16; k++) {
|
|
806
|
-
const
|
|
807
|
-
const a = (64 -
|
|
808
|
-
const b =
|
|
1052
|
+
const u = unq[indices[k]];
|
|
1053
|
+
const a = (64 - u) / 64;
|
|
1054
|
+
const b = u / 64;
|
|
809
1055
|
sAA += a * a;
|
|
810
1056
|
sBB += b * b;
|
|
811
1057
|
sAB += a * b;
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
sBV[c] += b * pixels8[base + c];
|
|
1058
|
+
for (let c = 0; c < C; c++) {
|
|
1059
|
+
sAV[c] += a * vals[k * C + c];
|
|
1060
|
+
sBV[c] += b * vals[k * C + c];
|
|
816
1061
|
}
|
|
817
1062
|
}
|
|
818
1063
|
const det = sAA * sBB - sAB * sAB;
|
|
819
1064
|
if (Math.abs(det) < 1e-9) return null;
|
|
820
|
-
const e0 =
|
|
821
|
-
const e1 =
|
|
822
|
-
for (let c = 0; c <
|
|
1065
|
+
const e0 = Array.from({ length: C }, () => 0);
|
|
1066
|
+
const e1 = Array.from({ length: C }, () => 0);
|
|
1067
|
+
for (let c = 0; c < C; c++) {
|
|
823
1068
|
e0[c] = clamp2(Math.round((sBB * sAV[c] - sAB * sBV[c]) / det), 0, 255);
|
|
824
1069
|
e1[c] = clamp2(Math.round((sAA * sBV[c] - sAB * sAV[c]) / det), 0, 255);
|
|
825
1070
|
}
|
|
@@ -831,101 +1076,677 @@ function encodeASTC4x4Block(pixels) {
|
|
|
831
1076
|
}
|
|
832
1077
|
const pixels8 = new Uint8Array(64);
|
|
833
1078
|
for (let k = 0; k < 64; k++) pixels8[k] = to82(pixels[k]);
|
|
834
|
-
|
|
835
|
-
let
|
|
836
|
-
|
|
837
|
-
pixels8[
|
|
838
|
-
pixels8[
|
|
839
|
-
pixels8[
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
pixels8[
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
1079
|
+
let gray = true;
|
|
1080
|
+
let opaque = true;
|
|
1081
|
+
for (let k = 0; k < 16; k++) {
|
|
1082
|
+
const r = pixels8[k * 4];
|
|
1083
|
+
if (pixels8[k * 4 + 1] !== r || pixels8[k * 4 + 2] !== r) gray = false;
|
|
1084
|
+
if (pixels8[k * 4 + 3] !== 255) opaque = false;
|
|
1085
|
+
}
|
|
1086
|
+
const cls = opaque ? gray ? CLASS_LUM : CLASS_RGB : CLASS_RGBA;
|
|
1087
|
+
const C = cls.channels.length;
|
|
1088
|
+
const vals = new Float64Array(16 * C);
|
|
1089
|
+
for (let k = 0; k < 16; k++) {
|
|
1090
|
+
for (let c = 0; c < C; c++) vals[k * C + c] = pixels8[k * 4 + cls.channels[c]];
|
|
1091
|
+
}
|
|
1092
|
+
const fp = farthestPair2(vals, C);
|
|
1093
|
+
let e0 = Array.from({ length: C }, (_, c) => vals[fp.i0 * C + c]);
|
|
1094
|
+
let e1 = Array.from({ length: C }, (_, c) => vals[fp.i1 * C + c]);
|
|
1095
|
+
let { indices, err } = totalSqError(vals, C, e0, e1, cls.unq);
|
|
1096
|
+
const refit = refitEndpoints2(vals, C, indices, cls.unq);
|
|
849
1097
|
if (refit) {
|
|
850
|
-
const
|
|
851
|
-
if (
|
|
1098
|
+
const second = totalSqError(vals, C, refit.e0, refit.e1, cls.unq);
|
|
1099
|
+
if (second.err < err) {
|
|
852
1100
|
e0 = refit.e0;
|
|
853
1101
|
e1 = refit.e1;
|
|
854
|
-
indices =
|
|
855
|
-
err =
|
|
1102
|
+
indices = second.indices;
|
|
1103
|
+
err = second.err;
|
|
856
1104
|
}
|
|
857
1105
|
}
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
1106
|
+
{
|
|
1107
|
+
const nSum = Math.min(C, 3);
|
|
1108
|
+
let s0 = 0;
|
|
1109
|
+
let s1 = 0;
|
|
1110
|
+
for (let c = 0; c < nSum; c++) {
|
|
1111
|
+
s0 += e0[c];
|
|
1112
|
+
s1 += e1[c];
|
|
1113
|
+
}
|
|
1114
|
+
if (s0 > s1) {
|
|
1115
|
+
const tmp = e0;
|
|
1116
|
+
e0 = e1;
|
|
1117
|
+
e1 = tmp;
|
|
1118
|
+
const wmax = cls.unq.length - 1;
|
|
1119
|
+
const inv = new Uint8Array(16);
|
|
1120
|
+
for (let k = 0; k < 16; k++) inv[k] = wmax - indices[k];
|
|
1121
|
+
indices = inv;
|
|
1122
|
+
}
|
|
867
1123
|
}
|
|
868
|
-
return packBlock3(e0, e1, indices);
|
|
1124
|
+
return packBlock3(cls, e0, e1, indices);
|
|
869
1125
|
}
|
|
870
|
-
function packBlock3(e0, e1, indices) {
|
|
1126
|
+
function packBlock3(cls, e0, e1, indices) {
|
|
871
1127
|
const bw = new BitWriter1282();
|
|
872
|
-
bw.write(0, 11,
|
|
1128
|
+
bw.write(0, 11, cls.blockMode);
|
|
873
1129
|
bw.write(11, 2, 0);
|
|
874
|
-
bw.write(13, 4,
|
|
875
|
-
|
|
876
|
-
|
|
1130
|
+
bw.write(13, 4, cls.cem);
|
|
1131
|
+
for (let c = 0; c < e0.length; c++) {
|
|
1132
|
+
bw.write(17 + c * 16, 8, e0[c]);
|
|
1133
|
+
bw.write(25 + c * 16, 8, e1[c]);
|
|
1134
|
+
}
|
|
877
1135
|
for (let k = 0; k < 16; k++) {
|
|
878
|
-
const w = indices[k]
|
|
879
|
-
|
|
880
|
-
|
|
1136
|
+
const w = indices[k];
|
|
1137
|
+
for (let j = 0; j < cls.weightBits; j++) {
|
|
1138
|
+
bw.write(127 - cls.weightBits * k - j, 1, w >> j & 1);
|
|
1139
|
+
}
|
|
881
1140
|
}
|
|
882
1141
|
return bw.toBytes();
|
|
883
1142
|
}
|
|
1143
|
+
var CLASS_BY_MODE = {
|
|
1144
|
+
[BLOCK_MODE_4x4_2BIT]: CLASS_RGBA,
|
|
1145
|
+
[BLOCK_MODE_4x4_3BIT]: CLASS_RGB,
|
|
1146
|
+
[BLOCK_MODE_4x4_5BIT]: CLASS_LUM
|
|
1147
|
+
};
|
|
884
1148
|
function decodeASTC4x4Block(block) {
|
|
885
1149
|
if (block.length !== 16) {
|
|
886
1150
|
throw new Error(`decodeASTC4x4Block: expected 16 bytes, got ${block.length}`);
|
|
887
1151
|
}
|
|
888
1152
|
const br = new BitReader1282(block);
|
|
889
1153
|
const mode = br.read(0, 11);
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
);
|
|
1154
|
+
const cls = CLASS_BY_MODE[mode];
|
|
1155
|
+
if (!cls) {
|
|
1156
|
+
throw new Error(`decodeASTC4x4Block: unsupported block mode 0x${mode.toString(16)}`);
|
|
894
1157
|
}
|
|
895
1158
|
const partCount = br.read(11, 2);
|
|
896
1159
|
if (partCount !== 0) {
|
|
897
1160
|
throw new Error(`decodeASTC4x4Block: multi-partition blocks not supported (count=${partCount + 1})`);
|
|
898
1161
|
}
|
|
899
1162
|
const cem = br.read(13, 4);
|
|
900
|
-
if (cem !==
|
|
901
|
-
throw new Error(`decodeASTC4x4Block:
|
|
1163
|
+
if (cem !== cls.cem) {
|
|
1164
|
+
throw new Error(`decodeASTC4x4Block: expected CEM ${cls.cem} with block mode 0x${mode.toString(16)}, got ${cem}`);
|
|
902
1165
|
}
|
|
1166
|
+
const nVals = cls.channels.length * 2;
|
|
903
1167
|
const v = [];
|
|
904
|
-
for (let i = 0; i <
|
|
905
|
-
const [v0, v1, v2, v3, v4, v5, v6, v7] = v;
|
|
1168
|
+
for (let i = 0; i < nVals; i++) v.push(br.read(17 + i * 8, 8));
|
|
906
1169
|
let e0;
|
|
907
1170
|
let e1;
|
|
908
|
-
if (
|
|
909
|
-
e0 = [
|
|
910
|
-
e1 = [
|
|
1171
|
+
if (cls.cem === CEM_LUM_DIRECT) {
|
|
1172
|
+
e0 = [v[0], v[0], v[0], 255];
|
|
1173
|
+
e1 = [v[1], v[1], v[1], 255];
|
|
911
1174
|
} else {
|
|
912
|
-
|
|
913
|
-
|
|
1175
|
+
const a0 = cls.cem === CEM_RGBA_DIRECT ? v[6] : 255;
|
|
1176
|
+
const a1 = cls.cem === CEM_RGBA_DIRECT ? v[7] : 255;
|
|
1177
|
+
if (v[0] + v[2] + v[4] <= v[1] + v[3] + v[5]) {
|
|
1178
|
+
e0 = [v[0], v[2], v[4], a0];
|
|
1179
|
+
e1 = [v[1], v[3], v[5], a1];
|
|
1180
|
+
} else {
|
|
1181
|
+
e0 = [v[1] + v[5] >> 1, v[3] + v[5] >> 1, v[5], a1];
|
|
1182
|
+
e1 = [v[0] + v[4] >> 1, v[2] + v[4] >> 1, v[4], a0];
|
|
1183
|
+
}
|
|
914
1184
|
}
|
|
915
1185
|
const weights = new Uint8Array(16);
|
|
916
1186
|
for (let k = 0; k < 16; k++) {
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
1187
|
+
let w = 0;
|
|
1188
|
+
for (let j = 0; j < cls.weightBits; j++) {
|
|
1189
|
+
w |= br.read(127 - cls.weightBits * k - j, 1) << j;
|
|
1190
|
+
}
|
|
1191
|
+
weights[k] = w;
|
|
920
1192
|
}
|
|
921
1193
|
const out = new Float32Array(64);
|
|
922
1194
|
for (let k = 0; k < 16; k++) {
|
|
923
|
-
const
|
|
1195
|
+
const u = cls.unq[weights[k]];
|
|
924
1196
|
const base = k * 4;
|
|
925
1197
|
for (let c = 0; c < 4; c++) {
|
|
926
|
-
out[base + c] =
|
|
1198
|
+
out[base + c] = interp16(e0[c], e1[c], u) / 65535;
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
return out;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
// src/etc2_ref.ts
|
|
1205
|
+
var MODIFIERS = [
|
|
1206
|
+
[2, 8, -2, -8],
|
|
1207
|
+
[5, 17, -5, -17],
|
|
1208
|
+
[9, 29, -9, -29],
|
|
1209
|
+
[13, 42, -13, -42],
|
|
1210
|
+
[18, 60, -18, -60],
|
|
1211
|
+
[24, 80, -24, -80],
|
|
1212
|
+
[33, 106, -33, -106],
|
|
1213
|
+
[47, 183, -47, -183]
|
|
1214
|
+
];
|
|
1215
|
+
var TH_DISTANCES = [3, 6, 11, 16, 23, 32, 41, 64];
|
|
1216
|
+
var clamp255 = (v) => v < 0 ? 0 : v > 255 ? 255 : v;
|
|
1217
|
+
var extend4 = (x) => x << 4 | x;
|
|
1218
|
+
var extend5 = (x) => x << 3 | x >> 2;
|
|
1219
|
+
var extend6 = (x) => x << 2 | x >> 4;
|
|
1220
|
+
var extend7 = (x) => x << 1 | x >> 6;
|
|
1221
|
+
var quant = (v, maxCode) => {
|
|
1222
|
+
const q = Math.floor(v * maxCode / 255 + 0.5);
|
|
1223
|
+
return q < 0 ? 0 : q > maxCode ? maxCode : q;
|
|
1224
|
+
};
|
|
1225
|
+
var signed3 = (bits) => bits > 3 ? bits - 8 : bits;
|
|
1226
|
+
function subblockTexels(flip, sb) {
|
|
1227
|
+
const out = [];
|
|
1228
|
+
for (let k = 0; k < 16; k++) {
|
|
1229
|
+
const x = k & 3;
|
|
1230
|
+
const y = k >> 2;
|
|
1231
|
+
const inSb1 = flip === 0 ? x >= 2 : y >= 2;
|
|
1232
|
+
if ((inSb1 ? 1 : 0) === sb) out.push(k);
|
|
1233
|
+
}
|
|
1234
|
+
return out;
|
|
1235
|
+
}
|
|
1236
|
+
var SUBBLOCKS = [
|
|
1237
|
+
[subblockTexels(0, 0), subblockTexels(0, 1)],
|
|
1238
|
+
[subblockTexels(1, 0), subblockTexels(1, 1)]
|
|
1239
|
+
];
|
|
1240
|
+
function fitSubblock(px, texels, base) {
|
|
1241
|
+
const best = { table: 0, indices: new Uint8Array(8), err: Infinity, modSum: 0 };
|
|
1242
|
+
const idx = new Uint8Array(8);
|
|
1243
|
+
for (let t = 0; t < 8; t++) {
|
|
1244
|
+
const mods = MODIFIERS[t];
|
|
1245
|
+
let err = 0;
|
|
1246
|
+
let modSum = 0;
|
|
1247
|
+
for (let i = 0; i < texels.length; i++) {
|
|
1248
|
+
const k = texels[i];
|
|
1249
|
+
const r = px[k * 3];
|
|
1250
|
+
const g = px[k * 3 + 1];
|
|
1251
|
+
const b = px[k * 3 + 2];
|
|
1252
|
+
let bestJ = 0;
|
|
1253
|
+
let bestD = Infinity;
|
|
1254
|
+
let bestM = 0;
|
|
1255
|
+
for (let j = 0; j < 4; j++) {
|
|
1256
|
+
const m = mods[j];
|
|
1257
|
+
const dr = clamp255(base[0] + m) - r;
|
|
1258
|
+
const dg = clamp255(base[1] + m) - g;
|
|
1259
|
+
const db = clamp255(base[2] + m) - b;
|
|
1260
|
+
const d = dr * dr + dg * dg + db * db;
|
|
1261
|
+
if (d < bestD) {
|
|
1262
|
+
bestD = d;
|
|
1263
|
+
bestJ = j;
|
|
1264
|
+
bestM = m;
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
idx[i] = bestJ;
|
|
1268
|
+
err += bestD;
|
|
1269
|
+
modSum += bestM;
|
|
1270
|
+
}
|
|
1271
|
+
if (err < best.err) {
|
|
1272
|
+
best.table = t;
|
|
1273
|
+
best.indices.set(idx);
|
|
1274
|
+
best.err = err;
|
|
1275
|
+
best.modSum = modSum;
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
return best;
|
|
1279
|
+
}
|
|
1280
|
+
function quantiseBases(avg0, avg1, diff, clampDelta) {
|
|
1281
|
+
if (!diff) {
|
|
1282
|
+
return { codes0: avg0.map((v) => quant(v, 15)), codes1: avg1.map((v) => quant(v, 15)) };
|
|
1283
|
+
}
|
|
1284
|
+
const codes0 = avg0.map((v) => quant(v, 31));
|
|
1285
|
+
const codes1 = [];
|
|
1286
|
+
for (let c = 0; c < 3; c++) {
|
|
1287
|
+
let d = quant(avg1[c], 31) - codes0[c];
|
|
1288
|
+
if (d < -4 || d > 3) {
|
|
1289
|
+
if (!clampDelta) return null;
|
|
1290
|
+
d = d < -4 ? -4 : 3;
|
|
1291
|
+
}
|
|
1292
|
+
codes1.push(codes0[c] + d);
|
|
1293
|
+
}
|
|
1294
|
+
return { codes0, codes1 };
|
|
1295
|
+
}
|
|
1296
|
+
var decodeBases = (codes, diff) => codes.map(diff ? extend5 : extend4);
|
|
1297
|
+
function fitEtc1(px, flip, diff, clampDelta, avg0, avg1, refits) {
|
|
1298
|
+
const texels0 = SUBBLOCKS[flip][0];
|
|
1299
|
+
const texels1 = SUBBLOCKS[flip][1];
|
|
1300
|
+
const q = quantiseBases(avg0, avg1, diff, clampDelta);
|
|
1301
|
+
if (!q) return null;
|
|
1302
|
+
let { codes0, codes1 } = q;
|
|
1303
|
+
let fit0 = fitSubblock(px, texels0, decodeBases(codes0, diff));
|
|
1304
|
+
let fit1 = fitSubblock(px, texels1, decodeBases(codes1, diff));
|
|
1305
|
+
let err = fit0.err + fit1.err;
|
|
1306
|
+
for (let round = 0; round < refits; round++) {
|
|
1307
|
+
const shift0 = fit0.modSum / texels0.length;
|
|
1308
|
+
const shift1 = fit1.modSum / texels1.length;
|
|
1309
|
+
const nAvg0 = avg0.map((v) => v - shift0);
|
|
1310
|
+
const nAvg1 = avg1.map((v) => v - shift1);
|
|
1311
|
+
const nq = quantiseBases(nAvg0, nAvg1, diff, true);
|
|
1312
|
+
if (!nq) break;
|
|
1313
|
+
if (nq.codes0.every((v, c) => v === codes0[c]) && nq.codes1.every((v, c) => v === codes1[c])) break;
|
|
1314
|
+
const nFit0 = fitSubblock(px, texels0, decodeBases(nq.codes0, diff));
|
|
1315
|
+
const nFit1 = fitSubblock(px, texels1, decodeBases(nq.codes1, diff));
|
|
1316
|
+
if (nFit0.err + nFit1.err >= err) break;
|
|
1317
|
+
codes0 = nq.codes0;
|
|
1318
|
+
codes1 = nq.codes1;
|
|
1319
|
+
fit0 = nFit0;
|
|
1320
|
+
fit1 = nFit1;
|
|
1321
|
+
err = fit0.err + fit1.err;
|
|
1322
|
+
}
|
|
1323
|
+
return { diff, flip, codes0, codes1, fit0, fit1, err };
|
|
1324
|
+
}
|
|
1325
|
+
var PLANAR_GINV = [
|
|
1326
|
+
[0.2875, -0.0125, -0.0125],
|
|
1327
|
+
[-0.0125, 0.4875, -0.3125],
|
|
1328
|
+
[-0.0125, -0.3125, 0.4875]
|
|
1329
|
+
];
|
|
1330
|
+
function planarError(px, o, h, v) {
|
|
1331
|
+
const ext = (codes) => [extend6(codes[0]), extend7(codes[1]), extend6(codes[2])];
|
|
1332
|
+
const eo = ext(o);
|
|
1333
|
+
const eh = ext(h);
|
|
1334
|
+
const ev = ext(v);
|
|
1335
|
+
let err = 0;
|
|
1336
|
+
for (let k = 0; k < 16; k++) {
|
|
1337
|
+
const x = k & 3;
|
|
1338
|
+
const y = k >> 2;
|
|
1339
|
+
for (let c = 0; c < 3; c++) {
|
|
1340
|
+
const val = clamp255(x * (eh[c] - eo[c]) + y * (ev[c] - eo[c]) + 4 * eo[c] + 2 >> 2);
|
|
1341
|
+
const d = val - px[k * 3 + c];
|
|
1342
|
+
err += d * d;
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
return err;
|
|
1346
|
+
}
|
|
1347
|
+
function fitPlanar(px, polish) {
|
|
1348
|
+
const o = [];
|
|
1349
|
+
const h = [];
|
|
1350
|
+
const v = [];
|
|
1351
|
+
const maxCode = [63, 127, 63];
|
|
1352
|
+
for (let c = 0; c < 3; c++) {
|
|
1353
|
+
let sA = 0;
|
|
1354
|
+
let sB = 0;
|
|
1355
|
+
let sC = 0;
|
|
1356
|
+
for (let k = 0; k < 16; k++) {
|
|
1357
|
+
const x = (k & 3) / 4;
|
|
1358
|
+
const y = (k >> 2) / 4;
|
|
1359
|
+
const p = px[k * 3 + c];
|
|
1360
|
+
sA += (1 - x - y) * p;
|
|
1361
|
+
sB += x * p;
|
|
1362
|
+
sC += y * p;
|
|
1363
|
+
}
|
|
1364
|
+
const oc = PLANAR_GINV[0][0] * sA + PLANAR_GINV[0][1] * sB + PLANAR_GINV[0][2] * sC;
|
|
1365
|
+
const hc = PLANAR_GINV[1][0] * sA + PLANAR_GINV[1][1] * sB + PLANAR_GINV[1][2] * sC;
|
|
1366
|
+
const vc = PLANAR_GINV[2][0] * sA + PLANAR_GINV[2][1] * sB + PLANAR_GINV[2][2] * sC;
|
|
1367
|
+
o.push(quant(clamp255(oc), maxCode[c]));
|
|
1368
|
+
h.push(quant(clamp255(hc), maxCode[c]));
|
|
1369
|
+
v.push(quant(clamp255(vc), maxCode[c]));
|
|
1370
|
+
}
|
|
1371
|
+
let err = planarError(px, o, h, v);
|
|
1372
|
+
if (polish) {
|
|
1373
|
+
const params = [o, h, v];
|
|
1374
|
+
for (let p = 0; p < 3; p++) {
|
|
1375
|
+
for (let c = 0; c < 3; c++) {
|
|
1376
|
+
const cur = params[p][c];
|
|
1377
|
+
for (const cand of [cur - 1, cur + 1]) {
|
|
1378
|
+
if (cand < 0 || cand > maxCode[c]) continue;
|
|
1379
|
+
params[p][c] = cand;
|
|
1380
|
+
const e = planarError(px, o, h, v);
|
|
1381
|
+
if (e < err) {
|
|
1382
|
+
err = e;
|
|
1383
|
+
} else {
|
|
1384
|
+
params[p][c] = cur;
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
return { o, h, v, err };
|
|
1391
|
+
}
|
|
1392
|
+
function wordsToBlock(hi, lo) {
|
|
1393
|
+
const out = new Uint8Array(8);
|
|
1394
|
+
out[0] = hi >>> 24 & 255;
|
|
1395
|
+
out[1] = hi >>> 16 & 255;
|
|
1396
|
+
out[2] = hi >>> 8 & 255;
|
|
1397
|
+
out[3] = hi & 255;
|
|
1398
|
+
out[4] = lo >>> 24 & 255;
|
|
1399
|
+
out[5] = lo >>> 16 & 255;
|
|
1400
|
+
out[6] = lo >>> 8 & 255;
|
|
1401
|
+
out[7] = lo & 255;
|
|
1402
|
+
return out;
|
|
1403
|
+
}
|
|
1404
|
+
function packIndices(cand) {
|
|
1405
|
+
let lo = 0;
|
|
1406
|
+
for (let sb = 0; sb < 2; sb++) {
|
|
1407
|
+
const texels = SUBBLOCKS[cand.flip][sb];
|
|
1408
|
+
const fit = sb === 0 ? cand.fit0 : cand.fit1;
|
|
1409
|
+
for (let i = 0; i < texels.length; i++) {
|
|
1410
|
+
const k = texels[i];
|
|
1411
|
+
const wire = (k & 3) * 4 + (k >> 2);
|
|
1412
|
+
const idx = fit.indices[i];
|
|
1413
|
+
lo |= (idx & 1) << wire;
|
|
1414
|
+
lo |= (idx >> 1 & 1) << 16 + wire;
|
|
927
1415
|
}
|
|
928
1416
|
}
|
|
1417
|
+
return lo >>> 0;
|
|
1418
|
+
}
|
|
1419
|
+
function packEtc1(cand) {
|
|
1420
|
+
const { codes0: c0, codes1: c1 } = cand;
|
|
1421
|
+
let hi;
|
|
1422
|
+
if (cand.diff) {
|
|
1423
|
+
const d = [c1[0] - c0[0], c1[1] - c0[1], c1[2] - c0[2]];
|
|
1424
|
+
hi = c0[0] << 27 | (d[0] & 7) << 24 | c0[1] << 19 | (d[1] & 7) << 16 | c0[2] << 11 | (d[2] & 7) << 8 | cand.fit0.table << 5 | cand.fit1.table << 2 | 2 | cand.flip;
|
|
1425
|
+
} else {
|
|
1426
|
+
hi = c0[0] << 28 | c1[0] << 24 | c0[1] << 20 | c1[1] << 16 | c0[2] << 12 | c1[2] << 8 | cand.fit0.table << 5 | cand.fit1.table << 2 | 0 | cand.flip;
|
|
1427
|
+
}
|
|
1428
|
+
return wordsToBlock(hi >>> 0, packIndices(cand));
|
|
1429
|
+
}
|
|
1430
|
+
function packPlanar(cand) {
|
|
1431
|
+
const ro = cand.o[0];
|
|
1432
|
+
const go = cand.o[1];
|
|
1433
|
+
const bo = cand.o[2];
|
|
1434
|
+
const rh = cand.h[0];
|
|
1435
|
+
const gh = cand.h[1];
|
|
1436
|
+
const bh = cand.h[2];
|
|
1437
|
+
const rv = cand.v[0];
|
|
1438
|
+
const gv = cand.v[1];
|
|
1439
|
+
const bv = cand.v[2];
|
|
1440
|
+
const rSum = (ro >> 2) + signed3((ro & 3) << 1 | go >> 6);
|
|
1441
|
+
const rFix = rSum < 0 ? 1 : 0;
|
|
1442
|
+
const gSum = (go >> 2 & 15) + signed3((go & 3) << 1 | bo >> 5);
|
|
1443
|
+
const gFix = gSum < 0 ? 1 : 0;
|
|
1444
|
+
const p = bo >> 3 & 3;
|
|
1445
|
+
const q = bo >> 1 & 3;
|
|
1446
|
+
const bFix3 = p + q >= 4 ? 7 : 0;
|
|
1447
|
+
const bFix1 = p + q >= 4 ? 0 : 1;
|
|
1448
|
+
const hi = rFix << 31 | ro << 25 | go >> 6 << 24 | gFix << 23 | (go & 63) << 17 | bo >> 5 << 16 | bFix3 << 13 | (bo >> 3 & 3) << 11 | bFix1 << 10 | (bo & 7) << 7 | rh >> 1 << 2 | 2 | // diffbit
|
|
1449
|
+
rh & 1;
|
|
1450
|
+
const lo = gh << 25 | bh << 19 | rv << 13 | gv << 6 | bv;
|
|
1451
|
+
return wordsToBlock(hi >>> 0, lo >>> 0);
|
|
1452
|
+
}
|
|
1453
|
+
var A3 = MODIFIERS.map((m) => 3 * m[0]);
|
|
1454
|
+
var B3 = MODIFIERS.map((m) => 3 * m[1]);
|
|
1455
|
+
var THR3 = MODIFIERS.map((m) => 1.5 * (m[0] + m[1]));
|
|
1456
|
+
var PLANAR_FUDGE = 8;
|
|
1457
|
+
function fastTableScore(D, t) {
|
|
1458
|
+
let acc = 0;
|
|
1459
|
+
for (let i = 0; i < D.length; i++) {
|
|
1460
|
+
const ad = Math.abs(D[i]);
|
|
1461
|
+
const m3 = ad > THR3[t] ? B3[t] : A3[t];
|
|
1462
|
+
acc += m3 * (m3 - 2 * ad);
|
|
1463
|
+
}
|
|
1464
|
+
return acc;
|
|
1465
|
+
}
|
|
1466
|
+
function fastSearch(D) {
|
|
1467
|
+
let mx = 0;
|
|
1468
|
+
for (let i = 0; i < D.length; i++) mx = Math.max(mx, Math.abs(D[i]));
|
|
1469
|
+
let cover = 0;
|
|
1470
|
+
while (cover < 7 && B3[cover] < mx) cover++;
|
|
1471
|
+
const tLo = cover === 0 ? 0 : cover - 1;
|
|
1472
|
+
const accLo = fastTableScore(D, tLo);
|
|
1473
|
+
const accHi = fastTableScore(D, cover);
|
|
1474
|
+
return accLo <= accHi ? { table: tLo, acc: accLo } : { table: cover, acc: accHi };
|
|
1475
|
+
}
|
|
1476
|
+
function fastIndices(D, t) {
|
|
1477
|
+
const indices = new Uint8Array(D.length);
|
|
1478
|
+
let modSum = 0;
|
|
1479
|
+
for (let i = 0; i < D.length; i++) {
|
|
1480
|
+
const d = D[i];
|
|
1481
|
+
const large = Math.abs(d) > THR3[t];
|
|
1482
|
+
const neg = d < 0;
|
|
1483
|
+
indices[i] = (large ? 1 : 0) | (neg ? 2 : 0);
|
|
1484
|
+
modSum += (neg ? -1 : 1) * (large ? B3[t] : A3[t]) / 3;
|
|
1485
|
+
}
|
|
1486
|
+
return { table: t, indices, err: 0, modSum };
|
|
1487
|
+
}
|
|
1488
|
+
function encodeFastBlock(px) {
|
|
1489
|
+
const luma = new Float64Array(16);
|
|
1490
|
+
const qsum = [
|
|
1491
|
+
[0, 0, 0],
|
|
1492
|
+
[0, 0, 0],
|
|
1493
|
+
[0, 0, 0],
|
|
1494
|
+
[0, 0, 0]
|
|
1495
|
+
];
|
|
1496
|
+
const qsq = [0, 0, 0, 0];
|
|
1497
|
+
const qlsq = [0, 0, 0, 0];
|
|
1498
|
+
for (let k = 0; k < 16; k++) {
|
|
1499
|
+
const r = px[k * 3];
|
|
1500
|
+
const g = px[k * 3 + 1];
|
|
1501
|
+
const b = px[k * 3 + 2];
|
|
1502
|
+
const l = r + g + b;
|
|
1503
|
+
luma[k] = l;
|
|
1504
|
+
const q = ((k & 3) >= 2 ? 1 : 0) | (k >> 2 >= 2 ? 2 : 0);
|
|
1505
|
+
qsum[q][0] += r;
|
|
1506
|
+
qsum[q][1] += g;
|
|
1507
|
+
qsum[q][2] += b;
|
|
1508
|
+
qsq[q] += r * r + g * g + b * b;
|
|
1509
|
+
qlsq[q] += l * l;
|
|
1510
|
+
}
|
|
1511
|
+
const pair = (a, b) => ({
|
|
1512
|
+
sum: [qsum[a][0] + qsum[b][0], qsum[a][1] + qsum[b][1], qsum[a][2] + qsum[b][2]],
|
|
1513
|
+
sq: qsq[a] + qsq[b],
|
|
1514
|
+
lsq: qlsq[a] + qlsq[b]
|
|
1515
|
+
});
|
|
1516
|
+
const constErr = (s, b) => s.sq - 2 * (b[0] * s.sum[0] + b[1] * s.sum[1] + b[2] * s.sum[2]) + 8 * (b[0] * b[0] + b[1] * b[1] + b[2] * b[2]);
|
|
1517
|
+
const Dof = (texels, lb) => texels.map((k) => luma[k] - lb);
|
|
1518
|
+
const evalCodes = (flip2, s0, s1, diff2, c) => {
|
|
1519
|
+
const b0 = decodeBases(c.codes0, diff2);
|
|
1520
|
+
const b1 = decodeBases(c.codes1, diff2);
|
|
1521
|
+
const lb0 = b0[0] + b0[1] + b0[2];
|
|
1522
|
+
const lb1 = b1[0] + b1[1] + b1[2];
|
|
1523
|
+
const f0 = fastSearch(Dof(SUBBLOCKS[flip2][0], lb0));
|
|
1524
|
+
const f1 = fastSearch(Dof(SUBBLOCKS[flip2][1], lb1));
|
|
1525
|
+
return {
|
|
1526
|
+
est: constErr(s0, b0) + constErr(s1, b1) + (f0.acc + f1.acc) / 3,
|
|
1527
|
+
diff: diff2,
|
|
1528
|
+
codes: c,
|
|
1529
|
+
t0: f0.table,
|
|
1530
|
+
t1: f1.table,
|
|
1531
|
+
lb0,
|
|
1532
|
+
lb1
|
|
1533
|
+
};
|
|
1534
|
+
};
|
|
1535
|
+
const evalFlip = (flip2, s0, s1) => {
|
|
1536
|
+
const avg0 = s0.sum.map((v2) => v2 / 8);
|
|
1537
|
+
const avg1 = s1.sum.map((v2) => v2 / 8);
|
|
1538
|
+
const tryDiff = quantiseBases(avg0, avg1, true, false);
|
|
1539
|
+
const diff2 = tryDiff !== null;
|
|
1540
|
+
const c = tryDiff ?? quantiseBases(avg0, avg1, false, false);
|
|
1541
|
+
return evalCodes(flip2, s0, s1, diff2, c);
|
|
1542
|
+
};
|
|
1543
|
+
const residual = (s) => {
|
|
1544
|
+
const dotSum = s.sum[0] * s.sum[0] + s.sum[1] * s.sum[1] + s.sum[2] * s.sum[2];
|
|
1545
|
+
const lsum = s.sum[0] + s.sum[1] + s.sum[2];
|
|
1546
|
+
return s.sq - dotSum / 8 - (s.lsq - lsum * lsum / 8) / 3;
|
|
1547
|
+
};
|
|
1548
|
+
const resA = residual(pair(0, 2)) + residual(pair(1, 3));
|
|
1549
|
+
const resB = residual(pair(0, 1)) + residual(pair(2, 3));
|
|
1550
|
+
let flip;
|
|
1551
|
+
let cur;
|
|
1552
|
+
if (Math.abs(resA - resB) < 1) {
|
|
1553
|
+
const fa = evalFlip(0, pair(0, 2), pair(1, 3));
|
|
1554
|
+
const fb = evalFlip(1, pair(0, 1), pair(2, 3));
|
|
1555
|
+
flip = fb.est < fa.est ? 1 : 0;
|
|
1556
|
+
cur = fb.est < fa.est ? fb : fa;
|
|
1557
|
+
} else {
|
|
1558
|
+
flip = resB < resA ? 1 : 0;
|
|
1559
|
+
cur = evalFlip(flip, flip === 0 ? pair(0, 2) : pair(0, 1), flip === 0 ? pair(1, 3) : pair(2, 3));
|
|
1560
|
+
}
|
|
1561
|
+
const texels0 = SUBBLOCKS[flip][0];
|
|
1562
|
+
const texels1 = SUBBLOCKS[flip][1];
|
|
1563
|
+
const diff = cur.diff;
|
|
1564
|
+
const codes = cur.codes;
|
|
1565
|
+
const fit0 = fastIndices(Dof(texels0, cur.lb0), cur.t0);
|
|
1566
|
+
const fit1 = fastIndices(Dof(texels1, cur.lb1), cur.t1);
|
|
1567
|
+
const o = [];
|
|
1568
|
+
const h = [];
|
|
1569
|
+
const v = [];
|
|
1570
|
+
const maxCode = [63, 127, 63];
|
|
1571
|
+
const extendOHV = [extend6, extend7, extend6];
|
|
1572
|
+
let planarEst = PLANAR_FUDGE;
|
|
1573
|
+
for (let c = 0; c < 3; c++) {
|
|
1574
|
+
let sA = 0;
|
|
1575
|
+
let sB = 0;
|
|
1576
|
+
let sC = 0;
|
|
1577
|
+
let sq = 0;
|
|
1578
|
+
for (let k = 0; k < 16; k++) {
|
|
1579
|
+
const x = (k & 3) / 4;
|
|
1580
|
+
const y = (k >> 2) / 4;
|
|
1581
|
+
const p = px[k * 3 + c];
|
|
1582
|
+
sA += (1 - x - y) * p;
|
|
1583
|
+
sB += x * p;
|
|
1584
|
+
sC += y * p;
|
|
1585
|
+
sq += p * p;
|
|
1586
|
+
}
|
|
1587
|
+
const oc = PLANAR_GINV[0][0] * sA + PLANAR_GINV[0][1] * sB + PLANAR_GINV[0][2] * sC;
|
|
1588
|
+
const hc = PLANAR_GINV[1][0] * sA + PLANAR_GINV[1][1] * sB + PLANAR_GINV[1][2] * sC;
|
|
1589
|
+
const vc = PLANAR_GINV[2][0] * sA + PLANAR_GINV[2][1] * sB + PLANAR_GINV[2][2] * sC;
|
|
1590
|
+
const qO = quant(oc, maxCode[c]);
|
|
1591
|
+
const qH = quant(hc, maxCode[c]);
|
|
1592
|
+
const qV = quant(vc, maxCode[c]);
|
|
1593
|
+
o.push(qO);
|
|
1594
|
+
h.push(qH);
|
|
1595
|
+
v.push(qV);
|
|
1596
|
+
const eO = extendOHV[c](qO);
|
|
1597
|
+
const eH = extendOHV[c](qH);
|
|
1598
|
+
const eV = extendOHV[c](qV);
|
|
1599
|
+
planarEst += sq - 2 * (eO * sA + eH * sB + eV * sC) + 3.5 * (eO * eO + eH * eH + eV * eV) + 0.5 * eO * eH + 0.5 * eO * eV + 4.5 * eH * eV;
|
|
1600
|
+
}
|
|
1601
|
+
if (cur.est <= planarEst) {
|
|
1602
|
+
return packEtc1({ diff, flip, codes0: codes.codes0, codes1: codes.codes1, fit0, fit1, err: cur.est });
|
|
1603
|
+
}
|
|
1604
|
+
return packPlanar({ o, h, v, err: planarEst });
|
|
1605
|
+
}
|
|
1606
|
+
function blockSse(px, block) {
|
|
1607
|
+
const decoded = decodeETC2Block(block);
|
|
1608
|
+
let sse = 0;
|
|
1609
|
+
for (let i = 0; i < 48; i++) {
|
|
1610
|
+
const d = decoded[i] * 255 - px[i];
|
|
1611
|
+
sse += d * d;
|
|
1612
|
+
}
|
|
1613
|
+
return sse;
|
|
1614
|
+
}
|
|
1615
|
+
function encodeETC2Block(pixels, { quality = "fast" } = {}) {
|
|
1616
|
+
if (pixels.length !== 48) {
|
|
1617
|
+
throw new Error(`encodeETC2Block: expected 48 values (16 RGB), got ${pixels.length}`);
|
|
1618
|
+
}
|
|
1619
|
+
const px = new Int32Array(48);
|
|
1620
|
+
for (let i = 0; i < 48; i++) {
|
|
1621
|
+
const v = Math.round(pixels[i] * 255);
|
|
1622
|
+
px[i] = v < 0 ? 0 : v > 255 ? 255 : v;
|
|
1623
|
+
}
|
|
1624
|
+
const fastBlock = encodeFastBlock(px);
|
|
1625
|
+
if (quality === "fast") return fastBlock;
|
|
1626
|
+
let bestEtc1 = null;
|
|
1627
|
+
for (let flip = 0; flip < 2; flip++) {
|
|
1628
|
+
const avgs = [];
|
|
1629
|
+
for (let sb = 0; sb < 2; sb++) {
|
|
1630
|
+
const texels = SUBBLOCKS[flip][sb];
|
|
1631
|
+
const a = [0, 0, 0];
|
|
1632
|
+
for (const k of texels) {
|
|
1633
|
+
a[0] += px[k * 3];
|
|
1634
|
+
a[1] += px[k * 3 + 1];
|
|
1635
|
+
a[2] += px[k * 3 + 2];
|
|
1636
|
+
}
|
|
1637
|
+
avgs.push(a.map((s) => s / texels.length));
|
|
1638
|
+
}
|
|
1639
|
+
const [avg0, avg1] = avgs;
|
|
1640
|
+
for (const t of [
|
|
1641
|
+
{ diff: true, clampDelta: true },
|
|
1642
|
+
{ diff: false, clampDelta: false }
|
|
1643
|
+
]) {
|
|
1644
|
+
const cand = fitEtc1(px, flip, t.diff, t.clampDelta, avg0, avg1, 4);
|
|
1645
|
+
if (cand && (!bestEtc1 || cand.err < bestEtc1.err)) bestEtc1 = cand;
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
const planar = fitPlanar(px, true);
|
|
1649
|
+
const highBlock = bestEtc1 && bestEtc1.err <= planar.err ? packEtc1(bestEtc1) : packPlanar(planar);
|
|
1650
|
+
return blockSse(px, highBlock) <= blockSse(px, fastBlock) ? highBlock : fastBlock;
|
|
1651
|
+
}
|
|
1652
|
+
function readETC2Mode(block) {
|
|
1653
|
+
const hi = (block[0] << 24 | block[1] << 16 | block[2] << 8 | block[3]) >>> 0;
|
|
1654
|
+
if ((hi >> 1 & 1) === 0) return "individual";
|
|
1655
|
+
const r = (hi >> 27 & 31) + signed3(hi >> 24 & 7);
|
|
1656
|
+
if (r < 0 || r > 31) return "T";
|
|
1657
|
+
const g = (hi >> 19 & 31) + signed3(hi >> 16 & 7);
|
|
1658
|
+
if (g < 0 || g > 31) return "H";
|
|
1659
|
+
const b = (hi >> 11 & 31) + signed3(hi >> 8 & 7);
|
|
1660
|
+
if (b < 0 || b > 31) return "planar";
|
|
1661
|
+
return "differential";
|
|
1662
|
+
}
|
|
1663
|
+
function decodeETC2Block(block) {
|
|
1664
|
+
if (block.length !== 8) {
|
|
1665
|
+
throw new Error(`decodeETC2Block: expected 8 bytes, got ${block.length}`);
|
|
1666
|
+
}
|
|
1667
|
+
const hi = (block[0] << 24 | block[1] << 16 | block[2] << 8 | block[3]) >>> 0;
|
|
1668
|
+
const lo = (block[4] << 24 | block[5] << 16 | block[6] << 8 | block[7]) >>> 0;
|
|
1669
|
+
const mode = readETC2Mode(block);
|
|
1670
|
+
const out = new Float32Array(48);
|
|
1671
|
+
const wireIndex = (k) => {
|
|
1672
|
+
const wire = (k & 3) * 4 + (k >> 2);
|
|
1673
|
+
return (lo >>> 16 + wire & 1) << 1 | lo >>> wire & 1;
|
|
1674
|
+
};
|
|
1675
|
+
const writeTexel = (k, r, g, b) => {
|
|
1676
|
+
out[k * 3] = clamp255(r) / 255;
|
|
1677
|
+
out[k * 3 + 1] = clamp255(g) / 255;
|
|
1678
|
+
out[k * 3 + 2] = clamp255(b) / 255;
|
|
1679
|
+
};
|
|
1680
|
+
if (mode === "planar") {
|
|
1681
|
+
const ro = extend6(hi >> 25 & 63);
|
|
1682
|
+
const go = extend7((hi >> 24 & 1) << 6 | hi >> 17 & 63);
|
|
1683
|
+
const bo = extend6((hi >> 16 & 1) << 5 | (hi >> 11 & 3) << 3 | hi >> 7 & 7);
|
|
1684
|
+
const rh = extend6((hi >> 2 & 31) << 1 | hi & 1);
|
|
1685
|
+
const gh = extend7(lo >>> 25 & 127);
|
|
1686
|
+
const bh = extend6(lo >>> 19 & 63);
|
|
1687
|
+
const rv = extend6(lo >>> 13 & 63);
|
|
1688
|
+
const gv = extend7(lo >>> 6 & 127);
|
|
1689
|
+
const bv = extend6(lo & 63);
|
|
1690
|
+
for (let k = 0; k < 16; k++) {
|
|
1691
|
+
const x = k & 3;
|
|
1692
|
+
const y = k >> 2;
|
|
1693
|
+
writeTexel(
|
|
1694
|
+
k,
|
|
1695
|
+
x * (rh - ro) + y * (rv - ro) + 4 * ro + 2 >> 2,
|
|
1696
|
+
x * (gh - go) + y * (gv - go) + 4 * go + 2 >> 2,
|
|
1697
|
+
x * (bh - bo) + y * (bv - bo) + 4 * bo + 2 >> 2
|
|
1698
|
+
);
|
|
1699
|
+
}
|
|
1700
|
+
return out;
|
|
1701
|
+
}
|
|
1702
|
+
if (mode === "T" || mode === "H") {
|
|
1703
|
+
let base12;
|
|
1704
|
+
let base22;
|
|
1705
|
+
let dIdx;
|
|
1706
|
+
if (mode === "T") {
|
|
1707
|
+
base12 = [(hi >> 27 & 3) << 2 | hi >> 24 & 3, hi >> 20 & 15, hi >> 16 & 15];
|
|
1708
|
+
base22 = [hi >> 12 & 15, hi >> 8 & 15, hi >> 4 & 15];
|
|
1709
|
+
dIdx = (hi >> 2 & 3) << 1 | hi & 1;
|
|
1710
|
+
} else {
|
|
1711
|
+
base12 = [hi >> 27 & 15, (hi >> 24 & 7) << 1 | hi >> 20 & 1, (hi >> 19 & 1) << 3 | hi >> 15 & 7];
|
|
1712
|
+
base22 = [hi >> 11 & 15, hi >> 7 & 15, hi >> 3 & 15];
|
|
1713
|
+
const v1 = base12[0] << 8 | base12[1] << 4 | base12[2];
|
|
1714
|
+
const v2 = base22[0] << 8 | base22[1] << 4 | base22[2];
|
|
1715
|
+
dIdx = (hi >> 2 & 1) << 2 | (hi & 1) << 1 | (v1 >= v2 ? 1 : 0);
|
|
1716
|
+
}
|
|
1717
|
+
const c1 = base12.map(extend4);
|
|
1718
|
+
const c2 = base22.map(extend4);
|
|
1719
|
+
const d = TH_DISTANCES[dIdx];
|
|
1720
|
+
const palette = mode === "T" ? [c1, c2.map((v) => v + d), c2, c2.map((v) => v - d)] : [c1.map((v) => v + d), c1.map((v) => v - d), c2.map((v) => v + d), c2.map((v) => v - d)];
|
|
1721
|
+
for (let k = 0; k < 16; k++) {
|
|
1722
|
+
const pc = palette[wireIndex(k)];
|
|
1723
|
+
writeTexel(k, pc[0], pc[1], pc[2]);
|
|
1724
|
+
}
|
|
1725
|
+
return out;
|
|
1726
|
+
}
|
|
1727
|
+
const diff = mode === "differential";
|
|
1728
|
+
let base1;
|
|
1729
|
+
let base2;
|
|
1730
|
+
if (diff) {
|
|
1731
|
+
const codes1 = [hi >> 27 & 31, hi >> 19 & 31, hi >> 11 & 31];
|
|
1732
|
+
const codes2 = codes1.map((v, c) => v + signed3(hi >> 24 - c * 8 & 7));
|
|
1733
|
+
base1 = codes1.map(extend5);
|
|
1734
|
+
base2 = codes2.map(extend5);
|
|
1735
|
+
} else {
|
|
1736
|
+
base1 = [hi >> 28 & 15, hi >> 20 & 15, hi >> 12 & 15].map(extend4);
|
|
1737
|
+
base2 = [hi >> 24 & 15, hi >> 16 & 15, hi >> 8 & 15].map(extend4);
|
|
1738
|
+
}
|
|
1739
|
+
const table1 = hi >> 5 & 7;
|
|
1740
|
+
const table2 = hi >> 2 & 7;
|
|
1741
|
+
const flip = hi & 1;
|
|
1742
|
+
for (let k = 0; k < 16; k++) {
|
|
1743
|
+
const x = k & 3;
|
|
1744
|
+
const y = k >> 2;
|
|
1745
|
+
const sb1 = flip === 0 ? x >= 2 : y >= 2;
|
|
1746
|
+
const base = sb1 ? base2 : base1;
|
|
1747
|
+
const m = MODIFIERS[sb1 ? table2 : table1][wireIndex(k)];
|
|
1748
|
+
writeTexel(k, base[0] + m, base[1] + m, base[2] + m);
|
|
1749
|
+
}
|
|
929
1750
|
return out;
|
|
930
1751
|
}
|
|
931
1752
|
export {
|
|
@@ -934,12 +1755,17 @@ export {
|
|
|
934
1755
|
decodeBC4Block,
|
|
935
1756
|
decodeBC5Block,
|
|
936
1757
|
decodeBC7Block,
|
|
1758
|
+
decodeBC7Mode1Block,
|
|
1759
|
+
decodeBC7Mode4Block,
|
|
937
1760
|
decodeBC7Mode6Block,
|
|
1761
|
+
decodeETC2Block,
|
|
938
1762
|
encodeASTC4x4Block,
|
|
939
1763
|
encodeBC1Block,
|
|
940
1764
|
encodeBC4Block,
|
|
941
1765
|
encodeBC5Block,
|
|
942
1766
|
encodeBC7Block,
|
|
943
1767
|
encodeBC7Mode6Block,
|
|
944
|
-
|
|
1768
|
+
encodeETC2Block,
|
|
1769
|
+
readBC7Mode,
|
|
1770
|
+
readETC2Mode
|
|
945
1771
|
};
|