@woosh/meep-engine 3.14.0 → 3.14.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/README.md +33 -64
- package/package.json +1 -1
- package/src/avif/native/DECISIONS.md +544 -536
- package/src/avif/native/heif/parse_avif_file.d.ts.map +1 -1
- package/src/avif/native/heif/parse_avif_file.js +384 -383
- package/src/avif/native/heif/parse_image_grid.d.ts.map +1 -1
- package/src/avif/native/heif/parse_image_grid.js +49 -48
- package/src/basis/BasisBitReader.d.ts +77 -0
- package/src/basis/BasisBitReader.d.ts.map +1 -0
- package/src/basis/BasisBitReader.js +231 -0
- package/src/basis/BasisHuffmanTable.d.ts +53 -0
- package/src/basis/BasisHuffmanTable.d.ts.map +1 -0
- package/src/basis/BasisHuffmanTable.js +263 -0
- package/src/basis/basis_read_huffman_table.d.ts +20 -0
- package/src/basis/basis_read_huffman_table.d.ts.map +1 -0
- package/src/basis/basis_read_huffman_table.js +187 -0
- package/src/basis/etc1s/Etc1sSelectorHistory.d.ts +50 -0
- package/src/basis/etc1s/Etc1sSelectorHistory.d.ts.map +1 -0
- package/src/basis/etc1s/Etc1sSelectorHistory.js +89 -0
- package/src/basis/etc1s/etc1s_block_colors.d.ts +14 -0
- package/src/basis/etc1s/etc1s_block_colors.d.ts.map +1 -0
- package/src/basis/etc1s/etc1s_block_colors.js +75 -0
- package/src/basis/etc1s/etc1s_decode_slice.d.ts +57 -0
- package/src/basis/etc1s/etc1s_decode_slice.d.ts.map +1 -0
- package/src/basis/etc1s/etc1s_decode_slice.js +258 -0
- package/src/basis/etc1s/etc1s_read_endpoint_codebook.d.ts +48 -0
- package/src/basis/etc1s/etc1s_read_endpoint_codebook.d.ts.map +1 -0
- package/src/basis/etc1s/etc1s_read_endpoint_codebook.js +111 -0
- package/src/basis/etc1s/etc1s_read_selector_codebook.d.ts +42 -0
- package/src/basis/etc1s/etc1s_read_selector_codebook.d.ts.map +1 -0
- package/src/basis/etc1s/etc1s_read_selector_codebook.js +127 -0
- package/src/basis/etc1s/etc1s_read_slice_tables.d.ts +54 -0
- package/src/basis/etc1s/etc1s_read_slice_tables.d.ts.map +1 -0
- package/src/basis/etc1s/etc1s_read_slice_tables.js +47 -0
- package/src/basis/transcode/build_range_plan.js +54 -0
- package/src/basis/transcode/etc1s_to_bc1.d.ts +24 -0
- package/src/basis/transcode/etc1s_to_bc1.d.ts.map +1 -0
- package/src/basis/transcode/etc1s_to_bc1.js +205 -0
- package/src/basis/transcode/etc1s_to_bc7.d.ts +30 -0
- package/src/basis/transcode/etc1s_to_bc7.d.ts.map +1 -0
- package/src/basis/transcode/etc1s_to_bc7.js +496 -0
- package/src/basis/transcode/fit_endpoints.d.ts +59 -0
- package/src/basis/transcode/fit_endpoints.d.ts.map +1 -0
- package/src/basis/transcode/fit_endpoints.js +226 -0
- package/src/{avif/native/isobmff → core/binary}/ByteCursor.d.ts +19 -6
- package/src/core/binary/ByteCursor.d.ts.map +1 -0
- package/src/{avif/native/isobmff → core/binary}/ByteCursor.js +41 -14
- package/src/engine/EngineHarness.js +1 -1
- package/src/engine/asset/codec/Codec.d.ts.map +1 -0
- package/src/engine/asset/codec/CodecWithFallback.d.ts.map +1 -0
- package/src/engine/asset/{loaders/image/codec → codec}/CodecWithFallback.js +2 -2
- package/src/engine/asset/loaders/image/IMAGE_CODEC_REVIEW_2026_08_28.md +4 -4
- package/src/engine/asset/loaders/image/ImageRGBADataLoader.d.ts +1 -1
- package/src/engine/asset/loaders/image/ImageRGBADataLoader.d.ts.map +1 -1
- package/src/engine/asset/loaders/image/ImageRGBADataLoader.js +1 -1
- package/src/engine/asset/loaders/image/codec/NativeImageDecoder.d.ts +1 -1
- package/src/engine/asset/loaders/image/codec/NativeImageDecoder.d.ts.map +1 -1
- package/src/engine/asset/loaders/image/codec/NativeImageDecoder.js +1 -1
- package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.d.ts +1 -1
- package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.d.ts.map +1 -1
- package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.js +1 -1
- package/src/engine/graphics/texture/atlas/TextureAtlas.d.ts.map +1 -1
- package/src/engine/graphics/texture/atlas/TextureAtlas.js +13 -0
- package/src/engine/physics/broadphase/generate_pairs.d.ts.map +1 -1
- package/src/engine/physics/broadphase/generate_pairs.js +7 -1
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/ktx2/KTX2_IDENTIFIER.d.ts +14 -0
- package/src/ktx2/KTX2_IDENTIFIER.d.ts.map +1 -0
- package/src/ktx2/KTX2_IDENTIFIER.js +15 -0
- package/src/ktx2/KhrDfModel.d.ts +35 -0
- package/src/ktx2/KhrDfModel.d.ts.map +1 -0
- package/src/ktx2/KhrDfModel.js +49 -0
- package/src/ktx2/SupercompressionScheme.d.ts +16 -0
- package/src/ktx2/SupercompressionScheme.d.ts.map +1 -0
- package/src/ktx2/SupercompressionScheme.js +23 -0
- package/src/ktx2/ktx2_read.d.ts +71 -0
- package/src/ktx2/ktx2_read.d.ts.map +1 -0
- package/src/ktx2/ktx2_read.js +581 -0
- package/src/ktx2/ktx2_read_basis_lz_global_data.d.ts +27 -0
- package/src/ktx2/ktx2_read_basis_lz_global_data.d.ts.map +1 -0
- package/src/ktx2/ktx2_read_basis_lz_global_data.js +189 -0
- package/src/ktx2/vk_format_to_texture_format.d.ts +55 -0
- package/src/ktx2/vk_format_to_texture_format.d.ts.map +1 -0
- package/src/ktx2/vk_format_to_texture_format.js +290 -0
- package/src/shade/descriptor/GPUTextureUsage.d.ts +23 -0
- package/src/shade/descriptor/GPUTextureUsage.d.ts.map +1 -0
- package/src/shade/descriptor/GPUTextureUsage.js +24 -0
- package/src/shade/descriptor/WebGPUExtensionType.d.ts +3 -0
- package/src/shade/descriptor/WebGPUExtensionType.js +26 -0
- package/src/shade/descriptor/texture/TextureDescriptor.d.ts +2 -6
- package/src/shade/descriptor/texture/TextureDescriptor.d.ts.map +1 -1
- package/src/shade/descriptor/texture/TextureDescriptor.js +24 -40
- package/src/shade/descriptor/texture/format/TextureFormat.d.ts +125 -0
- package/src/shade/descriptor/texture/format/TextureFormat.d.ts.map +1 -0
- package/src/shade/descriptor/texture/format/TextureFormat.js +146 -0
- package/src/shade/descriptor/texture/format/gpu_texture_format_info.d.ts +60 -0
- package/src/shade/descriptor/texture/format/gpu_texture_format_info.d.ts.map +1 -1
- package/src/shade/descriptor/texture/format/gpu_texture_format_info.js +102 -0
- package/src/shade/device/graph/TextureResourceDescriptor.d.ts.map +1 -1
- package/src/shade/device/graph/TextureResourceDescriptor.js +160 -155
- package/src/shade/device/mock/SoftwareGPUQueue.d.ts +11 -4
- package/src/shade/device/mock/SoftwareGPUQueue.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPUQueue.js +31 -37
- package/src/shade/device/mock/SoftwareGPUTexture.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPUTexture.js +8 -4
- package/src/shade/device/timing/profile/frame_graph_extract_topology.d.ts.map +1 -1
- package/src/shade/device/timing/profile/frame_graph_extract_topology.js +164 -174
- package/src/shade/playground/ground_seam/README.md +235 -0
- package/src/shade/playground/ground_seam/capture_scene_color.d.ts +45 -0
- package/src/shade/playground/ground_seam/capture_scene_color.d.ts.map +1 -0
- package/src/shade/playground/ground_seam/capture_scene_color.js +242 -0
- package/src/shade/playground/ground_seam/depth_step_across_seam.d.ts +11 -0
- package/src/shade/playground/ground_seam/depth_step_across_seam.d.ts.map +1 -0
- package/src/shade/playground/ground_seam/depth_step_across_seam.js +185 -0
- package/src/shade/playground/ground_seam/index.html +195 -0
- package/src/shade/playground/ground_seam/main.d.ts +2 -0
- package/src/shade/playground/ground_seam/main.d.ts.map +1 -0
- package/src/shade/playground/ground_seam/main.js +879 -0
- package/src/shade/playground/ground_seam/make_grid_texture.d.ts +29 -0
- package/src/shade/playground/ground_seam/make_grid_texture.d.ts.map +1 -0
- package/src/shade/playground/ground_seam/make_grid_texture.js +105 -0
- package/src/shade/playground/ground_seam/make_ground.d.ts +70 -0
- package/src/shade/playground/ground_seam/make_ground.d.ts.map +1 -0
- package/src/shade/playground/ground_seam/make_ground.js +161 -0
- package/src/shade/playground/ground_seam/measure_flicker.d.ts +71 -0
- package/src/shade/playground/ground_seam/measure_flicker.d.ts.map +1 -0
- package/src/shade/playground/ground_seam/measure_flicker.js +531 -0
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +2519 -2511
- package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
- package/src/shade/renderer/hiz/HierarchicalZBuffer.js +275 -274
- package/src/shade/renderer/light/GPULightCollection.d.ts.map +1 -1
- package/src/shade/renderer/light/GPULightCollection.js +323 -314
- package/src/shade/renderer/lightmap/GPULightMap.js +336 -336
- package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
- package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +12 -2
- package/src/shade/renderer/material/standard/fragment_gbuffer.d.ts.map +1 -1
- package/src/shade/renderer/material/standard/fragment_gbuffer.js +3 -1
- package/src/shade/renderer/material/standard/fragment_gbuffer_vt.js +169 -169
- package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.d.ts.map +1 -1
- package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.js +3 -1
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
- package/src/shade/renderer/rasterize/native/oit/chunk_forward_shade_standard_fragment_brick4.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/oit/chunk_forward_shade_standard_fragment_brick4.js +3 -1
- package/src/shade/renderer/rasterize/native/oit/chunk_forward_shade_standard_fragment_ibl.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/oit/chunk_forward_shade_standard_fragment_ibl.js +3 -1
- package/src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_tangent_normal.d.ts +28 -0
- package/src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_tangent_normal.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_tangent_normal.js +39 -0
- package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_full.d.ts +45 -0
- package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_full.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_full.js +94 -61
- package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_solve.d.ts +24 -0
- package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_solve.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_solve.js +43 -0
- package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +1462 -0
- package/src/shade/renderer/texture/TextureManager.d.ts.map +1 -1
- package/src/shade/renderer/texture/TextureManager.js +20 -8
- package/src/shade/renderer/texture/TextureRole.d.ts +19 -0
- package/src/shade/renderer/texture/TextureRole.d.ts.map +1 -0
- package/src/shade/renderer/texture/TextureRole.js +26 -0
- package/src/shade/renderer/texture/TextureVariantSet.d.ts +71 -0
- package/src/shade/renderer/texture/TextureVariantSet.d.ts.map +1 -0
- package/src/shade/renderer/texture/TextureVariantSet.js +105 -0
- package/src/shade/renderer/texture/download_texture_data.d.ts.map +1 -1
- package/src/shade/renderer/texture/download_texture_data.js +22 -0
- package/src/shade/renderer/texture/format/gpu_texture_compression_support.d.ts +15 -0
- package/src/shade/renderer/texture/format/gpu_texture_compression_support.d.ts.map +1 -0
- package/src/shade/renderer/texture/format/gpu_texture_compression_support.js +50 -0
- package/src/shade/renderer/texture/format/gpu_texture_format_can_generate_mipmaps.d.ts +27 -0
- package/src/shade/renderer/texture/format/gpu_texture_format_can_generate_mipmaps.d.ts.map +1 -0
- package/src/shade/renderer/texture/format/gpu_texture_format_can_generate_mipmaps.js +65 -0
- package/src/shade/renderer/texture/format/infer_format_from_parameters.d.ts +11 -0
- package/src/shade/renderer/texture/format/infer_format_from_parameters.d.ts.map +1 -0
- package/src/shade/renderer/texture/format/infer_format_from_parameters.js +88 -0
- package/src/shade/renderer/texture/format/texture_format_from_shade_image.d.ts +24 -0
- package/src/shade/renderer/texture/format/texture_format_from_shade_image.d.ts.map +1 -0
- package/src/shade/renderer/texture/format/texture_format_from_shade_image.js +71 -0
- package/src/shade/renderer/texture/format/texture_format_preference.d.ts +22 -0
- package/src/shade/renderer/texture/format/texture_format_preference.d.ts.map +1 -0
- package/src/shade/renderer/texture/format/texture_format_preference.js +89 -0
- package/src/shade/renderer/texture/format/texture_variant_select.d.ts +24 -0
- package/src/shade/renderer/texture/format/texture_variant_select.d.ts.map +1 -0
- package/src/shade/renderer/texture/format/texture_variant_select.js +38 -0
- package/src/shade/renderer/texture/shade_texture_might_have_alpha.d.ts +9 -1
- package/src/shade/renderer/texture/shade_texture_might_have_alpha.d.ts.map +1 -1
- package/src/shade/renderer/texture/shade_texture_might_have_alpha.js +73 -8
- package/src/shade/renderer/texture/source/AlphaMode.d.ts +27 -0
- package/src/shade/renderer/texture/source/AlphaMode.d.ts.map +1 -0
- package/src/shade/renderer/texture/source/AlphaMode.js +52 -0
- package/src/shade/renderer/texture/source/ShadeImage.d.ts +33 -0
- package/src/shade/renderer/texture/source/ShadeImage.d.ts.map +1 -1
- package/src/shade/renderer/texture/source/ShadeImage.js +74 -0
- package/src/shade/renderer/texture/source/ShadeTexelData.d.ts +78 -0
- package/src/shade/renderer/texture/source/ShadeTexelData.d.ts.map +1 -0
- package/src/shade/renderer/texture/source/ShadeTexelData.js +158 -0
- package/src/shade/renderer/texture/texture_descriptor_from_texture_shade.d.ts +0 -10
- package/src/shade/renderer/texture/texture_descriptor_from_texture_shade.d.ts.map +1 -1
- package/src/shade/renderer/texture/texture_descriptor_from_texture_shade.js +73 -175
- package/src/shade/renderer/texture/texture_write_level.d.ts +32 -0
- package/src/shade/renderer/texture/texture_write_level.d.ts.map +1 -0
- package/src/shade/renderer/texture/texture_write_level.js +77 -0
- package/src/shade/renderer/texture/texture_write_to_gpu.d.ts +8 -1
- package/src/shade/renderer/texture/texture_write_to_gpu.d.ts.map +1 -1
- package/src/shade/renderer/texture/texture_write_to_gpu.js +62 -37
- package/src/shade/renderer/texture/virtual/source/VTSourceImage.d.ts +8 -0
- package/src/shade/renderer/texture/virtual/source/VTSourceImage.d.ts.map +1 -1
- package/src/shade/renderer/texture/virtual/source/VTSourceImage.js +8 -0
- package/src/shade/util/texture_mip_extent.d.ts +49 -0
- package/src/shade/util/texture_mip_extent.d.ts.map +1 -0
- package/src/shade/util/texture_mip_extent.js +87 -0
- package/src/avif/native/isobmff/ByteCursor.d.ts.map +0 -1
- package/src/engine/asset/loaders/image/codec/Codec.d.ts.map +0 -1
- package/src/engine/asset/loaders/image/codec/CodecWithFallback.d.ts.map +0 -1
- package/src/shade/util/compute_max_mip_count.d.ts +0 -8
- package/src/shade/util/compute_max_mip_count.d.ts.map +0 -1
- package/src/shade/util/compute_max_mip_count.js +0 -27
- /package/src/engine/asset/{loaders/image/codec → codec}/Codec.d.ts +0 -0
- /package/src/engine/asset/{loaders/image/codec → codec}/Codec.js +0 -0
- /package/src/engine/asset/{loaders/image/codec → codec}/CodecWithFallback.d.ts +0 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { BasisBitReader } from "../BasisBitReader.js";
|
|
2
|
+
import { basis_read_huffman_table } from "../basis_read_huffman_table.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Texels in an ETC1S block, and so selectors in a codebook entry.
|
|
6
|
+
*
|
|
7
|
+
* @readonly
|
|
8
|
+
* @type {number}
|
|
9
|
+
*/
|
|
10
|
+
const SELECTORS_PER_ENTRY = 16;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Bytes one entry occupies in the raw form: four selectors of two bits in each.
|
|
14
|
+
*
|
|
15
|
+
* @readonly
|
|
16
|
+
* @type {number}
|
|
17
|
+
*/
|
|
18
|
+
const BYTES_PER_ENTRY = 4;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* One decoded selector codebook.
|
|
22
|
+
*
|
|
23
|
+
* @typedef {object} Etc1sSelectorCodebook
|
|
24
|
+
* @property {Uint8Array} selectors sixteen two-bit selectors per entry, one byte each, in
|
|
25
|
+
* raster order within the block
|
|
26
|
+
* @property {number} count
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Read the ETC1S selector codebook.
|
|
31
|
+
*
|
|
32
|
+
* Each entry is a block's sixteen two-bit selectors — which of the four colours the block's endpoint
|
|
33
|
+
* defines each texel takes. The entries are stored as four bytes, one per row of the block, and are
|
|
34
|
+
* either raw or coded as a byte-wise exclusive-or against the previous entry.
|
|
35
|
+
*
|
|
36
|
+
* **Selectors are stored one per byte rather than packed.** Four times the memory of the packed form
|
|
37
|
+
* and worth it: every block transcode reads all sixteen, and unpacking them here once is unpacking
|
|
38
|
+
* them once per codebook entry rather than once per block that references it.
|
|
39
|
+
*
|
|
40
|
+
* @param {Uint8Array} data the selectors section of the global data
|
|
41
|
+
* @param {number} count how many entries the section holds, from the global data header
|
|
42
|
+
* @returns {Etc1sSelectorCodebook}
|
|
43
|
+
* @throws {Error} for the global and hybrid codebook forms, which the format defines and no encoder
|
|
44
|
+
* produces
|
|
45
|
+
* @see the specification, section 8.0
|
|
46
|
+
*
|
|
47
|
+
* @author Alex Goldring
|
|
48
|
+
* @copyright Company Named Limited (c) 2026
|
|
49
|
+
*/
|
|
50
|
+
export function etc1s_read_selector_codebook(data, count) {
|
|
51
|
+
const reader = new BasisBitReader().init(data);
|
|
52
|
+
|
|
53
|
+
const global_codebook = reader.bits(1) !== 0;
|
|
54
|
+
const hybrid_codebook = reader.bits(1) !== 0;
|
|
55
|
+
const raw = reader.bits(1) !== 0;
|
|
56
|
+
|
|
57
|
+
/*
|
|
58
|
+
Both are reserved in the format and neither has ever been written: the specification says each
|
|
59
|
+
bit "should always be 0", because the encoder has no option that sets it. Refusing names the
|
|
60
|
+
feature rather than reading the codebook that follows as though the flag were clear, which would
|
|
61
|
+
produce a texture full of the wrong selectors.
|
|
62
|
+
*/
|
|
63
|
+
if (global_codebook) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
"Basis: the selector codebook declares a global codebook, which the format reserves and"
|
|
66
|
+
+ " no encoder emits. There is no global codebook here to resolve it against."
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (hybrid_codebook) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
"Basis: the selector codebook declares a hybrid global/local codebook, which the format"
|
|
73
|
+
+ " reserves and no encoder emits."
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const selectors = new Uint8Array(count * SELECTORS_PER_ENTRY);
|
|
78
|
+
|
|
79
|
+
if (raw) {
|
|
80
|
+
for (let i = 0; i < count; i++) {
|
|
81
|
+
for (let row = 0; row < BYTES_PER_ENTRY; row++) {
|
|
82
|
+
unpack_row(selectors, i, row, reader.bits(8));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return { selectors, count };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const delta_model = basis_read_huffman_table(reader);
|
|
90
|
+
|
|
91
|
+
const previous = new Uint8Array(BYTES_PER_ENTRY);
|
|
92
|
+
|
|
93
|
+
for (let i = 0; i < count; i++) {
|
|
94
|
+
for (let row = 0; row < BYTES_PER_ENTRY; row++) {
|
|
95
|
+
/*
|
|
96
|
+
The first entry is sent raw, and the rest as a delta against the entry before. The
|
|
97
|
+
exclusive-or is its own inverse, so one expression covers both: the first entry's
|
|
98
|
+
"previous" is zero, against which the delta is the value.
|
|
99
|
+
*/
|
|
100
|
+
const byte = i === 0
|
|
101
|
+
? reader.bits(8)
|
|
102
|
+
: delta_model.decode(reader) ^ previous[row];
|
|
103
|
+
|
|
104
|
+
previous[row] = byte;
|
|
105
|
+
|
|
106
|
+
unpack_row(selectors, i, row, byte);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return { selectors, count };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Spread one packed byte across the four selectors of a block row.
|
|
115
|
+
*
|
|
116
|
+
* @param {Uint8Array} selectors
|
|
117
|
+
* @param {number} entry
|
|
118
|
+
* @param {number} row
|
|
119
|
+
* @param {number} byte four two-bit selectors, the leftmost texel in the least significant pair
|
|
120
|
+
*/
|
|
121
|
+
function unpack_row(selectors, entry, row, byte) {
|
|
122
|
+
const base = entry * SELECTORS_PER_ENTRY + row * 4;
|
|
123
|
+
|
|
124
|
+
for (let column = 0; column < 4; column++) {
|
|
125
|
+
selectors[base + column] = (byte >> (column * 2)) & 3;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Huffman tables every slice in a file is decoded with, plus the size of the selector history.
|
|
3
|
+
*
|
|
4
|
+
* They are global rather than per-slice — one set covers every mip level, face and frame — which is
|
|
5
|
+
* what makes a mip chain cost little more than its base level.
|
|
6
|
+
*
|
|
7
|
+
* @typedef {object} Etc1sSliceTables
|
|
8
|
+
* @property {BasisHuffmanTable} endpoint_pred how each block in a 2x2 group takes its endpoint
|
|
9
|
+
* @property {BasisHuffmanTable} delta_endpoint an endpoint index, relative to the previous block's
|
|
10
|
+
* @property {BasisHuffmanTable} selector a selector index, a history reference, or a run
|
|
11
|
+
* @property {BasisHuffmanTable} selector_history_rle the length of such a run
|
|
12
|
+
* @property {number} selector_history_size entries in the move-to-front list
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Read the four slice-decoding Huffman tables and the selector history size.
|
|
16
|
+
*
|
|
17
|
+
* @param {Uint8Array} data the tables section of the global data
|
|
18
|
+
* @returns {Etc1sSliceTables}
|
|
19
|
+
* @throws {Error} for a section that runs out before the four tables do
|
|
20
|
+
* @see the specification, section 9.0
|
|
21
|
+
*
|
|
22
|
+
* @author Alex Goldring
|
|
23
|
+
* @copyright Company Named Limited (c) 2026
|
|
24
|
+
*/
|
|
25
|
+
export function etc1s_read_slice_tables(data: Uint8Array): Etc1sSliceTables;
|
|
26
|
+
/**
|
|
27
|
+
* The Huffman tables every slice in a file is decoded with, plus the size of the selector history.
|
|
28
|
+
*
|
|
29
|
+
* They are global rather than per-slice — one set covers every mip level, face and frame — which is
|
|
30
|
+
* what makes a mip chain cost little more than its base level.
|
|
31
|
+
*/
|
|
32
|
+
export type Etc1sSliceTables = {
|
|
33
|
+
/**
|
|
34
|
+
* how each block in a 2x2 group takes its endpoint
|
|
35
|
+
*/
|
|
36
|
+
endpoint_pred: BasisHuffmanTable;
|
|
37
|
+
/**
|
|
38
|
+
* an endpoint index, relative to the previous block's
|
|
39
|
+
*/
|
|
40
|
+
delta_endpoint: BasisHuffmanTable;
|
|
41
|
+
/**
|
|
42
|
+
* a selector index, a history reference, or a run
|
|
43
|
+
*/
|
|
44
|
+
selector: BasisHuffmanTable;
|
|
45
|
+
/**
|
|
46
|
+
* the length of such a run
|
|
47
|
+
*/
|
|
48
|
+
selector_history_rle: BasisHuffmanTable;
|
|
49
|
+
/**
|
|
50
|
+
* entries in the move-to-front list
|
|
51
|
+
*/
|
|
52
|
+
selector_history_size: number;
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=etc1s_read_slice_tables.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"etc1s_read_slice_tables.d.ts","sourceRoot":"","sources":["../../../../src/basis/etc1s/etc1s_read_slice_tables.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;GAYG;AAEH;;;;;;;;;;GAUG;AACH,8CARW,UAAU,GACR,gBAAgB,CAyB5B;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAhCa,MAAM"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { BasisBitReader } from "../BasisBitReader.js";
|
|
2
|
+
import { basis_read_huffman_table } from "../basis_read_huffman_table.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The Huffman tables every slice in a file is decoded with, plus the size of the selector history.
|
|
6
|
+
*
|
|
7
|
+
* They are global rather than per-slice — one set covers every mip level, face and frame — which is
|
|
8
|
+
* what makes a mip chain cost little more than its base level.
|
|
9
|
+
*
|
|
10
|
+
* @typedef {object} Etc1sSliceTables
|
|
11
|
+
* @property {BasisHuffmanTable} endpoint_pred how each block in a 2x2 group takes its endpoint
|
|
12
|
+
* @property {BasisHuffmanTable} delta_endpoint an endpoint index, relative to the previous block's
|
|
13
|
+
* @property {BasisHuffmanTable} selector a selector index, a history reference, or a run
|
|
14
|
+
* @property {BasisHuffmanTable} selector_history_rle the length of such a run
|
|
15
|
+
* @property {number} selector_history_size entries in the move-to-front list
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Read the four slice-decoding Huffman tables and the selector history size.
|
|
20
|
+
*
|
|
21
|
+
* @param {Uint8Array} data the tables section of the global data
|
|
22
|
+
* @returns {Etc1sSliceTables}
|
|
23
|
+
* @throws {Error} for a section that runs out before the four tables do
|
|
24
|
+
* @see the specification, section 9.0
|
|
25
|
+
*
|
|
26
|
+
* @author Alex Goldring
|
|
27
|
+
* @copyright Company Named Limited (c) 2026
|
|
28
|
+
*/
|
|
29
|
+
export function etc1s_read_slice_tables(data) {
|
|
30
|
+
const reader = new BasisBitReader().init(data);
|
|
31
|
+
|
|
32
|
+
const endpoint_pred = basis_read_huffman_table(reader);
|
|
33
|
+
const delta_endpoint = basis_read_huffman_table(reader);
|
|
34
|
+
const selector = basis_read_huffman_table(reader);
|
|
35
|
+
const selector_history_rle = basis_read_huffman_table(reader);
|
|
36
|
+
|
|
37
|
+
const selector_history_size = reader.bits(13);
|
|
38
|
+
|
|
39
|
+
// "Any remaining bits may be safely ignored" — the section is padded to a byte boundary
|
|
40
|
+
return {
|
|
41
|
+
endpoint_pred,
|
|
42
|
+
delta_endpoint,
|
|
43
|
+
selector,
|
|
44
|
+
selector_history_rle,
|
|
45
|
+
selector_history_size,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { SELECTOR_RANGES, selector_codebook_ranges } from "./fit_endpoints.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Which selector spans a file's codebook actually contains, and where each entry's span sits.
|
|
5
|
+
*
|
|
6
|
+
* Endpoints are fitted per (endpoint entry, selector span) pairing, and there are ten possible
|
|
7
|
+
* spans — but a real file uses only a few of them, and building a fit for spans no block has would
|
|
8
|
+
* be most of the work for none of the benefit. So the spans present are collected first and the
|
|
9
|
+
* templates are allocated against those alone.
|
|
10
|
+
*
|
|
11
|
+
* @typedef {object} Etc1sRangePlan
|
|
12
|
+
* @property {number} slot_count how many distinct spans the codebook contains
|
|
13
|
+
* @property {Uint8Array} range_of_slot the {@link SELECTOR_RANGES} index each slot stands for
|
|
14
|
+
* @property {Uint8Array} slot_of_entry one slot per selector codebook entry
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Work out the {@link Etc1sRangePlan} for a selector codebook.
|
|
19
|
+
*
|
|
20
|
+
* @param {Etc1sSelectorCodebook} selectors
|
|
21
|
+
* @returns {Etc1sRangePlan}
|
|
22
|
+
*
|
|
23
|
+
* @author Alex Goldring
|
|
24
|
+
* @copyright Company Named Limited (c) 2026
|
|
25
|
+
*/
|
|
26
|
+
export function build_range_plan(selectors) {
|
|
27
|
+
const range_of_entry = selector_codebook_ranges(selectors);
|
|
28
|
+
|
|
29
|
+
const slot_of_range = new Int32Array(SELECTOR_RANGES.length).fill(-1);
|
|
30
|
+
|
|
31
|
+
const range_of_slot_list = [];
|
|
32
|
+
|
|
33
|
+
for (let entry = 0; entry < range_of_entry.length; entry++) {
|
|
34
|
+
const range = range_of_entry[entry];
|
|
35
|
+
|
|
36
|
+
if (slot_of_range[range] < 0) {
|
|
37
|
+
slot_of_range[range] = range_of_slot_list.length;
|
|
38
|
+
|
|
39
|
+
range_of_slot_list.push(range);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const slot_of_entry = new Uint8Array(range_of_entry.length);
|
|
44
|
+
|
|
45
|
+
for (let entry = 0; entry < range_of_entry.length; entry++) {
|
|
46
|
+
slot_of_entry[entry] = slot_of_range[range_of_entry[entry]];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
slot_count: range_of_slot_list.length,
|
|
51
|
+
range_of_slot: Uint8Array.from(range_of_slot_list),
|
|
52
|
+
slot_of_entry,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transcode a decoded ETC1S slice to BC1.
|
|
3
|
+
*
|
|
4
|
+
* **Both formats put four colours on a line, which is what makes this cheap and good.** An ETC1S
|
|
5
|
+
* block is a base colour plus an intensity modifier applied equally to all three channels, so its
|
|
6
|
+
* four colours are collinear; BC1's are two endpoints plus two interpolants, which is the same
|
|
7
|
+
* shape. The transcode is therefore a re-parameterisation rather than a re-quantisation, and what it
|
|
8
|
+
* loses is only what 5:6:5 endpoints lose over ETC1S's 5:5:5-plus-modifier.
|
|
9
|
+
*
|
|
10
|
+
* **The work is per endpoint codebook entry, not per block.** A block's four colours depend only on
|
|
11
|
+
* which endpoint entry it names, so the endpoint pair and the selector-to-index mapping are computed
|
|
12
|
+
* once per entry — of which there are at most a few thousand — and every block that names it just
|
|
13
|
+
* writes them out. A texture is typically tens of thousands of blocks over a few hundred entries.
|
|
14
|
+
*
|
|
15
|
+
* @param {Etc1sSlice} slice
|
|
16
|
+
* @param {Etc1sEndpointCodebook} endpoints
|
|
17
|
+
* @param {Etc1sSelectorCodebook} selectors
|
|
18
|
+
* @returns {Uint8Array} tightly packed BC1 blocks, in raster order
|
|
19
|
+
*
|
|
20
|
+
* @author Alex Goldring
|
|
21
|
+
* @copyright Company Named Limited (c) 2026
|
|
22
|
+
*/
|
|
23
|
+
export function etc1s_to_bc1(slice: Etc1sSlice, endpoints: Etc1sEndpointCodebook, selectors: Etc1sSelectorCodebook): Uint8Array;
|
|
24
|
+
//# sourceMappingURL=etc1s_to_bc1.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"etc1s_to_bc1.d.ts","sourceRoot":"","sources":["../../../../src/basis/transcode/etc1s_to_bc1.js"],"names":[],"mappings":"AA0EA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qHALa,UAAU,CAuCtB"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { etc1s_block_colors } from "../etc1s/etc1s_block_colors.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Bytes one BC1 block occupies: two 16-bit endpoints and sixteen 2-bit indices.
|
|
5
|
+
*
|
|
6
|
+
* @readonly
|
|
7
|
+
* @type {number}
|
|
8
|
+
*/
|
|
9
|
+
const BC1_BLOCK_BYTES = 8;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Pack an eight-bit-per-channel colour into BC1's 5:6:5 endpoint.
|
|
13
|
+
*
|
|
14
|
+
* Rounding rather than truncating: truncation biases every endpoint darker, and over a whole texture
|
|
15
|
+
* that reads as a gamma shift rather than as noise.
|
|
16
|
+
*
|
|
17
|
+
* @param {number} r
|
|
18
|
+
* @param {number} g
|
|
19
|
+
* @param {number} b
|
|
20
|
+
* @returns {number} sixteen bits
|
|
21
|
+
*/
|
|
22
|
+
function pack565(r, g, b) {
|
|
23
|
+
const r5 = Math.min(31, (r * 31 + 127) / 255 | 0);
|
|
24
|
+
const g6 = Math.min(63, (g * 63 + 127) / 255 | 0);
|
|
25
|
+
const b5 = Math.min(31, (b * 31 + 127) / 255 | 0);
|
|
26
|
+
|
|
27
|
+
return (r5 << 11) | (g6 << 5) | b5;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The eight-bit colour a 5:6:5 endpoint decodes to, by the same bit replication hardware uses.
|
|
32
|
+
*
|
|
33
|
+
* @param {Uint8Array} out
|
|
34
|
+
* @param {number} offset
|
|
35
|
+
* @param {number} packed
|
|
36
|
+
*/
|
|
37
|
+
function unpack565(out, offset, packed) {
|
|
38
|
+
const r5 = (packed >> 11) & 31;
|
|
39
|
+
const g6 = (packed >> 5) & 63;
|
|
40
|
+
const b5 = packed & 31;
|
|
41
|
+
|
|
42
|
+
out[offset] = (r5 << 3) | (r5 >> 2);
|
|
43
|
+
out[offset + 1] = (g6 << 2) | (g6 >> 4);
|
|
44
|
+
out[offset + 2] = (b5 << 3) | (b5 >> 2);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Which of BC1's four colours best matches a target, given the block's decoded palette.
|
|
49
|
+
*
|
|
50
|
+
* @param {Uint8Array} palette twelve bytes, four `[r, g, b]` triples in BC1 index order
|
|
51
|
+
* @param {Uint8Array} target three bytes
|
|
52
|
+
* @param {number} target_offset
|
|
53
|
+
* @returns {number} `0` to `3`
|
|
54
|
+
*/
|
|
55
|
+
function closest_index(palette, target, target_offset) {
|
|
56
|
+
let best = 0;
|
|
57
|
+
let best_error = Infinity;
|
|
58
|
+
|
|
59
|
+
for (let i = 0; i < 4; i++) {
|
|
60
|
+
const dr = palette[i * 3] - target[target_offset];
|
|
61
|
+
const dg = palette[i * 3 + 1] - target[target_offset + 1];
|
|
62
|
+
const db = palette[i * 3 + 2] - target[target_offset + 2];
|
|
63
|
+
|
|
64
|
+
const error = dr * dr + dg * dg + db * db;
|
|
65
|
+
|
|
66
|
+
if (error < best_error) {
|
|
67
|
+
best_error = error;
|
|
68
|
+
best = i;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return best;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Transcode a decoded ETC1S slice to BC1.
|
|
77
|
+
*
|
|
78
|
+
* **Both formats put four colours on a line, which is what makes this cheap and good.** An ETC1S
|
|
79
|
+
* block is a base colour plus an intensity modifier applied equally to all three channels, so its
|
|
80
|
+
* four colours are collinear; BC1's are two endpoints plus two interpolants, which is the same
|
|
81
|
+
* shape. The transcode is therefore a re-parameterisation rather than a re-quantisation, and what it
|
|
82
|
+
* loses is only what 5:6:5 endpoints lose over ETC1S's 5:5:5-plus-modifier.
|
|
83
|
+
*
|
|
84
|
+
* **The work is per endpoint codebook entry, not per block.** A block's four colours depend only on
|
|
85
|
+
* which endpoint entry it names, so the endpoint pair and the selector-to-index mapping are computed
|
|
86
|
+
* once per entry — of which there are at most a few thousand — and every block that names it just
|
|
87
|
+
* writes them out. A texture is typically tens of thousands of blocks over a few hundred entries.
|
|
88
|
+
*
|
|
89
|
+
* @param {Etc1sSlice} slice
|
|
90
|
+
* @param {Etc1sEndpointCodebook} endpoints
|
|
91
|
+
* @param {Etc1sSelectorCodebook} selectors
|
|
92
|
+
* @returns {Uint8Array} tightly packed BC1 blocks, in raster order
|
|
93
|
+
*
|
|
94
|
+
* @author Alex Goldring
|
|
95
|
+
* @copyright Company Named Limited (c) 2026
|
|
96
|
+
*/
|
|
97
|
+
export function etc1s_to_bc1(slice, endpoints, selectors) {
|
|
98
|
+
const plan = build_range_plan(selectors);
|
|
99
|
+
|
|
100
|
+
const templates = build_templates(endpoints, plan);
|
|
101
|
+
|
|
102
|
+
const block_count = slice.blocks_x * slice.blocks_y;
|
|
103
|
+
|
|
104
|
+
const out = new Uint8Array(block_count * BC1_BLOCK_BYTES);
|
|
105
|
+
|
|
106
|
+
for (let block = 0; block < block_count; block++) {
|
|
107
|
+
const selector_entry = slice.selector_index[block];
|
|
108
|
+
const selector_base = selector_entry * 16;
|
|
109
|
+
|
|
110
|
+
const pairing = slice.endpoint_index[block] * plan.slot_count
|
|
111
|
+
+ plan.slot_of_entry[selector_entry];
|
|
112
|
+
|
|
113
|
+
const low = templates.low[pairing];
|
|
114
|
+
const high = templates.high[pairing];
|
|
115
|
+
const map = pairing * 4;
|
|
116
|
+
|
|
117
|
+
const o = block * BC1_BLOCK_BYTES;
|
|
118
|
+
|
|
119
|
+
out[o] = low & 255;
|
|
120
|
+
out[o + 1] = low >> 8;
|
|
121
|
+
out[o + 2] = high & 255;
|
|
122
|
+
out[o + 3] = high >> 8;
|
|
123
|
+
|
|
124
|
+
for (let row = 0; row < 4; row++) {
|
|
125
|
+
const base = selector_base + row * 4;
|
|
126
|
+
|
|
127
|
+
out[o + 4 + row] =
|
|
128
|
+
templates.selector_to_index[map + selectors.selectors[base]]
|
|
129
|
+
| (templates.selector_to_index[map + selectors.selectors[base + 1]] << 2)
|
|
130
|
+
| (templates.selector_to_index[map + selectors.selectors[base + 2]] << 4)
|
|
131
|
+
| (templates.selector_to_index[map + selectors.selectors[base + 3]] << 6);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* The BC1 endpoint pair and selector mapping for every entry of the endpoint codebook.
|
|
140
|
+
*
|
|
141
|
+
* @param {Etc1sEndpointCodebook} endpoints
|
|
142
|
+
* @returns {{low: Uint16Array, high: Uint16Array, selector_to_index: Uint8Array}} `low` is written
|
|
143
|
+
* first, and is the larger of the pair so the block decodes in four-colour mode
|
|
144
|
+
*/
|
|
145
|
+
function build_templates(endpoints) {
|
|
146
|
+
const count = endpoints.count;
|
|
147
|
+
|
|
148
|
+
const low = new Uint16Array(count);
|
|
149
|
+
const high = new Uint16Array(count);
|
|
150
|
+
const selector_to_index = new Uint8Array(count * 4);
|
|
151
|
+
|
|
152
|
+
const colors = new Uint8Array(12);
|
|
153
|
+
const palette = new Uint8Array(12);
|
|
154
|
+
|
|
155
|
+
for (let entry = 0; entry < count; entry++) {
|
|
156
|
+
etc1s_block_colors(colors, 0, endpoints.color5, endpoints.intensity, entry);
|
|
157
|
+
|
|
158
|
+
/*
|
|
159
|
+
The darkest and brightest of the four span the line; the middle two are recovered by BC1's
|
|
160
|
+
own interpolants, which sit at one and two thirds. ETC1S's middle colours are not exactly
|
|
161
|
+
there — the modifier table is not evenly spaced — so they are matched rather than assumed.
|
|
162
|
+
*/
|
|
163
|
+
let first = pack565(colors[9], colors[10], colors[11]);
|
|
164
|
+
let second = pack565(colors[0], colors[1], colors[2]);
|
|
165
|
+
|
|
166
|
+
/*
|
|
167
|
+
Four-colour mode needs the first endpoint to compare greater. Equal endpoints would select
|
|
168
|
+
three-colour mode, whose fourth index is transparent black — so they are nudged apart, which
|
|
169
|
+
is invisible because the block is a single colour either way.
|
|
170
|
+
*/
|
|
171
|
+
if (first < second) {
|
|
172
|
+
const swap = first;
|
|
173
|
+
|
|
174
|
+
first = second;
|
|
175
|
+
second = swap;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (first === second) {
|
|
179
|
+
second = first === 0 ? 0 : first - 1;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
low[entry] = first;
|
|
183
|
+
high[entry] = second;
|
|
184
|
+
|
|
185
|
+
unpack565(palette, 0, first);
|
|
186
|
+
unpack565(palette, 3, second);
|
|
187
|
+
|
|
188
|
+
/*
|
|
189
|
+
The specification's interpolants, truncating rather than rounding. It matters only that the
|
|
190
|
+
same arithmetic is used here and by whatever decodes the result: these colours exist to pick
|
|
191
|
+
indices, and picking them against a palette a decoder will not produce is how a transcoder
|
|
192
|
+
ends up half a level off everywhere.
|
|
193
|
+
*/
|
|
194
|
+
for (let c = 0; c < 3; c++) {
|
|
195
|
+
palette[6 + c] = (2 * palette[c] + palette[3 + c]) / 3 | 0;
|
|
196
|
+
palette[9 + c] = (palette[c] + 2 * palette[3 + c]) / 3 | 0;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
for (let selector = 0; selector < 4; selector++) {
|
|
200
|
+
selector_to_index[entry * 4 + selector] = closest_index(palette, colors, selector * 3);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return { low, high, selector_to_index };
|
|
205
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transcode a decoded ETC1S slice to BC7.
|
|
3
|
+
*
|
|
4
|
+
* **Two modes, chosen by whether the payload carries alpha, because BC7 cannot do both at once.**
|
|
5
|
+
* Mode 6 gives one index per texel, shared by all four channels, with four bits of it; mode 5 gives
|
|
6
|
+
* colour and alpha their own indices but only two bits each. An opaque payload wants the finer
|
|
7
|
+
* index; an alpha payload needs the independent one, because an ETC1S file's alpha slice has its own
|
|
8
|
+
* selectors, unrelated to the colour slice's, and a shared index could not express both.
|
|
9
|
+
*
|
|
10
|
+
* Neither mode loses much to ETC1S, for the reason {@link etc1s_to_bc1} spells out: an ETC1S block's
|
|
11
|
+
* four colours lie on a line, which is the shape both modes store natively. Mode 5's two-bit index
|
|
12
|
+
* is in fact an exact structural match — four colours, four index values — and gives up only the
|
|
13
|
+
* freedom to place the middle two, which ETC1S's modifier table has already fixed.
|
|
14
|
+
*
|
|
15
|
+
* **The work is per codebook entry, not per block.** A block's colours depend only on which endpoint
|
|
16
|
+
* entry it names, so endpoints and the selector-to-index mapping are computed once per entry and
|
|
17
|
+
* every block that names it just writes them out. Colour and alpha are tabulated separately, which
|
|
18
|
+
* is what lets mode 5 pair any colour entry with any alpha entry without a table of their product.
|
|
19
|
+
*
|
|
20
|
+
* @param {Etc1sSlice} slice the colour slice
|
|
21
|
+
* @param {Etc1sSlice|undefined} alpha_slice the alpha slice, when the payload has one
|
|
22
|
+
* @param {Etc1sEndpointCodebook} endpoints
|
|
23
|
+
* @param {Etc1sSelectorCodebook} selectors
|
|
24
|
+
* @returns {Uint8Array} tightly packed BC7 blocks, in raster order
|
|
25
|
+
*
|
|
26
|
+
* @author Alex Goldring
|
|
27
|
+
* @copyright Company Named Limited (c) 2026
|
|
28
|
+
*/
|
|
29
|
+
export function etc1s_to_bc7(slice: Etc1sSlice, alpha_slice: Etc1sSlice | undefined, endpoints: Etc1sEndpointCodebook, selectors: Etc1sSelectorCodebook): Uint8Array;
|
|
30
|
+
//# sourceMappingURL=etc1s_to_bc7.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"etc1s_to_bc7.d.ts","sourceRoot":"","sources":["../../../../src/basis/transcode/etc1s_to_bc7.js"],"names":[],"mappings":"AA4FA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,6DARW,aAAW,SAAS,uEAGlB,UAAU,CAStB"}
|