* Build a minimal KTX2 binary file in memory.
({
vkFormat = VK_FORMAT_BC1_RGB_UNORM_BLOCK,
width = 8,
height = 8,
levelCount = 1,
supercompressionScheme = 0,
blockBytes = 8,
} = {})
| 29 | * Build a minimal KTX2 binary file in memory. |
| 30 | */ |
| 31 | function buildKTX2Buffer({ |
| 32 | vkFormat = VK_FORMAT_BC1_RGB_UNORM_BLOCK, |
| 33 | width = 8, |
| 34 | height = 8, |
| 35 | levelCount = 1, |
| 36 | supercompressionScheme = 0, |
| 37 | blockBytes = 8, |
| 38 | } = {}) { |
| 39 | // Layout: |
| 40 | // [0..11] identifier (12 bytes) |
| 41 | // [12..79] header (68 bytes) — we use a 68-byte header area |
| 42 | // [80..] level index (levelCount × 24 bytes) |
| 43 | // then pixel data |
| 44 | |
| 45 | const levelIndexOffset = 80; |
| 46 | const levelIndexSize = levelCount * 24; |
| 47 | const pixelDataStart = levelIndexOffset + levelIndexSize; |
| 48 | |
| 49 | // calculate level sizes and total pixel data |
| 50 | const levelSizes = []; |
| 51 | let lw = width; |
| 52 | let lh = height; |
| 53 | for (let i = 0; i < levelCount; i++) { |
| 54 | const size = |
| 55 | Math.max(1, (lw + 3) >> 2) * Math.max(1, (lh + 3) >> 2) * blockBytes; |
| 56 | levelSizes.push(size); |
| 57 | lw = Math.max(1, lw >> 1); |
| 58 | lh = Math.max(1, lh >> 1); |
| 59 | } |
| 60 | |
| 61 | // In KTX2, level 0 in the index is the largest mip |
| 62 | // Levels are stored in the file smallest-first, but byte offsets handle this |
| 63 | let totalPixelSize = 0; |
| 64 | for (const s of levelSizes) { |
| 65 | totalPixelSize += s; |
| 66 | } |
| 67 | |
| 68 | const totalSize = pixelDataStart + totalPixelSize; |
| 69 | const buffer = new ArrayBuffer(totalSize); |
| 70 | |
| 71 | // write identifier |
| 72 | const idView = new Uint8Array(buffer, 0, 12); |
| 73 | for (let i = 0; i < 12; i++) { |
| 74 | idView[i] = KTX2_IDENTIFIER[i]; |
| 75 | } |
| 76 | |
| 77 | // write header at offset 12 (68 bytes) |
| 78 | const header = new DataView(buffer, 12, 68); |
| 79 | header.setUint32(0, vkFormat, true); // vkFormat |
| 80 | // typeSize at +4 |
| 81 | header.setUint32(4, 1, true); |
| 82 | header.setUint32(8, width, true); // pixelWidth |
| 83 | header.setUint32(12, height, true); // pixelHeight |
| 84 | header.setUint32(16, 0, true); // pixelDepth |
| 85 | header.setUint32(20, 0, true); // layerCount |
| 86 | header.setUint32(24, 1, true); // faceCount |
| 87 | header.setUint32(28, levelCount, true); // levelCount |
| 88 | header.setUint32(32, supercompressionScheme, true); |
no test coverage detected