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/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 interp82(e0, e1, w) {
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(pixels8) {
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
- const bj = j * 4;
747
- const dr = pixels8[bi] - pixels8[bj];
748
- const dg = pixels8[bi + 1] - pixels8[bj + 1];
749
- const db = pixels8[bi + 2] - pixels8[bj + 2];
750
- const da = pixels8[bi + 3] - pixels8[bj + 3];
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 pal = new Uint8Array(4 * 4);
763
- for (let i = 0; i < 4; i++) {
764
- const w = WEIGHT_UNQ_4[i];
765
- const base = i * 4;
766
- for (let c = 0; c < 4; c++) {
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 assignIndex2(pixel, palette) {
773
- let bestIdx = 0;
774
- let bestD = Infinity;
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
- const base = k * 4;
795
- const sel = assignIndex2([pixels8[base], pixels8[base + 1], pixels8[base + 2], pixels8[base + 3]], pal);
796
- indices[k] = sel.idx;
797
- err += sel.err;
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(pixels8, indices) {
1047
+ function refitEndpoints2(vals, C, indices, unq) {
802
1048
  let sAA = 0, sBB = 0, sAB = 0;
803
- const sAV = [0, 0, 0, 0];
804
- const sBV = [0, 0, 0, 0];
1049
+ const sAV = new Float64Array(C);
1050
+ const sBV = new Float64Array(C);
805
1051
  for (let k = 0; k < 16; k++) {
806
- const unq = WEIGHT_UNQ_4[indices[k]];
807
- const a = (64 - unq) / 64;
808
- const b = unq / 64;
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
- const base = k * 4;
813
- for (let c = 0; c < 4; c++) {
814
- sAV[c] += a * pixels8[base + c];
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 = [0, 0, 0, 0];
821
- const e1 = [0, 0, 0, 0];
822
- for (let c = 0; c < 4; 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
- const fp = farthestPair2(pixels8);
835
- let e0 = [
836
- pixels8[fp.i0 * 4],
837
- pixels8[fp.i0 * 4 + 1],
838
- pixels8[fp.i0 * 4 + 2],
839
- pixels8[fp.i0 * 4 + 3]
840
- ];
841
- let e1 = [
842
- pixels8[fp.i1 * 4],
843
- pixels8[fp.i1 * 4 + 1],
844
- pixels8[fp.i1 * 4 + 2],
845
- pixels8[fp.i1 * 4 + 3]
846
- ];
847
- let { indices, err } = totalSqError(pixels8, e0, e1);
848
- const refit = refitEndpoints2(pixels8, indices);
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 { indices: idx2, err: err2 } = totalSqError(pixels8, refit.e0, refit.e1);
851
- if (err2 < err) {
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 = idx2;
855
- err = err2;
1102
+ indices = second.indices;
1103
+ err = second.err;
856
1104
  }
857
1105
  }
858
- const s0 = e0[0] + e0[1] + e0[2];
859
- const s1 = e1[0] + e1[1] + e1[2];
860
- if (s0 > s1) {
861
- const tmp = e0;
862
- e0 = e1;
863
- e1 = tmp;
864
- const inv = new Uint8Array(16);
865
- for (let k = 0; k < 16; k++) inv[k] = 3 - indices[k];
866
- indices = inv;
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, BLOCK_MODE_4x4_2BIT);
1128
+ bw.write(0, 11, cls.blockMode);
873
1129
  bw.write(11, 2, 0);
874
- bw.write(13, 4, CEM_RGBA_DIRECT);
875
- const ep = [e0[0], e1[0], e0[1], e1[1], e0[2], e1[2], e0[3], e1[3]];
876
- for (let i = 0; i < 8; i++) bw.write(17 + i * 8, 8, ep[i]);
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] & 3;
879
- bw.write(127 - 2 * k, 1, w & 1);
880
- bw.write(126 - 2 * k, 1, w >> 1 & 1);
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
- if (mode !== BLOCK_MODE_4x4_2BIT) {
891
- throw new Error(
892
- `decodeASTC4x4Block: expected block mode 0x${BLOCK_MODE_4x4_2BIT.toString(16)}, got 0x${mode.toString(16)}`
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 !== CEM_RGBA_DIRECT) {
901
- throw new Error(`decodeASTC4x4Block: only CEM 12 supported, got ${cem}`);
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 < 8; i++) v.push(br.read(17 + i * 8, 8));
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 (v0 + v2 + v4 <= v1 + v3 + v5) {
909
- e0 = [v0, v2, v4, v6];
910
- e1 = [v1, v3, v5, v7];
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
- e0 = [v1 + v5 >> 1, v3 + v5 >> 1, v5, v7];
913
- e1 = [v0 + v4 >> 1, v2 + v4 >> 1, v4, v6];
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
- const lsb = br.read(127 - 2 * k, 1);
918
- const msb = br.read(126 - 2 * k, 1);
919
- weights[k] = lsb | msb << 1;
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 w = WEIGHT_UNQ_4[weights[k]];
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] = interp82(e0[c], e1[c], w) / 255;
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
- readBC7Mode
1768
+ encodeETC2Block,
1769
+ readBC7Mode,
1770
+ readETC2Mode
945
1771
  };