/** * Geometry merge utilities extracted from Scene. * * Pure functions that take mesh data arrays and return merged buffers. * No dependency on Scene internal state or GPU device. */ import type { MeshData } from '@ifc-lite/geometry'; /** * Per-vertex z-nudge salt (issue: lens/overlay colouring). * * The anti-z-fight depth nudge in `main.wgsl.ts` must produce the SAME depth for * a given surface in BOTH the base opaque pass and the lens/IDS/compare/4D * OVERLAY pass (the overlay pipeline uses `depthCompare: 'equal'`, so any depth * difference rejects every overlay fragment — colour silently fails to paint). * * Material-layer slices share their parent's expressId, so the nudge can't * separate their coincident coplanar caps from the id alone — it needs the * material colour. We bake an 8-bit hash of `MeshData.color` into the HIGH 8 * bits of the per-vertex entityId lane (the low 24 bits stay the picking id; * `encodeId24` masks the salt off). Because the salt comes from the geometry's * OWN colour — not the per-draw `baseColor` uniform — the base and overlay * passes compute an identical nudge, while distinct layers still separate. * * Returns a byte in [0,255]. Stamp it as `(id & 0x00FFFFFF) | (salt << 24)`. */ export declare function colorSaltByte(color?: readonly number[] | null): number; /** Stamp the colour salt into the high 8 bits, picking id into the low 24. */ export declare function packEntityLane(rawId: number, saltByte: number): number; /** * Merge multiple mesh geometries into single interleaved vertex/index buffers. * * Layout per vertex: position (3f) + normal (3f) + entityId (1u32) = 7 × 4 bytes. * Bounds are tracked during the merge pass to avoid a second iteration. */ export declare function mergeGeometry(meshDataArray: MeshData[], forcedOrigin?: [number, number, number]): { vertexData: Float32Array; indices: Uint32Array; bounds: { min: [number, number, number]; max: [number, number, number]; }; /** The local-frame origin actually used (forcedOrigin, or this batch's world * bbox centre). Stored positions are RELATIVE to it; the renderer draws with * model = translate(origin) so f32 vertex coords stay small. */ origin: [number, number, number]; }; /** * Split a meshDataArray into chunks where each chunk's largest buffer * (vertex or index) stays within maxBufferSize. * * Each mesh is kept intact — we never split a single element's geometry. * If a single mesh exceeds the limit on its own it is placed in a solo chunk * (WebGPU will clamp or error, but we don't silently drop geometry). */ export declare function splitMeshDataForBufferLimit(meshDataArray: MeshData[], maxBufferSize: number): MeshData[][]; //# sourceMappingURL=scene-geometry.d.ts.map