gputex 0.5.0 → 0.7.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 +63 -37
- package/dist/index.d.ts +153 -8
- package/dist/index.js +1038 -596
- package/dist/testing.d.ts +8 -5
- package/dist/testing.js +190 -34
- package/dist/three.d.ts +9 -130
- package/dist/three.js +659 -724
- package/package.json +1 -1
package/dist/testing.d.ts
CHANGED
|
@@ -110,8 +110,10 @@ type ASTC4x4Block = Uint8Array;
|
|
|
110
110
|
* grayscale + opaque → luminance, opaque → RGB, otherwise RGBA.
|
|
111
111
|
*
|
|
112
112
|
* Algorithm per class:
|
|
113
|
-
* 1. Quantise input to 8-bit; classify
|
|
114
|
-
*
|
|
113
|
+
* 1. Quantise input to 8-bit; classify (opaque colour tries both CEM 8
|
|
114
|
+
* bit budgets and keeps the lower-error one).
|
|
115
|
+
* 2. Farthest-pair over the class's channels → initial (e0, e1),
|
|
116
|
+
* quantised to the class's endpoint range.
|
|
115
117
|
* 3. Assign per-texel indices by nearest palette entry.
|
|
116
118
|
* 4. One LSQ refit pass; accept only if total error strictly decreases.
|
|
117
119
|
* 5. CEM 8/12: flip endpoints (and reflect weights) if
|
|
@@ -121,13 +123,14 @@ type ASTC4x4Block = Uint8Array;
|
|
|
121
123
|
declare function encodeASTC4x4Block(pixels: ASTC4x4Pixels): ASTC4x4Block;
|
|
122
124
|
/**
|
|
123
125
|
* Decode an ASTC 4×4 block produced by this encoder (or by any other
|
|
124
|
-
* encoder that respects our narrow subset: block modes 0x042/0x053/
|
|
125
|
-
* single partition, CEM 0/8/12
|
|
126
|
+
* encoder that respects our narrow subset: block modes 0x042/0x053/0x242/
|
|
127
|
+
* 0x253, single partition, CEM 0/8/12 — QUANT_192 endpoints with 0x242,
|
|
128
|
+
* 8-bit endpoints otherwise). Handles the
|
|
126
129
|
* blue-contraction branch even though our encoder doesn't produce it, so
|
|
127
130
|
* externally-supplied blocks round-trip predictably.
|
|
128
131
|
*
|
|
129
132
|
* The CEM is validated against the block mode's expected pairing (we only
|
|
130
|
-
* ever emit the
|
|
133
|
+
* ever emit the four fixed combinations above).
|
|
131
134
|
*
|
|
132
135
|
* Output: 16 RGBA pixels as 64 floats in [0, 1].
|
|
133
136
|
*/
|
package/dist/testing.js
CHANGED
|
@@ -922,33 +922,49 @@ function decodeBC7Block(block) {
|
|
|
922
922
|
// src/astc4x4_ref.ts
|
|
923
923
|
var BLOCK_MODE_4x4_2BIT = 66;
|
|
924
924
|
var BLOCK_MODE_4x4_3BIT = 83;
|
|
925
|
+
var BLOCK_MODE_4x4_4BIT = 578;
|
|
925
926
|
var BLOCK_MODE_4x4_5BIT = 595;
|
|
926
927
|
var CEM_LUM_DIRECT = 0;
|
|
927
928
|
var CEM_RGB_DIRECT = 8;
|
|
928
929
|
var CEM_RGBA_DIRECT = 12;
|
|
929
930
|
var WEIGHT_UNQ_4 = [0, 21, 43, 64];
|
|
930
931
|
var WEIGHT_UNQ_8 = [0, 9, 18, 27, 37, 46, 55, 64];
|
|
932
|
+
var WEIGHT_UNQ_16 = Array.from({ length: 16 }, (_, w) => {
|
|
933
|
+
const u = w << 2 | w >> 2;
|
|
934
|
+
return u > 32 ? u + 1 : u;
|
|
935
|
+
});
|
|
931
936
|
var WEIGHT_UNQ_32 = Array.from({ length: 32 }, (_, w) => w <= 15 ? 2 * w : 2 * w + 2);
|
|
932
937
|
var CLASS_LUM = {
|
|
933
938
|
cem: CEM_LUM_DIRECT,
|
|
934
939
|
blockMode: BLOCK_MODE_4x4_5BIT,
|
|
935
940
|
channels: [0],
|
|
936
941
|
weightBits: 5,
|
|
937
|
-
unq: WEIGHT_UNQ_32
|
|
942
|
+
unq: WEIGHT_UNQ_32,
|
|
943
|
+
endpointRange: 256
|
|
938
944
|
};
|
|
939
945
|
var CLASS_RGB = {
|
|
940
946
|
cem: CEM_RGB_DIRECT,
|
|
941
947
|
blockMode: BLOCK_MODE_4x4_3BIT,
|
|
942
948
|
channels: [0, 1, 2],
|
|
943
949
|
weightBits: 3,
|
|
944
|
-
unq: WEIGHT_UNQ_8
|
|
950
|
+
unq: WEIGHT_UNQ_8,
|
|
951
|
+
endpointRange: 256
|
|
952
|
+
};
|
|
953
|
+
var CLASS_RGB_Q192 = {
|
|
954
|
+
cem: CEM_RGB_DIRECT,
|
|
955
|
+
blockMode: BLOCK_MODE_4x4_4BIT,
|
|
956
|
+
channels: [0, 1, 2],
|
|
957
|
+
weightBits: 4,
|
|
958
|
+
unq: WEIGHT_UNQ_16,
|
|
959
|
+
endpointRange: 192
|
|
945
960
|
};
|
|
946
961
|
var CLASS_RGBA = {
|
|
947
962
|
cem: CEM_RGBA_DIRECT,
|
|
948
963
|
blockMode: BLOCK_MODE_4x4_2BIT,
|
|
949
964
|
channels: [0, 1, 2, 3],
|
|
950
965
|
weightBits: 2,
|
|
951
|
-
unq: WEIGHT_UNQ_4
|
|
966
|
+
unq: WEIGHT_UNQ_4,
|
|
967
|
+
endpointRange: 256
|
|
952
968
|
};
|
|
953
969
|
function clamp2(v, lo, hi) {
|
|
954
970
|
return v < lo ? lo : v > hi ? hi : v;
|
|
@@ -959,6 +975,84 @@ function to82(v) {
|
|
|
959
975
|
function interp16(e0, e1, w) {
|
|
960
976
|
return (64 - w) * e0 * 257 + w * e1 * 257 + 32 >> 6;
|
|
961
977
|
}
|
|
978
|
+
function unq192(value) {
|
|
979
|
+
const trit = value >> 6;
|
|
980
|
+
const bits = value & 63;
|
|
981
|
+
const A = bits & 1 ? 511 : 0;
|
|
982
|
+
const f = bits >> 5 & 1;
|
|
983
|
+
const B = (bits >> 1 & 31) << 4 | f;
|
|
984
|
+
const T = (trit * 5 + B ^ A) & 511;
|
|
985
|
+
return (A & 128 | T >> 2) & 255;
|
|
986
|
+
}
|
|
987
|
+
var Q192_VALUE_OF = (() => {
|
|
988
|
+
const t = new Int16Array(256).fill(-1);
|
|
989
|
+
for (let v = 0; v < 192; v++) t[unq192(v)] = v;
|
|
990
|
+
return t;
|
|
991
|
+
})();
|
|
992
|
+
function nearest192(x) {
|
|
993
|
+
const v = clamp2(Math.round(x), 0, 255);
|
|
994
|
+
if (Q192_VALUE_OF[v] >= 0) return v;
|
|
995
|
+
const lo = v - 1;
|
|
996
|
+
const hi = v + 1;
|
|
997
|
+
const loOk = lo >= 0 && Q192_VALUE_OF[lo] >= 0;
|
|
998
|
+
const hiOk = hi <= 255 && Q192_VALUE_OF[hi] >= 0;
|
|
999
|
+
if (loOk && hiOk) return x - lo <= hi - x ? lo : hi;
|
|
1000
|
+
if (loOk) return x - lo <= 2 ? lo : v + 2;
|
|
1001
|
+
return hiOk ? hi : v - 2;
|
|
1002
|
+
}
|
|
1003
|
+
function decodeTrits(T) {
|
|
1004
|
+
const bit = (x, i) => x >> i & 1;
|
|
1005
|
+
let C;
|
|
1006
|
+
let t3;
|
|
1007
|
+
let t4;
|
|
1008
|
+
if ((T >> 2 & 7) === 7) {
|
|
1009
|
+
C = (T >> 5 & 7) << 2 | T & 3;
|
|
1010
|
+
t4 = 2;
|
|
1011
|
+
t3 = 2;
|
|
1012
|
+
} else {
|
|
1013
|
+
C = T & 31;
|
|
1014
|
+
if ((T >> 5 & 3) === 3) {
|
|
1015
|
+
t4 = 2;
|
|
1016
|
+
t3 = bit(T, 7);
|
|
1017
|
+
} else {
|
|
1018
|
+
t4 = bit(T, 7);
|
|
1019
|
+
t3 = T >> 5 & 3;
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
let t0;
|
|
1023
|
+
let t1;
|
|
1024
|
+
let t2;
|
|
1025
|
+
if ((C & 3) === 3) {
|
|
1026
|
+
t2 = 2;
|
|
1027
|
+
t1 = bit(C, 4);
|
|
1028
|
+
t0 = bit(C, 3) << 1 | bit(C, 2) & ~bit(C, 3) & 1;
|
|
1029
|
+
} else if ((C >> 2 & 3) === 3) {
|
|
1030
|
+
t2 = 2;
|
|
1031
|
+
t1 = 2;
|
|
1032
|
+
t0 = C & 3;
|
|
1033
|
+
} else {
|
|
1034
|
+
t2 = bit(C, 4);
|
|
1035
|
+
t1 = C >> 2 & 3;
|
|
1036
|
+
t0 = bit(C, 1) << 1 | bit(C, 0) & ~bit(C, 1) & 1;
|
|
1037
|
+
}
|
|
1038
|
+
return [t0, t1, t2, t3, t4];
|
|
1039
|
+
}
|
|
1040
|
+
function encodeTrits(t0, t1, t2, t3, t4) {
|
|
1041
|
+
let C;
|
|
1042
|
+
if (t2 === 2 && t1 === 2) C = 12 | t0;
|
|
1043
|
+
else if (t2 === 2) C = t1 << 4 | t0 << 2 | 3;
|
|
1044
|
+
else C = t2 << 4 | t1 << 2 | t0;
|
|
1045
|
+
if (t3 === 2 && t4 === 2) return C >> 2 << 5 | 7 << 2 | C & 3;
|
|
1046
|
+
if (t4 === 2) return t3 << 7 | 3 << 5 | C;
|
|
1047
|
+
return t4 << 7 | t3 << 5 | C;
|
|
1048
|
+
}
|
|
1049
|
+
var TRIT_SLICES = [
|
|
1050
|
+
[0, 2],
|
|
1051
|
+
[2, 2],
|
|
1052
|
+
[4, 1],
|
|
1053
|
+
[5, 2],
|
|
1054
|
+
[7, 1]
|
|
1055
|
+
];
|
|
962
1056
|
var BitWriter1282 = class {
|
|
963
1057
|
bits = 0n;
|
|
964
1058
|
write(pos, nBits, value) {
|
|
@@ -1070,39 +1164,61 @@ function refitEndpoints2(vals, C, indices, unq) {
|
|
|
1070
1164
|
}
|
|
1071
1165
|
return { e0, e1 };
|
|
1072
1166
|
}
|
|
1073
|
-
function
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
const pixels8 = new Uint8Array(64);
|
|
1078
|
-
for (let k = 0; k < 64; k++) pixels8[k] = to82(pixels[k]);
|
|
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;
|
|
1167
|
+
function quantEndpoint(cls, e) {
|
|
1168
|
+
return cls.endpointRange === 192 ? e.map(nearest192) : e.map((v) => clamp2(Math.round(v), 0, 255));
|
|
1169
|
+
}
|
|
1170
|
+
function fitClass(cls, pixels8) {
|
|
1087
1171
|
const C = cls.channels.length;
|
|
1088
1172
|
const vals = new Float64Array(16 * C);
|
|
1089
1173
|
for (let k = 0; k < 16; k++) {
|
|
1090
1174
|
for (let c = 0; c < C; c++) vals[k * C + c] = pixels8[k * 4 + cls.channels[c]];
|
|
1091
1175
|
}
|
|
1092
1176
|
const fp = farthestPair2(vals, C);
|
|
1093
|
-
let e0 =
|
|
1094
|
-
|
|
1177
|
+
let e0 = quantEndpoint(
|
|
1178
|
+
cls,
|
|
1179
|
+
Array.from({ length: C }, (_, c) => vals[fp.i0 * C + c])
|
|
1180
|
+
);
|
|
1181
|
+
let e1 = quantEndpoint(
|
|
1182
|
+
cls,
|
|
1183
|
+
Array.from({ length: C }, (_, c) => vals[fp.i1 * C + c])
|
|
1184
|
+
);
|
|
1095
1185
|
let { indices, err } = totalSqError(vals, C, e0, e1, cls.unq);
|
|
1096
1186
|
const refit = refitEndpoints2(vals, C, indices, cls.unq);
|
|
1097
1187
|
if (refit) {
|
|
1098
|
-
const
|
|
1188
|
+
const r0 = quantEndpoint(cls, refit.e0);
|
|
1189
|
+
const r1 = quantEndpoint(cls, refit.e1);
|
|
1190
|
+
const second = totalSqError(vals, C, r0, r1, cls.unq);
|
|
1099
1191
|
if (second.err < err) {
|
|
1100
|
-
e0 =
|
|
1101
|
-
e1 =
|
|
1192
|
+
e0 = r0;
|
|
1193
|
+
e1 = r1;
|
|
1102
1194
|
indices = second.indices;
|
|
1103
1195
|
err = second.err;
|
|
1104
1196
|
}
|
|
1105
1197
|
}
|
|
1198
|
+
return { e0, e1, indices, err };
|
|
1199
|
+
}
|
|
1200
|
+
function encodeASTC4x4Block(pixels) {
|
|
1201
|
+
if (pixels.length !== 64) {
|
|
1202
|
+
throw new Error(`encodeASTC4x4Block: expected 64 values (16 RGBA), got ${pixels.length}`);
|
|
1203
|
+
}
|
|
1204
|
+
const pixels8 = new Uint8Array(64);
|
|
1205
|
+
for (let k = 0; k < 64; k++) pixels8[k] = to82(pixels[k]);
|
|
1206
|
+
let gray = true;
|
|
1207
|
+
let opaque = true;
|
|
1208
|
+
for (let k = 0; k < 16; k++) {
|
|
1209
|
+
const r = pixels8[k * 4];
|
|
1210
|
+
if (pixels8[k * 4 + 1] !== r || pixels8[k * 4 + 2] !== r) gray = false;
|
|
1211
|
+
if (pixels8[k * 4 + 3] !== 255) opaque = false;
|
|
1212
|
+
}
|
|
1213
|
+
const classes = opaque ? gray ? [CLASS_LUM] : [CLASS_RGB, CLASS_RGB_Q192] : [CLASS_RGBA];
|
|
1214
|
+
let best = null;
|
|
1215
|
+
for (const cls2 of classes) {
|
|
1216
|
+
const fit = fitClass(cls2, pixels8);
|
|
1217
|
+
if (!best || fit.err < best.err) best = { cls: cls2, ...fit };
|
|
1218
|
+
}
|
|
1219
|
+
const { cls } = best;
|
|
1220
|
+
let { e0, e1, indices } = best;
|
|
1221
|
+
const C = cls.channels.length;
|
|
1106
1222
|
{
|
|
1107
1223
|
const nSum = Math.min(C, 3);
|
|
1108
1224
|
let s0 = 0;
|
|
@@ -1128,9 +1244,29 @@ function packBlock3(cls, e0, e1, indices) {
|
|
|
1128
1244
|
bw.write(0, 11, cls.blockMode);
|
|
1129
1245
|
bw.write(11, 2, 0);
|
|
1130
1246
|
bw.write(13, 4, cls.cem);
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1247
|
+
const values = [];
|
|
1248
|
+
for (let c = 0; c < e0.length; c++) values.push(e0[c], e1[c]);
|
|
1249
|
+
if (cls.endpointRange === 192) {
|
|
1250
|
+
let pos = 17;
|
|
1251
|
+
for (let g = 0; g < values.length; g += 5) {
|
|
1252
|
+
const grp = values.slice(g, g + 5).map((v) => {
|
|
1253
|
+
const q = Q192_VALUE_OF[v];
|
|
1254
|
+
if (q < 0) throw new Error(`packBlock: ${v} is not a QUANT_192 level`);
|
|
1255
|
+
return q;
|
|
1256
|
+
});
|
|
1257
|
+
const t = [0, 0, 0, 0, 0];
|
|
1258
|
+
grp.forEach((q, i) => t[i] = q >> 6);
|
|
1259
|
+
const T = encodeTrits(t[0], t[1], t[2], t[3], t[4]);
|
|
1260
|
+
grp.forEach((q, i) => {
|
|
1261
|
+
bw.write(pos, 6, q & 63);
|
|
1262
|
+
pos += 6;
|
|
1263
|
+
const [start, count] = TRIT_SLICES[i];
|
|
1264
|
+
bw.write(pos, count, T >> start & (1 << count) - 1);
|
|
1265
|
+
pos += count;
|
|
1266
|
+
});
|
|
1267
|
+
}
|
|
1268
|
+
} else {
|
|
1269
|
+
values.forEach((v, i) => bw.write(17 + i * 8, 8, v));
|
|
1134
1270
|
}
|
|
1135
1271
|
for (let k = 0; k < 16; k++) {
|
|
1136
1272
|
const w = indices[k];
|
|
@@ -1140,19 +1276,20 @@ function packBlock3(cls, e0, e1, indices) {
|
|
|
1140
1276
|
}
|
|
1141
1277
|
return bw.toBytes();
|
|
1142
1278
|
}
|
|
1143
|
-
var
|
|
1144
|
-
[BLOCK_MODE_4x4_2BIT]: CLASS_RGBA,
|
|
1145
|
-
[BLOCK_MODE_4x4_3BIT]: CLASS_RGB,
|
|
1146
|
-
[
|
|
1279
|
+
var CLASS_BY_MODE_CEM = {
|
|
1280
|
+
[`${BLOCK_MODE_4x4_2BIT}:${CEM_RGBA_DIRECT}`]: CLASS_RGBA,
|
|
1281
|
+
[`${BLOCK_MODE_4x4_3BIT}:${CEM_RGB_DIRECT}`]: CLASS_RGB,
|
|
1282
|
+
[`${BLOCK_MODE_4x4_4BIT}:${CEM_RGB_DIRECT}`]: CLASS_RGB_Q192,
|
|
1283
|
+
[`${BLOCK_MODE_4x4_5BIT}:${CEM_LUM_DIRECT}`]: CLASS_LUM
|
|
1147
1284
|
};
|
|
1285
|
+
var SUPPORTED_MODES = /* @__PURE__ */ new Set([BLOCK_MODE_4x4_2BIT, BLOCK_MODE_4x4_3BIT, BLOCK_MODE_4x4_4BIT, BLOCK_MODE_4x4_5BIT]);
|
|
1148
1286
|
function decodeASTC4x4Block(block) {
|
|
1149
1287
|
if (block.length !== 16) {
|
|
1150
1288
|
throw new Error(`decodeASTC4x4Block: expected 16 bytes, got ${block.length}`);
|
|
1151
1289
|
}
|
|
1152
1290
|
const br = new BitReader1282(block);
|
|
1153
1291
|
const mode = br.read(0, 11);
|
|
1154
|
-
|
|
1155
|
-
if (!cls) {
|
|
1292
|
+
if (!SUPPORTED_MODES.has(mode)) {
|
|
1156
1293
|
throw new Error(`decodeASTC4x4Block: unsupported block mode 0x${mode.toString(16)}`);
|
|
1157
1294
|
}
|
|
1158
1295
|
const partCount = br.read(11, 2);
|
|
@@ -1160,12 +1297,31 @@ function decodeASTC4x4Block(block) {
|
|
|
1160
1297
|
throw new Error(`decodeASTC4x4Block: multi-partition blocks not supported (count=${partCount + 1})`);
|
|
1161
1298
|
}
|
|
1162
1299
|
const cem = br.read(13, 4);
|
|
1163
|
-
|
|
1164
|
-
|
|
1300
|
+
const cls = CLASS_BY_MODE_CEM[`${mode}:${cem}`];
|
|
1301
|
+
if (!cls) {
|
|
1302
|
+
throw new Error(`decodeASTC4x4Block: unsupported CEM ${cem} with block mode 0x${mode.toString(16)}`);
|
|
1165
1303
|
}
|
|
1166
1304
|
const nVals = cls.channels.length * 2;
|
|
1167
1305
|
const v = [];
|
|
1168
|
-
|
|
1306
|
+
if (cls.endpointRange === 192) {
|
|
1307
|
+
let pos = 17;
|
|
1308
|
+
for (let g = 0; g < nVals; g += 5) {
|
|
1309
|
+
const n = Math.min(5, nVals - g);
|
|
1310
|
+
const bits = [];
|
|
1311
|
+
let T = 0;
|
|
1312
|
+
for (let i = 0; i < n; i++) {
|
|
1313
|
+
bits.push(br.read(pos, 6));
|
|
1314
|
+
pos += 6;
|
|
1315
|
+
const [start, count] = TRIT_SLICES[i];
|
|
1316
|
+
T |= br.read(pos, count) << start;
|
|
1317
|
+
pos += count;
|
|
1318
|
+
}
|
|
1319
|
+
const t = decodeTrits(T);
|
|
1320
|
+
for (let i = 0; i < n; i++) v.push(unq192(t[i] << 6 | bits[i]));
|
|
1321
|
+
}
|
|
1322
|
+
} else {
|
|
1323
|
+
for (let i = 0; i < nVals; i++) v.push(br.read(17 + i * 8, 8));
|
|
1324
|
+
}
|
|
1169
1325
|
let e0;
|
|
1170
1326
|
let e1;
|
|
1171
1327
|
if (cls.cem === CEM_LUM_DIRECT) {
|
package/dist/three.d.ts
CHANGED
|
@@ -1,139 +1,18 @@
|
|
|
1
|
-
import { TextureHint, PreferredFormat, FormatQuality, SvgRasterSize, TextureFormat, Encoder, EncoderImageSource } from './index.js';
|
|
2
|
-
export { ASTC4x4Encoder, ASTC4x4WebGLEncoder, BC1Encoder, BC1WebGLEncoder, BC5Encoder, BC5WebGLEncoder, BC7Encoder, BC7EncoderOptions, BC7WebGLEncoder, Capabilities, ETC2Encoder, EncodeBytesResult, EncodeCallOptions, EncodeMipChainResult, EncodedLevelBytes, EncoderConstructor, EncoderOptions, ExtensionProvider, FeatureProvider, FormatSelection, FormatVariant, MipLevel, RasterizeSvgOptions, RawPixelSource, SelectFormatOptions, WebGLBlockEncoder, WebGLCapabilities, WebGLEncodeBytesResult, WebGLEncoderConstructor, WebGLEncoderImageSource, WebGLEncoderOptions, WebGLFormatSelection, WebGPUFeature, createWebGLContext, detectCapabilities, detectWebGLCapabilities, generateGpuMipChain, generateMipChain, getSharedWebGLContext, gpuMipLevelCount, isWebGLAvailable, padToBlockMultiple, rasterizeSvg, selectFormat, selectWebGLFormat } from './index.js';
|
|
1
|
+
import { CompressResult as CompressResult$1, CompressTextureSource, CompressOptions, TextureHint, PreferredFormat, FormatQuality, SvgRasterSize, TextureFormat, Encoder, EncoderImageSource } from './index.js';
|
|
2
|
+
export { ASTC4x4Encoder, ASTC4x4WebGLEncoder, BC1Encoder, BC1WebGLEncoder, BC5Encoder, BC5WebGLEncoder, BC7Encoder, BC7EncoderOptions, BC7WebGLEncoder, Capabilities, ETC2Encoder, EncodeBytesResult, EncodeCallOptions, EncodeMipChainResult, EncodedLevelBytes, EncoderConstructor, EncoderOptions, ExtensionProvider, FeatureProvider, FormatSelection, FormatVariant, MipLevel, RasterizeSvgOptions, RawPixelSource, SelectFormatOptions, WebGLBlockEncoder, WebGLCapabilities, WebGLEncodeBytesResult, WebGLEncoderConstructor, WebGLEncoderImageSource, WebGLEncoderOptions, WebGLFormatSelection, WebGPUFeature, clearTranscodeCache, compressTextureToBytes, createWebGLContext, detectCapabilities, detectWebGLCapabilities, generateGpuMipChain, generateMipChain, getSharedWebGLContext, gpuMipLevelCount, isWebGLAvailable, padToBlockMultiple, rasterizeSvg, releaseSharedGpuResources, selectFormat, selectWebGLFormat, setTranscodeCacheLimit } from './index.js';
|
|
3
3
|
import { Texture, CompressedTexture, Loader, CompressedPixelFormat } from 'three';
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
*
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
*
|
|
10
|
-
* SVG works through all of these: a URL to an `.svg` file, a string of
|
|
11
|
-
* inline SVG markup (detected by a leading `<`), an SVG Blob/File, or an
|
|
12
|
-
* HTMLImageElement whose src is SVG. Vector sources are rasterised to RGBA
|
|
13
|
-
* before encoding — see the `svgSize` option.
|
|
14
|
-
*/
|
|
15
|
-
type CompressTextureSource = string | Blob | File | ImageBitmap | HTMLImageElement | HTMLCanvasElement | OffscreenCanvas | ImageData;
|
|
16
|
-
interface CompressOptions {
|
|
17
|
-
/** How the texture will be used. Drives format selection. Default 'color'. */
|
|
18
|
-
hint?: TextureHint;
|
|
19
|
-
/**
|
|
20
|
-
* Prefer a specific format over the default choice when the device
|
|
21
|
-
* supports it; falls back to the normal selection (BC7 → ASTC → ETC2 →
|
|
22
|
-
* RGBA8) when it doesn't. Currently only 'bc1': half the memory of BC7
|
|
23
|
-
* for opaque colour textures, at lower quality. Only honoured with
|
|
24
|
-
* `hint: 'color'` — BC1 can't carry real alpha or normal maps.
|
|
25
|
-
*/
|
|
26
|
-
preferredFormat?: PreferredFormat;
|
|
27
|
-
/**
|
|
28
|
-
* Memory/fidelity trade-off for opaque colour textures. Default 'high'
|
|
29
|
-
* (BC7 / ASTC 4×4, 1 byte/pixel). 'low' picks the 4-bpp formats when the
|
|
30
|
-
* device has one — BC1 on desktop-class GPUs, ETC2 RGB8 on mobile-class
|
|
31
|
-
* ones — halving GPU memory at visibly lower quality on smooth content.
|
|
32
|
-
* Ignored for `hint: 'colorWithAlpha'` and `hint: 'normal'` (the 4-bpp
|
|
33
|
-
* formats can't carry them). On the WebGL fallback tier only BC1 is
|
|
34
|
-
* available at 'low'.
|
|
35
|
-
*/
|
|
36
|
-
quality?: FormatQuality;
|
|
37
|
-
/** Pick the sRGB or linear variant of the chosen format. Default 'srgb'. */
|
|
38
|
-
colorSpace?: 'srgb' | 'linear';
|
|
39
|
-
/**
|
|
40
|
-
* Rasterisation size for SVG sources. A number scales the SVG so its
|
|
41
|
-
* longest side matches (aspect ratio preserved); `{ width, height }`
|
|
42
|
-
* rasterises at exactly that size. Default: the SVG's intrinsic size
|
|
43
|
-
* (absolute width/height attributes, else the viewBox dimensions).
|
|
44
|
-
* Ignored for non-SVG sources.
|
|
45
|
-
*/
|
|
46
|
-
svgSize?: SvgRasterSize;
|
|
47
|
-
/** Flip the image vertically before encoding. Default true (matches Three.js convention). */
|
|
48
|
-
flipY?: boolean;
|
|
49
|
-
/** Generate a full mip chain down to 1×1 on the CPU, encode every level. */
|
|
50
|
-
mipmaps?: boolean;
|
|
51
|
-
/** Reuse an existing device (e.g. Three.js's renderer device) instead
|
|
52
|
-
* of creating a new one. WebGPU path only. When provided, the encoder
|
|
53
|
-
* never destroys it. */
|
|
54
|
-
device?: GPUDevice;
|
|
55
|
-
adapter?: GPUAdapter;
|
|
56
|
-
/**
|
|
57
|
-
* Keep the compressed bytes in a session-scoped in-memory LRU and reuse
|
|
58
|
-
* them on repeat calls, skipping BOTH the image decode and the encode —
|
|
59
|
-
* the dominant costs. Re-loading a texture later in the session (e.g.
|
|
60
|
-
* two worlds sharing an atlas) becomes a few ms. Keyed by source
|
|
61
|
-
* identity + selected format + encode options; capped at 256 MiB of
|
|
62
|
-
* compressed bytes by default (`setTranscodeCacheLimit()` to tune) and
|
|
63
|
-
* never touches persistent storage. Default false.
|
|
64
|
-
*
|
|
65
|
-
* URL and Blob/File sources get an identity automatically (URL string or
|
|
66
|
-
* content hash). Pixel sources (ImageBitmap, canvas, ImageData) are only
|
|
67
|
-
* cached when `cacheKey` is provided.
|
|
68
|
-
*/
|
|
69
|
-
cache?: boolean;
|
|
70
|
-
/**
|
|
71
|
-
* Explicit cache identity for the source, overriding the derived one.
|
|
72
|
-
* Use when you already know a stable name (e.g. an asset path) and want
|
|
73
|
-
* to skip content hashing, or to make pixel sources cacheable.
|
|
74
|
-
*/
|
|
75
|
-
cacheKey?: string;
|
|
76
|
-
}
|
|
77
|
-
interface CompressResult {
|
|
78
|
-
/** CompressedTexture on a compressed path; Texture on RGBA8 fallback. */
|
|
5
|
+
/** A `compressTexture()` result: a ready-to-use texture plus the same encode
|
|
6
|
+
* metadata `compressTextureToBytes()` returns (minus the raw `levels`). */
|
|
7
|
+
interface CompressResult extends Omit<CompressResult$1, 'levels' | 'fallbackBitmap'> {
|
|
8
|
+
/** `CompressedTexture` on a compressed path; a plain `Texture` on the RGBA8 fallback. */
|
|
79
9
|
texture: Texture | CompressedTexture;
|
|
80
|
-
/**
|
|
81
|
-
|
|
82
|
-
/** True iff we returned an uncompressed Texture because no encoder fit. */
|
|
83
|
-
fallbackUncompressed: boolean;
|
|
84
|
-
/**
|
|
85
|
-
* Which backend produced the result. 'webgpu' = compute path, 'webgl' =
|
|
86
|
-
* fragment-shader fallback, 'none' = uncompressed RGBA8.
|
|
87
|
-
*/
|
|
88
|
-
backend: 'webgpu' | 'webgl' | 'none';
|
|
89
|
-
/**
|
|
90
|
-
* True iff the chosen format is ASTC and the hint was 'normal'. The
|
|
91
|
-
* caller must apply the (R, W) → (x, y) swizzle in the material — ASTC
|
|
92
|
-
* has no 2-channel mode, so normal maps ride the RGBA path.
|
|
93
|
-
*/
|
|
94
|
-
astcNormalRemap: boolean;
|
|
95
|
-
width: number;
|
|
96
|
-
height: number;
|
|
97
|
-
mipLevels: number;
|
|
98
|
-
/** Wall-clock time of GPU encoding, summed across mip levels. */
|
|
99
|
-
encodeMs: number;
|
|
100
|
-
/**
|
|
101
|
-
* Wall-clock time to turn the source into decoded RGBA pixels: fetch /
|
|
102
|
-
* base64 decode, image decode, SVG rasterisation. Usually the dominant
|
|
103
|
-
* cost for large images — when a load feels slower than `encodeMs`
|
|
104
|
-
* suggests, this is where the time went.
|
|
105
|
-
*/
|
|
106
|
-
decodeMs: number;
|
|
107
|
-
/** Wall-clock time of the whole `compressTexture()` call: decode + CPU
|
|
108
|
-
* mip generation + encode + texture assembly. */
|
|
109
|
-
totalMs: number;
|
|
110
|
-
/** True when the result came from the in-memory transcode cache (the
|
|
111
|
-
* `cache` option) — no decode or encode ran; decodeMs/encodeMs are 0. */
|
|
112
|
-
cacheHit: boolean;
|
|
113
|
-
/** Dispose the texture and release GPU resources owned by this call.
|
|
114
|
-
* On the default path (no `device`/`adapter` option) the encoder and
|
|
115
|
-
* device are shared across `compressTexture()` calls and survive this —
|
|
116
|
-
* release those with `releaseSharedGpuResources()`. */
|
|
10
|
+
/** Dispose the texture. The shared encoder/device survive — release those
|
|
11
|
+
* with `releaseSharedGpuResources()`. */
|
|
117
12
|
destroy(): void;
|
|
118
13
|
}
|
|
119
|
-
/**
|
|
120
|
-
* Destroy the WebGPU device and encoders that `compressTexture()` shares
|
|
121
|
-
* across calls (created lazily when neither the `device` nor the `adapter`
|
|
122
|
-
* option is passed). Safe to call at any time — in-flight encodes on the
|
|
123
|
-
* shared device will fail, and the next `compressTexture()` call recreates
|
|
124
|
-
* everything. No-op when nothing is cached.
|
|
125
|
-
*/
|
|
126
|
-
declare function releaseSharedGpuResources(): void;
|
|
127
14
|
declare function compressTexture(source: CompressTextureSource, options?: CompressOptions): Promise<CompressResult>;
|
|
128
15
|
|
|
129
|
-
/**
|
|
130
|
-
* Cap the cache's total compressed payload in bytes (default 256 MiB).
|
|
131
|
-
* Lower it to evict immediately; 0 disables caching entirely.
|
|
132
|
-
*/
|
|
133
|
-
declare function setTranscodeCacheLimit(bytes: number): void;
|
|
134
|
-
/** Drop every cached transcode. Textures already built from entries are unaffected. */
|
|
135
|
-
declare function clearTranscodeCache(): void;
|
|
136
|
-
|
|
137
16
|
declare class GputexLoader extends Loader<Texture> {
|
|
138
17
|
/** Format-selection hint. Default 'color'. */
|
|
139
18
|
hint: TextureHint;
|
|
@@ -230,4 +109,4 @@ interface EncodeToTextureOptions {
|
|
|
230
109
|
*/
|
|
231
110
|
declare function encodeToTexture(encoder: Encoder, source: EncoderImageSource, { colorSpace, flipY }?: EncodeToTextureOptions): Promise<EncodeResult>;
|
|
232
111
|
|
|
233
|
-
export {
|
|
112
|
+
export { CompressOptions, type CompressResult, CompressTextureSource, type EncodeResult, type EncodeToTextureOptions, Encoder, EncoderImageSource, FormatQuality, GputexLoader, PreferredFormat, SvgRasterSize, TextureFormat, TextureHint, buildCompressedTexture, compressTexture, encodeToTexture, threeFormatFor };
|