@flighthq/texture-formats 0.1.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.
Files changed (45) hide show
  1. package/dist/byteReader.d.ts +14 -0
  2. package/dist/byteReader.d.ts.map +1 -0
  3. package/dist/byteReader.js +51 -0
  4. package/dist/byteReader.js.map +1 -0
  5. package/dist/detectTextureContainer.d.ts +2 -0
  6. package/dist/detectTextureContainer.d.ts.map +1 -0
  7. package/dist/detectTextureContainer.js +31 -0
  8. package/dist/detectTextureContainer.js.map +1 -0
  9. package/dist/index.d.ts +7 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +7 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/parseAtf.d.ts +3 -0
  14. package/dist/parseAtf.d.ts.map +1 -0
  15. package/dist/parseAtf.js +139 -0
  16. package/dist/parseAtf.js.map +1 -0
  17. package/dist/parseBasis.d.ts +3 -0
  18. package/dist/parseBasis.d.ts.map +1 -0
  19. package/dist/parseBasis.js +82 -0
  20. package/dist/parseBasis.js.map +1 -0
  21. package/dist/parseDds.d.ts +3 -0
  22. package/dist/parseDds.d.ts.map +1 -0
  23. package/dist/parseDds.js +151 -0
  24. package/dist/parseDds.js.map +1 -0
  25. package/dist/parseKtx2.d.ts +3 -0
  26. package/dist/parseKtx2.d.ts.map +1 -0
  27. package/dist/parseKtx2.js +173 -0
  28. package/dist/parseKtx2.js.map +1 -0
  29. package/dist/selectTextureContainer.d.ts +4 -0
  30. package/dist/selectTextureContainer.d.ts.map +1 -0
  31. package/dist/selectTextureContainer.js +15 -0
  32. package/dist/selectTextureContainer.js.map +1 -0
  33. package/dist/textureLevelLayout.d.ts +8 -0
  34. package/dist/textureLevelLayout.d.ts.map +1 -0
  35. package/dist/textureLevelLayout.js +109 -0
  36. package/dist/textureLevelLayout.js.map +1 -0
  37. package/package.json +37 -0
  38. package/src/byteReader.test.ts +105 -0
  39. package/src/detectTextureContainer.test.ts +33 -0
  40. package/src/parseAtf.test.ts +288 -0
  41. package/src/parseBasis.test.ts +124 -0
  42. package/src/parseDds.test.ts +146 -0
  43. package/src/parseKtx2.test.ts +135 -0
  44. package/src/selectTextureContainer.test.ts +38 -0
  45. package/src/textureLevelLayout.test.ts +45 -0
