/**
 * GSplatManager manages the rendering of splats using a work buffer, where all active splats are
 * stored and rendered from.
 *
 * Shared culling + compaction (raster GPU-sort path and compute renderer, WebGPU only):
 *   Interval compaction operates on contiguous intervals of splats (one per octree node).
 *   1. Cull + count (compute): each interval's bounding sphere is tested against frustum
 *      planes (or a fisheye cone). The pass writes the interval's splat count (or 0 if
 *      culled) into a count buffer.
 *   2. Prefix sum: exclusive prefix sum over the count buffer produces output offsets.
 *      The last element gives visibleCount.
 *   3. Scatter (compute): one workgroup per interval expands visible intervals into
 *      compactedSplatIds (flat list of work-buffer pixel indices).
 *
 * Raster renderer — CPU sorting (WebGPU and WebGL, {@link GSplatQuadRenderer}):
 *   1. Sort on worker: camera position and splat centers are sent to a web worker which
 *      performs a counting sort and returns the sorted order as orderBuffer.
 *   2. Render: the vertex shader reads orderBuffer[vertexId] → splatId.
 *      No culling or compaction is used.
 *
 * Compute tiled renderer (WebGPU only, {@link GSplatComputeLocalRenderer}):
 *   Uses shared steps 1-3 above, then runs a fully compute-based tiled pipeline:
 *   project splats into a cache, bin into screen tiles, sort per-tile by depth, and rasterize
 *   front-to-back. See {@link GSplatComputeLocalRenderer} for the full pass breakdown.
 *
 * @ignore
 */
