export interface VirtualMeshSource {
    /** xyz per vertex */
    positions: Float32Array;
    /** xyz per vertex */
    normals: Float32Array;
    /** Optional rgb per vertex, multiplied with the material color. */
    colors?: Float32Array;
    /** Optional uv per vertex (texture coordinates). Vertices on a UV seam must be separate vertices. */
    uvs?: Float32Array;
    indices: Uint32Array;
}
export interface VirtualMeshBuildOptions {
    /** Meshlets per group before simplification. */
    groupSize?: number;
    maxLodLevels?: number;
    /** A group that keeps more than this fraction of its triangles stops refining (its meshlets become roots). */
    maxGroupKeepRatio?: number;
    /** Fraction of a group's triangles kept by its simplification (the per-level reduction factor). */
    simplifyRatio?: number;
    /** Stop when a whole level removed less than this fraction of triangles. */
    minLevelReduction?: number;
    /** Remove small disconnected components while simplifying (good for foliage). */
    prune?: boolean;
    /**
     * Keep simplifying below a single meshlet once the remaining roots form the whole mesh, so distant
     * instances can draw a handful of triangles (or nothing, with `prune`) instead of a full meshlet.
     */
    tailSimplify?: boolean;
    /** Stop the tail at this many triangles. */
    minRootTriangles?: number;
    /**
     * Let coarse LODs switch to voxel proxies when those are more accurate than simplified triangles
     * (foliage and other aggregate geometry; solid meshes keep their triangles). Default true.
     */
    voxelLods?: boolean;
    /**
     * Finest voxel grid for those proxies, in cells along the longest side. Default 64. A finer grid (128) lowers the
     * smallest error a voxel level can have, so foliage made of many separate pieces (palm fronds, leaves) switches to
     * its cheap coarse levels closer to the camera. Builds take longer and use more memory.
     */
    voxelResolution?: number;
    /**
     * Keep simplifying groups of separate small pieces (leaf cards, grass blades) when edge collapses stall: each piece
     * is simplified on its own, then neighbouring pieces are thinned in pairs, the kept piece widened to cover both
     * (see aggregate.ts). Without it such groups keep every piece up to the voxel levels. Default true.
     */
    aggregateLods?: boolean;
    onProgress?: (fraction: number) => void | Promise<void>;
}
export interface VirtualMeshData {
    positions: Float32Array;
    normals: Float32Array;
    colors: Float32Array | null;
    /** uv per vertex, or null when the source had none. */
    uvs: Float32Array | null;
    /** Concatenated meshlet triangle lists, indexing `positions`. */
    indices: Uint32Array;
    meshletCount: number;
    /**
     * 4 x vec4 per meshlet:
     * [0] LOD sphere (center, radius)  - shared by all meshlets created from the same group
     * [1] parent LOD sphere (center, radius)
     * [2] (error, parentError, 0, 0) - object-space; parentError = ERROR_INFINITY for roots
     * [3] culling sphere (center, radius) - the meshlet's own geometry
     */
    meshletBounds: Float32Array;
    /**
     * uvec4 per meshlet: (triangleCount, firstIndex, lodLevel, vertexOffset).
     * `firstIndex / 3` is also the meshlet's first entry in `meshletTriangles`.
     */
    meshletInfo: Uint32Array;
    /** Global vertex ids, per meshlet, in meshlet-local order (`vertexOffset` indexes this). */
    meshletVertices: Uint32Array;
    /** One packed triangle per entry: three meshlet-local vertex ids in bits 0-7, 8-15, 16-23. */
    meshletTriangles: Uint32Array;
    /** Meshlets are sorted by LOD level. Per level: [firstMeshlet, meshletCount]. */
    levelRanges: Uint32Array;
    /** Per level: [smallest own error, largest parent error] in object space (parent may be ERROR_INFINITY). */
    levelErrors: Float32Array;
    /**
     * Per level: [largest own error, smallest parent error] in object space. Used by the fast path: if every
     * meshlet of a level passes the LOD test at the nearest distance (largest own error) and at the farthest
     * (smallest parent error), the level needs no per-meshlet test.
     */
    levelGuardErrors: Float32Array;
    /** Sphere enclosing every LOD and parent sphere: bounds the distances the LOD test can see. */
    lodBoundsSphere: [number, number, number, number];
    /** Sphere enclosing every meshlet's culling sphere (all LODs): if an instance sphere is inside the frustum, so are they. */
    cullBoundsSphere: [number, number, number, number];
    /**
     * DAG links (CPU only, for `verifyCutCoverage`; not stored in .vgeo files). Meshlet i belongs to the group that
     * `replacementGroup[i]` names (-1 for the coarsest meshlets), and that group is replaced by the coarser meshlets
     * `replacementIndices[replacementStart[g] .. replacementStart[g + 1]]`. Every meshlet of a group shares one list, so
     * the size stays linear even when a simplification step merges thousands of meshlets at once.
     */
    replacementGroup: Int32Array;
    replacementStart: Uint32Array;
    replacementIndices: Uint32Array;
    /** Whole-object bounding sphere (center xyz, radius). */
    boundingSphere: [number, number, number, number];
    stats: {
        leafTriangles: number;
        leafMeshlets: number;
        rootTriangles: number;
        rootMeshlets: number;
        lodLevels: number;
        /** Coarse levels built from voxel proxies (see voxelProxy.ts). */
        voxelLevels: number;
        /** Groups simplified piece by piece (see aggregate.ts; absent in files baked before it). */
        aggregateGroups?: number;
        buildMs: number;
    };
}
export declare function buildVirtualMesh(src: VirtualMeshSource, options?: VirtualMeshBuildOptions): Promise<VirtualMeshData>;
/**
 * How far the simplified mesh's bounding box retreats from the original's, per side (max over the 6
 * sides). An empty result counts as losing the whole extent. Used as a floor for the LOD error so a
 * version that lost its silhouette is only drawn once that loss is below the pixel threshold.
 */
export declare function extentShrink(before: Uint32Array, after: Uint32Array, positions: Float32Array): number;
/** Order-independent edge id. Safe while vertex ids stay below 2^26. */
export declare const edgeKey: (a: number, b: number) => number;