@@ -0,0 +1,14 @@
1
+ export interface ByteReader {
2
+ readonly view: DataView;
3
+ offset: number;
4
+ }
5
+ export declare function createByteReader(bytes: Readonly<Uint8Array>, offset?: number): ByteReader;
6
+ export declare function hasByteReaderBytes(reader: Readonly<ByteReader>, count: number): boolean;
7
+ export declare function readByteReaderU16(reader: ByteReader): number;
8
+ export declare function readByteReaderU24BigEndian(reader: ByteReader): number;
9
+ export declare function readByteReaderU32(reader: ByteReader): number;
10
+ export declare function readByteReaderU32BigEndian(reader: ByteReader): number;
11
+ export declare function readByteReaderU64(reader: ByteReader): number;
12
+ export declare function readByteReaderU8(reader: ByteReader): number;
13
+ export declare function skipByteReader(reader: ByteReader, count: number): void;
14
+ //# sourceMappingURL=byteReader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"byteReader.d.ts","sourceRoot":"","sources":["../src/byteReader.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,SAAI,GAAG,UAAU,CAEpF;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAEvF;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAI5D;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAMrE;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAI5D;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAIrE;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAK5D;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAI3D;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAEtE"}
@@ -0,0 +1,51 @@
1
+ // A minimal cursor over a byte buffer, shared by every container parser. KTX2, DDS, and the Basis
2
+ // container are little-endian (the `read*U16`/`U32`/`U64` helpers); ATF stores its block and header
3
+ // lengths big-endian, so `readByteReaderU24BigEndian` reads a legacy ATF's 3-byte block-length prefix
4
+ // and `readByteReaderU32BigEndian` reads a versioned ATF's 4-byte block/header lengths. The cursor
5
+ // is a plain `{ view, offset }` value with an advancing `offset`; read functions advance it, and every
6
+ // parser guards a read against `hasByteReaderBytes` first so a truncated file returns a sentinel `null`
7
+ // rather than throwing a `DataView` `RangeError`. `readByteReaderU64` returns the value as a JavaScript
8
+ // number, exact for the sub-2^53 offsets/lengths real containers use.
9
+ export function createByteReader(bytes, offset = 0) {
10
+ return { view: new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength), offset };
11
+ }
12
+ export function hasByteReaderBytes(reader, count) {
13
+ return count >= 0 && reader.offset + count <= reader.view.byteLength;
14
+ }
15
+ export function readByteReaderU16(reader) {
16
+ const value = reader.view.getUint16(reader.offset, true);
17
+ reader.offset += 2;
18
+ return value;
19
+ }
20
+ export function readByteReaderU24BigEndian(reader) {
21
+ const view = reader.view;
22
+ const offset = reader.offset;
23
+ const value = (view.getUint8(offset) << 16) | (view.getUint8(offset + 1) << 8) | view.getUint8(offset + 2);
24
+ reader.offset += 3;
25
+ return value;
26
+ }
27
+ export function readByteReaderU32(reader) {
28
+ const value = reader.view.getUint32(reader.offset, true);
29
+ reader.offset += 4;
30
+ return value;
31
+ }
32
+ export function readByteReaderU32BigEndian(reader) {
33
+ const value = reader.view.getUint32(reader.offset, false);
34
+ reader.offset += 4;
35
+ return value;
36
+ }
37
+ export function readByteReaderU64(reader) {
38
+ const low = reader.view.getUint32(reader.offset, true);
39
+ const high = reader.view.getUint32(reader.offset + 4, true);
40
+ reader.offset += 8;
41
+ return high * 0x1_0000_0000 + low;
42
+ }
43
+ export function readByteReaderU8(reader) {
44
+ const value = reader.view.getUint8(reader.offset);
45
+ reader.offset += 1;
46
+ return value;
47
+ }
48
+ export function skipByteReader(reader, count) {
49
+ reader.offset += count;
50
+ }
51
+ //# sourceMappingURL=byteReader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"byteReader.js","sourceRoot":"","sources":["../src/byteReader.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,oGAAoG;AACpG,sGAAsG;AACtG,mGAAmG;AACnG,uGAAuG;AACvG,wGAAwG;AACxG,wGAAwG;AACxG,sEAAsE;AAOtE,MAAM,UAAU,gBAAgB,CAAC,KAA2B,EAAE,MAAM,GAAG,CAAC;IACtE,OAAO,EAAE,IAAI,EAAE,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;AAC1F,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAA4B,EAAE,KAAa;IAC5E,OAAO,KAAK,IAAI,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAkB;IAClD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACzD,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;IACnB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,MAAkB;IAC3D,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IACzB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7B,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3G,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;IACnB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAkB;IAClD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACzD,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;IACnB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,MAAkB;IAC3D,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC1D,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;IACnB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAkB;IAClD,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACvD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;IAC5D,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;IACnB,OAAO,IAAI,GAAG,aAAa,GAAG,GAAG,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAkB;IACjD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;IACnB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAkB,EAAE,KAAa;IAC9D,MAAM,CAAC,MAAM,IAAI,KAAK,CAAC;AACzB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function detectTextureContainer(bytes: Readonly<Uint8Array>): 'atf' | 'basis' | 'dds' | 'ktx2' | null;
2
+ //# sourceMappingURL=detectTextureContainer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detectTextureContainer.d.ts","sourceRoot":"","sources":["../src/detectTextureContainer.ts"],"names":[],"mappings":"AAMA,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,KAAK,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,GAAG,IAAI,CAW3G"}
@@ -0,0 +1,31 @@
1
+ // Sniffs which GPU texture container a byte buffer holds from its magic bytes — `'ktx2'`, `'dds'`,
2
+ // `'basis'`, `'atf'`, or `null` when the header is too short or unrecognized. The texture-container
3
+ // sibling of `detectImageMimeType`: a cheap dispatcher to pick a `parse*` function without fully
4
+ // parsing, and the single point of container identification in the SDK. `'atf'` alone maps to the
5
+ // array-returning `parseAtf` (an ATF holds one-or-more peer encodings); the others map to a single
6
+ // `parse*` returning one `TextureContainer`.
7
+ export function detectTextureContainer(bytes) {
8
+ if (bytes.byteLength >= 12 && isKtx2Magic(bytes))
9
+ return 'ktx2';
10
+ // DDS: 'DDS ' (0x44 0x44 0x53 0x20)
11
+ if (bytes.byteLength >= 4 && bytes[0] === 0x44 && bytes[1] === 0x44 && bytes[2] === 0x53 && bytes[3] === 0x20) {
12
+ return 'dds';
13
+ }
14
+ // ATF: 'ATF' (0x41 0x54 0x46)
15
+ if (bytes.byteLength >= 3 && bytes[0] === 0x41 && bytes[1] === 0x54 && bytes[2] === 0x46)
16
+ return 'atf';
17
+ // Basis: m_sig 0x4273 little-endian ('s' then 'B')
18
+ if (bytes.byteLength >= 2 && bytes[0] === 0x73 && bytes[1] === 0x42)
19
+ return 'basis';
20
+ return null;
21
+ }
22
+ function isKtx2Magic(bytes) {
23
+ for (let i = 0; i < 12; i += 1) {
24
+ if (bytes[i] !== ktx2Magic[i])
25
+ return false;
26
+ }
27
+ return true;
28
+ }
29
+ // «KTX 20»\r\n\x1A\n
30
+ const ktx2Magic = [0xab, 0x4b, 0x54, 0x58, 0x20, 0x32, 0x30, 0xbb, 0x0d, 0x0a, 0x1a, 0x0a];
31
+ //# sourceMappingURL=detectTextureContainer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detectTextureContainer.js","sourceRoot":"","sources":["../src/detectTextureContainer.ts"],"names":[],"mappings":"AAAA,mGAAmG;AACnG,oGAAoG;AACpG,iGAAiG;AACjG,kGAAkG;AAClG,mGAAmG;AACnG,6CAA6C;AAC7C,MAAM,UAAU,sBAAsB,CAAC,KAA2B;IAChE,IAAI,KAAK,CAAC,UAAU,IAAI,EAAE,IAAI,WAAW,CAAC,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IAChE,oCAAoC;IACpC,IAAI,KAAK,CAAC,UAAU,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC9G,OAAO,KAAK,CAAC;IACf,CAAC;IACD,8BAA8B;IAC9B,IAAI,KAAK,CAAC,UAAU,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACvG,mDAAmD;IACnD,IAAI,KAAK,CAAC,UAAU,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QAAE,OAAO,OAAO,CAAC;IACpF,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,WAAW,CAAC,KAA2B;IAC9C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IAC9C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,qBAAqB;AACrB,MAAM,SAAS,GAAsB,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ export * from './detectTextureContainer';
2
+ export * from './parseAtf';
3
+ export * from './parseBasis';
4
+ export * from './parseDds';
5
+ export * from './parseKtx2';
6
+ export * from './selectTextureContainer';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export * from './detectTextureContainer';
2
+ export * from './parseAtf';
3
+ export * from './parseBasis';
4
+ export * from './parseDds';
5
+ export * from './parseKtx2';
6
+ export * from './selectTextureContainer';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { TextureContainer } from '@flighthq/types';
2
+ export declare function parseAtf(bytes: Readonly<Uint8Array>): TextureContainer[] | null;
3
+ //# sourceMappingURL=parseAtf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseAtf.d.ts","sourceRoot":"","sources":["../src/parseAtf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAsCxD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,gBAAgB,EAAE,GAAG,IAAI,CAqF/E"}
@@ -0,0 +1,139 @@
1
+ import { createByteReader, hasByteReaderBytes, readByteReaderU24BigEndian, readByteReaderU32BigEndian, } from './byteReader';
2
+ // Parses an ATF (Adobe Texture Format) container into an ARRAY of peer `TextureContainer`s, or returns
3
+ // `null` if the bytes are not ATF, are truncated, or carry an unsupported ATF format code. ATF is the
4
+ // Flash/Stage3D/AIR GPU-texture container (an OpenFL/Lime feature target). Unlike KTX2/DDS/Basis, a
5
+ // single ATF embeds the SAME texture in several GPU encodings (DXT + ETC + PVRTC, and — from version 3 —
6
+ // ETC2) so a Stage3D runtime picks the one its GPU supports at upload time. Flight expresses that
7
+ // multiplicity as the return cardinality — a single-format ATF yields a 1-element array; a
8
+ // cross-platform ATF yields N peer containers (no "primary"; use `selectTextureContainer` to pick one by
9
+ // GPU support). Each element is a standard single-format `TextureContainer`; the descriptor shape is
10
+ // unchanged from the other parsers.
11
+ //
12
+ // Container parse only: it locates each embedded encoding's format and per-level byte ranges. It never
13
+ // decodes pixels. The block byte ranges are reported "as stored"; for a cube map the six sides of one
14
+ // encoding become that encoding's container's `faces`.
15
+ //
16
+ // Header and block framing follow OpenFL's `ATFReader` (the ground-truth reader). The signature is
17
+ // `'ATF'`. A versioned file follows the signature marker byte `0xFF` at offset 6 with a version byte and
18
+ // a 32-bit big-endian payload length, putting the format header at offset 12; a legacy file (version 0)
19
+ // has no marker and carries a 24-bit big-endian length, putting the format header at offset 6. The
20
+ // format header is a type/format byte (bit 7 = cube-map flag, low 7 bits = ATF format code), then
21
+ // `log2(width)`, `log2(height)`, and the mip count. Blocks then follow as `side → mip level → GPU
22
+ // format`, each a big-endian length prefix (24-bit in a legacy file, 32-bit otherwise) followed by that
23
+ // many bytes; a zero length marks an absent block. The GPU-format slot order is fixed —
24
+ // 0 = DXT (`bc1`/`bc3`), 1 = ETC1, 2 = PVRTC 4bpp, and (version ≥ 3 only) 3 = ETC2 — so this parser
25
+ // walks every slot for every (side, level) and groups the non-empty blocks by slot into one peer
26
+ // `TextureContainer` each. Only the raw-compressed format codes are supported (2/3/12 opaque,
27
+ // 4/5/13 with alpha); the raw-BGRA codes (0/1) and the JPEG-XR/LZMA-wrapped variants are unsupported and
28
+ // return `null`.
29
+ export function parseAtf(bytes) {
30
+ if (!hasAtfSignature(bytes))
31
+ return null;
32
+ const versioned = bytes[6] === atfNewVersionMarker;
33
+ const headerOffset = versioned ? atfNewHeaderOffset : atfLegacyHeaderOffset;
34
+ if (bytes.byteLength < headerOffset + 4)
35
+ return null;
36
+ // `version` selects the block-length width (u24 for the legacy version-0 layout, u32 otherwise) and
37
+ // whether an ETC2 slot follows the DXT/ETC1/PVRTC trio.
38
+ const version = versioned ? bytes[7] : 0;
39
+ // The declared payload runs from the format header to the end; reject a file that claims more than it
40
+ // carries before walking any block.
41
+ const lengthReader = createByteReader(bytes, versioned ? 8 : 3);
42
+ const payloadLength = versioned ? readByteReaderU32BigEndian(lengthReader) : readByteReaderU24BigEndian(lengthReader);
43
+ if (headerOffset + payloadLength > bytes.byteLength)
44
+ return null;
45
+ const typeFormatByte = bytes[headerOffset];
46
+ const log2Width = bytes[headerOffset + 1];
47
+ const log2Height = bytes[headerOffset + 2];
48
+ const mipCount = bytes[headerOffset + 3];
49
+ const formatCode = typeFormatByte & atfFormatCodeMask;
50
+ const alpha = atfAlphaFormatCodes.has(formatCode);
51
+ if (!alpha && !atfOpaqueFormatCodes.has(formatCode))
52
+ return null; // raw-BGRA / JPEG-XR / LZMA — unsupported
53
+ if (log2Width > atfMaxLog2Dimension || log2Height > atfMaxLog2Dimension)
54
+ return null;
55
+ if (mipCount < 1)
56
+ return null;
57
+ const cube = (typeFormatByte & atfCubeFlag) !== 0;
58
+ const faces = cube ? 6 : 1;
59
+ const width = 1 << log2Width;
60
+ const height = 1 << log2Height;
61
+ // Slot order is fixed by the format: DXT, ETC1, PVRTC, then ETC2 only from version 3 onward.
62
+ const slotFormats = alpha ? atfAlphaSlotFormats : atfOpaqueSlotFormats;
63
+ const slotCount = version < atfEtc2Version ? atfBaseSlotCount : atfBaseSlotCount + 1;
64
+ // One located-level list per GPU-format slot, filled in the file's `side → level` walk order (so each
65
+ // list is face-major, then mip). A slot with no non-empty block is not a real peer and is dropped.
66
+ const perSlotLevels = [];
67
+ for (let slot = 0; slot < slotCount; slot += 1)
68
+ perSlotLevels.push([]);
69
+ const reader = createByteReader(bytes, headerOffset + 4);
70
+ const lengthWidth = version === 0 ? 3 : 4;
71
+ for (let side = 0; side < faces; side += 1) {
72
+ for (let level = 0; level < mipCount; level += 1) {
73
+ for (let slot = 0; slot < slotCount; slot += 1) {
74
+ if (!hasByteReaderBytes(reader, lengthWidth))
75
+ return null;
76
+ const blockLength = version === 0 ? readByteReaderU24BigEndian(reader) : readByteReaderU32BigEndian(reader);
77
+ if (!hasByteReaderBytes(reader, blockLength))
78
+ return null;
79
+ if (blockLength === 0)
80
+ continue; // absent encoding for this (side, level)
81
+ const byteOffset = reader.offset;
82
+ reader.offset += blockLength;
83
+ perSlotLevels[slot].push({
84
+ byteLength: blockLength,
85
+ byteOffset,
86
+ height: Math.max(1, height >> level),
87
+ width: Math.max(1, width >> level),
88
+ });
89
+ }
90
+ }
91
+ }
92
+ const containers = [];
93
+ for (let slot = 0; slot < slotCount; slot += 1) {
94
+ const levels = perSlotLevels[slot];
95
+ if (levels.length === 0)
96
+ continue;
97
+ containers.push({
98
+ depth: 1,
99
+ faces,
100
+ format: slotFormats[slot],
101
+ height,
102
+ layers: 1,
103
+ levels,
104
+ // The populated mip count, NOT the header's declared `mipCount`. png2atf "empty mipmaps"
105
+ // files declare the full chain (e.g. 9 for 256x256) but store only the base level; the empty
106
+ // levels are length-0 and skipped, so `levels` holds `faces * populatedMips` entries. Reporting
107
+ // the declared count would leave mipLevels inconsistent with levels.length.
108
+ mipLevels: levels.length / faces,
109
+ supercompression: 'None',
110
+ width,
111
+ });
112
+ }
113
+ if (containers.length === 0)
114
+ return null;
115
+ return containers;
116
+ }
117
+ function hasAtfSignature(bytes) {
118
+ // 'ATF' — 0x41 0x54 0x46. Seven bytes is the shortest header that can carry the version marker at 6.
119
+ return bytes.byteLength >= 7 && bytes[0] === 0x41 && bytes[1] === 0x54 && bytes[2] === 0x46;
120
+ }
121
+ const atfCubeFlag = 0x80;
122
+ const atfFormatCodeMask = 0x7f;
123
+ const atfLegacyHeaderOffset = 6;
124
+ const atfNewHeaderOffset = 12;
125
+ const atfNewVersionMarker = 0xff;
126
+ // 2^13 = 8192 is beyond any Stage3D texture; a larger shift signals a corrupt log2 dimension byte.
127
+ const atfMaxLog2Dimension = 13;
128
+ // Version 3 introduced the fourth (ETC2) GPU-format slot after the DXT/ETC1/PVRTC trio.
129
+ const atfEtc2Version = 3;
130
+ const atfBaseSlotCount = 3;
131
+ // The supported ATF format codes. Opaque codes carry a DXT1 (`bc1`) slot; alpha codes carry DXT5
132
+ // (`bc3`). The raw-BGRA codes 0/1 and the JPEG-XR/LZMA-wrapped variants are not supported.
133
+ const atfOpaqueFormatCodes = new Set([2, 3, 12]);
134
+ const atfAlphaFormatCodes = new Set([4, 5, 13]);
135
+ // GPU-format slot order (index = slot): DXT, ETC1, PVRTC 4bpp, ETC2. Sliced to `slotCount` so a
136
+ // version-0/1/2 file exposes only the first three.
137
+ const atfOpaqueSlotFormats = ['bc1', 'etc1', 'pvrtc4bppRgb', 'etc2Rgb'];
138
+ const atfAlphaSlotFormats = ['bc3', 'etc1', 'pvrtc4bppRgba', 'etc2Rgba'];
139
+ //# sourceMappingURL=parseAtf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseAtf.js","sourceRoot":"","sources":["../src/parseAtf.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { TextureContainer } from '@flighthq/types';
2
+ export declare function parseBasis(bytes: Readonly<Uint8Array>): TextureContainer | null;
3
+ //# sourceMappingURL=parseBasis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseBasis.d.ts","sourceRoot":"","sources":["../src/parseBasis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAwBxD,wBAAgB,UAAU,CAAC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,gBAAgB,GAAG,IAAI,CAqD/E"}
@@ -0,0 +1,82 @@
1
+ import { createByteReader, hasByteReaderBytes, readByteReaderU16, readByteReaderU32, readByteReaderU8, } from './byteReader';
2
+ // Parses a Basis Universal `.basis` container into a `TextureContainer`, or returns `null` if the bytes
3
+ // are not a `.basis` file, are truncated, or carry an unknown texture format.
4
+ //
5
+ // Reads the `basis_file_header` (`m_total_slices`, `m_total_images`, `m_tex_format` — ETC1S or UASTC —
6
+ // and `m_slice_desc_file_ofs`) and each `basis_slice_desc` (`m_level_index`, `m_orig_width/height`,
7
+ // `m_file_ofs`, `m_file_size`). Every slice becomes one `TextureContainerLevel` in slice-table order;
8
+ // `mipLevels` is the max `level_index` + 1 and `layers` is `m_total_images`. The payload is left
9
+ // compressed — transcoding ETC1S/UASTC to a GPU format is the caller's / `flight-rs`'s job.
10
+ //
11
+ // The ETC1S codebook/selector/table sections and per-slice CRCs are not read (they are inputs to the
12
+ // transcoder, not to locating a slice). Basis cube/video texture types are not distinguished — every
13
+ // image is reported as an array layer (`faces` = 1).
14
+ export function parseBasis(bytes) {
15
+ if (!hasBasisSignature(bytes))
16
+ return null;
17
+ if (bytes.byteLength < basisHeaderMinSize)
18
+ return null;
19
+ const header = createByteReader(bytes, basisTotalSlicesOffset);
20
+ const totalSlices = readByteReaderU16(header); // m_total_slices (offset 12)
21
+ const totalImages = readByteReaderU16(header); // m_total_images (offset 14)
22
+ const format = basisTexFormat[bytes[basisTexFormatOffset]]; // m_tex_format (offset 16)
23
+ if (format === undefined)
24
+ return null;
25
+ if (totalSlices === 0)
26
+ return null;
27
+ const sliceDescReader = createByteReader(bytes, basisSliceDescOffsetField);
28
+ const sliceDescOffset = readByteReaderU32(sliceDescReader);
29
+ const table = createByteReader(bytes, sliceDescOffset);
30
+ if (!hasByteReaderBytes(table, totalSlices * basisSliceDescSize))
31
+ return null;
32
+ const levels = [];
33
+ let baseWidth = 0;
34
+ let baseHeight = 0;
35
+ let maxLevel = 0;
36
+ for (let slice = 0; slice < totalSlices; slice += 1) {
37
+ const imageIndex = readByteReaderU16(table);
38
+ const levelIndex = readByteReaderU8(table);
39
+ readByteReaderU8(table); // m_flags
40
+ const width = readByteReaderU16(table);
41
+ const height = readByteReaderU16(table);
42
+ readByteReaderU16(table); // m_num_blocks_x
43
+ readByteReaderU16(table); // m_num_blocks_y
44
+ const byteOffset = readByteReaderU32(table);
45
+ const byteLength = readByteReaderU32(table);
46
+ readByteReaderU16(table); // m_slice_data_crc16
47
+ if (byteOffset + byteLength > bytes.byteLength)
48
+ return null;
49
+ if (imageIndex === 0 && levelIndex === 0) {
50
+ baseWidth = width;
51
+ baseHeight = height;
52
+ }
53
+ if (levelIndex + 1 > maxLevel)
54
+ maxLevel = levelIndex + 1;
55
+ levels.push({ byteLength, byteOffset, height, width });
56
+ }
57
+ return {
58
+ depth: 1,
59
+ faces: 1,
60
+ format,
61
+ height: baseHeight || (levels[0]?.height ?? 0),
62
+ layers: Math.max(1, totalImages),
63
+ levels,
64
+ mipLevels: Math.max(1, maxLevel),
65
+ supercompression: 'None',
66
+ width: baseWidth || (levels[0]?.width ?? 0),
67
+ };
68
+ }
69
+ function hasBasisSignature(bytes) {
70
+ // m_sig = 0x4273, stored little-endian: byte 0 = 0x73 ('s'), byte 1 = 0x42 ('B').
71
+ return bytes.byteLength >= 2 && bytes[0] === 0x73 && bytes[1] === 0x42;
72
+ }
73
+ const basisTotalSlicesOffset = 12;
74
+ const basisTexFormatOffset = 16;
75
+ const basisSliceDescOffsetField = 61;
76
+ const basisHeaderMinSize = 65; // through m_slice_desc_file_ofs (offset 61, 4 bytes)
77
+ const basisSliceDescSize = 22;
78
+ const basisTexFormat = {
79
+ 0: 'etc1s',
80
+ 1: 'uastc',
81
+ };
82
+ //# sourceMappingURL=parseBasis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseBasis.js","sourceRoot":"","sources":["../src/parseBasis.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { TextureContainer } from '@flighthq/types';
2
+ export declare function parseDds(bytes: Readonly<Uint8Array>): TextureContainer | null;
3
+ //# sourceMappingURL=parseDds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseDds.d.ts","sourceRoot":"","sources":["../src/parseDds.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAiBxD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,gBAAgB,GAAG,IAAI,CAsE7E"}
@@ -0,0 +1,151 @@
1
+ import { createByteReader, hasByteReaderBytes, readByteReaderU32, skipByteReader } from './byteReader';
2
+ import { computeTextureContainerLevels } from './textureLevelLayout';
3
+ // Parses a DDS container (DirectDraw Surface) into a `TextureContainer`, or returns `null` if the bytes
4
+ // are not DDS, are truncated, or carry a pixel format this package does not map (e.g. a legacy 16/24-bit
5
+ // layout, a YUV/luminance format, or a volume texture).
6
+ //
7
+ // Reads the `DDS_HEADER` (`dwHeight`/`dwWidth`/`dwMipMapCount`, the `DDS_PIXELFORMAT` FourCC, and
8
+ // `dwCaps2` for cubemaps) and, when the FourCC is `DX10`, the `DDS_HEADER_DXT10` extension
9
+ // (`dxgiFormat`, `miscFlag` for cube, `arraySize`). The format comes from the DXGI code, the FourCC
10
+ // (DXT1-5 / ATI1/2 / BC4-5 / DX9 float codes), or the RGBA channel masks for uncompressed data. DDS
11
+ // carries no level index, so every mip's byte range is computed from the block size (see
12
+ // `computeTextureContainerLevels`): sub-images are nested layer → face → mip, matching D3D subresource
13
+ // order (a cubemap's 6 faces each hold a full mip chain).
14
+ export function parseDds(bytes) {
15
+ if (!hasDdsMagic(bytes))
16
+ return null;
17
+ if (bytes.byteLength < ddsDataOffset)
18
+ return null;
19
+ const reader = createByteReader(bytes, 4);
20
+ skipByteReader(reader, 4); // dwSize
21
+ skipByteReader(reader, 4); // dwFlags
22
+ const dwHeight = readByteReaderU32(reader);
23
+ const dwWidth = readByteReaderU32(reader);
24
+ skipByteReader(reader, 4); // dwPitchOrLinearSize
25
+ const dwDepth = readByteReaderU32(reader);
26
+ const dwMipMapCount = readByteReaderU32(reader);
27
+ reader.offset = 80; // DDS_PIXELFORMAT.dwFlags
28
+ const pfFlags = readByteReaderU32(reader);
29
+ const fourCC = readByteReaderU32(reader);
30
+ const rgbBitCount = readByteReaderU32(reader);
31
+ const rMask = readByteReaderU32(reader);
32
+ const gMask = readByteReaderU32(reader);
33
+ const bMask = readByteReaderU32(reader);
34
+ const aMask = readByteReaderU32(reader);
35
+ reader.offset = 112; // dwCaps2
36
+ const caps2 = readByteReaderU32(reader);
37
+ if ((caps2 & ddsCaps2Volume) !== 0 || dwDepth > 1)
38
+ return null; // volume textures not modeled yet
39
+ let format;
40
+ let cube = (caps2 & ddsCaps2Cubemap) !== 0;
41
+ let layers = 1;
42
+ let dataOffset = ddsDataOffset;
43
+ if ((pfFlags & ddsPfFourCC) !== 0 && fourCC === ddsFourCcDx10) {
44
+ if (!hasByteReaderBytes(createByteReader(bytes, ddsDataOffset), 20))
45
+ return null;
46
+ const dx10 = createByteReader(bytes, ddsDataOffset);
47
+ const dxgiFormat = readByteReaderU32(dx10);
48
+ skipByteReader(dx10, 4); // resourceDimension
49
+ const miscFlag = readByteReaderU32(dx10);
50
+ const arraySize = readByteReaderU32(dx10);
51
+ format = ddsDxgiFormat[dxgiFormat] ?? null;
52
+ cube = cube || (miscFlag & ddsDx10MiscCube) !== 0;
53
+ layers = Math.max(1, arraySize);
54
+ dataOffset = ddsDataOffset + 20;
55
+ }
56
+ else if ((pfFlags & ddsPfFourCC) !== 0) {
57
+ format = ddsFourCcFormat[fourCC] ?? null;
58
+ }
59
+ else if ((pfFlags & ddsPfRgb) !== 0) {
60
+ format = mapDdsUncompressed(rgbBitCount, rMask, gMask, bMask, aMask);
61
+ }
62
+ else {
63
+ format = null;
64
+ }
65
+ if (format === null)
66
+ return null;
67
+ const width = Math.max(1, dwWidth);
68
+ const height = Math.max(1, dwHeight);
69
+ const faces = cube ? 6 : 1;
70
+ const mipLevels = Math.max(1, dwMipMapCount);
71
+ const layout = computeTextureContainerLevels(format, width, height, mipLevels, layers, faces, dataOffset);
72
+ if (layout === null || layout.endOffset > bytes.byteLength)
73
+ return null;
74
+ return {
75
+ depth: 1,
76
+ faces,
77
+ format,
78
+ height,
79
+ layers,
80
+ levels: layout.levels,
81
+ mipLevels,
82
+ supercompression: 'None',
83
+ width,
84
+ };
85
+ }
86
+ function hasDdsMagic(bytes) {
87
+ return bytes.byteLength >= 4 && bytes[0] === 0x44 && bytes[1] === 0x44 && bytes[2] === 0x53 && bytes[3] === 0x20;
88
+ }
89
+ function mapDdsUncompressed(rgbBitCount, rMask, gMask, bMask, aMask) {
90
+ if (rgbBitCount !== 32)
91
+ return null;
92
+ if (rMask === 0x00ff0000 && gMask === 0x0000ff00 && bMask === 0x000000ff && aMask === 0xff000000) {
93
+ return 'bgra8unorm';
94
+ }
95
+ if (rMask === 0x000000ff && gMask === 0x0000ff00 && bMask === 0x00ff0000 && aMask === 0xff000000) {
96
+ return 'rgba8unorm';
97
+ }
98
+ return null;
99
+ }
100
+ // 4 (magic) + 124 (DDS_HEADER). A DX10 file adds a 20-byte DDS_HEADER_DXT10 after this.
101
+ const ddsDataOffset = 128;
102
+ const ddsCaps2Cubemap = 0x200;
103
+ const ddsCaps2Volume = 0x20_0000;
104
+ const ddsDx10MiscCube = 0x4;
105
+ const ddsFourCcDx10 = 0x3031_5844; // 'DX10'
106
+ const ddsPfFourCC = 0x4;
107
+ const ddsPfRgb = 0x40;
108
+ // DXGI_FORMAT → `TextureContainerFormat`. The BC set (with sRGB twins), 8-bit RGBA/BGRA, and the two
109
+ // standard float formats. `_TYPELESS` and unmapped codes → `null`.
110
+ const ddsDxgiFormat = {
111
+ 2: 'rgba32f',
112
+ 10: 'rgba16f',
113
+ 28: 'rgba8unorm',
114
+ 29: 'rgba8Srgb',
115
+ 49: 'rg8unorm',
116
+ 61: 'r8unorm',
117
+ 71: 'bc1',
118
+ 72: 'bc1Srgb',
119
+ 74: 'bc2',
120
+ 75: 'bc2Srgb',
121
+ 77: 'bc3',
122
+ 78: 'bc3Srgb',
123
+ 80: 'bc4',
124
+ 81: 'bc4Snorm',
125
+ 83: 'bc5',
126
+ 84: 'bc5Snorm',
127
+ 87: 'bgra8unorm',
128
+ 91: 'bgra8Srgb',
129
+ 95: 'bc6hUfloat',
130
+ 96: 'bc6hSfloat',
131
+ 98: 'bc7',
132
+ 99: 'bc7Srgb',
133
+ };
134
+ // DDS_PIXELFORMAT.dwFourCC → format. Includes the DXT1-5 / ATI1-2 / BC4-5 block codes and the DX9
135
+ // D3DFMT float codes (113 = A16B16G16R16F, 116 = A32B32G32R32F) some tools store in the FourCC slot.
136
+ const ddsFourCcFormat = {
137
+ 113: 'rgba16f',
138
+ 116: 'rgba32f',
139
+ 0x3154_5844: 'bc1', // DXT1
140
+ 0x3254_5844: 'bc2', // DXT2
141
+ 0x3354_5844: 'bc2', // DXT3
142
+ 0x3454_5844: 'bc3', // DXT4
143
+ 0x3554_5844: 'bc3', // DXT5
144
+ 0x3149_5441: 'bc4', // ATI1
145
+ 0x5534_4342: 'bc4', // BC4U
146
+ 0x5334_4342: 'bc4Snorm', // BC4S
147
+ 0x3249_5441: 'bc5', // ATI2
148
+ 0x5535_4342: 'bc5', // BC5U
149
+ 0x5335_4342: 'bc5Snorm', // BC5S
150
+ };
151
+ //# sourceMappingURL=parseDds.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseDds.js","sourceRoot":"","sources":["../src/parseDds.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { TextureContainer } from '@flighthq/types';
2
+ export declare function parseKtx2(bytes: Readonly<Uint8Array>): TextureContainer | null;
3
+ //# sourceMappingURL=parseKtx2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseKtx2.d.ts","sourceRoot":"","sources":["../src/parseKtx2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAwBxD,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,gBAAgB,GAAG,IAAI,CAwE9E"}