UNPKG

@playcanvas/splat-transform

Version:

Library and CLI tool for 3D Gaussian splat format conversion and transformation

169 lines (168 loc) 7.8 kB
import { BlockMaskBuffer } from './block-mask-buffer'; import { BlockMaskMap } from './block-mask-map'; declare const SOLID_LO: number; declare const SOLID_HI: number; declare const BLOCK_EMPTY = 0; declare const BLOCK_SOLID = 1; declare const BLOCK_MIXED = 2; declare const FACE_MASKS_LO: number[]; declare const FACE_MASKS_HI: number[]; declare const BLOCKS_PER_WORD: number; declare const TYPE_MASK: number; declare const SOLID_WORD: number; declare const EVEN_BITS: number; /** * Read the 2-bit block type directly from a packed `types` Uint32Array. * Module-level so V8 can inline it into hot loops without method dispatch. * Equivalent to `grid.getBlockType(blockIdx)` when `types === grid.types`. * * @param types - Packed types array (16 blocks per word). * @param blockIdx - Linear block index. * @returns Block type: `BLOCK_EMPTY`, `BLOCK_SOLID`, or `BLOCK_MIXED`. */ declare const readBlockType: (types: Uint32Array, blockIdx: number) => number; /** * Write the 2-bit block type directly into a packed `types` Uint32Array. * Module-level so V8 can inline it into hot loops without method dispatch. * Caller is responsible for keeping the grid's `masks` consistent (only * `MIXED` blocks should have a mask entry). * * @param types - Packed types array (16 blocks per word). * @param blockIdx - Linear block index. * @param value - Block type to set. */ declare const writeBlockType: (types: Uint32Array, blockIdx: number, value: number) => void; declare class SparseVoxelGrid { readonly nx: number; readonly ny: number; readonly nz: number; readonly nbx: number; readonly nby: number; readonly nbz: number; readonly bStride: number; /** * Packed block types: 2 bits per block, 16 blocks per Uint32 word. * Length = ceil(totalBlocks / 16). */ types: Uint32Array; /** Voxel masks for MIXED blocks, keyed on global block index. */ masks: BlockMaskMap; constructor(nx: number, ny: number, nz: number); /** * Read the 2-bit block type at the given block index. * * @param blockIdx - Linear block index (`bx + by*nbx + bz*bStride`). * @returns Block type: `BLOCK_EMPTY`, `BLOCK_SOLID`, or `BLOCK_MIXED`. */ getBlockType(blockIdx: number): number; /** * Write the 2-bit block type at the given block index. Caller is * responsible for keeping `masks` consistent (only `MIXED` blocks * should have a mask entry; `EMPTY`/`SOLID` should not). * * @param blockIdx - Linear block index. * @param value - Block type to set. */ setBlockType(blockIdx: number, value: number): void; getVoxel(ix: number, iy: number, iz: number): number; setVoxel(ix: number, iy: number, iz: number): void; orBlock(blockIdx: number, lo: number, hi: number): void; clear(): void; /** * Release the large backing arrays once a grid has been consumed. */ releaseStorage(): void; clone(): SparseVoxelGrid; static fromBuffer(acc: BlockMaskBuffer, nx: number, ny: number, nz: number, onProgress?: (done: number, total: number) => void): SparseVoxelGrid; toBuffer(cropMinBx: number, cropMinBy: number, cropMinBz: number, cropMaxBx: number, cropMaxBy: number, cropMaxBz: number, onProgress?: (done: number, total: number) => void): BlockMaskBuffer; /** * Crop this grid to a block-aligned sub-region. Returns a fresh grid of * size `(cropMaxBx-cropMinBx)*4 x (cropMaxBy-cropMinBy)*4 x (cropMaxBz-cropMinBz)*4` * containing the same data with origin shifted to (cropMinBx, cropMinBy, cropMinBz). * * Iterates only non-empty blocks of the source via word-level skipping. * * @param cropMinBx - Min block X (inclusive). * @param cropMinBy - Min block Y (inclusive). * @param cropMinBz - Min block Z (inclusive). * @param cropMaxBx - Max block X (exclusive). * @param cropMaxBy - Max block Y (exclusive). * @param cropMaxBz - Max block Z (exclusive). * @param onProgress - Optional progress callback over source `types` words. * @returns Newly allocated cropped grid. */ cropTo(cropMinBx: number, cropMinBy: number, cropMinBz: number, cropMaxBx: number, cropMaxBy: number, cropMaxBz: number, onProgress?: (done: number, total: number) => void): SparseVoxelGrid; /** * Crop this grid to a sub-region with inverted occupancy: source EMPTY * becomes destination SOLID, source SOLID becomes destination EMPTY, * source MIXED becomes destination MIXED with bitwise-inverted mask. * * The destination grid has dimensions matching the crop window. Used by * carve to flip the navigable region (1=navigable) into the runtime's * occupancy convention (1=blocked). * * Note: cropping the EMPTY-becomes-SOLID region is exact within the crop * window only. Since the source grid's EMPTY blocks become SOLID in the * output, the output's `types` for empty blocks must be set rather than * left at their default. We therefore initialize the entire output to * SOLID (word fill) and then patch any non-EMPTY source blocks. * * @param cropMinBx - Min block X (inclusive). * @param cropMinBy - Min block Y (inclusive). * @param cropMinBz - Min block Z (inclusive). * @param cropMaxBx - Max block X (exclusive). * @param cropMaxBy - Max block Y (exclusive). * @param cropMaxBz - Max block Z (exclusive). * @param onProgress - Optional progress callback over source `types` words. * @returns Newly allocated cropped + inverted grid. */ cropToInverted(cropMinBx: number, cropMinBy: number, cropMinBz: number, cropMaxBx: number, cropMaxBy: number, cropMaxBz: number, onProgress?: (done: number, total: number) => void): SparseVoxelGrid; /** * Get the bounding box of occupied blocks. * * @param onProgress - Optional progress callback over `types` words. * @returns Block coordinate bounds, or null if no blocks are occupied. */ getOccupiedBlockBounds(onProgress?: (done: number, total: number) => void): { minBx: number; minBy: number; minBz: number; maxBx: number; maxBy: number; maxBz: number; } | null; /** * Get the bounding box of navigable (non-fully-solid) blocks. A block is * navigable if it is EMPTY or MIXED (i.e. contains at least one empty * voxel). Useful when the runtime treats out-of-grid as solid, so fully * solid blocks beyond the navigable region can be cropped away. * * @param onProgress - Optional progress callback over `types` words. * @returns Block coordinate bounds, or null if every block is solid. */ getNavigableBlockBounds(onProgress?: (done: number, total: number) => void): { minBx: number; minBy: number; minBz: number; maxBx: number; maxBy: number; maxBz: number; } | null; /** * Find the nearest free (unblocked) voxel to a seed position using * expanding cube shells. * * @param blocked - Grid to search for free cells in. * @param seedIx - Seed voxel X coordinate. * @param seedIy - Seed voxel Y coordinate. * @param seedIz - Seed voxel Z coordinate. * @param maxRadius - Maximum search radius in voxels. * @returns Coordinates of the nearest free voxel, or null. */ static findNearestFreeCell(blocked: SparseVoxelGrid, seedIx: number, seedIy: number, seedIz: number, maxRadius: number): { ix: number; iy: number; iz: number; } | null; } export { BLOCK_EMPTY, BLOCK_MIXED, BLOCK_SOLID, BLOCKS_PER_WORD, EVEN_BITS, FACE_MASKS_HI, FACE_MASKS_LO, SOLID_HI, SOLID_LO, SOLID_WORD, SparseVoxelGrid, TYPE_MASK, readBlockType, writeBlockType };