@forgeax/engine-codec 0.1.2
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/LICENSE +202 -0
- package/README.md +268 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/__tests__/basis-encode-fast-preset.unit.test.d.ts +2 -0
- package/dist/__tests__/basis-encode-fast-preset.unit.test.d.ts.map +1 -0
- package/dist/__tests__/basis-encode-lifecycle.unit.test.d.ts +2 -0
- package/dist/__tests__/basis-encode-lifecycle.unit.test.d.ts.map +1 -0
- package/dist/__tests__/basis-encode-mode-owner.test-d.d.ts +2 -0
- package/dist/__tests__/basis-encode-mode-owner.test-d.d.ts.map +1 -0
- package/dist/__tests__/basis-transcoder.unit.test.d.ts +2 -0
- package/dist/__tests__/basis-transcoder.unit.test.d.ts.map +1 -0
- package/dist/__tests__/block-format.unit.test.d.ts +2 -0
- package/dist/__tests__/block-format.unit.test.d.ts.map +1 -0
- package/dist/__tests__/byte-identical-falsification.test.d.ts +2 -0
- package/dist/__tests__/byte-identical-falsification.test.d.ts.map +1 -0
- package/dist/__tests__/codec-errors.test-d.d.ts +2 -0
- package/dist/__tests__/codec-errors.test-d.d.ts.map +1 -0
- package/dist/__tests__/codec-errors.unit.test.d.ts +2 -0
- package/dist/__tests__/codec-errors.unit.test.d.ts.map +1 -0
- package/dist/__tests__/compression-field.unit.test.d.ts +19 -0
- package/dist/__tests__/compression-field.unit.test.d.ts.map +1 -0
- package/dist/__tests__/encode-pixel-limit.unit.test.d.ts +2 -0
- package/dist/__tests__/encode-pixel-limit.unit.test.d.ts.map +1 -0
- package/dist/__tests__/encode-roundtrip.unit.test.d.ts +2 -0
- package/dist/__tests__/encode-roundtrip.unit.test.d.ts.map +1 -0
- package/dist/__tests__/ktx2-basis-capability-matrix.unit.test.d.ts +2 -0
- package/dist/__tests__/ktx2-basis-capability-matrix.unit.test.d.ts.map +1 -0
- package/dist/__tests__/ktx2-errors.test.d.ts +2 -0
- package/dist/__tests__/ktx2-errors.test.d.ts.map +1 -0
- package/dist/__tests__/ktx2-parse-scheme0.test.d.ts +2 -0
- package/dist/__tests__/ktx2-parse-scheme0.test.d.ts.map +1 -0
- package/dist/__tests__/ktx2-parse-scheme2.test.d.ts +2 -0
- package/dist/__tests__/ktx2-parse-scheme2.test.d.ts.map +1 -0
- package/dist/__tests__/ktx2-scheme1-and-transcode-errors.unit.test.d.ts +2 -0
- package/dist/__tests__/ktx2-scheme1-and-transcode-errors.unit.test.d.ts.map +1 -0
- package/dist/__tests__/ktx2-to-texture.integration.test.d.ts +2 -0
- package/dist/__tests__/ktx2-to-texture.integration.test.d.ts.map +1 -0
- package/dist/__tests__/runtime-validation.unit.test.d.ts +2 -0
- package/dist/__tests__/runtime-validation.unit.test.d.ts.map +1 -0
- package/dist/__tests__/transcode-select-target.unit.test.d.ts +2 -0
- package/dist/__tests__/transcode-select-target.unit.test.d.ts.map +1 -0
- package/dist/__tests__/wasm-init-smoke.test.d.ts +2 -0
- package/dist/__tests__/wasm-init-smoke.test.d.ts.map +1 -0
- package/dist/__tests__/zstd-deterministic.unit.test.d.ts +2 -0
- package/dist/__tests__/zstd-deterministic.unit.test.d.ts.map +1 -0
- package/dist/__tests__/zstd-encode-singleton.unit.test.d.ts +2 -0
- package/dist/__tests__/zstd-encode-singleton.unit.test.d.ts.map +1 -0
- package/dist/__tests__/zstd-roundtrip.unit.test.d.ts +2 -0
- package/dist/__tests__/zstd-roundtrip.unit.test.d.ts.map +1 -0
- package/dist/__tests__/zstd-singleton.unit.test.d.ts +2 -0
- package/dist/__tests__/zstd-singleton.unit.test.d.ts.map +1 -0
- package/dist/basis-transcoder.d.ts +86 -0
- package/dist/basis-transcoder.d.ts.map +1 -0
- package/dist/block-format.d.ts +41 -0
- package/dist/block-format.d.ts.map +1 -0
- package/dist/encode/basis-encode.d.ts +68 -0
- package/dist/encode/basis-encode.d.ts.map +1 -0
- package/dist/encode/index.d.ts +10 -0
- package/dist/encode/index.d.ts.map +1 -0
- package/dist/encode/index.mjs +207 -0
- package/dist/encode/index.mjs.map +1 -0
- package/dist/encode-impl.d.ts +30 -0
- package/dist/encode-impl.d.ts.map +1 -0
- package/dist/errors.d.ts +61 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +672 -0
- package/dist/index.mjs.map +1 -0
- package/dist/ktx2.d.ts +111 -0
- package/dist/ktx2.d.ts.map +1 -0
- package/dist/transcode.d.ts +55 -0
- package/dist/transcode.d.ts.map +1 -0
- package/dist/wasm/basis-types.d.ts +179 -0
- package/dist/wasm/basis-types.d.ts.map +1 -0
- package/dist/zstd.d.ts +28 -0
- package/dist/zstd.d.ts.map +1 -0
- package/package.json +71 -0
- package/pkg/basis_transcoder.mjs +2 -0
- package/pkg/basis_transcoder.wasm +0 -0
- package/pkg/encode/basis_encoder.mjs +2 -0
- package/pkg/encode/basis_encoder.wasm +0 -0
- package/scripts/build-wasm.mjs +370 -0
- package/scripts/content-key.mjs +85 -0
- package/scripts/ensure-wasm.mjs +38 -0
- package/scripts/fetch-basis.mjs +150 -0
- package/scripts/fetch-wasm.mjs +97 -0
- package/src/__tests__/basis-encode-fast-preset.unit.test.ts +204 -0
- package/src/__tests__/basis-encode-lifecycle.unit.test.ts +249 -0
- package/src/__tests__/basis-encode-mode-owner.test-d.ts +39 -0
- package/src/__tests__/basis-transcoder.unit.test.ts +502 -0
- package/src/__tests__/block-format.unit.test.ts +215 -0
- package/src/__tests__/byte-identical-falsification.test.ts +164 -0
- package/src/__tests__/codec-errors.test-d.ts +67 -0
- package/src/__tests__/codec-errors.unit.test.ts +128 -0
- package/src/__tests__/compression-field.unit.test.ts +245 -0
- package/src/__tests__/encode-pixel-limit.unit.test.ts +117 -0
- package/src/__tests__/encode-roundtrip.unit.test.ts +239 -0
- package/src/__tests__/ktx2-basis-capability-matrix.unit.test.ts +241 -0
- package/src/__tests__/ktx2-errors.test.ts +239 -0
- package/src/__tests__/ktx2-parse-scheme0.test.ts +263 -0
- package/src/__tests__/ktx2-parse-scheme2.test.ts +220 -0
- package/src/__tests__/ktx2-scheme1-and-transcode-errors.unit.test.ts +178 -0
- package/src/__tests__/ktx2-to-texture.integration.test.ts +384 -0
- package/src/__tests__/runtime-validation.unit.test.ts +19 -0
- package/src/__tests__/transcode-select-target.unit.test.ts +167 -0
- package/src/__tests__/wasm-init-smoke.test.ts +102 -0
- package/src/__tests__/zstd-deterministic.unit.test.ts +49 -0
- package/src/__tests__/zstd-encode-singleton.unit.test.ts +63 -0
- package/src/__tests__/zstd-roundtrip.unit.test.ts +87 -0
- package/src/__tests__/zstd-singleton.unit.test.ts +105 -0
- package/src/basis-transcoder.ts +380 -0
- package/src/block-format.ts +128 -0
- package/src/encode/basis-encode.ts +264 -0
- package/src/encode/index.ts +19 -0
- package/src/encode-impl.ts +103 -0
- package/src/errors.ts +79 -0
- package/src/index.ts +38 -0
- package/src/ktx2.ts +469 -0
- package/src/transcode.ts +99 -0
- package/src/wasm/basis-types.ts +220 -0
- package/src/zstd.ts +85 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,672 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
function codecError(code, detail) {
|
|
3
|
+
const hints = {
|
|
4
|
+
"decompression-failed": "Check catalog row compression field and asset binary consistency; re-run asset import.",
|
|
5
|
+
"codec-init-failed": "Uncompressed assets are still loadable. Verify the codec module is installed correctly.",
|
|
6
|
+
"ktx2-parse-failed": "Check that the KTX2 file is valid and not truncated. Re-import the texture asset.",
|
|
7
|
+
"ktx2-unsupported-scheme": "This supercompression scheme requires a future codec upgrade. Check the codec README Loop 2 extension points.",
|
|
8
|
+
"transcode-failed": "Basis transcode failed for this source/target format pair. Verify the KTX2 payload is a valid Basis (ETC1S / UASTC) texture and re-import the asset.",
|
|
9
|
+
"ktx2-encode-failed": "Basis encode failed for this compression mode. Verify the source image dimensions / pixel format match the mode (LDR rgba8 vs HDR rgba16float) and retry the asset import."
|
|
10
|
+
};
|
|
11
|
+
return {
|
|
12
|
+
ok: false,
|
|
13
|
+
error: {
|
|
14
|
+
code,
|
|
15
|
+
expected: "valid compressed data or supported compression scheme",
|
|
16
|
+
hint: hints[code],
|
|
17
|
+
detail
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// src/basis-transcoder.ts
|
|
23
|
+
var TRANSCODER_GLUE = new URL("../pkg/basis_transcoder.mjs", import.meta.url);
|
|
24
|
+
var TRANSCODER_WASM = new URL("../pkg/basis_transcoder.wasm", import.meta.url);
|
|
25
|
+
var defaultImporter = async () => {
|
|
26
|
+
const factory = (await import(
|
|
27
|
+
/* @vite-ignore */
|
|
28
|
+
TRANSCODER_GLUE.href
|
|
29
|
+
)).default;
|
|
30
|
+
const mod = await factory({ locateFile: () => TRANSCODER_WASM.href });
|
|
31
|
+
mod.initializeBasis();
|
|
32
|
+
return mod;
|
|
33
|
+
};
|
|
34
|
+
var importer = defaultImporter;
|
|
35
|
+
var _initPromise = null;
|
|
36
|
+
function initBasisTranscoder() {
|
|
37
|
+
if (_initPromise !== null) return _initPromise;
|
|
38
|
+
_initPromise = importer().catch((cause) => {
|
|
39
|
+
_initPromise = null;
|
|
40
|
+
throw new Error("codec-init-failed", { cause });
|
|
41
|
+
});
|
|
42
|
+
return _initPromise;
|
|
43
|
+
}
|
|
44
|
+
function inspectBasisSource(file, meta, profile) {
|
|
45
|
+
if (meta.colorSpace !== "srgb" && meta.colorSpace !== "linear") {
|
|
46
|
+
return codecError("ktx2-parse-failed", {
|
|
47
|
+
reason: "raw Basis source requires Meta.colorSpace=srgb|linear"
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
if (file.getNumImages() <= 0 || file.getNumLevels(0) <= 0) {
|
|
51
|
+
return codecError("ktx2-parse-failed", { reason: "invalid raw Basis source shape" });
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
ok: true,
|
|
55
|
+
value: {
|
|
56
|
+
colorSpace: meta.colorSpace,
|
|
57
|
+
profile,
|
|
58
|
+
width: file.getImageWidth(0, 0),
|
|
59
|
+
height: file.getImageHeight(0, 0),
|
|
60
|
+
levelCount: file.getNumLevels(0),
|
|
61
|
+
imageCount: file.getNumImages()
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function basisTargetFor(mod, format) {
|
|
66
|
+
const e = mod.transcoder_texture_format;
|
|
67
|
+
switch (format) {
|
|
68
|
+
case "bc7-rgba-unorm":
|
|
69
|
+
case "bc7-rgba-unorm-srgb":
|
|
70
|
+
return e.cTFBC7_RGBA.value;
|
|
71
|
+
case "bc5-rg-unorm":
|
|
72
|
+
return e.cTFBC5_RG.value;
|
|
73
|
+
case "bc4-r-unorm":
|
|
74
|
+
return e.cTFBC4_R.value;
|
|
75
|
+
case "bc6h-rgb-ufloat":
|
|
76
|
+
return e.cTFBC6H.value;
|
|
77
|
+
case "etc2-rgba8unorm":
|
|
78
|
+
case "etc2-rgba8unorm-srgb":
|
|
79
|
+
return e.cTFETC2_RGBA.value;
|
|
80
|
+
case "astc-4x4-unorm":
|
|
81
|
+
case "astc-4x4-unorm-srgb":
|
|
82
|
+
return e.cTFASTC_4x4_RGBA.value;
|
|
83
|
+
case "rgba16float":
|
|
84
|
+
return e.cTFRGBA_HALF.value;
|
|
85
|
+
case "rgba8unorm":
|
|
86
|
+
case "rgba8unorm-srgb":
|
|
87
|
+
case "rg8unorm":
|
|
88
|
+
case "r8unorm":
|
|
89
|
+
return e.cTFRGBA32.value;
|
|
90
|
+
default:
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async function transcodeKtx2(parsed, targetFormat) {
|
|
95
|
+
let mod;
|
|
96
|
+
try {
|
|
97
|
+
mod = await initBasisTranscoder();
|
|
98
|
+
} catch {
|
|
99
|
+
return codecError("codec-init-failed", { stage: "dynamic-import-basis-transcoder" });
|
|
100
|
+
}
|
|
101
|
+
const targetEnum = basisTargetFor(mod, targetFormat);
|
|
102
|
+
if (targetEnum === null) {
|
|
103
|
+
return codecError("transcode-failed", {
|
|
104
|
+
sourceFormat: `dfd-model-${parsed.dfd?.colorModel ?? "unknown"}`,
|
|
105
|
+
targetFormat
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
let file;
|
|
109
|
+
try {
|
|
110
|
+
file = new mod.KTX2File(parsed.rawBytes);
|
|
111
|
+
} catch {
|
|
112
|
+
return codecError("transcode-failed", {
|
|
113
|
+
sourceFormat: `dfd-model-${parsed.dfd?.colorModel ?? "unknown"}`,
|
|
114
|
+
targetFormat
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
let result = codecError("transcode-failed", {
|
|
118
|
+
sourceFormat: `dfd-model-${parsed.dfd?.colorModel ?? "unknown"}`,
|
|
119
|
+
targetFormat
|
|
120
|
+
});
|
|
121
|
+
try {
|
|
122
|
+
if (!file.isValid()) {
|
|
123
|
+
result = codecError("transcode-failed", {
|
|
124
|
+
sourceFormat: "invalid-ktx2-file",
|
|
125
|
+
targetFormat
|
|
126
|
+
});
|
|
127
|
+
} else if (file.startTranscoding() === 0) {
|
|
128
|
+
result = codecError("transcode-failed", {
|
|
129
|
+
sourceFormat: "start-transcoding-failed",
|
|
130
|
+
targetFormat
|
|
131
|
+
});
|
|
132
|
+
} else {
|
|
133
|
+
const levels = file.getLevels();
|
|
134
|
+
const mips = [];
|
|
135
|
+
let failed = false;
|
|
136
|
+
for (let level = 0; level < levels; level++) {
|
|
137
|
+
const info = file.getImageLevelInfo(level, 0, 0);
|
|
138
|
+
const size = file.getImageTranscodedSizeInBytes(level, 0, 0, targetEnum);
|
|
139
|
+
const dst = new Uint8Array(size);
|
|
140
|
+
const ok = file.transcodeImage(dst, level, 0, 0, targetEnum, 0, -1, -1);
|
|
141
|
+
if (ok === 0) {
|
|
142
|
+
result = codecError("transcode-failed", {
|
|
143
|
+
sourceFormat: `dfd-model-${parsed.dfd?.colorModel ?? "unknown"}-level-${level}`,
|
|
144
|
+
targetFormat
|
|
145
|
+
});
|
|
146
|
+
failed = true;
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
mips.push({ level, width: info.origWidth, height: info.origHeight, data: dst });
|
|
150
|
+
}
|
|
151
|
+
if (!failed) {
|
|
152
|
+
result = {
|
|
153
|
+
ok: true,
|
|
154
|
+
value: {
|
|
155
|
+
format: targetFormat,
|
|
156
|
+
width: file.getWidth(),
|
|
157
|
+
height: file.getHeight(),
|
|
158
|
+
mips
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
} catch {
|
|
164
|
+
result = codecError("transcode-failed", {
|
|
165
|
+
sourceFormat: `dfd-model-${parsed.dfd?.colorModel ?? "unknown"}`,
|
|
166
|
+
targetFormat
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
file.close();
|
|
171
|
+
} catch {
|
|
172
|
+
if (result.ok) {
|
|
173
|
+
result = codecError("transcode-failed", {
|
|
174
|
+
sourceFormat: `dfd-model-${parsed.dfd?.colorModel ?? "unknown"}`,
|
|
175
|
+
targetFormat
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
async function transcodeBasis(bytes, targetFormat) {
|
|
182
|
+
let mod;
|
|
183
|
+
try {
|
|
184
|
+
mod = await initBasisTranscoder();
|
|
185
|
+
} catch {
|
|
186
|
+
return codecError("codec-init-failed", { stage: "dynamic-import-basis-transcoder" });
|
|
187
|
+
}
|
|
188
|
+
const targetEnum = basisTargetFor(mod, targetFormat);
|
|
189
|
+
if (targetEnum === null || mod.BasisFile === void 0) {
|
|
190
|
+
return codecError("transcode-failed", {
|
|
191
|
+
sourceFormat: "raw-basis",
|
|
192
|
+
targetFormat
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
let file;
|
|
196
|
+
try {
|
|
197
|
+
file = new mod.BasisFile(bytes);
|
|
198
|
+
} catch {
|
|
199
|
+
return codecError("transcode-failed", {
|
|
200
|
+
sourceFormat: "raw-basis",
|
|
201
|
+
targetFormat
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
let result = codecError("transcode-failed", {
|
|
205
|
+
sourceFormat: "raw-basis",
|
|
206
|
+
targetFormat
|
|
207
|
+
});
|
|
208
|
+
try {
|
|
209
|
+
if (file.getNumImages() <= 0 || file.getNumLevels(0) <= 0) {
|
|
210
|
+
result = codecError("transcode-failed", { sourceFormat: "invalid-basis-file", targetFormat });
|
|
211
|
+
} else if (file.startTranscoding() === 0) {
|
|
212
|
+
result = codecError("transcode-failed", {
|
|
213
|
+
sourceFormat: "start-transcoding-failed",
|
|
214
|
+
targetFormat
|
|
215
|
+
});
|
|
216
|
+
} else {
|
|
217
|
+
const mips = [];
|
|
218
|
+
let failed = false;
|
|
219
|
+
for (let level = 0; level < file.getNumLevels(0); level++) {
|
|
220
|
+
const width = file.getImageWidth(0, level);
|
|
221
|
+
const height = file.getImageHeight(0, level);
|
|
222
|
+
const size = file.getImageTranscodedSizeInBytes(0, level, targetEnum);
|
|
223
|
+
const data = new Uint8Array(size);
|
|
224
|
+
if (file.transcodeImage(data, 0, level, targetEnum, 0) === 0) {
|
|
225
|
+
result = codecError("transcode-failed", {
|
|
226
|
+
sourceFormat: `raw-basis-level-${level}`,
|
|
227
|
+
targetFormat
|
|
228
|
+
});
|
|
229
|
+
failed = true;
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
mips.push({ level, width, height, data });
|
|
233
|
+
}
|
|
234
|
+
if (!failed) {
|
|
235
|
+
result = {
|
|
236
|
+
ok: true,
|
|
237
|
+
value: {
|
|
238
|
+
format: targetFormat,
|
|
239
|
+
width: mips[0]?.width ?? 0,
|
|
240
|
+
height: mips[0]?.height ?? 0,
|
|
241
|
+
mips
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
} catch {
|
|
247
|
+
result = codecError("transcode-failed", {
|
|
248
|
+
sourceFormat: "raw-basis",
|
|
249
|
+
targetFormat
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
try {
|
|
253
|
+
file.close();
|
|
254
|
+
} catch {
|
|
255
|
+
if (result.ok) {
|
|
256
|
+
result = codecError("transcode-failed", {
|
|
257
|
+
sourceFormat: "raw-basis",
|
|
258
|
+
targetFormat
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return result;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// src/block-format.ts
|
|
266
|
+
var BLOCK_TABLE = /* @__PURE__ */ new Map([
|
|
267
|
+
// -- BC (S3TC / RGTC / BPTC) --
|
|
268
|
+
["bc1-rgba-unorm", { blockW: 4, blockH: 4, bytesPerBlock: 8 }],
|
|
269
|
+
["bc1-rgba-unorm-srgb", { blockW: 4, blockH: 4, bytesPerBlock: 8 }],
|
|
270
|
+
["bc2-rgba-unorm", { blockW: 4, blockH: 4, bytesPerBlock: 16 }],
|
|
271
|
+
["bc2-rgba-unorm-srgb", { blockW: 4, blockH: 4, bytesPerBlock: 16 }],
|
|
272
|
+
["bc3-rgba-unorm", { blockW: 4, blockH: 4, bytesPerBlock: 16 }],
|
|
273
|
+
["bc3-rgba-unorm-srgb", { blockW: 4, blockH: 4, bytesPerBlock: 16 }],
|
|
274
|
+
["bc4-r-unorm", { blockW: 4, blockH: 4, bytesPerBlock: 8 }],
|
|
275
|
+
["bc4-r-snorm", { blockW: 4, blockH: 4, bytesPerBlock: 8 }],
|
|
276
|
+
["bc5-rg-unorm", { blockW: 4, blockH: 4, bytesPerBlock: 16 }],
|
|
277
|
+
["bc5-rg-snorm", { blockW: 4, blockH: 4, bytesPerBlock: 16 }],
|
|
278
|
+
["bc6h-rgb-ufloat", { blockW: 4, blockH: 4, bytesPerBlock: 16 }],
|
|
279
|
+
["bc6h-rgb-float", { blockW: 4, blockH: 4, bytesPerBlock: 16 }],
|
|
280
|
+
["bc7-rgba-unorm", { blockW: 4, blockH: 4, bytesPerBlock: 16 }],
|
|
281
|
+
["bc7-rgba-unorm-srgb", { blockW: 4, blockH: 4, bytesPerBlock: 16 }],
|
|
282
|
+
// -- ETC2 / EAC --
|
|
283
|
+
["etc2-rgb8unorm", { blockW: 4, blockH: 4, bytesPerBlock: 8 }],
|
|
284
|
+
["etc2-rgb8unorm-srgb", { blockW: 4, blockH: 4, bytesPerBlock: 8 }],
|
|
285
|
+
["etc2-rgb8a1unorm", { blockW: 4, blockH: 4, bytesPerBlock: 8 }],
|
|
286
|
+
["etc2-rgb8a1unorm-srgb", { blockW: 4, blockH: 4, bytesPerBlock: 8 }],
|
|
287
|
+
["etc2-rgba8unorm", { blockW: 4, blockH: 4, bytesPerBlock: 16 }],
|
|
288
|
+
["etc2-rgba8unorm-srgb", { blockW: 4, blockH: 4, bytesPerBlock: 16 }],
|
|
289
|
+
["eac-r11unorm", { blockW: 4, blockH: 4, bytesPerBlock: 8 }],
|
|
290
|
+
["eac-r11snorm", { blockW: 4, blockH: 4, bytesPerBlock: 8 }],
|
|
291
|
+
["eac-rg11unorm", { blockW: 4, blockH: 4, bytesPerBlock: 16 }],
|
|
292
|
+
["eac-rg11snorm", { blockW: 4, blockH: 4, bytesPerBlock: 16 }],
|
|
293
|
+
// -- ASTC (all 16 bytes/block; block dims from the format name) --
|
|
294
|
+
["astc-4x4-unorm", { blockW: 4, blockH: 4, bytesPerBlock: 16 }],
|
|
295
|
+
["astc-4x4-unorm-srgb", { blockW: 4, blockH: 4, bytesPerBlock: 16 }],
|
|
296
|
+
["astc-5x4-unorm", { blockW: 5, blockH: 4, bytesPerBlock: 16 }],
|
|
297
|
+
["astc-5x4-unorm-srgb", { blockW: 5, blockH: 4, bytesPerBlock: 16 }],
|
|
298
|
+
["astc-5x5-unorm", { blockW: 5, blockH: 5, bytesPerBlock: 16 }],
|
|
299
|
+
["astc-5x5-unorm-srgb", { blockW: 5, blockH: 5, bytesPerBlock: 16 }],
|
|
300
|
+
["astc-6x5-unorm", { blockW: 6, blockH: 5, bytesPerBlock: 16 }],
|
|
301
|
+
["astc-6x5-unorm-srgb", { blockW: 6, blockH: 5, bytesPerBlock: 16 }],
|
|
302
|
+
["astc-6x6-unorm", { blockW: 6, blockH: 6, bytesPerBlock: 16 }],
|
|
303
|
+
["astc-6x6-unorm-srgb", { blockW: 6, blockH: 6, bytesPerBlock: 16 }],
|
|
304
|
+
["astc-8x5-unorm", { blockW: 8, blockH: 5, bytesPerBlock: 16 }],
|
|
305
|
+
["astc-8x5-unorm-srgb", { blockW: 8, blockH: 5, bytesPerBlock: 16 }],
|
|
306
|
+
["astc-8x6-unorm", { blockW: 8, blockH: 6, bytesPerBlock: 16 }],
|
|
307
|
+
["astc-8x6-unorm-srgb", { blockW: 8, blockH: 6, bytesPerBlock: 16 }],
|
|
308
|
+
["astc-8x8-unorm", { blockW: 8, blockH: 8, bytesPerBlock: 16 }],
|
|
309
|
+
["astc-8x8-unorm-srgb", { blockW: 8, blockH: 8, bytesPerBlock: 16 }],
|
|
310
|
+
["astc-10x5-unorm", { blockW: 10, blockH: 5, bytesPerBlock: 16 }],
|
|
311
|
+
["astc-10x5-unorm-srgb", { blockW: 10, blockH: 5, bytesPerBlock: 16 }],
|
|
312
|
+
["astc-10x6-unorm", { blockW: 10, blockH: 6, bytesPerBlock: 16 }],
|
|
313
|
+
["astc-10x6-unorm-srgb", { blockW: 10, blockH: 6, bytesPerBlock: 16 }],
|
|
314
|
+
["astc-10x8-unorm", { blockW: 10, blockH: 8, bytesPerBlock: 16 }],
|
|
315
|
+
["astc-10x8-unorm-srgb", { blockW: 10, blockH: 8, bytesPerBlock: 16 }],
|
|
316
|
+
["astc-10x10-unorm", { blockW: 10, blockH: 10, bytesPerBlock: 16 }],
|
|
317
|
+
["astc-10x10-unorm-srgb", { blockW: 10, blockH: 10, bytesPerBlock: 16 }],
|
|
318
|
+
["astc-12x10-unorm", { blockW: 12, blockH: 10, bytesPerBlock: 16 }],
|
|
319
|
+
["astc-12x10-unorm-srgb", { blockW: 12, blockH: 10, bytesPerBlock: 16 }],
|
|
320
|
+
["astc-12x12-unorm", { blockW: 12, blockH: 12, bytesPerBlock: 16 }],
|
|
321
|
+
["astc-12x12-unorm-srgb", { blockW: 12, blockH: 12, bytesPerBlock: 16 }]
|
|
322
|
+
]);
|
|
323
|
+
function blockParamsForFormat(format) {
|
|
324
|
+
return BLOCK_TABLE.get(format) ?? null;
|
|
325
|
+
}
|
|
326
|
+
function isCompressedFormat(format) {
|
|
327
|
+
return BLOCK_TABLE.has(format);
|
|
328
|
+
}
|
|
329
|
+
function bytesPerRow(format, width) {
|
|
330
|
+
const params = BLOCK_TABLE.get(format);
|
|
331
|
+
if (params === void 0) return null;
|
|
332
|
+
return Math.ceil(width / params.blockW) * params.bytesPerBlock;
|
|
333
|
+
}
|
|
334
|
+
function rowsPerImage(format, height) {
|
|
335
|
+
const params = BLOCK_TABLE.get(format);
|
|
336
|
+
if (params === void 0) return null;
|
|
337
|
+
return Math.ceil(height / params.blockH);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// src/zstd.ts
|
|
341
|
+
var defaultImporter2 = () => import('fzstd').then((mod) => mod.decompress);
|
|
342
|
+
var importer2 = defaultImporter2;
|
|
343
|
+
var _initPromise2 = null;
|
|
344
|
+
function getDecompressor() {
|
|
345
|
+
if (_initPromise2 !== null) {
|
|
346
|
+
return _initPromise2;
|
|
347
|
+
}
|
|
348
|
+
_initPromise2 = importer2().catch((cause) => {
|
|
349
|
+
_initPromise2 = null;
|
|
350
|
+
throw new Error("codec-init-failed", { cause });
|
|
351
|
+
});
|
|
352
|
+
return _initPromise2;
|
|
353
|
+
}
|
|
354
|
+
async function decompressZstd(bytes) {
|
|
355
|
+
let decompress;
|
|
356
|
+
try {
|
|
357
|
+
decompress = await getDecompressor();
|
|
358
|
+
} catch {
|
|
359
|
+
return codecError("codec-init-failed", { stage: "dynamic-import-fzstd" });
|
|
360
|
+
}
|
|
361
|
+
try {
|
|
362
|
+
const result = decompress(bytes);
|
|
363
|
+
return { ok: true, value: result };
|
|
364
|
+
} catch {
|
|
365
|
+
return codecError("decompression-failed", {
|
|
366
|
+
reason: "zstd decompression failed: corrupt or invalid compressed data"
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// src/ktx2.ts
|
|
372
|
+
var KTX2_IDENTIFIER = new Uint8Array([
|
|
373
|
+
171,
|
|
374
|
+
75,
|
|
375
|
+
84,
|
|
376
|
+
88,
|
|
377
|
+
32,
|
|
378
|
+
50,
|
|
379
|
+
48,
|
|
380
|
+
187,
|
|
381
|
+
13,
|
|
382
|
+
10,
|
|
383
|
+
26,
|
|
384
|
+
10
|
|
385
|
+
]);
|
|
386
|
+
function ktx2ColorSpace(parsed) {
|
|
387
|
+
switch (parsed.dfd?.transferFunction) {
|
|
388
|
+
case 1:
|
|
389
|
+
return "linear";
|
|
390
|
+
case 2:
|
|
391
|
+
return "srgb";
|
|
392
|
+
default:
|
|
393
|
+
return void 0;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
var TD = new TextDecoder();
|
|
397
|
+
function readU32(bytes, byteOffset) {
|
|
398
|
+
return new DataView(bytes.buffer, bytes.byteOffset + byteOffset, 4).getUint32(0, true);
|
|
399
|
+
}
|
|
400
|
+
function readU64(bytes, byteOffset) {
|
|
401
|
+
return Number(new DataView(bytes.buffer, bytes.byteOffset + byteOffset, 8).getBigUint64(0, true));
|
|
402
|
+
}
|
|
403
|
+
function assertBounds(bytes, offset, length, context) {
|
|
404
|
+
if (offset + length > bytes.length) {
|
|
405
|
+
throw new Error(
|
|
406
|
+
`KTX2 parse ${context}: OOB (offset=${offset}, length=${length}, fileSize=${bytes.length})`
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
function parseDfd(bytes, offset, _dfdByteLength) {
|
|
411
|
+
assertBounds(bytes, offset, 4, "DFD-totalSize");
|
|
412
|
+
const totalSize = readU32(bytes, offset);
|
|
413
|
+
assertBounds(bytes, offset, totalSize, "DFD-block");
|
|
414
|
+
const dbOff = offset + 4;
|
|
415
|
+
const word0 = readU32(bytes, dbOff);
|
|
416
|
+
const vendorId = word0 & 131071;
|
|
417
|
+
const descriptorType = word0 >>> 17 & 32767;
|
|
418
|
+
const word1 = readU32(bytes, dbOff + 4);
|
|
419
|
+
const versionNumber = word1 & 65535;
|
|
420
|
+
const descriptorBlockSize = word1 >>> 16 & 65535;
|
|
421
|
+
const word2 = readU32(bytes, dbOff + 8);
|
|
422
|
+
const colorModel = word2 & 255;
|
|
423
|
+
const colorPrimaries = word2 >>> 8 & 255;
|
|
424
|
+
const transferFunction = word2 >>> 16 & 255;
|
|
425
|
+
const flags = word2 >>> 24 & 255;
|
|
426
|
+
const word3 = readU32(bytes, dbOff + 12);
|
|
427
|
+
const texelBlockDim0 = word3 & 255;
|
|
428
|
+
const texelBlockDim1 = word3 >>> 8 & 255;
|
|
429
|
+
const texelBlockDim2 = word3 >>> 16 & 255;
|
|
430
|
+
const texelBlockDim3 = word3 >>> 24 & 255;
|
|
431
|
+
const word4 = readU32(bytes, dbOff + 16);
|
|
432
|
+
const word5 = readU32(bytes, dbOff + 20);
|
|
433
|
+
const bytesPlane = [
|
|
434
|
+
word4 & 255,
|
|
435
|
+
word4 >>> 8 & 255,
|
|
436
|
+
word4 >>> 16 & 255,
|
|
437
|
+
word4 >>> 24 & 255,
|
|
438
|
+
word5 & 255,
|
|
439
|
+
word5 >>> 8 & 255,
|
|
440
|
+
word5 >>> 16 & 255,
|
|
441
|
+
word5 >>> 24 & 255
|
|
442
|
+
];
|
|
443
|
+
const sampleBase = dbOff + 24;
|
|
444
|
+
const numSamples = (descriptorBlockSize - 24) / 16;
|
|
445
|
+
const samples = [];
|
|
446
|
+
for (let i = 0; i < numSamples; i++) {
|
|
447
|
+
const so = sampleBase + i * 16;
|
|
448
|
+
const sw0 = readU32(bytes, so);
|
|
449
|
+
const sw1 = readU32(bytes, so + 4);
|
|
450
|
+
const sw2 = readU32(bytes, so + 8);
|
|
451
|
+
const sw3 = readU32(bytes, so + 12);
|
|
452
|
+
samples.push({
|
|
453
|
+
qualifiers: sw0 & 15,
|
|
454
|
+
channelType: sw0 >>> 4 & 255,
|
|
455
|
+
bitLength: (sw0 >>> 12 & 4095) + 1,
|
|
456
|
+
// stored as actual-1 per spec
|
|
457
|
+
bitOffset: sw0 >>> 24 & 255,
|
|
458
|
+
samplePosition: [
|
|
459
|
+
sw1 & 255,
|
|
460
|
+
sw1 >>> 8 & 255,
|
|
461
|
+
sw1 >>> 16 & 255,
|
|
462
|
+
sw1 >>> 24 & 255
|
|
463
|
+
],
|
|
464
|
+
sampleLower: sw2,
|
|
465
|
+
sampleUpper: sw3
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
return {
|
|
469
|
+
totalSize,
|
|
470
|
+
vendorId,
|
|
471
|
+
descriptorType,
|
|
472
|
+
versionNumber,
|
|
473
|
+
descriptorBlockSize,
|
|
474
|
+
colorModel,
|
|
475
|
+
colorPrimaries,
|
|
476
|
+
transferFunction,
|
|
477
|
+
flags,
|
|
478
|
+
texelBlockDimension: [texelBlockDim0, texelBlockDim1, texelBlockDim2, texelBlockDim3],
|
|
479
|
+
bytesPlane,
|
|
480
|
+
samples
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
function parseKv(bytes, offset, kvdByteLength) {
|
|
484
|
+
if (kvdByteLength === 0) return [];
|
|
485
|
+
const entries = [];
|
|
486
|
+
let pos = offset;
|
|
487
|
+
const end = offset + kvdByteLength;
|
|
488
|
+
while (pos < end) {
|
|
489
|
+
assertBounds(bytes, pos, 4, "KV-keyAndValueByteLength");
|
|
490
|
+
const keyAndValueByteLength = readU32(bytes, pos);
|
|
491
|
+
pos += 4;
|
|
492
|
+
assertBounds(bytes, pos, keyAndValueByteLength, "KV-payload");
|
|
493
|
+
const raw = bytes.slice(pos, pos + keyAndValueByteLength);
|
|
494
|
+
let nulIdx = raw.indexOf(0);
|
|
495
|
+
if (nulIdx === -1) nulIdx = raw.length;
|
|
496
|
+
const key = TD.decode(raw.slice(0, nulIdx));
|
|
497
|
+
const value = raw.slice(nulIdx + 1);
|
|
498
|
+
entries.push({ key, value });
|
|
499
|
+
pos += keyAndValueByteLength;
|
|
500
|
+
const remainder = pos & 3;
|
|
501
|
+
if (remainder !== 0) {
|
|
502
|
+
pos += 4 - remainder;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return entries;
|
|
506
|
+
}
|
|
507
|
+
async function parseKtx2(bytes) {
|
|
508
|
+
try {
|
|
509
|
+
if (bytes.length < 12) {
|
|
510
|
+
return codecError("ktx2-parse-failed", {
|
|
511
|
+
reason: "truncated-identifier: file shorter than 12-byte KTX2 magic"
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
for (let i = 0; i < 12; i++) {
|
|
515
|
+
const expectedByte = KTX2_IDENTIFIER[i];
|
|
516
|
+
if (expectedByte === void 0 || bytes[i] !== expectedByte) {
|
|
517
|
+
return codecError("ktx2-parse-failed", {
|
|
518
|
+
reason: "invalid-identifier: not a KTX2 2.0 file"
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
if (bytes.length < 80) {
|
|
523
|
+
return codecError("ktx2-parse-failed", {
|
|
524
|
+
reason: "truncated-header: file too short for KTX2 header + index (min 80 bytes)"
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
const header = {
|
|
528
|
+
vkFormat: readU32(bytes, 12),
|
|
529
|
+
typeSize: readU32(bytes, 16),
|
|
530
|
+
pixelWidth: readU32(bytes, 20),
|
|
531
|
+
pixelHeight: readU32(bytes, 24),
|
|
532
|
+
pixelDepth: readU32(bytes, 28),
|
|
533
|
+
layerCount: readU32(bytes, 32),
|
|
534
|
+
faceCount: readU32(bytes, 36),
|
|
535
|
+
levelCount: readU32(bytes, 40),
|
|
536
|
+
supercompressionScheme: readU32(bytes, 44)
|
|
537
|
+
};
|
|
538
|
+
const index = {
|
|
539
|
+
dfdByteOffset: readU32(bytes, 48),
|
|
540
|
+
dfdByteLength: readU32(bytes, 52),
|
|
541
|
+
kvdByteOffset: readU32(bytes, 56),
|
|
542
|
+
kvdByteLength: readU32(bytes, 60),
|
|
543
|
+
sgdByteOffset: readU64(bytes, 64),
|
|
544
|
+
sgdByteLength: readU64(bytes, 72)
|
|
545
|
+
};
|
|
546
|
+
const scheme = header.supercompressionScheme;
|
|
547
|
+
if (scheme !== 0 && scheme !== 1 && scheme !== 2) {
|
|
548
|
+
return codecError("ktx2-unsupported-scheme", { scheme });
|
|
549
|
+
}
|
|
550
|
+
const numLevels = Math.max(1, header.levelCount);
|
|
551
|
+
const levelIndexStart = 80;
|
|
552
|
+
assertBounds(bytes, levelIndexStart, numLevels * 24, "level-index");
|
|
553
|
+
const levelIndex = [];
|
|
554
|
+
for (let i = 0; i < numLevels; i++) {
|
|
555
|
+
const off = levelIndexStart + i * 24;
|
|
556
|
+
const byteOffset = readU64(bytes, off);
|
|
557
|
+
const byteLength = readU64(bytes, off + 8);
|
|
558
|
+
const uncompressedByteLength = readU64(bytes, off + 16);
|
|
559
|
+
if (byteOffset + byteLength > bytes.length) {
|
|
560
|
+
return codecError("ktx2-parse-failed", {
|
|
561
|
+
reason: `level-index-OOB: level ${i} byteOffset=${byteOffset} byteLength=${byteLength} exceeds file size=${bytes.length}`
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
levelIndex.push({ byteOffset, byteLength, uncompressedByteLength });
|
|
565
|
+
}
|
|
566
|
+
let dfd = null;
|
|
567
|
+
if (index.dfdByteLength > 0) {
|
|
568
|
+
assertBounds(bytes, index.dfdByteOffset, index.dfdByteLength, "DFD");
|
|
569
|
+
dfd = parseDfd(bytes, index.dfdByteOffset, index.dfdByteLength);
|
|
570
|
+
}
|
|
571
|
+
let kvEntries = [];
|
|
572
|
+
if (index.kvdByteLength > 0) {
|
|
573
|
+
assertBounds(bytes, index.kvdByteOffset, index.kvdByteLength, "KVD");
|
|
574
|
+
kvEntries = parseKv(bytes, index.kvdByteOffset, index.kvdByteLength);
|
|
575
|
+
}
|
|
576
|
+
let sgd = null;
|
|
577
|
+
if (index.sgdByteLength > 0) {
|
|
578
|
+
assertBounds(bytes, index.sgdByteOffset, index.sgdByteLength, "SGD");
|
|
579
|
+
sgd = bytes.slice(index.sgdByteOffset, index.sgdByteOffset + index.sgdByteLength);
|
|
580
|
+
}
|
|
581
|
+
return {
|
|
582
|
+
ok: true,
|
|
583
|
+
value: {
|
|
584
|
+
header,
|
|
585
|
+
index,
|
|
586
|
+
levelIndex,
|
|
587
|
+
dfd,
|
|
588
|
+
kvEntries,
|
|
589
|
+
sgd,
|
|
590
|
+
rawBytes: bytes
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
} catch (err) {
|
|
594
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
595
|
+
return codecError("ktx2-parse-failed", { reason: `internal: ${message}` });
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
function levelIndexForMip(totalLevels, mipLevel) {
|
|
599
|
+
const entryIdx = totalLevels - 1 - mipLevel;
|
|
600
|
+
if (entryIdx < 0 || entryIdx >= totalLevels) return -1;
|
|
601
|
+
return entryIdx;
|
|
602
|
+
}
|
|
603
|
+
async function ktx2LevelsToRGBA(parsed, level = 0) {
|
|
604
|
+
const totalLevels = parsed.levelIndex.length;
|
|
605
|
+
const entryIdx = levelIndexForMip(totalLevels, level);
|
|
606
|
+
if (entryIdx < 0) {
|
|
607
|
+
return codecError("ktx2-parse-failed", { reason: `mip level ${level} does not exist` });
|
|
608
|
+
}
|
|
609
|
+
const entry = parsed.levelIndex[entryIdx];
|
|
610
|
+
if (!entry) {
|
|
611
|
+
return codecError("ktx2-parse-failed", {
|
|
612
|
+
reason: `mip level ${level} has no level index entry`
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
if (parsed.header.supercompressionScheme === 0) {
|
|
616
|
+
const slice = parsed.rawBytes.slice(entry.byteOffset, entry.byteOffset + entry.byteLength);
|
|
617
|
+
return { ok: true, value: new Uint8Array(slice) };
|
|
618
|
+
}
|
|
619
|
+
if (parsed.header.supercompressionScheme === 2) {
|
|
620
|
+
const compressedSlice = parsed.rawBytes.slice(
|
|
621
|
+
entry.byteOffset,
|
|
622
|
+
entry.byteOffset + entry.byteLength
|
|
623
|
+
);
|
|
624
|
+
const result = await decompressZstd(new Uint8Array(compressedSlice));
|
|
625
|
+
if (!result.ok) {
|
|
626
|
+
return codecError("ktx2-parse-failed", {
|
|
627
|
+
reason: `zstd decompression failed for level ${level}: ${result.error.detail}`
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
return result;
|
|
631
|
+
}
|
|
632
|
+
return codecError("ktx2-unsupported-scheme", {
|
|
633
|
+
scheme: parsed.header.supercompressionScheme
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// src/transcode.ts
|
|
638
|
+
function selectRgba(srgb, caps) {
|
|
639
|
+
if (caps.bc) return srgb ? "bc7-rgba-unorm-srgb" : "bc7-rgba-unorm";
|
|
640
|
+
if (caps.astc) return srgb ? "astc-4x4-unorm-srgb" : "astc-4x4-unorm";
|
|
641
|
+
if (caps.etc2) return srgb ? "etc2-rgba8unorm-srgb" : "etc2-rgba8unorm";
|
|
642
|
+
return srgb ? "rgba8unorm-srgb" : "rgba8unorm";
|
|
643
|
+
}
|
|
644
|
+
function selectRg(caps) {
|
|
645
|
+
if (caps.bc) return "bc5-rg-unorm";
|
|
646
|
+
if (caps.etc2) return "eac-rg11unorm";
|
|
647
|
+
return "rg8unorm";
|
|
648
|
+
}
|
|
649
|
+
function selectR(caps) {
|
|
650
|
+
if (caps.bc) return "bc4-r-unorm";
|
|
651
|
+
if (caps.etc2) return "eac-r11unorm";
|
|
652
|
+
return "r8unorm";
|
|
653
|
+
}
|
|
654
|
+
function selectHdr(caps) {
|
|
655
|
+
if (caps.bc) return "bc6h-rgb-ufloat";
|
|
656
|
+
return "rgba16float";
|
|
657
|
+
}
|
|
658
|
+
function selectTranscodeTarget(source, caps) {
|
|
659
|
+
if (source.model === "uastc-hdr") return selectHdr(caps);
|
|
660
|
+
switch (source.channels) {
|
|
661
|
+
case "rgba":
|
|
662
|
+
return selectRgba(source.srgb, caps);
|
|
663
|
+
case "rg":
|
|
664
|
+
return selectRg(caps);
|
|
665
|
+
case "r":
|
|
666
|
+
return selectR(caps);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
export { KTX2_IDENTIFIER, blockParamsForFormat, bytesPerRow, codecError, decompressZstd, initBasisTranscoder, inspectBasisSource, isCompressedFormat, ktx2ColorSpace, ktx2LevelsToRGBA, parseKtx2, rowsPerImage, selectTranscodeTarget, transcodeBasis, transcodeKtx2 };
|
|
671
|
+
//# sourceMappingURL=index.mjs.map
|
|
672
|
+
//# sourceMappingURL=index.mjs.map
|