import { BatchedMesh, Box3, Color, type Material, Object3D } from "three";
import { type LineMaterial } from "three/examples/jsm/Addons";
import { type BufferElement } from "../..";
/**
 * Inject per-instance alpha support into a material for use with BatchedMesh.
 *
 * Three.js's built-in BatchedMesh shader reads only `.rgb` from the colors texture,
 * discarding the alpha channel. This injection:
 * 1. Reads `.a` from `batchingColorTexture` in the vertex shader
 * 2. Passes it as a varying `vBatchAlpha` to the fragment shader
 * 3. Applies alpha to `gl_FragColor.a` and discards fully transparent fragments
 *
 * This enables: per-instance hide (alpha=0 → discard), ghost (alpha=0.1),
 * selection outline detection (alpha=0.99).
 */
export declare function injectBatchedMeshAlphaShader(material: Material): void;
/**
 * Special alpha value to mark selected vertices for fast outline detection.
 * The AlphaSelectionOutlinePass detects this value with ZERO extra render passes.
 */
export declare const SELECTION_ALPHA_V3 = 0.99;
/**
 * ViralBatchedMeshV3 — Wraps Three.js `BatchedMesh` for high-performance BIM rendering.
 *
 * Key advantages over ViralBatchedMesh (V1):
 * - **Per-element frustum culling** — Only visible elements are rendered when zoomed in
 * - **Automatic depth sorting** — Opaque front-to-back (reduces overdraw), transparent back-to-front
 * - **WEBGL_multi_draw** — Single draw call with multiple ranges (automatic)
 * - **GPU-native visibility** — `setVisibleAt()` fully skips hidden elements (no vertex shader cost)
 * - **O(1) raycast→element lookup** — `batchId` on intersection replaces linear `findElementByFaceIndex`
 *
 * Each BIM element's geometry is added as a separate "geometry" in the inner `BatchedMesh`,
 * with one instance per element at identity matrix (positions are already in world space).
 */
