@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,263 @@
|
|
|
1
|
+
import { BasisBitReader } from "./BasisBitReader.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Longest code the format permits, from the specification's `cHuffmanMaxSupportedCodeSize`.
|
|
5
|
+
*
|
|
6
|
+
* @readonly
|
|
7
|
+
* @type {number}
|
|
8
|
+
*/
|
|
9
|
+
export const HUFFMAN_MAX_CODE_SIZE = 16;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Most symbols a table may describe, from the specification's `cHuffmanMaxSyms` — `1 << 14`.
|
|
13
|
+
*
|
|
14
|
+
* @readonly
|
|
15
|
+
* @type {number}
|
|
16
|
+
*/
|
|
17
|
+
export const HUFFMAN_MAX_SYMBOLS = 1 << 14;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Bits the fast lookup covers. A code no longer than this is decoded by one array read.
|
|
21
|
+
*
|
|
22
|
+
* Ten is the reference decoder's choice and a reasonable one: the table costs 1024 entries per
|
|
23
|
+
* Huffman table, and the codes that miss it are by construction the rare symbols.
|
|
24
|
+
*
|
|
25
|
+
* @readonly
|
|
26
|
+
* @type {number}
|
|
27
|
+
*/
|
|
28
|
+
const FAST_LOOKUP_BITS = 10;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Bits of a {@link BasisHuffmanTable#fast} entry given over to the code length, which is at most
|
|
32
|
+
* {@link HUFFMAN_MAX_CODE_SIZE} and so needs five.
|
|
33
|
+
*
|
|
34
|
+
* @readonly
|
|
35
|
+
* @type {number}
|
|
36
|
+
*/
|
|
37
|
+
const FAST_LENGTH_BITS = 5;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* A canonical Huffman decoding table, built from per-symbol code lengths.
|
|
41
|
+
*
|
|
42
|
+
* **Canonical in the Deflate sense**, which the specification says outright: codes are assigned in
|
|
43
|
+
* order of increasing length and, within a length, increasing symbol. What differs from Deflate is
|
|
44
|
+
* only where the bits come from — {@link BasisBitReader} hands them over least significant first, so
|
|
45
|
+
* a code appears in the stream with its bits reversed, and the fast table is indexed by that
|
|
46
|
+
* reversal.
|
|
47
|
+
*
|
|
48
|
+
* **Incomplete tables are legal.** The specification calls out the single-symbol case explicitly —
|
|
49
|
+
* one symbol with a one-bit code, assigned the code zero, leaving half the code space unused. So an
|
|
50
|
+
* under-full table is built rather than refused, and only a code that actually lands in the unused
|
|
51
|
+
* space throws.
|
|
52
|
+
*
|
|
53
|
+
* @author Alex Goldring
|
|
54
|
+
* @copyright Company Named Limited (c) 2026
|
|
55
|
+
*/
|
|
56
|
+
export class BasisHuffmanTable {
|
|
57
|
+
/**
|
|
58
|
+
* `(symbol << FAST_LENGTH_BITS) | code_length` for each of the `1 << FAST_LOOKUP_BITS` possible
|
|
59
|
+
* peeks, or `0` where no code of at most {@link FAST_LOOKUP_BITS} bits starts with those bits.
|
|
60
|
+
*
|
|
61
|
+
* Packed into one array rather than two because it is read once per symbol on the hottest path
|
|
62
|
+
* in the transcoder.
|
|
63
|
+
*
|
|
64
|
+
* @type {Int32Array}
|
|
65
|
+
*/
|
|
66
|
+
#fast = null;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Number of codes of each length, indexed by length. Entry 0 is unused.
|
|
70
|
+
* @type {Int32Array}
|
|
71
|
+
*/
|
|
72
|
+
#length_count = null;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Smallest canonical code of each length, most significant bit first.
|
|
76
|
+
* @type {Int32Array}
|
|
77
|
+
*/
|
|
78
|
+
#first_code = null;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Index into {@link #sorted_symbols} of the first symbol of each length.
|
|
82
|
+
* @type {Int32Array}
|
|
83
|
+
*/
|
|
84
|
+
#first_index = null;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Symbols with a non-zero code length, ordered by length then by symbol — which is the order
|
|
88
|
+
* canonical codes are assigned in, so a code's rank within its length indexes straight into it.
|
|
89
|
+
* @type {Int32Array}
|
|
90
|
+
*/
|
|
91
|
+
#sorted_symbols = null;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Build the table from an array of per-symbol code lengths, `0` meaning "symbol not used".
|
|
95
|
+
*
|
|
96
|
+
* @param {Uint8Array} code_lengths
|
|
97
|
+
* @returns {BasisHuffmanTable} this
|
|
98
|
+
* @throws {Error} for a length past the format's maximum, or a set of lengths that
|
|
99
|
+
* over-subscribes the code space
|
|
100
|
+
*/
|
|
101
|
+
init(code_lengths) {
|
|
102
|
+
const symbol_count = code_lengths.length;
|
|
103
|
+
|
|
104
|
+
const length_count = new Int32Array(HUFFMAN_MAX_CODE_SIZE + 1);
|
|
105
|
+
|
|
106
|
+
for (let symbol = 0; symbol < symbol_count; symbol++) {
|
|
107
|
+
const length = code_lengths[symbol];
|
|
108
|
+
|
|
109
|
+
if (length > HUFFMAN_MAX_CODE_SIZE) {
|
|
110
|
+
throw new Error(
|
|
111
|
+
`Basis: a Huffman symbol declares a code length of ${length} bits, and the`
|
|
112
|
+
+ ` format's longest code is ${HUFFMAN_MAX_CODE_SIZE}`
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
length_count[length]++;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// a length of zero means "unused", not "a zero-bit code", so it takes no code space
|
|
120
|
+
length_count[0] = 0;
|
|
121
|
+
|
|
122
|
+
const first_code = new Int32Array(HUFFMAN_MAX_CODE_SIZE + 2);
|
|
123
|
+
const first_index = new Int32Array(HUFFMAN_MAX_CODE_SIZE + 2);
|
|
124
|
+
|
|
125
|
+
let code = 0;
|
|
126
|
+
let index = 0;
|
|
127
|
+
|
|
128
|
+
for (let length = 1; length <= HUFFMAN_MAX_CODE_SIZE; length++) {
|
|
129
|
+
first_code[length] = code;
|
|
130
|
+
first_index[length] = index;
|
|
131
|
+
|
|
132
|
+
code += length_count[length];
|
|
133
|
+
index += length_count[length];
|
|
134
|
+
|
|
135
|
+
/*
|
|
136
|
+
After absorbing every code of this length, `code` counts the codes that would exist if
|
|
137
|
+
the tree were full at this depth. More than that means two symbols were handed the same
|
|
138
|
+
prefix, which is a corrupt table rather than an unusual one — unlike the under-full case
|
|
139
|
+
the specification explicitly permits.
|
|
140
|
+
*/
|
|
141
|
+
if (code > (1 << length)) {
|
|
142
|
+
throw new Error(
|
|
143
|
+
`Basis: the Huffman code lengths over-subscribe the code space at length`
|
|
144
|
+
+ ` ${length}, so no canonical table can be built from them`
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
code <<= 1;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const sorted_symbols = new Int32Array(index);
|
|
152
|
+
const next_index = first_index.slice();
|
|
153
|
+
|
|
154
|
+
for (let symbol = 0; symbol < symbol_count; symbol++) {
|
|
155
|
+
const length = code_lengths[symbol];
|
|
156
|
+
|
|
157
|
+
if (length !== 0) {
|
|
158
|
+
sorted_symbols[next_index[length]++] = symbol;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
this.#length_count = length_count;
|
|
163
|
+
this.#first_code = first_code;
|
|
164
|
+
this.#first_index = first_index;
|
|
165
|
+
this.#sorted_symbols = sorted_symbols;
|
|
166
|
+
|
|
167
|
+
this.#build_fast_lookup(code_lengths, symbol_count);
|
|
168
|
+
|
|
169
|
+
return this;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Fill {@link #fast} so a peek of {@link FAST_LOOKUP_BITS} bits resolves any short code without
|
|
174
|
+
* walking the tree.
|
|
175
|
+
*
|
|
176
|
+
* @param {Uint8Array} code_lengths
|
|
177
|
+
* @param {number} symbol_count
|
|
178
|
+
*/
|
|
179
|
+
#build_fast_lookup(code_lengths, symbol_count) {
|
|
180
|
+
const fast = new Int32Array(1 << FAST_LOOKUP_BITS);
|
|
181
|
+
|
|
182
|
+
const next_code = this.#first_code.slice();
|
|
183
|
+
|
|
184
|
+
for (let symbol = 0; symbol < symbol_count; symbol++) {
|
|
185
|
+
const length = code_lengths[symbol];
|
|
186
|
+
|
|
187
|
+
if (length === 0) {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const canonical = next_code[length]++;
|
|
192
|
+
|
|
193
|
+
if (length > FAST_LOOKUP_BITS) {
|
|
194
|
+
// left to the slow path, which rebuilds the code as it reads rather than tabulating
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/*
|
|
199
|
+
The stream hands bits over least significant first, so a code arrives reversed within
|
|
200
|
+
its own width. Every peek whose low `length` bits match that reversal decodes to this
|
|
201
|
+
symbol, whatever the bits above happen to be — which is what the stride fills in.
|
|
202
|
+
*/
|
|
203
|
+
let reversed = 0;
|
|
204
|
+
|
|
205
|
+
for (let bit = 0; bit < length; bit++) {
|
|
206
|
+
reversed |= ((canonical >>> (length - 1 - bit)) & 1) << bit;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const packed = (symbol << FAST_LENGTH_BITS) | length;
|
|
210
|
+
|
|
211
|
+
for (let i = reversed; i < fast.length; i += 1 << length) {
|
|
212
|
+
fast[i] = packed;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
this.#fast = fast;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Read one symbol.
|
|
221
|
+
*
|
|
222
|
+
* @param {BasisBitReader} reader
|
|
223
|
+
* @returns {number} the symbol
|
|
224
|
+
* @throws {Error} for a prefix that matches no code in the table
|
|
225
|
+
*/
|
|
226
|
+
decode(reader) {
|
|
227
|
+
const packed = this.#fast[reader.peek(FAST_LOOKUP_BITS)];
|
|
228
|
+
|
|
229
|
+
if (packed !== 0) {
|
|
230
|
+
reader.consume(packed & ((1 << FAST_LENGTH_BITS) - 1));
|
|
231
|
+
|
|
232
|
+
return packed >>> FAST_LENGTH_BITS;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/*
|
|
236
|
+
Either a code longer than the fast lookup covers, or one that is not in the table at all.
|
|
237
|
+
Rebuild it a bit at a time, most significant first, which is the order canonical codes
|
|
238
|
+
compare in.
|
|
239
|
+
*/
|
|
240
|
+
let code = 0;
|
|
241
|
+
|
|
242
|
+
for (let length = 1; length <= HUFFMAN_MAX_CODE_SIZE; length++) {
|
|
243
|
+
code = (code << 1) | ((reader.peek(length) >>> (length - 1)) & 1);
|
|
244
|
+
|
|
245
|
+
const count = this.#length_count[length];
|
|
246
|
+
|
|
247
|
+
if (count !== 0) {
|
|
248
|
+
const offset = code - this.#first_code[length];
|
|
249
|
+
|
|
250
|
+
if (offset >= 0 && offset < count) {
|
|
251
|
+
reader.consume(length);
|
|
252
|
+
|
|
253
|
+
return this.#sorted_symbols[this.#first_index[length] + offset];
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
throw new Error(
|
|
259
|
+
`Basis: a ${HUFFMAN_MAX_CODE_SIZE} bit prefix matched no code in the Huffman table,`
|
|
260
|
+
+ ` which means the bitstream and the table disagree`
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read one of the format's compressed Huffman tables.
|
|
3
|
+
*
|
|
4
|
+
* The table is described by its symbols' code lengths, and those lengths are themselves run-length
|
|
5
|
+
* and Huffman coded — the same two-level arrangement Deflate uses, which the specification says it
|
|
6
|
+
* is deliberately compatible with. So this reads a small table first, then uses it to read the
|
|
7
|
+
* lengths of the one that was asked for.
|
|
8
|
+
*
|
|
9
|
+
* @param {BasisBitReader} reader positioned at the start of the table
|
|
10
|
+
* @returns {BasisHuffmanTable}
|
|
11
|
+
* @throws {Error} naming the field, for a table whose header or code lengths are not self-consistent
|
|
12
|
+
* @see the specification, section 6.0
|
|
13
|
+
*
|
|
14
|
+
* @author Alex Goldring
|
|
15
|
+
* @copyright Company Named Limited (c) 2026
|
|
16
|
+
*/
|
|
17
|
+
export function basis_read_huffman_table(reader: BasisBitReader): BasisHuffmanTable;
|
|
18
|
+
import { BasisBitReader } from "./BasisBitReader.js";
|
|
19
|
+
import { BasisHuffmanTable } from "./BasisHuffmanTable.js";
|
|
20
|
+
//# sourceMappingURL=basis_read_huffman_table.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"basis_read_huffman_table.d.ts","sourceRoot":"","sources":["../../../src/basis/basis_read_huffman_table.js"],"names":[],"mappings":"AA4EA;;;;;;;;;;;;;;;GAeG;AACH,iDARW,cAAc,GACZ,iBAAiB,CAqG7B;+BA1L8B,qBAAqB;kCAK7C,wBAAwB"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { BasisBitReader } from "./BasisBitReader.js";
|
|
2
|
+
import {
|
|
3
|
+
BasisHuffmanTable,
|
|
4
|
+
HUFFMAN_MAX_CODE_SIZE,
|
|
5
|
+
HUFFMAN_MAX_SYMBOLS
|
|
6
|
+
} from "./BasisHuffmanTable.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Symbols in the little table that codes the big table's code lengths: the seventeen lengths
|
|
10
|
+
* `[0, 16]` plus four run codes. The specification's `cHuffmanTotalCodelengthCodes`.
|
|
11
|
+
*
|
|
12
|
+
* @readonly
|
|
13
|
+
* @type {number}
|
|
14
|
+
*/
|
|
15
|
+
const CODELENGTH_CODE_COUNT = 21;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A run of symbols with no code, three to ten long. The specification's `cHuffmanSmallZeroRunCode`.
|
|
19
|
+
*
|
|
20
|
+
* @readonly
|
|
21
|
+
* @type {number}
|
|
22
|
+
*/
|
|
23
|
+
const SMALL_ZERO_RUN_CODE = 17;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A run of symbols with no code, eleven to a hundred and thirty-eight long.
|
|
27
|
+
*
|
|
28
|
+
* @readonly
|
|
29
|
+
* @type {number}
|
|
30
|
+
*/
|
|
31
|
+
const BIG_ZERO_RUN_CODE = 18;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A run repeating the previous symbol's code length, three to six long.
|
|
35
|
+
*
|
|
36
|
+
* @readonly
|
|
37
|
+
* @type {number}
|
|
38
|
+
*/
|
|
39
|
+
const SMALL_REPEAT_CODE = 19;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* A run repeating the previous symbol's code length, seven to a hundred and thirty-four long.
|
|
43
|
+
*
|
|
44
|
+
* @readonly
|
|
45
|
+
* @type {number}
|
|
46
|
+
*/
|
|
47
|
+
const BIG_REPEAT_CODE = 20;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Extra bits, and the minimum the run may be, for each of the four run codes — indexed by the code
|
|
51
|
+
* itself so the decode loop reads them rather than branching four ways.
|
|
52
|
+
*
|
|
53
|
+
* @readonly
|
|
54
|
+
* @type {Object<number, {extra_bits: number, minimum: number}>}
|
|
55
|
+
*/
|
|
56
|
+
const RUNS = {
|
|
57
|
+
[SMALL_ZERO_RUN_CODE]: { extra_bits: 3, minimum: 3 },
|
|
58
|
+
[BIG_ZERO_RUN_CODE]: { extra_bits: 7, minimum: 11 },
|
|
59
|
+
[SMALL_REPEAT_CODE]: { extra_bits: 2, minimum: 3 },
|
|
60
|
+
[BIG_REPEAT_CODE]: { extra_bits: 7, minimum: 7 },
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The order the code lengths of the little table arrive in.
|
|
65
|
+
*
|
|
66
|
+
* Not sorted, and not arbitrary: the run codes come first and the ordinary lengths radiate outward
|
|
67
|
+
* from eight, so the lengths a typical table never uses cluster at the end and can be left unsent.
|
|
68
|
+
*
|
|
69
|
+
* @readonly
|
|
70
|
+
* @type {number[]}
|
|
71
|
+
*/
|
|
72
|
+
const CODELENGTH_CODE_ORDER = [
|
|
73
|
+
SMALL_ZERO_RUN_CODE, BIG_ZERO_RUN_CODE, SMALL_REPEAT_CODE, BIG_REPEAT_CODE,
|
|
74
|
+
0, 8, 7, 9, 6, 0xA, 5, 0xB, 4, 0xC, 3, 0xD, 2, 0xE, 1, 0xF, 0x10,
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Read one of the format's compressed Huffman tables.
|
|
79
|
+
*
|
|
80
|
+
* The table is described by its symbols' code lengths, and those lengths are themselves run-length
|
|
81
|
+
* and Huffman coded — the same two-level arrangement Deflate uses, which the specification says it
|
|
82
|
+
* is deliberately compatible with. So this reads a small table first, then uses it to read the
|
|
83
|
+
* lengths of the one that was asked for.
|
|
84
|
+
*
|
|
85
|
+
* @param {BasisBitReader} reader positioned at the start of the table
|
|
86
|
+
* @returns {BasisHuffmanTable}
|
|
87
|
+
* @throws {Error} naming the field, for a table whose header or code lengths are not self-consistent
|
|
88
|
+
* @see the specification, section 6.0
|
|
89
|
+
*
|
|
90
|
+
* @author Alex Goldring
|
|
91
|
+
* @copyright Company Named Limited (c) 2026
|
|
92
|
+
*/
|
|
93
|
+
export function basis_read_huffman_table(reader) {
|
|
94
|
+
const total_used_syms = reader.bits(14);
|
|
95
|
+
|
|
96
|
+
if (total_used_syms === 0 || total_used_syms > HUFFMAN_MAX_SYMBOLS) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
`Basis: a Huffman table declares ${total_used_syms} symbols, and the format allows`
|
|
99
|
+
+ ` 1 to ${HUFFMAN_MAX_SYMBOLS}`
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const codelength_code_count = reader.bits(5);
|
|
104
|
+
|
|
105
|
+
if (codelength_code_count === 0 || codelength_code_count > CODELENGTH_CODE_COUNT) {
|
|
106
|
+
throw new Error(
|
|
107
|
+
`Basis: a Huffman table declares ${codelength_code_count} code length codes, and the`
|
|
108
|
+
+ ` format allows 1 to ${CODELENGTH_CODE_COUNT}`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const codelength_code_lengths = new Uint8Array(CODELENGTH_CODE_COUNT);
|
|
113
|
+
|
|
114
|
+
for (let i = 0; i < codelength_code_count; i++) {
|
|
115
|
+
codelength_code_lengths[CODELENGTH_CODE_ORDER[i]] = reader.bits(3);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const codelength_table = new BasisHuffmanTable().init(codelength_code_lengths);
|
|
119
|
+
|
|
120
|
+
const code_lengths = new Uint8Array(total_used_syms);
|
|
121
|
+
|
|
122
|
+
let symbol = 0;
|
|
123
|
+
|
|
124
|
+
while (symbol < total_used_syms) {
|
|
125
|
+
const code = codelength_table.decode(reader);
|
|
126
|
+
|
|
127
|
+
if (code <= HUFFMAN_MAX_CODE_SIZE) {
|
|
128
|
+
code_lengths[symbol++] = code;
|
|
129
|
+
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const run = RUNS[code];
|
|
134
|
+
|
|
135
|
+
if (run === undefined) {
|
|
136
|
+
throw new Error(
|
|
137
|
+
`Basis: a Huffman table's code length stream used symbol ${code}, and only`
|
|
138
|
+
+ ` 0 to ${BIG_REPEAT_CODE} are defined`
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const count = reader.bits(run.extra_bits) + run.minimum;
|
|
143
|
+
|
|
144
|
+
if (symbol + count > total_used_syms) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
`Basis: a run of ${count} code lengths starting at symbol ${symbol} overruns the`
|
|
147
|
+
+ ` ${total_used_syms} symbols the Huffman table declared`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const repeats = code === SMALL_REPEAT_CODE || code === BIG_REPEAT_CODE;
|
|
152
|
+
|
|
153
|
+
if (!repeats) {
|
|
154
|
+
// a zero run; the array is already zero, so the run only has to advance past it
|
|
155
|
+
symbol += count;
|
|
156
|
+
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/*
|
|
161
|
+
The specification forbids a repeat as the first symbol, and forbids repeating a length of
|
|
162
|
+
zero — the run says "the same as the last one" and there has to be a last one for it to
|
|
163
|
+
name. Both would otherwise read as a run of unused symbols, which is what a zero run is for.
|
|
164
|
+
*/
|
|
165
|
+
if (symbol === 0) {
|
|
166
|
+
throw new Error(
|
|
167
|
+
"Basis: a Huffman table's code length stream opens with a repeat run, which has no"
|
|
168
|
+
+ " previous length to repeat"
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const previous = code_lengths[symbol - 1];
|
|
173
|
+
|
|
174
|
+
if (previous === 0) {
|
|
175
|
+
throw new Error(
|
|
176
|
+
`Basis: a Huffman table's code length stream repeats symbol ${symbol - 1}, which has`
|
|
177
|
+
+ ` no code — a zero run is how unused symbols are spelled`
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
code_lengths.fill(previous, symbol, symbol + count);
|
|
182
|
+
|
|
183
|
+
symbol += count;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return new BasisHuffmanTable().init(code_lengths);
|
|
187
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The recently used selector indices, as an approximate move-to-front list.
|
|
3
|
+
*
|
|
4
|
+
* A slice refers to a selector either by its codebook index or by its position in this list, and the
|
|
5
|
+
* second is cheaper whenever a block reuses something a nearby block used — which most blocks do.
|
|
6
|
+
* What makes it *approximate* is the two shortcuts it takes over a real move-to-front transform, and
|
|
7
|
+
* both matter to a decoder because they define the state exactly:
|
|
8
|
+
*
|
|
9
|
+
* - **A used entry swaps with the one at half its index** rather than moving to the front and
|
|
10
|
+
* shifting everything after it along. So a repeatedly used entry walks toward the front
|
|
11
|
+
* geometrically instead of arriving in one step, and the list is never actually re-ordered.
|
|
12
|
+
* - **A new entry overwrites at a rover** that sweeps the back half of the list and wraps, rather
|
|
13
|
+
* than pushing the oldest entry off the end.
|
|
14
|
+
*
|
|
15
|
+
* Both make the encoder's and decoder's work constant per block instead of linear in the list, which
|
|
16
|
+
* for a list of up to several thousand entries is the whole reason it is affordable at all.
|
|
17
|
+
*
|
|
18
|
+
* @author Alex Goldring
|
|
19
|
+
* @copyright Company Named Limited (c) 2026
|
|
20
|
+
*/
|
|
21
|
+
export class Etc1sSelectorHistory {
|
|
22
|
+
/**
|
|
23
|
+
* @param {number} size from the slice tables section; may be zero, for a file whose blocks never
|
|
24
|
+
* refer to the history
|
|
25
|
+
*/
|
|
26
|
+
constructor(size: number);
|
|
27
|
+
/**
|
|
28
|
+
* @returns {number}
|
|
29
|
+
*/
|
|
30
|
+
get size(): number;
|
|
31
|
+
/**
|
|
32
|
+
* @param {number} index
|
|
33
|
+
* @returns {number} the selector codebook index remembered there
|
|
34
|
+
*/
|
|
35
|
+
at(index: number): number;
|
|
36
|
+
/**
|
|
37
|
+
* Remember a selector index that was referred to by its codebook index.
|
|
38
|
+
*
|
|
39
|
+
* @param {number} value
|
|
40
|
+
*/
|
|
41
|
+
add(value: number): void;
|
|
42
|
+
/**
|
|
43
|
+
* Promote the entry at `index`, having just referred to it.
|
|
44
|
+
*
|
|
45
|
+
* @param {number} index
|
|
46
|
+
*/
|
|
47
|
+
use(index: number): void;
|
|
48
|
+
#private;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=Etc1sSelectorHistory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Etc1sSelectorHistory.d.ts","sourceRoot":"","sources":["../../../../src/basis/etc1s/Etc1sSelectorHistory.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH;IAaI;;;OAGG;IACH,kBAHW,MAAM,EAMhB;IAED;;OAEG;IACH,mBAEC;IAED;;;OAGG;IACH,UAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;;OAIG;IACH,WAFW,MAAM,QAQhB;IAED;;;;OAIG;IACH,WAFW,MAAM,QAchB;;CACJ"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The recently used selector indices, as an approximate move-to-front list.
|
|
3
|
+
*
|
|
4
|
+
* A slice refers to a selector either by its codebook index or by its position in this list, and the
|
|
5
|
+
* second is cheaper whenever a block reuses something a nearby block used — which most blocks do.
|
|
6
|
+
* What makes it *approximate* is the two shortcuts it takes over a real move-to-front transform, and
|
|
7
|
+
* both matter to a decoder because they define the state exactly:
|
|
8
|
+
*
|
|
9
|
+
* - **A used entry swaps with the one at half its index** rather than moving to the front and
|
|
10
|
+
* shifting everything after it along. So a repeatedly used entry walks toward the front
|
|
11
|
+
* geometrically instead of arriving in one step, and the list is never actually re-ordered.
|
|
12
|
+
* - **A new entry overwrites at a rover** that sweeps the back half of the list and wraps, rather
|
|
13
|
+
* than pushing the oldest entry off the end.
|
|
14
|
+
*
|
|
15
|
+
* Both make the encoder's and decoder's work constant per block instead of linear in the list, which
|
|
16
|
+
* for a list of up to several thousand entries is the whole reason it is affordable at all.
|
|
17
|
+
*
|
|
18
|
+
* @author Alex Goldring
|
|
19
|
+
* @copyright Company Named Limited (c) 2026
|
|
20
|
+
*/
|
|
21
|
+
export class Etc1sSelectorHistory {
|
|
22
|
+
/**
|
|
23
|
+
* @type {Int32Array}
|
|
24
|
+
*/
|
|
25
|
+
#values = null;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Where {@link add} writes next. Sweeps the back half of {@link #values} and wraps to its
|
|
29
|
+
* middle, so the front half is only ever reached by {@link use} promoting something into it.
|
|
30
|
+
* @type {number}
|
|
31
|
+
*/
|
|
32
|
+
#rover = 0;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param {number} size from the slice tables section; may be zero, for a file whose blocks never
|
|
36
|
+
* refer to the history
|
|
37
|
+
*/
|
|
38
|
+
constructor(size) {
|
|
39
|
+
this.#values = new Int32Array(size);
|
|
40
|
+
this.#rover = size >> 1;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @returns {number}
|
|
45
|
+
*/
|
|
46
|
+
get size() {
|
|
47
|
+
return this.#values.length;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @param {number} index
|
|
52
|
+
* @returns {number} the selector codebook index remembered there
|
|
53
|
+
*/
|
|
54
|
+
at(index) {
|
|
55
|
+
return this.#values[index];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Remember a selector index that was referred to by its codebook index.
|
|
60
|
+
*
|
|
61
|
+
* @param {number} value
|
|
62
|
+
*/
|
|
63
|
+
add(value) {
|
|
64
|
+
this.#values[this.#rover++] = value;
|
|
65
|
+
|
|
66
|
+
if (this.#rover === this.#values.length) {
|
|
67
|
+
this.#rover = this.#values.length >> 1;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Promote the entry at `index`, having just referred to it.
|
|
73
|
+
*
|
|
74
|
+
* @param {number} index
|
|
75
|
+
*/
|
|
76
|
+
use(index) {
|
|
77
|
+
if (index === 0) {
|
|
78
|
+
// already as far forward as the list goes, and halving would swap it with itself
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const half = index >> 1;
|
|
83
|
+
|
|
84
|
+
const promoted = this.#values[index];
|
|
85
|
+
|
|
86
|
+
this.#values[index] = this.#values[half];
|
|
87
|
+
this.#values[half] = promoted;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The four colours a block's endpoint entry defines, which its selectors choose between.
|
|
3
|
+
*
|
|
4
|
+
* @param {Uint8Array} out receives twelve bytes, four `[r, g, b]` triples darkest first
|
|
5
|
+
* @param {number} out_offset
|
|
6
|
+
* @param {Uint8Array} color5 the endpoint codebook's channel array
|
|
7
|
+
* @param {Uint8Array} intensity the endpoint codebook's intensity array
|
|
8
|
+
* @param {number} endpoint_index
|
|
9
|
+
*
|
|
10
|
+
* @author Alex Goldring
|
|
11
|
+
* @copyright Company Named Limited (c) 2026
|
|
12
|
+
*/
|
|
13
|
+
export function etc1s_block_colors(out: Uint8Array, out_offset: number, color5: Uint8Array, intensity: Uint8Array, endpoint_index: number): void;
|
|
14
|
+
//# sourceMappingURL=etc1s_block_colors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"etc1s_block_colors.d.ts","sourceRoot":"","sources":["../../../../src/basis/etc1s/etc1s_block_colors.js"],"names":[],"mappings":"AAgDA;;;;;;;;;;;GAWG;AACH,wCATW,UAAU,cACV,MAAM,UACN,UAAU,aACV,UAAU,kBACV,MAAM,QAmBhB"}
|