export class GSplatManager {
    /**
     * @param {GraphicsDevice} device - The graphics device.
     * @param {GSplatDirector} director - The director.
     * @param {Layer} layer - The layer.
     * @param {GraphNode} cameraNode - The camera node.
     */
    constructor(device: GraphicsDevice, director: GSplatDirector, layer: Layer, cameraNode: GraphNode);
    /** @type {GraphicsDevice} */
    device: GraphicsDevice;
    /** @type {GraphNode} */
    node: GraphNode;
    /** @type {GSplatWorkBuffer} */
    workBuffer: GSplatWorkBuffer;
    /** @type {GSplatRenderer} */
    renderer: GSplatRenderer;
    /**
     * A map of versioned world states, keyed by version.
     *
     * @type {Map<number, GSplatWorldState>}
     */
    worldStates: Map<number, GSplatWorldState>;
    /**
     * The version of the last world state.
     */
    lastWorldStateVersion: number;
    /**
     * The currently active renderer mode. Starts as undefined so the first
     * prepareRendererMode() call always creates the appropriate resources.
     *
     * @type {number|undefined}
     */
    activeRenderer: number | undefined;
    /**
     * When true, {@link updateWorldState} must rebuild the splat set.
     *
     * @type {boolean}
     * @private
     */
    private _worldStateDirty;
    /**
     * CPU-based sorter (when not using GPU sorting).
     *
     * @type {GSplatUnifiedSorter|null}
     */
    cpuSorter: GSplatUnifiedSorter | null;
    /**
     * GPU-based radix sorter (raster GPU sort path).
     *
     * @type {ComputeRadixSort|null}
     */
    gpuSorter: ComputeRadixSort | null;
    /**
     * Interval-based GPU compaction (raster GPU sort / compute paths).
     *
     * @type {GSplatIntervalCompaction|null}
     */
    intervalCompaction: GSplatIntervalCompaction | null;
    /**
     * Compute projector + sort keys for {@link GSPLAT_RENDERER_RASTER_GPU_SORT}.
     *
     * @type {GSplatProjector|null}
     */
    projector: GSplatProjector | null;
    /**
     * Indirect draw slot index for the current frame (-1 when not using indirect draw).
     */
    indirectDrawSlot: number;
    /**
     * Indirect dispatch slot for raster GPU sort (projector + radix) and compute paths.
     * The compute local renderer builds its own indirect args in private buffers
     * and does not use these slots.
     */
    indirectDispatchSlot: number;
    /**
     * Total intervals from the last interval compaction dispatch. Needed for
     * writeIndirectArgs to index into the prefix sum buffer for visible count.
     */
    lastCompactedNumIntervals: number;
    /** @type {number} */
    sortedVersion: number;
    /**
     * When true, suppresses ready=true in frame:ready until a fullUpdate cycle runs.
     * Only set when octreeInstances exist and params change (dirty).
     *
     * @private
     */
    private _awaitingLodUpdate;
    /**
     * Cached work buffer format version for detecting extra stream changes.
     *
     * @private
     */
    private _workBufferFormatVersion;
    /**
     * Flag set when the work buffer needs a full rebuild due to format changes.
     *
     * @private
     */
    private _workBufferRebuildRequired;
    /**
     * Number of blocks uploaded to the work buffer this frame.
     */
    bufferCopyUploaded: number;
    /**
     * Total number of blocks in the work buffer this frame.
     */
    bufferCopyTotal: number;
    /**
     * Tracks placement state changes (format version, modifier hash, numSplats, centersVersion).
     *
     * @type {GSplatPlacementStateTracker}
     * @private
     */
    private _stateTracker;
    /**
     * Tracks last seen centersVersion per resource ID for detecting centers updates.
     *
     * @type {Map<number, number>}
     * @private
     */
    private _centersVersions;
    /** @type {number} */
    framesTillFullUpdate: number;
    /** @type {Vec3} */
    lastLodCameraPos: Vec3;
    /** @type {Vec3} */
    lastLodCameraFwd: Vec3;
    /** @type {number} */
    lastLodCameraFov: number;
    /** @type {Vec3} */
    lastSortCameraPos: Vec3;
    /** @type {Vec3} */
    lastSortCameraFwd: Vec3;
    /** @type {Vec3} */
    lastCullingCameraFwd: Vec3;
    /** @type {Mat4} */
    lastCullingProjMat: Mat4;
    /** @type {boolean} */
    sortNeeded: boolean;
    /**
     * Budget balancer for global splat budget enforcement.
     *
     * @type {GSplatBudgetBalancer}
     * @private
     */
    private _budgetBalancer;
    /**
     * Dynamic scale factor applied to LOD parameters during budget enforcement. Shifts all
     * LOD boundaries uniformly to bring the initial estimate closer to the budget target,
     * reducing balancer work. Applied directly to lodBaseDistance and gently to lodMultiplier.
     * Values > 1 push boundaries outward (more splats), values < 1 pull them inward
     * (fewer splats).
     *
     * @private
     */
    private _budgetScale;
    /**
     * Persistent block allocator for work buffer pixel allocations. Grows on demand.
     *
     * @type {BlockAllocator}
     * @private
     */
    private _allocator;
    /**
     * Maps allocId (from GSplatPlacement) to the corresponding MemBlock in the allocator.
     * Shared with GSplatWorldState constructors which mutate it during diff.
     *
     * @type {Map<number, MemBlock>}
     * @private
     */
    private _allocationMap;
    /** @type {Vec3} */
    lastColorUpdateCameraPos: Vec3;
    /** @type {GraphNode} */
    cameraNode: GraphNode;
    /** @type {Scene} */
    scene: Scene;
    /**
     * Layer placements, only non-octree placements are included.
     *
     * @type {GSplatPlacement[]}
     */
    layerPlacements: GSplatPlacement[];
    /** @type {boolean} */
    layerPlacementsDirty: boolean;
    /**
     * True when placements have been added or removed since the last world state was created.
     * Triggers a full work buffer rebuild so boundsBaseIndex stays consistent.
     *
     * @private
     */
    private _placementSetChanged;
    /** @type {Map<GSplatPlacement, GSplatOctreeInstance>} */
    octreeInstances: Map<GSplatPlacement, GSplatOctreeInstance>;
    /**
     * Octree instances scheduled for destruction. We collect their releases and destroy them
     * when creating the next world state
     *
     * @type {GSplatOctreeInstance[]}
     */
    octreeInstancesToDestroy: GSplatOctreeInstance[];
    /**
     * Flag set when new octree instances are added, to trigger immediate LOD evaluation.
     */
    hasNewOctreeInstances: boolean;
    /**
     * Bitmask flags controlling which render passes this manager participates in.
     *
     * @type {number|undefined}
     */
    renderMode: number | undefined;
    director: GSplatDirector;
    layer: Layer;
    destroy(): void;
    _destroyed: boolean;
    /**
     * Destroys GPU sorting resources (radix sorter, projector, compaction).
     *
     * @private
     */
    private destroyGpuSorting;
    /**
     * Destroys interval compaction resources.
     *
     * @param {boolean} [useCpuSort] - Whether to switch the renderer to CPU-sorted mode.
     * @private
     */
    private destroyIntervalCompaction;
    /**
     * Destroys CPU sorting resources (worker-based sorter).
     *
     * @private
     */
    private destroyCpuSorting;
    /**
     * GPU radix sort + projector for hybrid raster (no separate sort-key compute pass).
     *
     * @private
     */
    private initHybridSorting;
    /**
     * Creates the CPU sorter and prepares it for the current world state. Disables any
     * GPU-side indirect draw and hides the mesh until the first sort result arrives.
     *
     * @private
     */
    private initCpuSorting;
    get material(): import("../materials/shader-material.js").ShaderMaterial;
    /**
     * Dispatches a renderer-specific pick pipeline and returns the configured pick mesh instance.
     * The local compute renderer renders to pick textures; the hybrid renderer refreshes its
     * shared projector/sort buffers for the picker camera and returns a transient pick mesh.
     *
     * @param {object} camera - The camera.
     * @param {number} width - Pick target width.
     * @param {number} height - Pick target height.
     * @returns {import('../mesh-instance.js').MeshInstance|null} The pick mesh instance, or null.
     */
    prepareForPicking(camera: object, width: number, height: number): import("../mesh-instance.js").MeshInstance | null;
    /**
     * Creates the CPU sorter (Web Worker based).
     *
     * @returns {GSplatUnifiedSorter} The created sorter.
     */
    createSorter(): GSplatUnifiedSorter;
    /**
     * Sets the render mode for this manager and its renderer.
     *
     * @param {number} renderMode - Bitmask flags controlling render passes (GSPLAT_FORWARD, GSPLAT_SHADOW, or both).
     * @ignore
     */
    setRenderMode(renderMode: number): void;
    /**
     * True when frustum culling can run (bounds data available).
     *
     * @type {boolean}
     * @private
     */
    private get canCull();
    /**
     * Creates the renderer and sort resources for the given mode. Used at init time.
     *
     * @param {number} mode - The GSPLAT_RENDERER_* constant.
     * @private
     */
    private _createRenderer;
    /**
     * Checks whether the resolved renderer mode has changed and transitions to the new mode.
     * Handles renderer mode transitions (CPU raster, hybrid, compute)
     * (quad <-> compute).
     *
     * @private
     */
    private prepareRendererMode;
    /**
     * Supply the manager with the placements to use. This is used to update the manager when the
     * layer's placements have changed, called infrequently.
     *
     * @param {GSplatPlacement[]} placements - The placements to reconcile with.
     */
    reconcile(placements: GSplatPlacement[]): void;
    updateWorldState(): void;
    onSorted(count: any, version: any, orderData: any): void;
    /**
     * Rebuilds the work buffer for a world state on its first sort.
     * Resizes buffer, renders changed splats, syncs transforms, and handles pending releases.
     *
     * @param {GSplatWorldState} worldState - The world state to rebuild for.
     * @param {number} count - The number of splats.
     * @param {boolean} [forceFullRebuild] - Force rendering all splats (e.g. format change).
     */
    rebuildWorkBuffer(worldState: GSplatWorldState, count: number, forceFullRebuild?: boolean): void;
    /**
     * Cleans up old world states between the last sorted version and the new version.
     * Merges upload requirements from skipped states into the active state, then
     * decrements ref counts and destroys old states.
     *
     * @param {number} newVersion - The new version to clean up to.
     */
    cleanupOldWorldStates(newVersion: number): void;
    /**
     * Applies incremental work buffer updates for splats that have changed.
     * Detects transform changes and color update thresholds, then batch renders updates.
     * Sets sortNeeded = true when splats move.
     *
     * @param {GSplatWorldState} state - The world state to update.
     */
    applyWorkBufferUpdates(state: GSplatWorldState): void;
    /**
     * Tests if the camera has moved or rotated enough to require LOD update.
     *
     * @returns {boolean} True if camera moved/rotated over thresholds, otherwise false.
     */
    testCameraMovedForLod(): boolean;
    /**
     * Tests if the camera has moved enough to require re-sorting.
     * - For radial sorting: only position matters (rotation doesn't affect sort order)
     * - For directional sorting: only forward direction matters (position doesn't affect sort order)
     *
     * @returns {boolean} True if camera moved enough to require re-sorting, otherwise false.
     */
    testCameraMovedForSort(): boolean;
    /**
     * Tests if the camera frustum has changed since the last sort or compaction. Checks both
     * projection matrix and camera rotation. Used to trigger re-culling/compaction independently of
     * sort-key changes.
     *
     * @returns {boolean} True if the frustum changed.
     */
    testFrustumChanged(): boolean;
    /**
     * Updates the camera tracking state for color accumulation calculations.
     * Called after any render that updates colors (full or color-only).
     */
    updateColorCameraTracking(): void;
    /**
     * Determines the colorization mode for rendering based on debug flags.
     *
     * @returns {Array<number[]>|undefined} Color array for debug visualization, or undefined for normal rendering
     */
    getDebugColors(): Array<number[]> | undefined;
    /**
     * Calculates camera translation delta since last color update.
     * Updates and returns the shared _cameraDeltas object.
     *
     * @returns {{ translationDelta: number }} Shared camera movement deltas object
     */
    calculateColorCameraDeltas(): {
        translationDelta: number;
    };
    /**
     * Fires the frame:ready event with current sorting and loading state.
     */
    fireFrameReadyEvent(): void;
    /**
     * Computes max world-space distance across all octree instances. Used for sqrt-based bucket
     * distribution in budget balancing. Non-octree placements are excluded since they have fixed
     * splat counts and don't participate in LOD-based budget balancing.
     *
     * @returns {number} Maximum world-space distance, minimum 1 to avoid division by zero.
     * @private
     */
    private computeGlobalMaxDistance;
    /**
     * Enforces global splat budget across all octree instances using phased approach.
     *
     * @param {number} budget - Target splat budget from GSplatParams.splatBudget.
     * @private
     */
    private _enforceBudget;
    /**
     * Detects if the work buffer format has been replaced (e.g. dataFormat changed) and
     * recreates the work buffer if needed.
     *
     * @private
     */
    private handleFormatChange;
    update(): number;
    /**
     * Hybrid GPU path: interval compaction, projector (keys + proj cache), indirect radix sort
     * over projector keys (indices are dense in projCache), then hybrid raster bindings.
     *
     * @param {GSplatWorldState} worldState - The world state to sort.
     */
    sortGpuHybrid(worldState: GSplatWorldState): void;
    /**
     * Runs the shared hybrid projector + indirect radix sort path for a specific camera.
     *
     * @param {GSplatWorldState} worldState - The world state to sort.
     * @param {GraphNode} cameraNode - Camera node used for projection and sort keys.
     * @param {number} viewportWidth - Projection viewport width in pixels.
     * @param {number} viewportHeight - Projection viewport height in pixels.
     * @param {number} alphaClip - Projector producer alpha threshold.
     * @param {boolean} pickMode - Whether projector writes pcId into the cache.
     * @returns {StorageBuffer|null} The sorted cache indices, or null if no work was dispatched.
     * @private
     */
    private sortGpuHybridForCamera;
    /**
     * Runs frustum culling and interval compaction on the GPU, then passes the compacted
     * splat ID buffer directly to the local compute renderer (no key generation or radix sort).
     *
     * @param {GSplatWorldState} worldState - The world state to compact.
     * @private
     */
    private compactGpu;
    /**
     * Allocates per-frame indirect draw and dispatch slots and runs writeIndirectArgs
     * for interval compaction.
     *
     * @param {number} numIntervals - Total interval count (index into prefix sum for visible count).
     * @private
     */
    private allocateAndWriteIntervalIndirectArgs;
    /**
     * Applies hybrid GPU sort results to the renderer with indirect draw from interval compaction.
     *
     * @param {StorageBuffer} sortedIndices - Buffer containing sorted splat IDs.
     * @private
     */
    private applyGpuSortResults;
    /**
     * Prepares frustum culling data: updates the GPU transform buffers and computes
     * frustum planes from the camera. The actual culling test runs inline in the
     * interval compaction compute shader.
     *
     * @param {GSplatWorldState} worldState - The world state whose splats provide transforms.
     * @param {GraphNode} [cameraNode] - Camera node to cull against.
     * @private
     */
    private _runFrustumCulling;
    /**
     * Computes the min/max effective distances for the current world state.
     *
     * @param {GSplatWorldState} worldState - The world state.
     * @param {GraphNode} [cameraNode] - Camera node to measure distances from.
     * @returns {{minDist: number, maxDist: number}} The distance range.
     */
    computeDistanceRange(worldState: GSplatWorldState, cameraNode?: GraphNode): {
        minDist: number;
        maxDist: number;
    };
    /**
     * Sorts the splats using CPU worker (asynchronous).
     *
     * @param {GSplatWorldState} lastState - The last world state.
     */
    sortCpu(lastState: GSplatWorldState): void;
    /**
     * Prepares sort parameters data for the sorter worker.
     *
     * @param {GSplatWorldState} worldState - The world state containing all needed data.
     * @returns {object} - Data for sorter worker.
     */
    prepareSortParameters(worldState: GSplatWorldState): object;
}
import type { GraphicsDevice } from '../../platform/graphics/graphics-device.js';
import { GraphNode } from '../graph-node.js';
import { GSplatWorkBuffer } from './gsplat-work-buffer.js';
import type { GSplatRenderer } from './gsplat-renderer.js';
import { GSplatWorldState } from './gsplat-world-state.js';
import { GSplatUnifiedSorter } from './gsplat-unified-sorter.js';
import { ComputeRadixSort } from '../graphics/radix-sort/compute-radix-sort.js';
import { GSplatIntervalCompaction } from './gsplat-interval-compaction.js';
import { GSplatProjector } from './gsplat-projector.js';
import { Vec3 } from '../../core/math/vec3.js';
import { Mat4 } from '../../core/math/mat4.js';
import type { Scene } from '../scene.js';
import type { GSplatPlacement } from './gsplat-placement.js';
import { GSplatOctreeInstance } from './gsplat-octree-instance.js';
import type { GSplatDirector } from './gsplat-director.js';
import type { Layer } from '../layer.js';
