@woosh/meep-engine 3.14.1 → 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 +31 -24
- 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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse_image_grid.d.ts","sourceRoot":"","sources":["../../../../../src/avif/native/heif/parse_image_grid.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"parse_image_grid.d.ts","sourceRoot":"","sources":["../../../../../src/avif/native/heif/parse_image_grid.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;GAcG;AACH,0CAPW,UAAU,GACR,SAAS,CAmCrB;0BA9CyB,eAAe"}
|
|
@@ -1,48 +1,49 @@
|
|
|
1
|
-
import { ByteCursor } from "
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* @
|
|
14
|
-
* @
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* @
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
grid.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
grid.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
grid.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
1
|
+
import { ByteCursor } from "../../../core/binary/ByteCursor.js";
|
|
2
|
+
import { EndianType } from "../../../core/binary/EndianType.js";
|
|
3
|
+
import { ImageGrid } from "./AvifFile.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Parse a `grid` derived image's payload.
|
|
7
|
+
*
|
|
8
|
+
* This is not a box: it is the item's own data, laid out as version, flags, the tile counts and
|
|
9
|
+
* the assembled output size. Bit 0 of `flags` widens the output dimensions from 16 to 32 bits.
|
|
10
|
+
*
|
|
11
|
+
* The tile counts are stored minus one, so a grid always has at least one row and one column.
|
|
12
|
+
*
|
|
13
|
+
* @param {Uint8Array} payload
|
|
14
|
+
* @returns {ImageGrid}
|
|
15
|
+
* @see ISO/IEC 23008-12 section 6.6.2.3 "Image grid"
|
|
16
|
+
*
|
|
17
|
+
* @author Alex Goldring
|
|
18
|
+
* @copyright Company Named Limited (c) 2026
|
|
19
|
+
*/
|
|
20
|
+
export function parse_image_grid(payload) {
|
|
21
|
+
const cursor = new ByteCursor().init(payload, EndianType.BigEndian);
|
|
22
|
+
|
|
23
|
+
const version = cursor.u8();
|
|
24
|
+
|
|
25
|
+
if (version !== 0) {
|
|
26
|
+
throw new Error(`grid version ${version} is not supported`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const flags = cursor.u8();
|
|
30
|
+
|
|
31
|
+
const grid = new ImageGrid();
|
|
32
|
+
|
|
33
|
+
grid.rows = cursor.u8() + 1;
|
|
34
|
+
grid.columns = cursor.u8() + 1;
|
|
35
|
+
|
|
36
|
+
if ((flags & 1) !== 0) {
|
|
37
|
+
grid.output_width = cursor.u32();
|
|
38
|
+
grid.output_height = cursor.u32();
|
|
39
|
+
} else {
|
|
40
|
+
grid.output_width = cursor.u16();
|
|
41
|
+
grid.output_height = cursor.u16();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (grid.output_width === 0 || grid.output_height === 0) {
|
|
45
|
+
throw new Error(`grid declares a ${grid.output_width}x${grid.output_height} output`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return grid;
|
|
49
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LSB-first bit cursor over a byte range, with the speculative peek a Huffman decoder needs.
|
|
3
|
+
*
|
|
4
|
+
* **Why this is not {@link BitReader}.** `avif/native/bitstream/BitReader.js` is the other bit
|
|
5
|
+
* reader in this tree and it does not fit, for two reasons that are about the format rather than
|
|
6
|
+
* about convenience:
|
|
7
|
+
*
|
|
8
|
+
* 1. **It is MSB-first, and Basis is LSB-first.** The specification is explicit — "Huffman codes are
|
|
9
|
+
* stored in each output byte in LSB to MSB order. (This is opposite of the JPEG format)". Bit
|
|
10
|
+
* order is not a parameter that could be added the way {@link ByteCursor} took a byte order:
|
|
11
|
+
* a byte order is a property of a *field*, applied once per read, while a bit order changes what
|
|
12
|
+
* the single-bit primitive means and so changes every accessor beneath it.
|
|
13
|
+
* 2. **Huffman decoding needs peek-then-consume, which a descriptor reader has no reason to offer.**
|
|
14
|
+
* A canonical code's length is not known until it has been looked up, so the decoder reads bits
|
|
15
|
+
* it may not consume. `BitReader`'s `f(n)` is sequential by construction.
|
|
16
|
+
*
|
|
17
|
+
* One class doing both would be a flag on every method. So this is a second bit reader,
|
|
18
|
+
* deliberately, and it stays in `basis/` rather than moving to `core/binary/` until something other
|
|
19
|
+
* than Basis wants it — the same rule `ByteCursor` moved under, applied in the direction that says
|
|
20
|
+
* "not yet".
|
|
21
|
+
*
|
|
22
|
+
* **Peeking past the end reads zeros; consuming past it throws.** The two have to differ. A Huffman
|
|
23
|
+
* peek is speculative and legitimately runs off the end of a section — the last code in a stream is
|
|
24
|
+
* rarely flush with a byte boundary — so refusing there would refuse well-formed files. Consuming is
|
|
25
|
+
* a different claim, and a stream that runs out mid-symbol is corrupt.
|
|
26
|
+
*
|
|
27
|
+
* @author Alex Goldring
|
|
28
|
+
* @copyright Company Named Limited (c) 2026
|
|
29
|
+
*/
|
|
30
|
+
export class BasisBitReader {
|
|
31
|
+
/**
|
|
32
|
+
* Point the reader at a byte range.
|
|
33
|
+
*
|
|
34
|
+
* @param {Uint8Array} data
|
|
35
|
+
* @param {number} [byte_offset]
|
|
36
|
+
* @param {number} [byte_length]
|
|
37
|
+
* @returns {BasisBitReader} this
|
|
38
|
+
* @throws {Error} for a range outside `data`
|
|
39
|
+
*/
|
|
40
|
+
init(data: Uint8Array, byte_offset?: number, byte_length?: number): BasisBitReader;
|
|
41
|
+
/**
|
|
42
|
+
* Look at the next `count` bits without consuming them. Bits past the end of the range read as
|
|
43
|
+
* zero — see the note on the class.
|
|
44
|
+
*
|
|
45
|
+
* @param {number} count `0` to 24; the Huffman decoder's longest peek is 16
|
|
46
|
+
* @returns {number}
|
|
47
|
+
*/
|
|
48
|
+
peek(count: number): number;
|
|
49
|
+
/**
|
|
50
|
+
* Drop the next `count` bits.
|
|
51
|
+
*
|
|
52
|
+
* @param {number} count
|
|
53
|
+
* @throws {Error} when the bits dropped were never in the range
|
|
54
|
+
*/
|
|
55
|
+
consume(count: number): void;
|
|
56
|
+
/**
|
|
57
|
+
* Read `count` bits, least significant first.
|
|
58
|
+
*
|
|
59
|
+
* @param {number} count `0` to 24
|
|
60
|
+
* @returns {number}
|
|
61
|
+
* @throws {Error} when the range does not hold them
|
|
62
|
+
*/
|
|
63
|
+
bits(count: number): number;
|
|
64
|
+
/**
|
|
65
|
+
* The specification's variable-length code: `chunk_bits` of payload plus a continuation bit,
|
|
66
|
+
* repeated until the continuation bit is clear.
|
|
67
|
+
*
|
|
68
|
+
* @param {number} chunk_bits
|
|
69
|
+
* @returns {number}
|
|
70
|
+
* @throws {Error} for a code that would not fit in 32 bits, which is a corrupt stream rather
|
|
71
|
+
* than a large number
|
|
72
|
+
* @see the specification's `decode_vlc`, section 10.2
|
|
73
|
+
*/
|
|
74
|
+
vlc(chunk_bits: number): number;
|
|
75
|
+
#private;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=BasisBitReader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BasisBitReader.d.ts","sourceRoot":"","sources":["../../../src/basis/BasisBitReader.js"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH;IAyCI;;;;;;;;OAQG;IACH,WANW,UAAU,gBACV,MAAM,gBACN,MAAM,GACJ,cAAc,CAmB1B;IA6BD;;;;;;OAMG;IACH,YAHW,MAAM,GACJ,MAAM,CAUlB;IAED;;;;;OAKG;IACH,eAHW,MAAM,QAwBhB;IAED;;;;;;OAMG;IACH,YAJW,MAAM,GACJ,MAAM,CASlB;IAED;;;;;;;;;OASG;IACH,gBANW,MAAM,GACJ,MAAM,CA+BlB;;CACJ"}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bits are consumed into a 32-bit accumulator; this is how many it may hold.
|
|
3
|
+
*
|
|
4
|
+
* @readonly
|
|
5
|
+
* @type {number}
|
|
6
|
+
*/
|
|
7
|
+
const ACCUMULATOR_CAPACITY = 32;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* LSB-first bit cursor over a byte range, with the speculative peek a Huffman decoder needs.
|
|
11
|
+
*
|
|
12
|
+
* **Why this is not {@link BitReader}.** `avif/native/bitstream/BitReader.js` is the other bit
|
|
13
|
+
* reader in this tree and it does not fit, for two reasons that are about the format rather than
|
|
14
|
+
* about convenience:
|
|
15
|
+
*
|
|
16
|
+
* 1. **It is MSB-first, and Basis is LSB-first.** The specification is explicit — "Huffman codes are
|
|
17
|
+
* stored in each output byte in LSB to MSB order. (This is opposite of the JPEG format)". Bit
|
|
18
|
+
* order is not a parameter that could be added the way {@link ByteCursor} took a byte order:
|
|
19
|
+
* a byte order is a property of a *field*, applied once per read, while a bit order changes what
|
|
20
|
+
* the single-bit primitive means and so changes every accessor beneath it.
|
|
21
|
+
* 2. **Huffman decoding needs peek-then-consume, which a descriptor reader has no reason to offer.**
|
|
22
|
+
* A canonical code's length is not known until it has been looked up, so the decoder reads bits
|
|
23
|
+
* it may not consume. `BitReader`'s `f(n)` is sequential by construction.
|
|
24
|
+
*
|
|
25
|
+
* One class doing both would be a flag on every method. So this is a second bit reader,
|
|
26
|
+
* deliberately, and it stays in `basis/` rather than moving to `core/binary/` until something other
|
|
27
|
+
* than Basis wants it — the same rule `ByteCursor` moved under, applied in the direction that says
|
|
28
|
+
* "not yet".
|
|
29
|
+
*
|
|
30
|
+
* **Peeking past the end reads zeros; consuming past it throws.** The two have to differ. A Huffman
|
|
31
|
+
* peek is speculative and legitimately runs off the end of a section — the last code in a stream is
|
|
32
|
+
* rarely flush with a byte boundary — so refusing there would refuse well-formed files. Consuming is
|
|
33
|
+
* a different claim, and a stream that runs out mid-symbol is corrupt.
|
|
34
|
+
*
|
|
35
|
+
* @author Alex Goldring
|
|
36
|
+
* @copyright Company Named Limited (c) 2026
|
|
37
|
+
*/
|
|
38
|
+
export class BasisBitReader {
|
|
39
|
+
/**
|
|
40
|
+
* Bytes being read. Not owned.
|
|
41
|
+
* @type {Uint8Array}
|
|
42
|
+
*/
|
|
43
|
+
#data = null;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Index into {@link #data} of the next byte to pull into {@link #accumulator}.
|
|
47
|
+
* @type {number}
|
|
48
|
+
*/
|
|
49
|
+
#byte_position = 0;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Index into {@link #data} one past the last readable byte.
|
|
53
|
+
* @type {number}
|
|
54
|
+
*/
|
|
55
|
+
#end = 0;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Buffered bits, least significant first. Only the low {@link #bit_count} are meaningful.
|
|
59
|
+
* @type {number}
|
|
60
|
+
*/
|
|
61
|
+
#accumulator = 0;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* How many of {@link #accumulator}'s bits are meaningful.
|
|
65
|
+
* @type {number}
|
|
66
|
+
*/
|
|
67
|
+
#bit_count = 0;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Bits of {@link #accumulator} that were manufactured past {@link #end} rather than read.
|
|
71
|
+
*
|
|
72
|
+
* They sit at the most significant end, since that is where a refill puts them. Consuming far
|
|
73
|
+
* enough to reach them is the overrun that throws.
|
|
74
|
+
*
|
|
75
|
+
* @type {number}
|
|
76
|
+
*/
|
|
77
|
+
#phantom_bits = 0;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Point the reader at a byte range.
|
|
81
|
+
*
|
|
82
|
+
* @param {Uint8Array} data
|
|
83
|
+
* @param {number} [byte_offset]
|
|
84
|
+
* @param {number} [byte_length]
|
|
85
|
+
* @returns {BasisBitReader} this
|
|
86
|
+
* @throws {Error} for a range outside `data`
|
|
87
|
+
*/
|
|
88
|
+
init(data, byte_offset = 0, byte_length = data.length - byte_offset) {
|
|
89
|
+
if (byte_offset < 0 || byte_length < 0 || byte_offset + byte_length > data.length) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
`Basis: a bit reader range of [${byte_offset}, ${byte_offset + byte_length}) is`
|
|
92
|
+
+ ` outside the ${data.length} byte buffer it was given`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
this.#data = data;
|
|
97
|
+
this.#byte_position = byte_offset;
|
|
98
|
+
this.#end = byte_offset + byte_length;
|
|
99
|
+
this.#accumulator = 0;
|
|
100
|
+
this.#bit_count = 0;
|
|
101
|
+
this.#phantom_bits = 0;
|
|
102
|
+
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Fill {@link #accumulator} to at least `count` meaningful bits, manufacturing zeros past the
|
|
108
|
+
* end of the range.
|
|
109
|
+
*
|
|
110
|
+
* @param {number} count
|
|
111
|
+
*/
|
|
112
|
+
#fill(count) {
|
|
113
|
+
while (this.#bit_count < count) {
|
|
114
|
+
const past_end = this.#byte_position >= this.#end;
|
|
115
|
+
|
|
116
|
+
const byte = past_end ? 0 : this.#data[this.#byte_position];
|
|
117
|
+
|
|
118
|
+
if (past_end) {
|
|
119
|
+
this.#phantom_bits += 8;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
this.#byte_position++;
|
|
123
|
+
|
|
124
|
+
/*
|
|
125
|
+
`<<` is a signed 32-bit shift, so a byte landing on bits 24..31 would make the
|
|
126
|
+
accumulator negative; `>>> 0` puts it back in the unsigned range the masks assume.
|
|
127
|
+
*/
|
|
128
|
+
this.#accumulator = (this.#accumulator | (byte << this.#bit_count)) >>> 0;
|
|
129
|
+
this.#bit_count += 8;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Look at the next `count` bits without consuming them. Bits past the end of the range read as
|
|
135
|
+
* zero — see the note on the class.
|
|
136
|
+
*
|
|
137
|
+
* @param {number} count `0` to 24; the Huffman decoder's longest peek is 16
|
|
138
|
+
* @returns {number}
|
|
139
|
+
*/
|
|
140
|
+
peek(count) {
|
|
141
|
+
if (count === 0) {
|
|
142
|
+
return 0;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
this.#fill(count);
|
|
146
|
+
|
|
147
|
+
return this.#accumulator & ((1 << count) - 1);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Drop the next `count` bits.
|
|
152
|
+
*
|
|
153
|
+
* @param {number} count
|
|
154
|
+
* @throws {Error} when the bits dropped were never in the range
|
|
155
|
+
*/
|
|
156
|
+
consume(count) {
|
|
157
|
+
if (count === 0) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
this.#fill(count);
|
|
162
|
+
|
|
163
|
+
/*
|
|
164
|
+
The phantom bits sit at the top of the accumulator, so the bits being consumed are real
|
|
165
|
+
exactly when the meaningful ones below them outnumber the request.
|
|
166
|
+
*/
|
|
167
|
+
if (this.#bit_count - this.#phantom_bits < count) {
|
|
168
|
+
throw new Error(
|
|
169
|
+
`Basis: the bitstream ended mid-symbol — ${count} bits were asked for and only`
|
|
170
|
+
+ ` ${Math.max(this.#bit_count - this.#phantom_bits, 0)} remain in the section`
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
this.#accumulator = count === ACCUMULATOR_CAPACITY ? 0 : this.#accumulator >>> count;
|
|
175
|
+
|
|
176
|
+
this.#bit_count -= count;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Read `count` bits, least significant first.
|
|
181
|
+
*
|
|
182
|
+
* @param {number} count `0` to 24
|
|
183
|
+
* @returns {number}
|
|
184
|
+
* @throws {Error} when the range does not hold them
|
|
185
|
+
*/
|
|
186
|
+
bits(count) {
|
|
187
|
+
const value = this.peek(count);
|
|
188
|
+
|
|
189
|
+
this.consume(count);
|
|
190
|
+
|
|
191
|
+
return value;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* The specification's variable-length code: `chunk_bits` of payload plus a continuation bit,
|
|
196
|
+
* repeated until the continuation bit is clear.
|
|
197
|
+
*
|
|
198
|
+
* @param {number} chunk_bits
|
|
199
|
+
* @returns {number}
|
|
200
|
+
* @throws {Error} for a code that would not fit in 32 bits, which is a corrupt stream rather
|
|
201
|
+
* than a large number
|
|
202
|
+
* @see the specification's `decode_vlc`, section 10.2
|
|
203
|
+
*/
|
|
204
|
+
vlc(chunk_bits) {
|
|
205
|
+
const chunk_size = 1 << chunk_bits;
|
|
206
|
+
const chunk_mask = chunk_size - 1;
|
|
207
|
+
|
|
208
|
+
let value = 0;
|
|
209
|
+
let offset = 0;
|
|
210
|
+
|
|
211
|
+
for (; ;) {
|
|
212
|
+
const chunk = this.bits(chunk_bits + 1);
|
|
213
|
+
|
|
214
|
+
value |= (chunk & chunk_mask) << offset;
|
|
215
|
+
offset += chunk_bits;
|
|
216
|
+
|
|
217
|
+
if ((chunk & chunk_size) === 0) {
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (offset >= ACCUMULATOR_CAPACITY) {
|
|
222
|
+
throw new Error(
|
|
223
|
+
`Basis: a variable-length code ran past ${ACCUMULATOR_CAPACITY} bits without`
|
|
224
|
+
+ ` terminating, which no valid stream does`
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return value >>> 0;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Longest code the format permits, from the specification's `cHuffmanMaxSupportedCodeSize`.
|
|
3
|
+
*
|
|
4
|
+
* @readonly
|
|
5
|
+
* @type {number}
|
|
6
|
+
*/
|
|
7
|
+
export const HUFFMAN_MAX_CODE_SIZE: number;
|
|
8
|
+
/**
|
|
9
|
+
* Most symbols a table may describe, from the specification's `cHuffmanMaxSyms` — `1 << 14`.
|
|
10
|
+
*
|
|
11
|
+
* @readonly
|
|
12
|
+
* @type {number}
|
|
13
|
+
*/
|
|
14
|
+
export const HUFFMAN_MAX_SYMBOLS: number;
|
|
15
|
+
/**
|
|
16
|
+
* A canonical Huffman decoding table, built from per-symbol code lengths.
|
|
17
|
+
*
|
|
18
|
+
* **Canonical in the Deflate sense**, which the specification says outright: codes are assigned in
|
|
19
|
+
* order of increasing length and, within a length, increasing symbol. What differs from Deflate is
|
|
20
|
+
* only where the bits come from — {@link BasisBitReader} hands them over least significant first, so
|
|
21
|
+
* a code appears in the stream with its bits reversed, and the fast table is indexed by that
|
|
22
|
+
* reversal.
|
|
23
|
+
*
|
|
24
|
+
* **Incomplete tables are legal.** The specification calls out the single-symbol case explicitly —
|
|
25
|
+
* one symbol with a one-bit code, assigned the code zero, leaving half the code space unused. So an
|
|
26
|
+
* under-full table is built rather than refused, and only a code that actually lands in the unused
|
|
27
|
+
* space throws.
|
|
28
|
+
*
|
|
29
|
+
* @author Alex Goldring
|
|
30
|
+
* @copyright Company Named Limited (c) 2026
|
|
31
|
+
*/
|
|
32
|
+
export class BasisHuffmanTable {
|
|
33
|
+
/**
|
|
34
|
+
* Build the table from an array of per-symbol code lengths, `0` meaning "symbol not used".
|
|
35
|
+
*
|
|
36
|
+
* @param {Uint8Array} code_lengths
|
|
37
|
+
* @returns {BasisHuffmanTable} this
|
|
38
|
+
* @throws {Error} for a length past the format's maximum, or a set of lengths that
|
|
39
|
+
* over-subscribes the code space
|
|
40
|
+
*/
|
|
41
|
+
init(code_lengths: Uint8Array): BasisHuffmanTable;
|
|
42
|
+
/**
|
|
43
|
+
* Read one symbol.
|
|
44
|
+
*
|
|
45
|
+
* @param {BasisBitReader} reader
|
|
46
|
+
* @returns {number} the symbol
|
|
47
|
+
* @throws {Error} for a prefix that matches no code in the table
|
|
48
|
+
*/
|
|
49
|
+
decode(reader: BasisBitReader): number;
|
|
50
|
+
#private;
|
|
51
|
+
}
|
|
52
|
+
import { BasisBitReader } from "./BasisBitReader.js";
|
|
53
|
+
//# sourceMappingURL=BasisHuffmanTable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BasisHuffmanTable.d.ts","sourceRoot":"","sources":["../../../src/basis/BasisHuffmanTable.js"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,oCAFU,MAAM,CAEwB;AAExC;;;;;GAKG;AACH,kCAFU,MAAM,CAE2B;AAsB3C;;;;;;;;;;;;;;;;GAgBG;AACH;IAqCI;;;;;;;OAOG;IACH,mBALW,UAAU,GACR,iBAAiB,CAyE7B;IAiDD;;;;;;OAMG;IACH,eAJW,cAAc,GACZ,MAAM,CAuClB;;CACJ;+BAtQ8B,qBAAqB"}
|