export declare class ViralBatchedMeshV3 extends Object3D {
    /**
     * The inner Three.js BatchedMesh that does the actual rendering.
     * Exposed for direct access when needed (e.g. adding to selectables).
     */
    innerMesh: BatchedMesh;
    globalMaterialIndex: number;
    _bufferElements: BufferElement[];
    private _originalColor;
    /**
     * Map: "modelId:elementId" → instanceId[] (one element can have multiple solids)
     */
    private _elementToInstances;
    /**
     * Reverse map: instanceId → { modelId, elementId }
     * Used for O(1) raycast lookup via `batchId`.
     */
    private _instanceToElement;
    /**
     * instanceId → geometryId (for bounding box lookups)
     */
    private _instanceToGeometry;
    private _selectedElements;
    private _hidingElements;
    private _isolatingElements;
    private _hiddenSet;
    private _isolatedSet;
    private _elementOpacityMap;
    private _elementOriginalColors;
    private _temporaryColors;
    private _ghostColors;
    private _instanceColors;
    private _currentMaxInstances;
    private _currentMaxVertices;
    private _currentMaxIndices;
    private _usedInstances;
    private _usedVertices;
    private _usedIndices;
    private _depthPrePassMesh;
    private _originalTransparent;
    private _originalDepthWrite;
    private _originalRenderOrder;
    constructor(material: Material, initialCapacity?: {
        maxInstances?: number;
        maxVertices?: number;
        maxIndices?: number;
    });
    /**
     * Set color AND alpha for an instance.
     * Three.js `setColorAt` only writes RGB; the alpha channel in the colors texture
     * must be written manually for our custom shader to pick up.
     */
    private _setColorAlphaAt;
    /**
     * Add buffer elements to this batched mesh.
     * Each BufferElement becomes a geometry + instance in the inner BatchedMesh.
     */
    addBufferElements(bufferElements: BufferElement[], materialColor: Color): void;
    /**
     * Append more elements to this batched mesh (streaming/incremental loading).
     */
    batch(newBufferElements: BufferElement[]): void;
    /**
     * [INFRA-04] Apply GPU usage hints to the merged BatchedMesh geometry.
     * Position/normal/index are write-once → StaticDrawUsage.
     * V3 colors are managed via DataTexture (_colorsTexture), not BufferAttribute,
     * so DynamicDrawUsage is not applicable for color here.
     */
    private _applyGeometryUsageHints;
    private _ensureCapacity;
    /**
     * O(1) raycast result → element identification.
     * Use `intersection.batchId` from Three.js BatchedMesh raycast.
     */
    findElementByBatchId(batchId: number): {
        modelId: string;
        elementId: string;
    } | null;
    /**
     * Compatibility shim: same signature as ViralBatchedMesh.findElementByFaceIndex.
     * For BatchedMesh, we use batchId instead, but this allows gradual migration.
     * @deprecated Use findElementByBatchId(intersection.batchId) instead
     */
    findElementByFaceIndex(_faceIndex: number): {
        modelId: string;
        elementId: string;
    } | null;
    /**
     * Get buffer elements matching the given element IDs.
     */
    getElements(elements: {
        modelId: string;
        elementId: string;
    }[]): BufferElement[];
    getElementsByModel(modelIndex: number): BufferElement[];
    select(elements: {
        modelId: string;
        elementId: string;
    }[], excepts?: {
        elements: {
            modelId: string;
            elementId: string;
        }[];
        color: {
            r: number;
            g: number;
            b: number;
        };
    }[]): void;
    get selectedElements(): {
        modelId: string;
        elementId: string;
    }[];
    get hidingElements(): {
        modelId: string;
        elementId: string;
    }[];
    get isolatingElements(): {
        modelId: string;
        elementId: string;
    }[];
    unselect(): void;
    hide(elements?: {
        modelId: string;
        elementId: string;
    }[]): void;
    isolate(elements?: {
        modelId: string;
        elementId: string;
    }[]): {
        modelId: string;
        elementId: string;
    }[];
    isolateModel(modelIds: string[]): void;
    show(elements: {
        modelId: string;
        elementId: string;
    }[]): void;
    reset(): void;
    isElementVisible(modelId: string, elementId: string): boolean;
    setElementOpacity(elements: {
        modelId: string;
        elementId: string;
    }[], opacity: number): void;
    getElementOpacity(modelId: string, elementId: string): number;
    setElementGhost(elements: {
        modelId: string;
        elementId: string;
    }[], ghostOpacity?: number, desaturate?: boolean, ghostColor?: {
        r: number;
        g: number;
        b: number;
    }): void;
    ghostExcept(focusElements: {
        modelId: string;
        elementId: string;
    }[], ghostOpacity?: number, ghostColor?: {
        r: number;
        g: number;
        b: number;
    }): void;
    resetElementOpacity(): void;
    changeColor(elements: {
        modelId: string;
        elementId: string;
    }[], color: {
        r: number;
        g: number;
        b: number;
    }, isTemporary?: boolean): void;
    clearTemporaryColors(elements?: {
        modelId: string;
        elementId: string;
    }[] | null): void;
    resetColor(elements: {
        modelId: string;
        elementId: string;
    }[] | null, _excepts?: {
        elements: {
            modelId: string;
            elementId: string;
        }[];
        color: {
            r: number;
            g: number;
            b: number;
        };
    }[]): void;
    private _edgeLines;
    private _edgeRanges;
    private _edgeThreshold;
    private _edgeMaterial;
    enableEdgePerElement(material: LineMaterial, thresholdDeg?: number): void;
    disableEdge(): void;
    enableEdge(): void;
    refreshEdgesIfAny(): void;
    private _buildMergedEdges;
    isolateEdge(elements?: {
        modelId: string;
        elementId: string;
    }[]): void;
    hideEdge(elements?: {
        modelId: string;
        elementId: string;
    }[]): void;
    edgeReset(): void;
    getElementBoxs(elements: {
        modelId: string;
        elementId: string;
    }[]): Box3 | null;
    getTotalVertexCount(): number;
    getObjectCount(): number;
    get isBatching(): boolean;
    private _isGeneratedLights;
    private _pointLight;
    enableLights(): void;
    disableLights(): void;
    private _calculateCenter;
    private _getFarthestDistance;
    /**
     * Create a depth-only pre-pass mesh that writes depth ONLY for focused (opaque) elements.
     *
     * Strategy: Build a **separate** geometry containing only focused elements' vertices.
     * A plain Mesh renders this geometry with a depth-only MeshBasicMaterial (colorWrite=false,
     * depthWrite=true). Ghost elements are excluded entirely — their geometry is not in the
     * pre-pass mesh, so they never write depth.
     *
     * This ensures opaque elements correctly occlude what's behind them in the depth buffer,
     * while ghost elements (rendered by the main BatchedMesh with depthWrite=false and
     * transparent=true) blend properly without blocking opaque geometry behind them.
     *
     * Since V3 uses identity transforms (positions are already in world space),
     * the pre-pass mesh renders at the correct positions.
     *
     * **Previous approach** (shared geometry + per-vertex color attribute) was buggy:
     * Adding a `color` attribute to the shared BatchedMesh geometry caused the BatchedMesh
     * shader to recompile with `USE_COLOR`, applying both vertex colors AND batching texture
     * colors simultaneously, corrupting rendering. Also, a plain Mesh cannot properly render
     * BatchedMesh geometry which uses WEBGL_multi_draw with internal draw ranges.
     */
    private _createDepthPrePass;
    private _removeDepthPrePass;
    private _getEffectiveAlpha;
    private _getResetColor;
    /**
     * Check if any element currently has opacity below 1.0 (ghost/semi-transparent).
     */
    private _hasTransparentElements;
    /**
     * Update material transparency state based on current element opacities.
     *
     * For originally-opaque materials (concrete, steel, etc.):
     * - Enables `transparent = true` + `depthWrite = false` for ghost blending
     * - Creates depth pre-pass that writes depth ONLY for focused (opaque) elements
     * - Sets `renderOrder = 1` so the main mesh renders after the depth pre-pass
     *
     * For originally-transparent materials (glass, etc.):
     * - Material is already `transparent = true` + `depthWrite = false`
     * - Ghost elements are handled by per-instance alpha (shader discards alpha < 0.01)
     * - No depth pre-pass needed — transparent materials should never write depth
     * - Material state is NOT changed to avoid making focused elements opaque
     *
     * When all elements are fully opaque:
     * - Restores original material state
     * - Removes the depth pre-pass
     */
    private _updateMaterialTransparency;
    dispose(): void;
}
