gputex 0.1.2 → 0.3.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.
@@ -0,0 +1,945 @@
1
+ // src/bc1_ref.ts
2
+ var WA = [1, 0, 2 / 3, 1 / 3];
3
+ var WB = [0, 1, 1 / 3, 2 / 3];
4
+ function clamp01(v) {
5
+ return v < 0 ? 0 : v > 1 ? 1 : v;
6
+ }
7
+ function to565(r, g, b) {
8
+ const ri = Math.max(0, Math.min(31, Math.floor(r * 31 + 0.5)));
9
+ const gi = Math.max(0, Math.min(63, Math.floor(g * 63 + 0.5)));
10
+ const bi = Math.max(0, Math.min(31, Math.floor(b * 31 + 0.5)));
11
+ return ri << 11 | gi << 5 | bi;
12
+ }
13
+ function from565(c) {
14
+ const r = c >> 11 & 31;
15
+ const g = c >> 5 & 63;
16
+ const b = c & 31;
17
+ const r8 = Math.floor((r * 527 + 23) / 64);
18
+ const g8 = Math.floor((g * 259 + 33) / 64);
19
+ const b8 = Math.floor((b * 527 + 23) / 64);
20
+ return [r8 / 255, g8 / 255, b8 / 255];
21
+ }
22
+ function buildPalette4(c0, c1) {
23
+ const p0 = from565(c0);
24
+ const p1 = from565(c1);
25
+ const pal = new Float32Array(12);
26
+ for (let j = 0; j < 4; j++) {
27
+ pal[j * 3] = WA[j] * p0[0] + WB[j] * p1[0];
28
+ pal[j * 3 + 1] = WA[j] * p0[1] + WB[j] * p1[1];
29
+ pal[j * 3 + 2] = WA[j] * p0[2] + WB[j] * p1[2];
30
+ }
31
+ return pal;
32
+ }
33
+ function assignIndices(pixels, pal, outIdx) {
34
+ let err = 0;
35
+ for (let k = 0; k < 16; k++) {
36
+ const r = pixels[k * 3];
37
+ const g = pixels[k * 3 + 1];
38
+ const b = pixels[k * 3 + 2];
39
+ let bestJ = 0;
40
+ let bestD = Infinity;
41
+ for (let j = 0; j < 4; j++) {
42
+ const dr = pal[j * 3] - r;
43
+ const dg = pal[j * 3 + 1] - g;
44
+ const db = pal[j * 3 + 2] - b;
45
+ const d = dr * dr + dg * dg + db * db;
46
+ if (d < bestD) {
47
+ bestD = d;
48
+ bestJ = j;
49
+ }
50
+ }
51
+ outIdx[k] = bestJ;
52
+ err += bestD;
53
+ }
54
+ return err;
55
+ }
56
+ function refitEndpoints(pixels, indices) {
57
+ let sAA = 0, sBB = 0, sAB = 0;
58
+ const sAV = [0, 0, 0];
59
+ const sBV = [0, 0, 0];
60
+ for (let k = 0; k < 16; k++) {
61
+ const a = WA[indices[k]];
62
+ const b = WB[indices[k]];
63
+ sAA += a * a;
64
+ sBB += b * b;
65
+ sAB += a * b;
66
+ for (let c = 0; c < 3; c++) {
67
+ const v = pixels[k * 3 + c];
68
+ sAV[c] += a * v;
69
+ sBV[c] += b * v;
70
+ }
71
+ }
72
+ const det = sAA * sBB - sAB * sAB;
73
+ if (Math.abs(det) < 1e-9) return null;
74
+ const e0 = [0, 0, 0];
75
+ const e1 = [0, 0, 0];
76
+ for (let c = 0; c < 3; c++) {
77
+ e0[c] = clamp01((sBB * sAV[c] - sAB * sBV[c]) / det);
78
+ e1[c] = clamp01((sAA * sBV[c] - sAB * sAV[c]) / det);
79
+ }
80
+ return { e0, e1 };
81
+ }
82
+ function principalAxis(pixels, mean, seed) {
83
+ let rr = 0, rg = 0, rb = 0, gg = 0, gb = 0, bb = 0;
84
+ for (let k = 0; k < 16; k++) {
85
+ const dr = pixels[k * 3] - mean[0];
86
+ const dg = pixels[k * 3 + 1] - mean[1];
87
+ const db = pixels[k * 3 + 2] - mean[2];
88
+ rr += dr * dr;
89
+ rg += dr * dg;
90
+ rb += dr * db;
91
+ gg += dg * dg;
92
+ gb += dg * db;
93
+ bb += db * db;
94
+ }
95
+ let vx = seed[0], vy = seed[1], vz = seed[2];
96
+ let len = Math.sqrt(vx * vx + vy * vy + vz * vz);
97
+ if (len < 1e-9) return null;
98
+ vx /= len;
99
+ vy /= len;
100
+ vz /= len;
101
+ for (let iter = 0; iter < 8; iter++) {
102
+ const nx = rr * vx + rg * vy + rb * vz;
103
+ const ny = rg * vx + gg * vy + gb * vz;
104
+ const nz = rb * vx + gb * vy + bb * vz;
105
+ len = Math.sqrt(nx * nx + ny * ny + nz * nz);
106
+ if (len < 1e-12) return null;
107
+ vx = nx / len;
108
+ vy = ny / len;
109
+ vz = nz / len;
110
+ }
111
+ return [vx, vy, vz];
112
+ }
113
+ function packBlock(c0, c1, indices) {
114
+ const out = new Uint8Array(8);
115
+ out[0] = c0 & 255;
116
+ out[1] = c0 >> 8 & 255;
117
+ out[2] = c1 & 255;
118
+ out[3] = c1 >> 8 & 255;
119
+ let bits = 0;
120
+ for (let k = 0; k < 16; k++) bits |= (indices[k] & 3) << k * 2;
121
+ out[4] = bits & 255;
122
+ out[5] = bits >>> 8 & 255;
123
+ out[6] = bits >>> 16 & 255;
124
+ out[7] = bits >>> 24 & 255;
125
+ return out;
126
+ }
127
+ function fitFromEndpoints(pixels, hi, lo, maxRefits, best) {
128
+ let c0 = to565(hi[0], hi[1], hi[2]);
129
+ let c1 = to565(lo[0], lo[1], lo[2]);
130
+ if (c0 === c1) {
131
+ if (c1 > 0) c1 -= 1;
132
+ else c0 += 1;
133
+ } else if (c0 < c1) {
134
+ const t = c0;
135
+ c0 = c1;
136
+ c1 = t;
137
+ }
138
+ const idx = new Uint8Array(16);
139
+ let pal = buildPalette4(c0, c1);
140
+ let err = assignIndices(pixels, pal, idx);
141
+ if (err < best.err) {
142
+ best.c0 = c0;
143
+ best.c1 = c1;
144
+ best.indices.set(idx);
145
+ best.err = err;
146
+ }
147
+ for (let pass = 0; pass < maxRefits; pass++) {
148
+ const refit = refitEndpoints(pixels, idx);
149
+ if (!refit) break;
150
+ let nc0 = to565(refit.e0[0], refit.e0[1], refit.e0[2]);
151
+ let nc1 = to565(refit.e1[0], refit.e1[1], refit.e1[2]);
152
+ if (nc0 < nc1) {
153
+ const t = nc0;
154
+ nc0 = nc1;
155
+ nc1 = t;
156
+ }
157
+ if (nc0 === nc1) break;
158
+ if (nc0 === c0 && nc1 === c1) break;
159
+ pal = buildPalette4(nc0, nc1);
160
+ const nerr = assignIndices(pixels, pal, idx);
161
+ c0 = nc0;
162
+ c1 = nc1;
163
+ err = nerr;
164
+ if (nerr < best.err) {
165
+ best.c0 = nc0;
166
+ best.c1 = nc1;
167
+ best.indices.set(idx);
168
+ best.err = nerr;
169
+ }
170
+ }
171
+ }
172
+ function encodeBC1Block(pixels, { quality = "fast" } = {}) {
173
+ if (pixels.length !== 48) {
174
+ throw new Error(`encodeBC1Block: expected 48 values (16 RGB), got ${pixels.length}`);
175
+ }
176
+ const bbMin = [1, 1, 1];
177
+ const bbMax = [0, 0, 0];
178
+ const mean = [0, 0, 0];
179
+ for (let k = 0; k < 16; k++) {
180
+ for (let c = 0; c < 3; c++) {
181
+ const v = pixels[k * 3 + c];
182
+ if (v < bbMin[c]) bbMin[c] = v;
183
+ if (v > bbMax[c]) bbMax[c] = v;
184
+ mean[c] += v;
185
+ }
186
+ }
187
+ for (let c = 0; c < 3; c++) mean[c] /= 16;
188
+ const best = { c0: 0, c1: 0, indices: new Uint8Array(16), err: Infinity };
189
+ const inset = [(bbMax[0] - bbMin[0]) / 16, (bbMax[1] - bbMin[1]) / 16, (bbMax[2] - bbMin[2]) / 16];
190
+ const bboxHi = [clamp01(bbMax[0] - inset[0]), clamp01(bbMax[1] - inset[1]), clamp01(bbMax[2] - inset[2])];
191
+ const bboxLo = [clamp01(bbMin[0] + inset[0]), clamp01(bbMin[1] + inset[1]), clamp01(bbMin[2] + inset[2])];
192
+ if (quality === "high") {
193
+ const diag = [bbMax[0] - bbMin[0], bbMax[1] - bbMin[1], bbMax[2] - bbMin[2]];
194
+ const axis = principalAxis(pixels, mean, diag);
195
+ if (axis) {
196
+ let tMin = Infinity;
197
+ let tMax = -Infinity;
198
+ for (let k = 0; k < 16; k++) {
199
+ const t = (pixels[k * 3] - mean[0]) * axis[0] + (pixels[k * 3 + 1] - mean[1]) * axis[1] + (pixels[k * 3 + 2] - mean[2]) * axis[2];
200
+ if (t < tMin) tMin = t;
201
+ if (t > tMax) tMax = t;
202
+ }
203
+ const pad = (tMax - tMin) / 16;
204
+ const tHi = tMax - pad;
205
+ const tLo = tMin + pad;
206
+ const pcaHi = [
207
+ clamp01(mean[0] + tHi * axis[0]),
208
+ clamp01(mean[1] + tHi * axis[1]),
209
+ clamp01(mean[2] + tHi * axis[2])
210
+ ];
211
+ const pcaLo = [
212
+ clamp01(mean[0] + tLo * axis[0]),
213
+ clamp01(mean[1] + tLo * axis[1]),
214
+ clamp01(mean[2] + tLo * axis[2])
215
+ ];
216
+ fitFromEndpoints(pixels, pcaHi, pcaLo, 3, best);
217
+ }
218
+ fitFromEndpoints(pixels, bboxHi, bboxLo, 3, best);
219
+ } else {
220
+ fitFromEndpoints(pixels, bboxHi, bboxLo, 1, best);
221
+ }
222
+ return packBlock(best.c0, best.c1, best.indices);
223
+ }
224
+ function decodeBC1Block(block) {
225
+ if (block.length !== 8) {
226
+ throw new Error(`decodeBC1Block: expected 8 bytes, got ${block.length}`);
227
+ }
228
+ const c0 = block[0] | block[1] << 8;
229
+ const c1 = block[2] | block[3] << 8;
230
+ const p0 = from565(c0);
231
+ const p1 = from565(c1);
232
+ const pal = [p0, p1, [0, 0, 0], [0, 0, 0]];
233
+ if (c0 > c1) {
234
+ for (let c = 0; c < 3; c++) {
235
+ pal[2][c] = (2 * p0[c] + p1[c]) / 3;
236
+ pal[3][c] = (p0[c] + 2 * p1[c]) / 3;
237
+ }
238
+ } else {
239
+ for (let c = 0; c < 3; c++) {
240
+ pal[2][c] = (p0[c] + p1[c]) / 2;
241
+ pal[3][c] = 0;
242
+ }
243
+ }
244
+ const bits = (block[4] | block[5] << 8 | block[6] << 16 | block[7] << 24) >>> 0;
245
+ const out = new Float32Array(48);
246
+ for (let k = 0; k < 16; k++) {
247
+ const idx = bits >>> k * 2 & 3;
248
+ out[k * 3] = pal[idx][0];
249
+ out[k * 3 + 1] = pal[idx][1];
250
+ out[k * 3 + 2] = pal[idx][2];
251
+ }
252
+ return out;
253
+ }
254
+
255
+ // src/bc4_ref.ts
256
+ var PALETTE_SIZE = 8;
257
+ var W0_6 = [1, 0, 6 / 7, 5 / 7, 4 / 7, 3 / 7, 2 / 7, 1 / 7];
258
+ var W1_6 = [0, 1, 1 / 7, 2 / 7, 3 / 7, 4 / 7, 5 / 7, 6 / 7];
259
+ var W0_4 = [1, 0, 4 / 5, 3 / 5, 2 / 5, 1 / 5, 0, 0];
260
+ var W1_4 = [0, 1, 1 / 5, 2 / 5, 3 / 5, 4 / 5, 0, 0];
261
+ var PAL4_CONST = [0, 0, 0, 0, 0, 0, 0, 1];
262
+ function clamp012(v) {
263
+ return v < 0 ? 0 : v > 1 ? 1 : v;
264
+ }
265
+ function quantize8(v) {
266
+ return Math.max(0, Math.min(255, Math.round(v * 255)));
267
+ }
268
+ function buildPalette6(r0, r1) {
269
+ const p = new Float32Array(PALETTE_SIZE);
270
+ for (let j = 0; j < PALETTE_SIZE; j++) p[j] = W0_6[j] * r0 + W1_6[j] * r1;
271
+ return p;
272
+ }
273
+ function buildPalette42(r0, r1) {
274
+ const p = new Float32Array(PALETTE_SIZE);
275
+ for (let j = 0; j < PALETTE_SIZE; j++) {
276
+ p[j] = W0_4[j] * r0 + W1_4[j] * r1 + PAL4_CONST[j];
277
+ }
278
+ return p;
279
+ }
280
+ function assignIndex(value, palette) {
281
+ let bestIdx = 0;
282
+ let bestD = Infinity;
283
+ for (let j = 0; j < PALETTE_SIZE; j++) {
284
+ const d = palette[j] - value;
285
+ const d2 = d * d;
286
+ if (d2 < bestD) {
287
+ bestD = d2;
288
+ bestIdx = j;
289
+ }
290
+ }
291
+ return { idx: bestIdx, err: bestD };
292
+ }
293
+ function sumSquaredError(values, palette, indices) {
294
+ let e = 0;
295
+ for (let k = 0; k < 16; k++) {
296
+ const d = palette[indices[k]] - values[k];
297
+ e += d * d;
298
+ }
299
+ return e;
300
+ }
301
+ function refitEndpoints6Interp(values, indices) {
302
+ let sumAA = 0, sumBB = 0, sumAB = 0, sumAV = 0, sumBV = 0;
303
+ for (let k = 0; k < 16; k++) {
304
+ const a = W0_6[indices[k]];
305
+ const b = W1_6[indices[k]];
306
+ const v = values[k];
307
+ sumAA += a * a;
308
+ sumBB += b * b;
309
+ sumAB += a * b;
310
+ sumAV += a * v;
311
+ sumBV += b * v;
312
+ }
313
+ const det = sumAA * sumBB - sumAB * sumAB;
314
+ if (Math.abs(det) < 1e-9) return null;
315
+ const r0 = (sumBB * sumAV - sumAB * sumBV) / det;
316
+ const r1 = (sumAA * sumBV - sumAB * sumAV) / det;
317
+ return { r0: clamp012(r0), r1: clamp012(r1) };
318
+ }
319
+ function packBlock2(red0, red1, indices) {
320
+ const out = new Uint8Array(8);
321
+ out[0] = red0;
322
+ out[1] = red1;
323
+ let bits = 0n;
324
+ for (let k = 0; k < 16; k++) {
325
+ bits |= BigInt(indices[k] & 7) << BigInt(3 * k);
326
+ }
327
+ for (let i = 0; i < 6; i++) {
328
+ out[2 + i] = Number(bits >> BigInt(i * 8) & 0xffn);
329
+ }
330
+ return out;
331
+ }
332
+ function encodeBC4Block(values) {
333
+ if (values.length !== 16) {
334
+ throw new Error(`encodeBC4Block: expected 16 values, got ${values.length}`);
335
+ }
336
+ let vmin = Infinity, vmax = -Infinity;
337
+ for (let k = 0; k < 16; k++) {
338
+ const v = values[k];
339
+ if (v < vmin) vmin = v;
340
+ if (v > vmax) vmax = v;
341
+ }
342
+ vmin = clamp012(vmin);
343
+ vmax = clamp012(vmax);
344
+ let r0b = quantize8(vmax);
345
+ let r1b = quantize8(vmin);
346
+ if (r0b === r1b) {
347
+ if (r1b > 0) r1b -= 1;
348
+ else r0b += 1;
349
+ }
350
+ const pal = buildPalette6(r0b / 255, r1b / 255);
351
+ const indices = new Uint8Array(16);
352
+ for (let k = 0; k < 16; k++) {
353
+ indices[k] = assignIndex(values[k], pal).idx;
354
+ }
355
+ let bestErr = sumSquaredError(values, pal, indices);
356
+ let bestR0 = r0b, bestR1 = r1b;
357
+ let bestIndices = indices.slice();
358
+ const refit = refitEndpoints6Interp(values, indices);
359
+ if (refit) {
360
+ const qR0 = quantize8(refit.r0);
361
+ const qR1 = quantize8(refit.r1);
362
+ if (qR0 > qR1) {
363
+ const pal2 = buildPalette6(qR0 / 255, qR1 / 255);
364
+ const idx2 = new Uint8Array(16);
365
+ for (let k = 0; k < 16; k++) idx2[k] = assignIndex(values[k], pal2).idx;
366
+ const err2 = sumSquaredError(values, pal2, idx2);
367
+ if (err2 < bestErr) {
368
+ bestErr = err2;
369
+ bestR0 = qR0;
370
+ bestR1 = qR1;
371
+ bestIndices = idx2;
372
+ }
373
+ }
374
+ }
375
+ return packBlock2(bestR0, bestR1, bestIndices);
376
+ }
377
+ function decodeBC4Block(block) {
378
+ if (block.length !== 8) {
379
+ throw new Error(`decodeBC4Block: expected 8 bytes, got ${block.length}`);
380
+ }
381
+ const r0b = block[0];
382
+ const r1b = block[1];
383
+ const palette = r0b > r1b ? buildPalette6(r0b / 255, r1b / 255) : buildPalette42(r0b / 255, r1b / 255);
384
+ let bits = 0n;
385
+ for (let i = 0; i < 6; i++) bits |= BigInt(block[2 + i]) << BigInt(i * 8);
386
+ const out = new Float32Array(16);
387
+ for (let k = 0; k < 16; k++) {
388
+ const idx = Number(bits >> BigInt(3 * k) & 7n);
389
+ out[k] = palette[idx];
390
+ }
391
+ return out;
392
+ }
393
+
394
+ // src/bc5_ref.ts
395
+ function encodeBC5Block(r, g) {
396
+ if (r.length !== 16 || g.length !== 16) {
397
+ throw new Error(`encodeBC5Block: expected two arrays of 16, got ${r.length} / ${g.length}`);
398
+ }
399
+ const out = new Uint8Array(16);
400
+ out.set(encodeBC4Block(r), 0);
401
+ out.set(encodeBC4Block(g), 8);
402
+ return out;
403
+ }
404
+ function decodeBC5Block(block) {
405
+ if (block.length !== 16) {
406
+ throw new Error(`decodeBC5Block: expected 16 bytes, got ${block.length}`);
407
+ }
408
+ return {
409
+ r: decodeBC4Block(block.subarray(0, 8)),
410
+ g: decodeBC4Block(block.subarray(8, 16))
411
+ };
412
+ }
413
+
414
+ // src/bc7_ref.ts
415
+ var W4 = [0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64];
416
+ function clamp(v, lo, hi) {
417
+ return v < lo ? lo : v > hi ? hi : v;
418
+ }
419
+ function to8(v) {
420
+ return clamp(Math.round(v * 255), 0, 255);
421
+ }
422
+ function interp8(e0, e1, w) {
423
+ return (64 - w) * e0 + w * e1 + 32 >> 6;
424
+ }
425
+ var BitWriter128 = class {
426
+ bits = 0n;
427
+ pos = 0;
428
+ write(value, nBits) {
429
+ if (this.pos + nBits > 128) throw new Error("BitWriter128 overflow");
430
+ const v = BigInt(value) & (1n << BigInt(nBits)) - 1n;
431
+ this.bits |= v << BigInt(this.pos);
432
+ this.pos += nBits;
433
+ }
434
+ toBytes() {
435
+ const out = new Uint8Array(16);
436
+ for (let i = 0; i < 16; i++) {
437
+ out[i] = Number(this.bits >> BigInt(i * 8) & 0xffn);
438
+ }
439
+ return out;
440
+ }
441
+ };
442
+ var BitReader128 = class {
443
+ bits;
444
+ pos = 0;
445
+ constructor(block) {
446
+ let b = 0n;
447
+ for (let i = 0; i < 16; i++) b |= BigInt(block[i]) << BigInt(i * 8);
448
+ this.bits = b;
449
+ }
450
+ read(nBits) {
451
+ const v = Number(this.bits >> BigInt(this.pos) & (1n << BigInt(nBits)) - 1n);
452
+ this.pos += nBits;
453
+ return v;
454
+ }
455
+ };
456
+ function readBC7Mode(block) {
457
+ const br = new BitReader128(block);
458
+ for (let m = 0; m < 8; m++) {
459
+ if (br.read(1) === 1) return m;
460
+ }
461
+ throw new Error("BC7: no mode bit found in first 8 bits");
462
+ }
463
+ function quantizeChannelWithPbit(ideal8, p) {
464
+ const q = clamp(Math.round((ideal8 - p) / 2), 0, 127);
465
+ const effective = q << 1 | p;
466
+ const d = effective - ideal8;
467
+ return { q, err: d * d };
468
+ }
469
+ function quantizeEndpoint(ideal8, p) {
470
+ const out = [0, 0, 0, 0];
471
+ let err = 0;
472
+ for (let c = 0; c < 4; c++) {
473
+ const r = quantizeChannelWithPbit(ideal8[c], p);
474
+ out[c] = r.q;
475
+ err += r.err;
476
+ }
477
+ return { rgba: out, err };
478
+ }
479
+ function buildPalette62(e0, e1) {
480
+ const pal = new Uint8Array(16 * 4);
481
+ for (let i = 0; i < 16; i++) {
482
+ const w = W4[i];
483
+ const base = i * 4;
484
+ for (let c = 0; c < 4; c++) {
485
+ pal[base + c] = interp8(e0[c], e1[c], w);
486
+ }
487
+ }
488
+ return pal;
489
+ }
490
+ function assignIndex6(pixel, palette) {
491
+ let bestIdx = 0;
492
+ let bestD = Infinity;
493
+ for (let i = 0; i < 16; i++) {
494
+ const base = i * 4;
495
+ const dr = palette[base] - pixel[0];
496
+ const dg = palette[base + 1] - pixel[1];
497
+ const db = palette[base + 2] - pixel[2];
498
+ const da = palette[base + 3] - pixel[3];
499
+ const d = dr * dr + dg * dg + db * db + da * da;
500
+ if (d < bestD) {
501
+ bestD = d;
502
+ bestIdx = i;
503
+ }
504
+ }
505
+ return { idx: bestIdx, err: bestD };
506
+ }
507
+ function refitEndpointsMode6(pixels8, indices) {
508
+ let sAA = 0, sBB = 0, sAB = 0;
509
+ const sAV = [0, 0, 0, 0];
510
+ const sBV = [0, 0, 0, 0];
511
+ for (let k = 0; k < 16; k++) {
512
+ const i = indices[k];
513
+ const a = (64 - W4[i]) / 64;
514
+ const b = W4[i] / 64;
515
+ sAA += a * a;
516
+ sBB += b * b;
517
+ sAB += a * b;
518
+ const base = k * 4;
519
+ for (let c = 0; c < 4; c++) {
520
+ sAV[c] += a * pixels8[base + c];
521
+ sBV[c] += b * pixels8[base + c];
522
+ }
523
+ }
524
+ const det = sAA * sBB - sAB * sAB;
525
+ if (Math.abs(det) < 1e-9) return null;
526
+ const e0 = [0, 0, 0, 0];
527
+ const e1 = [0, 0, 0, 0];
528
+ for (let c = 0; c < 4; c++) {
529
+ const r0 = (sBB * sAV[c] - sAB * sBV[c]) / det;
530
+ const r1 = (sAA * sBV[c] - sAB * sAV[c]) / det;
531
+ e0[c] = clamp(Math.round(r0), 0, 255);
532
+ e1[c] = clamp(Math.round(r1), 0, 255);
533
+ }
534
+ return { e0, e1 };
535
+ }
536
+ function totalSqErrorForEndpoints(pixels8, e0_8, e1_8) {
537
+ const pal = buildPalette62(e0_8, e1_8);
538
+ const indices = new Uint8Array(16);
539
+ let err = 0;
540
+ for (let k = 0; k < 16; k++) {
541
+ const base = k * 4;
542
+ const sel = assignIndex6([pixels8[base], pixels8[base + 1], pixels8[base + 2], pixels8[base + 3]], pal);
543
+ indices[k] = sel.idx;
544
+ err += sel.err;
545
+ }
546
+ return { indices, err };
547
+ }
548
+ function packMode6Block(e0_7, e1_7, p0, p1, indices) {
549
+ if ((indices[0] & 8) !== 0) {
550
+ throw new Error("packMode6Block: pixel 0 index MSB must be 0 (anchor rule)");
551
+ }
552
+ const bw = new BitWriter128();
553
+ bw.write(0, 6);
554
+ bw.write(1, 1);
555
+ for (let c = 0; c < 4; c++) {
556
+ bw.write(e0_7[c], 7);
557
+ bw.write(e1_7[c], 7);
558
+ }
559
+ bw.write(p0, 1);
560
+ bw.write(p1, 1);
561
+ bw.write(indices[0] & 7, 3);
562
+ for (let k = 1; k < 16; k++) bw.write(indices[k] & 15, 4);
563
+ return bw.toBytes();
564
+ }
565
+ function farthestPair(pixels8) {
566
+ let best = -1;
567
+ let bi0 = 0, bi1 = 1;
568
+ for (let i = 0; i < 16; i++) {
569
+ const bi = i * 4;
570
+ for (let j = i + 1; j < 16; j++) {
571
+ const bj = j * 4;
572
+ const dr = pixels8[bi] - pixels8[bj];
573
+ const dg = pixels8[bi + 1] - pixels8[bj + 1];
574
+ const db = pixels8[bi + 2] - pixels8[bj + 2];
575
+ const da = pixels8[bi + 3] - pixels8[bj + 3];
576
+ const d = dr * dr + dg * dg + db * db + da * da;
577
+ if (d > best) {
578
+ best = d;
579
+ bi0 = i;
580
+ bi1 = j;
581
+ }
582
+ }
583
+ }
584
+ return { i0: bi0, i1: bi1 };
585
+ }
586
+ function encodeBC7Mode6Block(pixels) {
587
+ if (pixels.length !== 64) {
588
+ throw new Error(`encodeBC7Mode6Block: expected 64 values (16 RGBA), got ${pixels.length}`);
589
+ }
590
+ const pixels8 = new Uint8Array(64);
591
+ for (let k = 0; k < 64; k++) pixels8[k] = to8(pixels[k]);
592
+ const farthest = farthestPair(pixels8);
593
+ const ideal0 = [
594
+ pixels8[farthest.i0 * 4],
595
+ pixels8[farthest.i0 * 4 + 1],
596
+ pixels8[farthest.i0 * 4 + 2],
597
+ pixels8[farthest.i0 * 4 + 3]
598
+ ];
599
+ const ideal1 = [
600
+ pixels8[farthest.i1 * 4],
601
+ pixels8[farthest.i1 * 4 + 1],
602
+ pixels8[farthest.i1 * 4 + 2],
603
+ pixels8[farthest.i1 * 4 + 3]
604
+ ];
605
+ function quantPair(ideal, p) {
606
+ const r = quantizeEndpoint(ideal, p);
607
+ const eight = [
608
+ r.rgba[0] << 1 | p,
609
+ r.rgba[1] << 1 | p,
610
+ r.rgba[2] << 1 | p,
611
+ r.rgba[3] << 1 | p
612
+ ];
613
+ return { seven: r.rgba, eight, err: r.err };
614
+ }
615
+ let best = tryPbitCombos(pixels8, ideal0, ideal1, quantPair);
616
+ const refit = refitEndpointsMode6(pixels8, best.indices);
617
+ if (refit) {
618
+ const candidate = tryPbitCombos(pixels8, refit.e0, refit.e1, quantPair);
619
+ if (candidate.err < best.err) best = candidate;
620
+ }
621
+ let e0_7 = best.e0_7;
622
+ let e1_7 = best.e1_7;
623
+ let p0 = best.p0;
624
+ let p1 = best.p1;
625
+ let indices = best.indices;
626
+ if ((indices[0] & 8) !== 0) {
627
+ const tmp7 = e0_7;
628
+ e0_7 = e1_7;
629
+ e1_7 = tmp7;
630
+ const tmpP = p0;
631
+ p0 = p1;
632
+ p1 = tmpP;
633
+ const inv = new Uint8Array(16);
634
+ for (let k = 0; k < 16; k++) inv[k] = 15 - indices[k];
635
+ indices = inv;
636
+ }
637
+ return packMode6Block(e0_7, e1_7, p0, p1, indices);
638
+ }
639
+ function tryPbitCombos(pixels8, ideal0, ideal1, quantPair) {
640
+ let best = null;
641
+ for (const p0 of [0, 1]) {
642
+ const q0 = quantPair(ideal0, p0);
643
+ for (const p1 of [0, 1]) {
644
+ const q1 = quantPair(ideal1, p1);
645
+ const { indices, err } = totalSqErrorForEndpoints(pixels8, q0.eight, q1.eight);
646
+ if (best == null || err < best.err) {
647
+ best = { e0_7: q0.seven, e1_7: q1.seven, p0, p1, indices, err };
648
+ }
649
+ }
650
+ }
651
+ if (best == null) throw new Error("unreachable: tryPbitCombos no-op");
652
+ return best;
653
+ }
654
+ function decodeBC7Mode6Block(block) {
655
+ if (block.length !== 16) {
656
+ throw new Error(`decodeBC7Mode6Block: expected 16 bytes, got ${block.length}`);
657
+ }
658
+ const mode = readBC7Mode(block);
659
+ if (mode !== 6) {
660
+ throw new Error(`decodeBC7Mode6Block: expected mode 6, got mode ${mode}`);
661
+ }
662
+ const br = new BitReader128(block);
663
+ br.read(7);
664
+ const r0 = br.read(7), r1 = br.read(7);
665
+ const g0 = br.read(7), g1 = br.read(7);
666
+ const b0 = br.read(7), b1 = br.read(7);
667
+ const a0 = br.read(7), a1 = br.read(7);
668
+ const p0 = br.read(1), p1 = br.read(1);
669
+ const e0 = [r0 << 1 | p0, g0 << 1 | p0, b0 << 1 | p0, a0 << 1 | p0];
670
+ const e1 = [r1 << 1 | p1, g1 << 1 | p1, b1 << 1 | p1, a1 << 1 | p1];
671
+ const pal = buildPalette62(e0, e1);
672
+ const out = new Float32Array(64);
673
+ const idx0 = br.read(3);
674
+ for (let c = 0; c < 4; c++) out[c] = pal[idx0 * 4 + c] / 255;
675
+ for (let k = 1; k < 16; k++) {
676
+ const idx = br.read(4);
677
+ const base = k * 4;
678
+ for (let c = 0; c < 4; c++) out[base + c] = pal[idx * 4 + c] / 255;
679
+ }
680
+ return out;
681
+ }
682
+ function encodeBC7Block(pixels) {
683
+ return encodeBC7Mode6Block(pixels);
684
+ }
685
+ function decodeBC7Block(block) {
686
+ const mode = readBC7Mode(block);
687
+ switch (mode) {
688
+ case 6:
689
+ return decodeBC7Mode6Block(block);
690
+ default:
691
+ throw new Error(`decodeBC7Block: mode ${mode} not supported by this reference decoder`);
692
+ }
693
+ }
694
+
695
+ // src/astc4x4_ref.ts
696
+ var BLOCK_MODE_4x4_2BIT = 66;
697
+ var CEM_RGBA_DIRECT = 12;
698
+ var WEIGHT_UNQ_4 = [0, 21, 43, 64];
699
+ function clamp2(v, lo, hi) {
700
+ return v < lo ? lo : v > hi ? hi : v;
701
+ }
702
+ function to82(v) {
703
+ return clamp2(Math.round(v * 255), 0, 255);
704
+ }
705
+ function interp82(e0, e1, w) {
706
+ return (64 - w) * e0 + w * e1 + 32 >> 6;
707
+ }
708
+ var BitWriter1282 = class {
709
+ bits = 0n;
710
+ write(pos, nBits, value) {
711
+ if (pos < 0 || nBits < 0 || pos + nBits > 128) {
712
+ throw new Error(`BitWriter128: out-of-range write pos=${pos}, n=${nBits}`);
713
+ }
714
+ const mask = (1n << BigInt(nBits)) - 1n;
715
+ this.bits &= ~(mask << BigInt(pos));
716
+ this.bits |= (BigInt(value) & mask) << BigInt(pos);
717
+ }
718
+ toBytes() {
719
+ const out = new Uint8Array(16);
720
+ let b = this.bits;
721
+ for (let i = 0; i < 16; i++) {
722
+ out[i] = Number(b & 0xffn);
723
+ b >>= 8n;
724
+ }
725
+ return out;
726
+ }
727
+ };
728
+ var BitReader1282 = class {
729
+ bits;
730
+ constructor(block) {
731
+ let b = 0n;
732
+ for (let i = 0; i < 16; i++) b |= BigInt(block[i]) << BigInt(i * 8);
733
+ this.bits = b;
734
+ }
735
+ read(pos, nBits) {
736
+ const mask = (1n << BigInt(nBits)) - 1n;
737
+ return Number(this.bits >> BigInt(pos) & mask);
738
+ }
739
+ };
740
+ function farthestPair2(pixels8) {
741
+ let best = -1;
742
+ let bi0 = 0, bi1 = 1;
743
+ for (let i = 0; i < 16; i++) {
744
+ const bi = i * 4;
745
+ 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;
752
+ if (d > best) {
753
+ best = d;
754
+ bi0 = i;
755
+ bi1 = j;
756
+ }
757
+ }
758
+ }
759
+ return { i0: bi0, i1: bi1 };
760
+ }
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);
768
+ }
769
+ }
770
+ return pal;
771
+ }
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);
791
+ const indices = new Uint8Array(16);
792
+ let err = 0;
793
+ 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;
798
+ }
799
+ return { indices, err };
800
+ }
801
+ function refitEndpoints2(pixels8, indices) {
802
+ let sAA = 0, sBB = 0, sAB = 0;
803
+ const sAV = [0, 0, 0, 0];
804
+ const sBV = [0, 0, 0, 0];
805
+ 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;
809
+ sAA += a * a;
810
+ sBB += b * b;
811
+ 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];
816
+ }
817
+ }
818
+ const det = sAA * sBB - sAB * sAB;
819
+ 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++) {
823
+ e0[c] = clamp2(Math.round((sBB * sAV[c] - sAB * sBV[c]) / det), 0, 255);
824
+ e1[c] = clamp2(Math.round((sAA * sBV[c] - sAB * sAV[c]) / det), 0, 255);
825
+ }
826
+ return { e0, e1 };
827
+ }
828
+ function encodeASTC4x4Block(pixels) {
829
+ if (pixels.length !== 64) {
830
+ throw new Error(`encodeASTC4x4Block: expected 64 values (16 RGBA), got ${pixels.length}`);
831
+ }
832
+ const pixels8 = new Uint8Array(64);
833
+ 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);
849
+ if (refit) {
850
+ const { indices: idx2, err: err2 } = totalSqError(pixels8, refit.e0, refit.e1);
851
+ if (err2 < err) {
852
+ e0 = refit.e0;
853
+ e1 = refit.e1;
854
+ indices = idx2;
855
+ err = err2;
856
+ }
857
+ }
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;
867
+ }
868
+ return packBlock3(e0, e1, indices);
869
+ }
870
+ function packBlock3(e0, e1, indices) {
871
+ const bw = new BitWriter1282();
872
+ bw.write(0, 11, BLOCK_MODE_4x4_2BIT);
873
+ 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]);
877
+ 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);
881
+ }
882
+ return bw.toBytes();
883
+ }
884
+ function decodeASTC4x4Block(block) {
885
+ if (block.length !== 16) {
886
+ throw new Error(`decodeASTC4x4Block: expected 16 bytes, got ${block.length}`);
887
+ }
888
+ const br = new BitReader1282(block);
889
+ 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
+ );
894
+ }
895
+ const partCount = br.read(11, 2);
896
+ if (partCount !== 0) {
897
+ throw new Error(`decodeASTC4x4Block: multi-partition blocks not supported (count=${partCount + 1})`);
898
+ }
899
+ const cem = br.read(13, 4);
900
+ if (cem !== CEM_RGBA_DIRECT) {
901
+ throw new Error(`decodeASTC4x4Block: only CEM 12 supported, got ${cem}`);
902
+ }
903
+ 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;
906
+ let e0;
907
+ let e1;
908
+ if (v0 + v2 + v4 <= v1 + v3 + v5) {
909
+ e0 = [v0, v2, v4, v6];
910
+ e1 = [v1, v3, v5, v7];
911
+ } else {
912
+ e0 = [v1 + v5 >> 1, v3 + v5 >> 1, v5, v7];
913
+ e1 = [v0 + v4 >> 1, v2 + v4 >> 1, v4, v6];
914
+ }
915
+ const weights = new Uint8Array(16);
916
+ 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;
920
+ }
921
+ const out = new Float32Array(64);
922
+ for (let k = 0; k < 16; k++) {
923
+ const w = WEIGHT_UNQ_4[weights[k]];
924
+ const base = k * 4;
925
+ for (let c = 0; c < 4; c++) {
926
+ out[base + c] = interp82(e0[c], e1[c], w) / 255;
927
+ }
928
+ }
929
+ return out;
930
+ }
931
+ export {
932
+ decodeASTC4x4Block,
933
+ decodeBC1Block,
934
+ decodeBC4Block,
935
+ decodeBC5Block,
936
+ decodeBC7Block,
937
+ decodeBC7Mode6Block,
938
+ encodeASTC4x4Block,
939
+ encodeBC1Block,
940
+ encodeBC4Block,
941
+ encodeBC5Block,
942
+ encodeBC7Block,
943
+ encodeBC7Mode6Block,
944
+ readBC7Mode
945
+ };