@woosh/meep-engine 3.25.0 → 3.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/core/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +542 -0
- package/src/core/binary/lz4/LZ4_LEVEL.d.ts +33 -0
- package/src/core/binary/lz4/LZ4_LEVEL.d.ts.map +1 -0
- package/src/core/binary/lz4/LZ4_LEVEL.js +32 -0
- package/src/core/binary/lz4/lz4_compress_block_at_level.d.ts +33 -0
- package/src/core/binary/lz4/lz4_compress_block_at_level.d.ts.map +1 -0
- package/src/core/binary/lz4/lz4_compress_block_at_level.js +47 -0
- package/src/core/binary/lz4/lz4_compress_block_hc.d.ts +40 -0
- package/src/core/binary/lz4/lz4_compress_block_hc.d.ts.map +1 -0
- package/src/core/binary/lz4/lz4_compress_block_hc.js +1382 -0
- package/src/core/binary/lz4/lz4_decompress_block.d.ts +2 -1
- package/src/core/binary/lz4/lz4_decompress_block.d.ts.map +1 -1
- package/src/core/binary/lz4/lz4_decompress_block.js +31 -6
- package/src/core/geom/3d/shape/HeightMapShape3D.d.ts +66 -0
- package/src/core/geom/3d/shape/HeightMapShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/HeightMapShape3D.js +314 -20
- package/src/core/geom/3d/shape/PosedShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/PosedShape3D.js +57 -0
- package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/TransformedShape3D.js +102 -0
- package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/UnionShape3D.js +64 -0
- package/src/engine/physics/cloth/MEASUREMENTS.md +582 -0
- package/src/engine/physics/cloth/PLAN.md +330 -49
- package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts +84 -17
- package/src/engine/physics/cloth/collider/ClothColliderIndex.d.ts.map +1 -1
- package/src/engine/physics/cloth/collider/ClothColliderIndex.js +451 -42
- package/src/engine/physics/cloth/ecs/ClothInstance.d.ts +65 -7
- package/src/engine/physics/cloth/ecs/ClothInstance.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothInstance.js +72 -8
- package/src/engine/physics/cloth/ecs/ClothSystem.d.ts +25 -4
- package/src/engine/physics/cloth/ecs/ClothSystem.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothSystem.js +75 -8
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +41 -4
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothWorld.js +207 -63
- package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts +10 -0
- package/src/engine/physics/cloth/ecs/WorkerClothSystem.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/WorkerClothSystem.js +17 -1
- package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts +27 -3
- package/src/engine/physics/cloth/ecs/cloth_dynamics_map.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_dynamics_map.js +28 -3
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts +75 -10
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_gather_colliders.js +131 -12
- package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts +19 -0
- package/src/engine/physics/cloth/ecs/cloth_seed_rig.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_seed_rig.js +249 -201
- package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts +21 -0
- package/src/engine/physics/cloth/ecs/cloth_seed_subtree.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_seed_subtree.js +62 -1
- package/src/engine/physics/cloth/ecs/cloth_write_back.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/cloth_write_back.js +18 -10
- package/src/engine/physics/cloth/playground/collide_main.js +1 -1
- package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts +29 -8
- package/src/engine/physics/cloth/solver/cloth_contact_find.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_contact_find.js +37 -9
- package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts +12 -2
- package/src/engine/physics/cloth/solver/cloth_solver_constants.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/cloth_solver_constants.js +12 -2
- package/src/engine/physics/cloth/solver/cloth_step_instance.js +1 -1
- package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts +9 -2
- package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.d.ts.map +1 -1
- package/src/engine/physics/cloth/solver/constraint/cloth_backstop_row.js +9 -2
- package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts +23 -9
- package/src/engine/physics/cloth/wind/AbstractClothWind.d.ts.map +1 -1
- package/src/engine/physics/cloth/wind/AbstractClothWind.js +23 -9
- package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts +7 -5
- package/src/engine/physics/cloth/wind/ClothAmbientWind.d.ts.map +1 -1
- package/src/engine/physics/cloth/wind/ClothAmbientWind.js +12 -9
- package/src/engine/physics/cloth/wind/ClothFluidWind.d.ts.map +1 -1
- package/src/engine/physics/cloth/wind/ClothFluidWind.js +5 -2
- package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts +7 -2
- package/src/engine/physics/cloth/wind/cloth_sample_air.d.ts.map +1 -1
- package/src/engine/physics/cloth/wind/cloth_sample_air.js +12 -5
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/shade/playground/vgeo_runtime/README.md +167 -22
- package/src/shade/playground/vgeo_runtime/index.html +112 -62
- package/src/shade/playground/vgeo_runtime/main.js +660 -83
- package/src/shade/playground/vgeo_viewer/sample_asset.d.ts.map +1 -1
- package/src/shade/playground/vgeo_viewer/sample_asset.js +19 -2
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts +11 -0
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +16 -8
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +16 -11
- package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +73 -5
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +26 -15
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +5 -3
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +18 -0
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +20 -0
- package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.js +56 -9
- package/src/shade/renderer/geometry/virtual/build/vgeo_build.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +1 -0
- package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts +22 -0
- package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js +24 -0
- package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts +12 -0
- package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.js +13 -0
- package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts +8 -1
- package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.js +11 -3
- package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts +9 -0
- package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.js +10 -1
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.d.ts +18 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_ENTRY_COUNT.js +17 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.d.ts +8 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_PARENT_REF.js +7 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.d.ts +3 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.js +16 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.d.ts +14 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_ENTRY_SIZE.js +13 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.d.ts +11 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/page/VGEO_PARENT_PAGE_ENTRY_SIZE.js +10 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts +20 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoByteSource.js +20 -2
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts +4 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerHeader.js +4 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts +29 -3
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +81 -122
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts +40 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPage.js +44 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts +69 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoPageFetcherCore.js +236 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts +14 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoReadOptions.js +15 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.d.ts +31 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_byte_source_from_descriptor.js +32 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts +10 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_fetch_byte_source.js +21 -1
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.d.ts +15 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_transfer.js +84 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts +22 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_page_worker_serve.js +96 -0
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.js +55 -0
- package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js +202 -13
- package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +147 -10
- package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +637 -0
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts +33 -36
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryPool.js +109 -193
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts +58 -28
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.js +77 -105
- package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +37 -0
- package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +105 -22
- package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +548 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts +29 -50
- package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.js +47 -489
- package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts +84 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.js +393 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts +234 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.js +1363 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.d.ts +81 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoResidencyOptions.js +89 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts +53 -34
- package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoRuntimeTables.js +407 -124
- package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts +100 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.js +219 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.d.ts +17 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_EXPAND.js +47 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.d.ts +20 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_FLAG_COARSEN.js +19 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_PARAMS_STRUCT.js +30 -12
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_access.js +15 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.js +18 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_prepare.js +5 -15
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.d.ts +3 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_queue_remainder.js +77 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.d.ts +3 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_reseed.js +186 -0
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_seed.js +20 -8
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.js +580 -188
- package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts +15 -18
- package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/cut/vgeo_cut_feedback_layout.js +19 -28
- package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +45 -25
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.d.ts +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT.js +11 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_CUT_STAT_COUNT.js +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.d.ts +0 -1
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_FEEDBACK_OFFSET.js +12 -10
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.d.ts +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_OFFSET.js +8 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts +7 -2
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_GROUP_ROW_WORDS.js +8 -3
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.d.ts +2 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_OFFSET.js +19 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PAGE_ROW_WORDS.js +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.d.ts +5 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_OFFSET.js +22 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.d.ts +14 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_PARENT_ROW_WORDS.js +13 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.d.ts +17 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/layout/VGEO_QUEUE_TARGET_PARENT_BIT.js +16 -0
- package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.d.ts +15 -0
- package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/make_vgeo_page_worker.js +16 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.d.ts +23 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_frontier_words.js +28 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.d.ts +2 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.d.ts.map +1 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_page.worker.js +13 -0
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts +10 -5
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_page_block_words.js +15 -6
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts +6 -1
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_write_page_block.js +38 -1
- package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/sharc/shader/shader_sharc_evict.js +4 -3
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_emit.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_emit.js +6 -3
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_simulate.js +6 -3
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
- package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +12 -4
- package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts +2 -0
- package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.js +58 -57
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_mesh_filter_2way.js +3 -5
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.js +3 -4
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +3 -4
- package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/pass0/pass_mesh_cull.js +7 -7
- package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/fast/graph_extract_meshes_from_bucket.js +83 -78
- package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +7 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +7 -1
- package/src/shade/renderer/scene/GPUSceneContext.d.ts +22 -2
- package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
- package/src/shade/renderer/scene/GPUSceneContext.js +59 -4
- package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
- package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +92 -16
- package/src/shade/renderer/view/GPUViewContext.d.ts +5 -0
- package/src/shade/renderer/view/GPUViewContext.d.ts.map +1 -1
- package/src/shade/renderer/view/GPUViewContext.js +21 -0
- package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLLanguageCore.js +74 -3
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyManager.js +0 -723
- package/src/shade/renderer/geometry/virtual/residency/VGeoResidencyOptions.js +0 -50
- package/src/shade/renderer/shader/chunk/jobs/NOTES.md +0 -47
- package/src/shade/renderer/shader/chunk/jobs/chunk_job_system.js +0 -102
|
@@ -17,6 +17,8 @@ import { VGEO_NODE_RECORD_SIZE } from "../page/VGEO_NODE_RECORD_SIZE.js";
|
|
|
17
17
|
import { VGEO_PAGE_HEADER_SIZE } from "../page/VGEO_PAGE_HEADER_SIZE.js";
|
|
18
18
|
import { VGEO_PAGE_MAGIC } from "../frame/VGEO_PAGE_MAGIC.js";
|
|
19
19
|
import { VGEO_PAGE_OFFSET } from "../page/VGEO_PAGE_OFFSET.js";
|
|
20
|
+
import { VGEO_PARENT_ENTRY_SIZE } from "../page/VGEO_PARENT_ENTRY_SIZE.js";
|
|
21
|
+
import { VGEO_PARENT_PAGE_ENTRY_SIZE } from "../page/VGEO_PARENT_PAGE_ENTRY_SIZE.js";
|
|
20
22
|
import { vgeo_read_frame_extent } from "../frame/vgeo_read_frame_extent.js";
|
|
21
23
|
import { VGeoPage } from "./VGeoPage.js";
|
|
22
24
|
|
|
@@ -127,6 +129,7 @@ export function vgeo_read_page(frame_bytes, page_index) {
|
|
|
127
129
|
read_group_table(result);
|
|
128
130
|
read_node_table(result);
|
|
129
131
|
read_cluster_table(result);
|
|
132
|
+
read_parent_tables(result);
|
|
130
133
|
|
|
131
134
|
return result;
|
|
132
135
|
}
|
|
@@ -290,6 +293,7 @@ function read_group_table(page) {
|
|
|
290
293
|
page.group_cluster_first = new Uint16Array(count);
|
|
291
294
|
page.group_cluster_count = new Uint16Array(count);
|
|
292
295
|
page.group_parent_count = new Uint16Array(count);
|
|
296
|
+
page.group_parent_first = new Uint32Array(count);
|
|
293
297
|
|
|
294
298
|
for (let i = 0; i < count; i++) {
|
|
295
299
|
const record = VGEO_PAGE_HEADER_SIZE + i * VGEO_GROUP_RECORD_SIZE;
|
|
@@ -297,6 +301,57 @@ function read_group_table(page) {
|
|
|
297
301
|
page.group_cluster_first[i] = data.getUint16(record, LE);
|
|
298
302
|
page.group_cluster_count[i] = data.getUint16(record + 2, LE);
|
|
299
303
|
page.group_parent_count[i] = data.getUint16(record + 4, LE);
|
|
304
|
+
page.group_parent_first[i] = data.getUint16(record + 6, LE);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* The parent-page table and the group-parent table, in that order, from `parent_table_offset`.
|
|
310
|
+
*
|
|
311
|
+
* **A zero offset is a container without an upward edge**, not a malformed one: those bytes were
|
|
312
|
+
* reserved before `format_version` 4 and written as zero, so every container built earlier says
|
|
313
|
+
* so about itself, and this leaves the arrays empty rather than reading the payload as a table.
|
|
314
|
+
* Nothing downstream has to ask what version it is holding.
|
|
315
|
+
*
|
|
316
|
+
* @param {VGeoPage} page
|
|
317
|
+
* @throws {Error} when the tables run past the decoded page
|
|
318
|
+
*/
|
|
319
|
+
function read_parent_tables(page) {
|
|
320
|
+
const data = page.data;
|
|
321
|
+
|
|
322
|
+
const table = data.getUint32(VGEO_PAGE_OFFSET.PARENT_TABLE_OFFSET, LE);
|
|
323
|
+
|
|
324
|
+
if (table === 0) {
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const page_count = data.getUint16(VGEO_PAGE_OFFSET.PARENT_PAGE_COUNT, LE);
|
|
329
|
+
const entry_count = data.getUint16(VGEO_PAGE_OFFSET.PARENT_ENTRY_COUNT, LE);
|
|
330
|
+
|
|
331
|
+
const entries = table + page_count * VGEO_PARENT_PAGE_ENTRY_SIZE;
|
|
332
|
+
const end = entries + entry_count * VGEO_PARENT_ENTRY_SIZE;
|
|
333
|
+
|
|
334
|
+
if (end > page.bytes.byteLength) {
|
|
335
|
+
throw new Error(
|
|
336
|
+
`virtual geometry: page ${page.index} parent tables end at ${end}, past the`
|
|
337
|
+
+ ` ${page.bytes.byteLength} bytes it decoded to`
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
page.parent_page_index = new Uint32Array(page_count);
|
|
342
|
+
|
|
343
|
+
for (let i = 0; i < page_count; i++) {
|
|
344
|
+
page.parent_page_index[i] = data.getUint32(table + i * VGEO_PARENT_PAGE_ENTRY_SIZE, LE);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
page.parent_ref = new Uint16Array(entry_count);
|
|
348
|
+
page.parent_cluster = new Uint16Array(entry_count);
|
|
349
|
+
|
|
350
|
+
for (let i = 0; i < entry_count; i++) {
|
|
351
|
+
const record = entries + i * VGEO_PARENT_ENTRY_SIZE;
|
|
352
|
+
|
|
353
|
+
page.parent_ref[i] = data.getUint16(record, LE);
|
|
354
|
+
page.parent_cluster[i] = data.getUint16(record + 2, LE);
|
|
300
355
|
}
|
|
301
356
|
}
|
|
302
357
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vgeo_validate_container.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"vgeo_validate_container.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js"],"names":[],"mappings":"AAgtDA;;;;;GAKG;AACH,gDAHW,YAAY,GACV,UAAU,EAAE,CAqFxB;6BAzyD4B,4CAA4C;2BAkD9C,iBAAiB"}
|
|
@@ -30,7 +30,10 @@ import { VGEO_MAX_CHILD_REF } from "./cluster/VGEO_MAX_CHILD_REF.js";
|
|
|
30
30
|
import { VGEO_MAX_CLUSTER_TRIANGLE_COUNT } from "./cluster/VGEO_MAX_CLUSTER_TRIANGLE_COUNT.js";
|
|
31
31
|
import { VGEO_MAX_CLUSTER_VERTEX_COUNT } from "./cluster/VGEO_MAX_CLUSTER_VERTEX_COUNT.js";
|
|
32
32
|
import { VGEO_MAX_GROUP_CLUSTER_COUNT } from "./page/VGEO_MAX_GROUP_CLUSTER_COUNT.js";
|
|
33
|
+
import { VGEO_MAX_PARENT_REF } from "./page/VGEO_MAX_PARENT_REF.js";
|
|
33
34
|
import { VGEO_MIN_READER_VERSION } from "./header/VGEO_MIN_READER_VERSION.js";
|
|
35
|
+
import { VGEO_PARENT_ENTRY_SIZE } from "./page/VGEO_PARENT_ENTRY_SIZE.js";
|
|
36
|
+
import { VGEO_PARENT_PAGE_ENTRY_SIZE } from "./page/VGEO_PARENT_PAGE_ENTRY_SIZE.js";
|
|
34
37
|
import { VGEO_NO_CHILD } from "./cluster/VGEO_NO_CHILD.js";
|
|
35
38
|
import { VGEO_NO_GROUP } from "./cluster/VGEO_NO_GROUP.js";
|
|
36
39
|
import { VGEO_NODE_FANOUT } from "./page/VGEO_NODE_FANOUT.js";
|
|
@@ -114,12 +117,42 @@ class DecodedPage {
|
|
|
114
117
|
payload_offset = 0;
|
|
115
118
|
payload_size = 0;
|
|
116
119
|
|
|
120
|
+
/**
|
|
121
|
+
* Start of the parent section — the parent-page table, then the group-parent table. Zero on a
|
|
122
|
+
* page written before `format_version` 4, which carries neither.
|
|
123
|
+
* @type {number}
|
|
124
|
+
*/
|
|
125
|
+
parent_table_offset = 0;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* @type {number}
|
|
129
|
+
*/
|
|
130
|
+
parent_entry_count = 0;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @type {number}
|
|
134
|
+
*/
|
|
135
|
+
parent_page_count = 0;
|
|
136
|
+
|
|
117
137
|
/**
|
|
118
138
|
* `[page_index, ...]` in child-table order.
|
|
119
139
|
* @type {number[]}
|
|
120
140
|
*/
|
|
121
141
|
child_pages = [];
|
|
122
142
|
|
|
143
|
+
/**
|
|
144
|
+
* `[page_index, ...]` in parent-page-table order.
|
|
145
|
+
* @type {number[]}
|
|
146
|
+
*/
|
|
147
|
+
parent_pages = [];
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* The group-parent table, flat: `[parent_ref, parent_cluster, ...]` in table order, which the
|
|
151
|
+
* groups' `parent_first` slices.
|
|
152
|
+
* @type {number[]}
|
|
153
|
+
*/
|
|
154
|
+
parent_entries = [];
|
|
155
|
+
|
|
123
156
|
/**
|
|
124
157
|
* Position `buffer` at a page-relative offset.
|
|
125
158
|
* @param {number} offset
|
|
@@ -617,13 +650,9 @@ function decode_page(buffer, frame, level_count, out) {
|
|
|
617
650
|
page.payload_size = decoded.readUint32();
|
|
618
651
|
page.node_table_offset = decoded.readUint32();
|
|
619
652
|
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
break;
|
|
625
|
-
}
|
|
626
|
-
}
|
|
653
|
+
page.parent_table_offset = decoded.readUint32();
|
|
654
|
+
page.parent_entry_count = decoded.readUint16();
|
|
655
|
+
page.parent_page_count = decoded.readUint16();
|
|
627
656
|
|
|
628
657
|
page.seek(VGEO_PAGE_OFFSET.METRIC);
|
|
629
658
|
|
|
@@ -674,7 +703,22 @@ function decode_page(buffer, frame, level_count, out) {
|
|
|
674
703
|
return undefined;
|
|
675
704
|
}
|
|
676
705
|
|
|
677
|
-
const
|
|
706
|
+
const expected_parent_table_offset = page.cluster_table_offset
|
|
707
|
+
+ page.cluster_count * VGEO_CLUSTER_RECORD_SIZE;
|
|
708
|
+
|
|
709
|
+
if (page.parent_table_offset !== expected_parent_table_offset) {
|
|
710
|
+
out.push(new VGeoDefect(VGEO_DEFECT.PAGE_LAYOUT, `page ${frame.page_index}: parent_table_offset is ${page.parent_table_offset}, expected ${expected_parent_table_offset}`));
|
|
711
|
+
|
|
712
|
+
return undefined;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
if (page.parent_page_count > page.parent_entry_count) {
|
|
716
|
+
out.push(new VGeoDefect(VGEO_DEFECT.PAGE_LAYOUT, `page ${frame.page_index}: parent_page_count is ${page.parent_page_count}, above the ${page.parent_entry_count} entries that could name a page`));
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
const expected_payload_offset = page.parent_table_offset
|
|
720
|
+
+ page.parent_page_count * VGEO_PARENT_PAGE_ENTRY_SIZE
|
|
721
|
+
+ page.parent_entry_count * VGEO_PARENT_ENTRY_SIZE;
|
|
678
722
|
|
|
679
723
|
if (page.payload_offset !== expected_payload_offset) {
|
|
680
724
|
out.push(new VGeoDefect(VGEO_DEFECT.PAGE_LAYOUT, `page ${frame.page_index}: payload_offset is ${page.payload_offset}, expected ${expected_payload_offset}`));
|
|
@@ -1016,7 +1060,7 @@ function check_child_tables(buffer, frames, pages, out) {
|
|
|
1016
1060
|
/**
|
|
1017
1061
|
* @param {DecodedPage} page
|
|
1018
1062
|
* @param {VGeoDefect[]} out
|
|
1019
|
-
* @returns {{cluster_first:number, cluster_count:number, parent_cluster_count:number}[]}
|
|
1063
|
+
* @returns {{cluster_first:number, cluster_count:number, parent_cluster_count:number, parent_first:number}[]}
|
|
1020
1064
|
*/
|
|
1021
1065
|
function read_groups(page, out) {
|
|
1022
1066
|
const result = [];
|
|
@@ -1024,6 +1068,7 @@ function read_groups(page, out) {
|
|
|
1024
1068
|
const buffer = page.buffer;
|
|
1025
1069
|
|
|
1026
1070
|
let expected_first = 0;
|
|
1071
|
+
let expected_parent_first = 0;
|
|
1027
1072
|
|
|
1028
1073
|
for (let g = 0; g < page.group_count; g++) {
|
|
1029
1074
|
page.seek(VGEO_PAGE_HEADER_SIZE + g * VGEO_GROUP_RECORD_SIZE);
|
|
@@ -1032,12 +1077,9 @@ function read_groups(page, out) {
|
|
|
1032
1077
|
cluster_first: buffer.readUint16(),
|
|
1033
1078
|
cluster_count: buffer.readUint16(),
|
|
1034
1079
|
parent_cluster_count: buffer.readUint16(),
|
|
1080
|
+
parent_first: buffer.readUint16(),
|
|
1035
1081
|
};
|
|
1036
1082
|
|
|
1037
|
-
if (buffer.readUint16() !== 0) {
|
|
1038
|
-
out.push(new VGeoDefect(VGEO_DEFECT.GROUP, `page ${page.page_index} group ${g}: reserved is not zero`));
|
|
1039
|
-
}
|
|
1040
|
-
|
|
1041
1083
|
if (group.cluster_count < 1 || group.cluster_count > VGEO_MAX_GROUP_CLUSTER_COUNT) {
|
|
1042
1084
|
out.push(new VGeoDefect(VGEO_DEFECT.GROUP, `page ${page.page_index} group ${g}: cluster_count ${group.cluster_count} is outside [1, ${VGEO_MAX_GROUP_CLUSTER_COUNT}]`));
|
|
1043
1085
|
}
|
|
@@ -1048,6 +1090,12 @@ function read_groups(page, out) {
|
|
|
1048
1090
|
|
|
1049
1091
|
expected_first = group.cluster_first + group.cluster_count;
|
|
1050
1092
|
|
|
1093
|
+
if (group.parent_first !== expected_parent_first) {
|
|
1094
|
+
out.push(new VGeoDefect(VGEO_DEFECT.GROUP, `page ${page.page_index} group ${g}: parent_first ${group.parent_first}, expected ${expected_parent_first}; a page's groups must tile its group-parent table in order`));
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
expected_parent_first = group.parent_first + group.parent_cluster_count;
|
|
1098
|
+
|
|
1051
1099
|
result.push(group);
|
|
1052
1100
|
}
|
|
1053
1101
|
|
|
@@ -1055,9 +1103,147 @@ function read_groups(page, out) {
|
|
|
1055
1103
|
out.push(new VGeoDefect(VGEO_DEFECT.GROUP, `page ${page.page_index}: groups cover ${expected_first} clusters, the page holds ${page.cluster_count}`));
|
|
1056
1104
|
}
|
|
1057
1105
|
|
|
1106
|
+
if (expected_parent_first !== page.parent_entry_count) {
|
|
1107
|
+
out.push(new VGeoDefect(VGEO_DEFECT.GROUP, `page ${page.page_index}: groups cover ${expected_parent_first} parent entries, the page's table holds ${page.parent_entry_count}`));
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1058
1110
|
return result;
|
|
1059
1111
|
}
|
|
1060
1112
|
|
|
1113
|
+
/**
|
|
1114
|
+
* Read the two parent tables onto the page, and check the shape of what they hold before anything
|
|
1115
|
+
* tries to resolve it.
|
|
1116
|
+
*
|
|
1117
|
+
* @param {DecodedPage} page
|
|
1118
|
+
* @param {VGeoDefect[]} out
|
|
1119
|
+
*/
|
|
1120
|
+
function read_parent_tables(page, out) {
|
|
1121
|
+
const buffer = page.buffer;
|
|
1122
|
+
|
|
1123
|
+
page.seek(page.parent_table_offset);
|
|
1124
|
+
|
|
1125
|
+
for (let i = 0; i < page.parent_page_count; i++) {
|
|
1126
|
+
page.parent_pages.push(buffer.readUint32());
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
// Ascending and distinct, so that a parent page resolves to one reference and the refine-side
|
|
1130
|
+
// election in a runtime reading this table is deterministic.
|
|
1131
|
+
for (let i = 1; i < page.parent_pages.length; i++) {
|
|
1132
|
+
if (page.parent_pages[i] <= page.parent_pages[i - 1]) {
|
|
1133
|
+
out.push(new VGeoDefect(VGEO_DEFECT.PAGE_LAYOUT, `page ${page.page_index} parent page entry ${i}: page index ${page.parent_pages[i]} does not follow ${page.parent_pages[i - 1]}; the table is ascending and deduplicated`));
|
|
1134
|
+
|
|
1135
|
+
break;
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
for (const parent_page of page.parent_pages) {
|
|
1140
|
+
if (parent_page === page.page_index) {
|
|
1141
|
+
out.push(new VGeoDefect(VGEO_DEFECT.PAGE_LAYOUT, `page ${page.page_index}: its own index is in its parent-page table, where SAME_PAGE belongs`));
|
|
1142
|
+
|
|
1143
|
+
break;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
page.seek(page.parent_table_offset + page.parent_page_count * VGEO_PARENT_PAGE_ENTRY_SIZE);
|
|
1148
|
+
|
|
1149
|
+
for (let i = 0; i < page.parent_entry_count; i++) {
|
|
1150
|
+
const parent_ref = buffer.readUint16();
|
|
1151
|
+
const parent_cluster = buffer.readUint16();
|
|
1152
|
+
|
|
1153
|
+
if (parent_ref !== VGEO_SAME_PAGE
|
|
1154
|
+
&& (parent_ref > VGEO_MAX_PARENT_REF || parent_ref >= page.parent_page_count)) {
|
|
1155
|
+
out.push(new VGeoDefect(VGEO_DEFECT.GROUP, `page ${page.page_index} parent entry ${i}: parent_ref ${parent_ref} is outside the ${page.parent_page_count}-entry parent-page table`));
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
page.parent_entries.push(parent_ref, parent_cluster);
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/**
|
|
1163
|
+
* The upward edge, checked against the downward one it mirrors — format §11.16.
|
|
1164
|
+
*
|
|
1165
|
+
* Every parent reference must resolve to a cluster that really does name this group as its child,
|
|
1166
|
+
* and each group's list must be sorted and free of repeats. The first is what makes a coarsen legal
|
|
1167
|
+
* at all; the second is what lets a runtime elect one appender out of a group's parents by taking
|
|
1168
|
+
* the first entry of the list, rather than carrying a bitmask sized by instances times groups.
|
|
1169
|
+
*
|
|
1170
|
+
* It is checked by rebuilding the lists from the cluster records and comparing, rather than by
|
|
1171
|
+
* resolving each reference on its own: the downward edge is already validated by {@link check_dag},
|
|
1172
|
+
* so rebuilding from it catches a *missing* parent as well as a wrong one.
|
|
1173
|
+
*
|
|
1174
|
+
* @param {DecodedPage[]} pages
|
|
1175
|
+
* @param {object[][]} page_groups
|
|
1176
|
+
* @param {object[][]} page_clusters
|
|
1177
|
+
* @param {VGeoDefect[]} out
|
|
1178
|
+
*/
|
|
1179
|
+
function check_parent_tables(pages, page_groups, page_clusters, out) {
|
|
1180
|
+
/**
|
|
1181
|
+
* `page:group` to the parents the cluster records say it has, in the order §11.16 requires.
|
|
1182
|
+
* @type {Map<string, {page: number, cluster: number}[]>}
|
|
1183
|
+
*/
|
|
1184
|
+
const expected = new Map();
|
|
1185
|
+
|
|
1186
|
+
for (const page of pages) {
|
|
1187
|
+
for (const cluster of page_clusters[page.page_index]) {
|
|
1188
|
+
if (cluster.child_ref === VGEO_NO_CHILD) {
|
|
1189
|
+
continue;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
const child_page = cluster.child_ref === VGEO_SAME_PAGE
|
|
1193
|
+
? page.page_index
|
|
1194
|
+
: page.child_pages[cluster.child_ref];
|
|
1195
|
+
|
|
1196
|
+
if (child_page === undefined) {
|
|
1197
|
+
// a broken child reference, which check_dag reports; nothing to mirror
|
|
1198
|
+
continue;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
const id = `${child_page}:${cluster.child_group}`;
|
|
1202
|
+
|
|
1203
|
+
let list = expected.get(id);
|
|
1204
|
+
|
|
1205
|
+
if (list === undefined) {
|
|
1206
|
+
expected.set(id, list = []);
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
list.push({ page: page.page_index, cluster: cluster.index });
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
for (const list of expected.values()) {
|
|
1214
|
+
list.sort((a, b) => a.page - b.page || a.cluster - b.cluster);
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
for (const page of pages) {
|
|
1218
|
+
page_groups[page.page_index].forEach((group, group_index) => {
|
|
1219
|
+
const want = expected.get(`${page.page_index}:${group_index}`) ?? [];
|
|
1220
|
+
|
|
1221
|
+
if (group.parent_first + group.parent_cluster_count > page.parent_entry_count) {
|
|
1222
|
+
out.push(new VGeoDefect(VGEO_DEFECT.GROUP, `page ${page.page_index} group ${group_index}: parents ${group.parent_first}..${group.parent_first + group.parent_cluster_count} run past the ${page.parent_entry_count}-entry table`));
|
|
1223
|
+
|
|
1224
|
+
return;
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
for (let i = 0; i < group.parent_cluster_count && i < want.length; i++) {
|
|
1228
|
+
const base = (group.parent_first + i) * 2;
|
|
1229
|
+
|
|
1230
|
+
const parent_ref = page.parent_entries[base];
|
|
1231
|
+
const parent_cluster = page.parent_entries[base + 1];
|
|
1232
|
+
|
|
1233
|
+
const named_page = parent_ref === VGEO_SAME_PAGE
|
|
1234
|
+
? page.page_index
|
|
1235
|
+
: page.parent_pages[parent_ref];
|
|
1236
|
+
|
|
1237
|
+
if (named_page !== want[i].page || parent_cluster !== want[i].cluster) {
|
|
1238
|
+
out.push(new VGeoDefect(VGEO_DEFECT.GROUP, `page ${page.page_index} group ${group_index} parent ${i}: names page ${named_page} cluster ${parent_cluster}, but the ${i}th cluster refining into this group is page ${want[i].page} cluster ${want[i].cluster}`));
|
|
1239
|
+
|
|
1240
|
+
break;
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
});
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1061
1247
|
/**
|
|
1062
1248
|
* Decode a cluster's local positions from its payload — the only way to check that the culling
|
|
1063
1249
|
* bounds actually bound anything.
|
|
@@ -1617,6 +1803,8 @@ export function vgeo_validate_container(buffer) {
|
|
|
1617
1803
|
const groups = read_groups(page, out);
|
|
1618
1804
|
const clusters = read_clusters(page, out);
|
|
1619
1805
|
|
|
1806
|
+
read_parent_tables(page, out);
|
|
1807
|
+
|
|
1620
1808
|
page_groups.push(groups);
|
|
1621
1809
|
page_clusters.push(clusters);
|
|
1622
1810
|
|
|
@@ -1637,6 +1825,7 @@ export function vgeo_validate_container(buffer) {
|
|
|
1637
1825
|
}
|
|
1638
1826
|
|
|
1639
1827
|
check_page_nodes(pages, page_groups, page_clusters, out);
|
|
1828
|
+
check_parent_tables(pages, page_groups, page_clusters, out);
|
|
1640
1829
|
|
|
1641
1830
|
check_dag(pages, page_groups, page_clusters, level_count, out);
|
|
1642
1831
|
check_directory(buffer, frames, pages, out);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vgeo_write_container.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/format/vgeo_write_container.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"vgeo_write_container.d.ts","sourceRoot":"","sources":["../../../../../../../src/shade/renderer/geometry/virtual/format/vgeo_write_container.js"],"names":[],"mappings":"AA4bA;;;;;;;;GAQG;AACH,4CANW,qBAAqB,8BAGnB,YAAY,CAmNxB;6BAppB4B,4CAA4C"}
|
|
@@ -24,6 +24,8 @@ import { VGEO_HEADER_SIZE } from "./header/VGEO_HEADER_SIZE.js";
|
|
|
24
24
|
import { VGEO_LEVEL_RECORD_SIZE } from "./header/VGEO_LEVEL_RECORD_SIZE.js";
|
|
25
25
|
import { VGEO_MAGIC } from "./header/VGEO_MAGIC.js";
|
|
26
26
|
import { VGEO_MAX_CHILD_REF } from "./cluster/VGEO_MAX_CHILD_REF.js";
|
|
27
|
+
import { VGEO_MAX_PARENT_ENTRY_COUNT } from "./page/VGEO_MAX_PARENT_ENTRY_COUNT.js";
|
|
28
|
+
import { VGEO_MAX_PARENT_REF } from "./page/VGEO_MAX_PARENT_REF.js";
|
|
27
29
|
import { VGEO_MIN_READER_VERSION } from "./header/VGEO_MIN_READER_VERSION.js";
|
|
28
30
|
import { VGEO_NO_CHILD } from "./cluster/VGEO_NO_CHILD.js";
|
|
29
31
|
import { VGEO_NO_GROUP } from "./cluster/VGEO_NO_GROUP.js";
|
|
@@ -32,7 +34,10 @@ import { VGEO_NODE_RECORD_SIZE } from "./page/VGEO_NODE_RECORD_SIZE.js";
|
|
|
32
34
|
import { VGEO_PAGE_HEADER_SIZE } from "./page/VGEO_PAGE_HEADER_SIZE.js";
|
|
33
35
|
import { VGEO_PAGE_MAGIC } from "./frame/VGEO_PAGE_MAGIC.js";
|
|
34
36
|
import { VGEO_PAGE_OFFSET } from "./page/VGEO_PAGE_OFFSET.js";
|
|
37
|
+
import { VGEO_PARENT_ENTRY_SIZE } from "./page/VGEO_PARENT_ENTRY_SIZE.js";
|
|
38
|
+
import { VGEO_PARENT_PAGE_ENTRY_SIZE } from "./page/VGEO_PARENT_PAGE_ENTRY_SIZE.js";
|
|
35
39
|
import { VGEO_PAYLOAD_ENCODING_SHADE_MESHLET_V1 } from "./header/VGEO_PAYLOAD_ENCODING_SHADE_MESHLET_V1.js";
|
|
40
|
+
import { VGEO_SAME_PAGE } from "./cluster/VGEO_SAME_PAGE.js";
|
|
36
41
|
import { vgeo_scan_frames } from "./frame/vgeo_scan_frames.js";
|
|
37
42
|
|
|
38
43
|
/**
|
|
@@ -98,28 +103,84 @@ class PageBlob {
|
|
|
98
103
|
}
|
|
99
104
|
|
|
100
105
|
/**
|
|
101
|
-
* Count how many clusters name each group,
|
|
102
|
-
* derived, so recomputing
|
|
106
|
+
* Count how many clusters name each group, index the groups and clusters within their pages, and
|
|
107
|
+
* build the upward edge. All of it is derived, so recomputing it here keeps a caller from having to
|
|
108
|
+
* maintain any of it.
|
|
109
|
+
*
|
|
110
|
+
* The upward edge is the one piece that cannot be resolved while a single page is written: a
|
|
111
|
+
* group's parents live in whichever pages happen to refine into it, so the map is built across the
|
|
112
|
+
* whole page set once and then read per page.
|
|
103
113
|
*
|
|
104
114
|
* @param {VirtualGeometryPage[]} pages
|
|
115
|
+
* @returns {Map<VirtualGeometryGroup, {page: number, cluster: number}[]>} each group's parents,
|
|
116
|
+
* sorted by (page index, cluster index) — the order format §11.16 requires, and the order the
|
|
117
|
+
* runtime's refine-side election depends on being deterministic
|
|
105
118
|
*/
|
|
106
119
|
function resolve_group_references(pages) {
|
|
107
120
|
for (const page of pages) {
|
|
121
|
+
let cluster_index = 0;
|
|
122
|
+
|
|
108
123
|
page.groups.forEach((group, index) => {
|
|
109
124
|
group.index_in_page = index;
|
|
110
125
|
group.parent_cluster_count = 0;
|
|
126
|
+
|
|
127
|
+
for (const cluster of group.clusters) {
|
|
128
|
+
cluster.index_in_page = cluster_index;
|
|
129
|
+
cluster_index++;
|
|
130
|
+
}
|
|
111
131
|
});
|
|
112
132
|
}
|
|
113
133
|
|
|
134
|
+
/** @type {Map<VirtualGeometryGroup, {page: number, cluster: number}[]>} */
|
|
135
|
+
const parents = new Map();
|
|
136
|
+
|
|
114
137
|
for (const page of pages) {
|
|
115
138
|
for (const group of page.groups) {
|
|
116
139
|
for (const cluster of group.clusters) {
|
|
117
|
-
|
|
118
|
-
|
|
140
|
+
const child = cluster.child_group;
|
|
141
|
+
|
|
142
|
+
if (child === undefined) {
|
|
143
|
+
continue;
|
|
119
144
|
}
|
|
145
|
+
|
|
146
|
+
child.parent_cluster_count++;
|
|
147
|
+
|
|
148
|
+
let list = parents.get(child);
|
|
149
|
+
|
|
150
|
+
if (list === undefined) {
|
|
151
|
+
parents.set(child, list = []);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
list.push({ page: page.index, cluster: cluster.index_in_page });
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
for (const list of parents.values()) {
|
|
160
|
+
list.sort((a, b) => a.page - b.page || a.cluster - b.cluster);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return parents;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @param {VirtualGeometryPage} page
|
|
168
|
+
* @param {Map<VirtualGeometryGroup, {page: number, cluster: number}[]>} parents
|
|
169
|
+
* @returns {number[]} distinct indices of *other* pages holding a parent of one of this page's
|
|
170
|
+
* groups, ascending; a parent in this page is named by `VGEO_SAME_PAGE` and is not here
|
|
171
|
+
*/
|
|
172
|
+
function collect_parent_pages(page, parents) {
|
|
173
|
+
const seen = new Set();
|
|
174
|
+
|
|
175
|
+
for (const group of page.groups) {
|
|
176
|
+
for (const parent of parents.get(group) ?? []) {
|
|
177
|
+
if (parent.page !== page.index) {
|
|
178
|
+
seen.add(parent.page);
|
|
120
179
|
}
|
|
121
180
|
}
|
|
122
181
|
}
|
|
182
|
+
|
|
183
|
+
return Array.from(seen).sort((a, b) => a - b);
|
|
123
184
|
}
|
|
124
185
|
|
|
125
186
|
/**
|
|
@@ -149,9 +210,10 @@ function collect_child_pages(page) {
|
|
|
149
210
|
/**
|
|
150
211
|
* @param {VirtualGeometryPage} page
|
|
151
212
|
* @param {number[]} child_pages
|
|
213
|
+
* @param {Map<VirtualGeometryGroup, {page: number, cluster: number}[]>} parents
|
|
152
214
|
* @returns {Uint8Array} the decoded page
|
|
153
215
|
*/
|
|
154
|
-
function build_page_blob(page, child_pages) {
|
|
216
|
+
function build_page_blob(page, child_pages, parents) {
|
|
155
217
|
const clusters = [];
|
|
156
218
|
|
|
157
219
|
for (const group of page.groups) {
|
|
@@ -160,9 +222,41 @@ function build_page_blob(page, child_pages) {
|
|
|
160
222
|
}
|
|
161
223
|
}
|
|
162
224
|
|
|
225
|
+
const parent_pages = collect_parent_pages(page, parents);
|
|
226
|
+
|
|
227
|
+
let parent_entry_count = 0;
|
|
228
|
+
|
|
229
|
+
for (const group of page.groups) {
|
|
230
|
+
parent_entry_count += (parents.get(group) ?? []).length;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
assert.lessThanOrEqual(
|
|
234
|
+
parent_entry_count, VGEO_MAX_PARENT_ENTRY_COUNT,
|
|
235
|
+
'page group-parent table must stay within what parent_first can index (format §11.15)'
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
assert.lessThanOrEqual(
|
|
239
|
+
parent_pages.length, VGEO_MAX_PARENT_REF + 1,
|
|
240
|
+
'page parent-page table must stay within what parent_ref can index'
|
|
241
|
+
);
|
|
242
|
+
|
|
163
243
|
const node_table_offset = VGEO_PAGE_HEADER_SIZE + page.groups.length * VGEO_GROUP_RECORD_SIZE;
|
|
164
244
|
const cluster_table_offset = node_table_offset + page.nodes.length * VGEO_NODE_RECORD_SIZE;
|
|
165
|
-
|
|
245
|
+
|
|
246
|
+
/*
|
|
247
|
+
The parent section sits between the cluster records and the payload rather than beside the
|
|
248
|
+
group table, which keeps `node_table_offset`'s "= 56 + 8·group_count" true and leaves every
|
|
249
|
+
offset a reader before format 4 computed exactly where it was. Both tables hold 4-byte entries
|
|
250
|
+
and the sections above them are all multiples of four, so the payload stays word-aligned —
|
|
251
|
+
format §11.8's promise, which the meshlet batch divides by four without rounding.
|
|
252
|
+
*/
|
|
253
|
+
const parent_table_offset = cluster_table_offset + clusters.length * VGEO_CLUSTER_RECORD_SIZE;
|
|
254
|
+
|
|
255
|
+
const group_parent_table_offset = parent_table_offset
|
|
256
|
+
+ parent_pages.length * VGEO_PARENT_PAGE_ENTRY_SIZE;
|
|
257
|
+
|
|
258
|
+
const payload_offset = group_parent_table_offset
|
|
259
|
+
+ parent_entry_count * VGEO_PARENT_ENTRY_SIZE;
|
|
166
260
|
|
|
167
261
|
let payload_size = 0;
|
|
168
262
|
|
|
@@ -185,6 +279,9 @@ function build_page_blob(page, child_pages) {
|
|
|
185
279
|
buffer.writeUint32(payload_offset);
|
|
186
280
|
buffer.writeUint32(payload_size);
|
|
187
281
|
buffer.writeUint32(node_table_offset);
|
|
282
|
+
buffer.writeUint32(parent_table_offset);
|
|
283
|
+
buffer.writeUint16(parent_entry_count);
|
|
284
|
+
buffer.writeUint16(parent_pages.length);
|
|
188
285
|
|
|
189
286
|
// The page's own metric, so an installed page can be re-tested from itself rather than from
|
|
190
287
|
// whichever of its parents happened to reference it.
|
|
@@ -216,16 +313,56 @@ function build_page_blob(page, child_pages) {
|
|
|
216
313
|
child_ref_of_page.set(page_index, index);
|
|
217
314
|
});
|
|
218
315
|
|
|
316
|
+
/**
|
|
317
|
+
* `page_index -> parent-page-table index`. The same shape as above and resolved the same way;
|
|
318
|
+
* a parent inside this page is `VGEO_SAME_PAGE` and is not in the table at all.
|
|
319
|
+
* @type {Map<number, number>}
|
|
320
|
+
*/
|
|
321
|
+
const parent_ref_of_page = new Map();
|
|
322
|
+
|
|
323
|
+
parent_pages.forEach((page_index, index) => {
|
|
324
|
+
assert.lessThanOrEqual(index, VGEO_MAX_PARENT_REF, 'parent table index must stay below the sentinel range');
|
|
325
|
+
|
|
326
|
+
parent_ref_of_page.set(page_index, index);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
parent_pages.forEach((page_index, index) => {
|
|
330
|
+
buffer.position = parent_table_offset + index * VGEO_PARENT_PAGE_ENTRY_SIZE;
|
|
331
|
+
|
|
332
|
+
buffer.writeUint32(page_index);
|
|
333
|
+
});
|
|
334
|
+
|
|
219
335
|
let cluster_index = 0;
|
|
220
336
|
let cursor = 0;
|
|
221
337
|
|
|
338
|
+
let parent_first = 0;
|
|
339
|
+
|
|
222
340
|
page.groups.forEach((group, group_index) => {
|
|
341
|
+
const group_parents = parents.get(group) ?? [];
|
|
342
|
+
|
|
343
|
+
assert.equal(
|
|
344
|
+
group_parents.length, group.parent_cluster_count,
|
|
345
|
+
'a group\'s parent list and its parent_cluster_count are the same fact twice'
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
group_parents.forEach((parent, index) => {
|
|
349
|
+
buffer.position = group_parent_table_offset
|
|
350
|
+
+ (parent_first + index) * VGEO_PARENT_ENTRY_SIZE;
|
|
351
|
+
|
|
352
|
+
buffer.writeUint16(
|
|
353
|
+
parent.page === page.index ? VGEO_SAME_PAGE : parent_ref_of_page.get(parent.page)
|
|
354
|
+
);
|
|
355
|
+
buffer.writeUint16(parent.cluster);
|
|
356
|
+
});
|
|
357
|
+
|
|
223
358
|
buffer.position = VGEO_PAGE_HEADER_SIZE + group_index * VGEO_GROUP_RECORD_SIZE;
|
|
224
359
|
|
|
225
360
|
buffer.writeUint16(cluster_index);
|
|
226
361
|
buffer.writeUint16(group.clusters.length);
|
|
227
362
|
buffer.writeUint16(group.parent_cluster_count);
|
|
228
|
-
buffer.writeUint16(
|
|
363
|
+
buffer.writeUint16(parent_first);
|
|
364
|
+
|
|
365
|
+
parent_first += group_parents.length;
|
|
229
366
|
|
|
230
367
|
for (const cluster of group.clusters) {
|
|
231
368
|
const offset = cluster_table_offset + cluster_index * VGEO_CLUSTER_RECORD_SIZE;
|
|
@@ -322,19 +459,19 @@ export function vgeo_write_container(pages, options) {
|
|
|
322
459
|
assert.equal(page.index, index, `page ${index} carries index ${page.index}`);
|
|
323
460
|
});
|
|
324
461
|
|
|
325
|
-
resolve_group_references(pages);
|
|
462
|
+
const parents = resolve_group_references(pages);
|
|
326
463
|
|
|
327
464
|
const blobs = pages.map((page) => {
|
|
328
465
|
const blob = new PageBlob();
|
|
329
466
|
|
|
330
467
|
blob.child_pages = collect_child_pages(page);
|
|
331
468
|
|
|
332
|
-
const decoded = build_page_blob(page, blob.child_pages);
|
|
469
|
+
const decoded = build_page_blob(page, blob.child_pages, parents);
|
|
333
470
|
|
|
334
471
|
// Compression happens here, before a single offset is known, and that is what keeps the
|
|
335
472
|
// layout non-circular: a frame's extent follows from its *stored* size and its child count,
|
|
336
473
|
// and neither depends on any offset value, because the child table is plaintext.
|
|
337
|
-
const encoded = vgeo_encode_frame_blob(decoded, options.codec);
|
|
474
|
+
const encoded = vgeo_encode_frame_blob(decoded, options.codec, options.codec_level);
|
|
338
475
|
|
|
339
476
|
blob.codec = encoded.codec;
|
|
340
477
|
blob.stored = encoded.bytes;
|