"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module Rendering
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.IndexBuffer = void 0;
exports.splitPointStringParams = splitPointStringParams;
exports.splitMeshParams = splitMeshParams;
exports.splitPolylineParams = splitPolylineParams;
const core_bentley_1 = require("@itwin/core-bentley");
const core_common_1 = require("@itwin/core-common");
const EdgeParams_1 = require("./EdgeParams");
const VertexTable_1 = require("./VertexTable");
const VertexIndices_1 = require("./VertexIndices");
const SurfaceParams_1 = require("./SurfaceParams");
/** Builds up a [[VertexIndices]].
 * Exported strictly for tests.
 * @internal
 */
class IndexBuffer {
    constructor(initialCapacity = 3) {
        this._index32 = new Uint32Array(1);
        this._index8 = new Uint8Array(this._index32.buffer, 0, 3);
        this._builder = new core_bentley_1.Uint8ArrayBuilder({ initialCapacity: initialCapacity * 3 });
    }
    get numIndices() {
        (0, core_bentley_1.assert)((this._builder.length % 3) === 0);
        return this._builder.length / 3;
    }
    push(index) {
        this._index32[0] = index;
        this._builder.append(this._index8);
    }
    toVertexIndices() {
        return new VertexIndices_1.VertexIndices(this._builder.toTypedArray());
    }
}
exports.IndexBuffer = IndexBuffer;
/** Builds up a [[VertexTable]]. */
class VertexBuffer {
    /** `source` is the original table containing the vertex data from which individual vertices will be obtained. */
    constructor(source) {
        this._source = source;
        this._builder = new core_bentley_1.Uint32ArrayBuilder({ initialCapacity: 3 * source.numRgbaPerVertex });
    }
    /** The number of vertices currently in the table. */
    get length() {
        (0, core_bentley_1.assert)((this._builder.length % this.vertexSize) === 0);
        return this._builder.length / this.vertexSize;
    }
    /** The number of 32-bit unsigned integers (RGBA values) per vertex. */
    get vertexSize() {
        return this._source.numRgbaPerVertex;
    }
    /** Append a vertex. `vertex` must be of size [[vertexSize]]. */
    push(vertex) {
        (0, core_bentley_1.assert)(vertex.length === this.vertexSize);
        this._builder.append(vertex);
    }
    /** Construct the finished vertex table. */
    buildVertexTable(maxDimension, colorTable, materialAtlasTable) {
        const source = this._source;
        colorTable = colorTable ?? source.uniformColor;
        (0, core_bentley_1.assert)(undefined !== colorTable);
        const colorTableLength = colorTable instanceof Uint32Array ? colorTable.length : 0;
        const materialAtlasTableLength = materialAtlasTable instanceof Uint32Array ? materialAtlasTable.length : 0;
        const dimensions = (0, VertexTable_1.computeDimensions)(this.length, this.vertexSize, colorTableLength + materialAtlasTableLength, maxDimension);
        let rgbaData = this._builder.toTypedArray();
        if (dimensions.width * dimensions.height > rgbaData.length) {
            const prevData = rgbaData;
            rgbaData = new Uint32Array(dimensions.width * dimensions.height);
            rgbaData.set(prevData, 0);
        }
        let tableSize = this.vertexSize * this.length;
        if (colorTable instanceof Uint32Array) {
            rgbaData.set(colorTable, tableSize);
            tableSize += colorTable.length;
        }
        if (materialAtlasTable instanceof Uint32Array)
            rgbaData.set(materialAtlasTable, tableSize);
        return {
            data: new Uint8Array(rgbaData.buffer, rgbaData.byteOffset, rgbaData.byteLength),
            usesUnquantizedPositions: source.usesUnquantizedPositions,
            qparams: source.qparams,
            width: dimensions.width,
            height: dimensions.height,
            hasTranslucency: source.hasTranslucency,
            uniformColor: colorTable instanceof core_common_1.ColorDef ? colorTable : undefined,
            featureIndexType: source.featureIndexType,
            uniformFeatureID: source.uniformFeatureID,
            numVertices: this.length,
            numRgbaPerVertex: source.numRgbaPerVertex,
            uvParams: source.uvParams,
        };
    }
}
/** Remaps portions of a source color table into a filtered target color table. */
class ColorTableRemapper {
    constructor(colorTable) {
        this._remappedIndices = new Map();
        this.colors = [];
        this._32 = new Uint32Array(1);
        this._16 = new Uint16Array(this._32.buffer);
        this._colorTable = colorTable;
    }
    /** Extract the color index stored in `vertex`, ensure it is present in the remapped color table, and return its index in that table. */
    remap(vertex, usesUnquantizedPositions) {
        const vertIndex = usesUnquantizedPositions ? 4 : 1;
        const shortIndex = usesUnquantizedPositions ? 0 : 1;
        this._32[0] = vertex[vertIndex];
        const oldIndex = this._16[shortIndex];
        let newIndex = this._remappedIndices.get(oldIndex);
        if (undefined === newIndex) {
            newIndex = this.colors.length;
            this._remappedIndices.set(oldIndex, newIndex);
            const color = this._colorTable[oldIndex];
            this.colors.push(color);
        }
        this._16[shortIndex] = newIndex;
        vertex[vertIndex] = this._32[0];
    }
    /** Construct the finished color table. */
    buildColorTable() {
        (0, core_bentley_1.assert)(this.colors.length > 0);
        return this.colors.length > 1 ? new Uint32Array(this.colors) : core_common_1.ColorDef.fromAbgr(this.colors[0]);
    }
}
class MaterialAtlasRemapper {
    constructor(_atlasTable, createMaterial) {
        this._remappedIndices = new Map();
        this.materials = [];
        this._32 = new Uint32Array(1);
        this._8 = new Uint8Array(this._32.buffer);
        this._atlasTable = _atlasTable;
        this._createMaterial = createMaterial;
    }
    /** Extract the mat index stored in `vertex`, ensure it is present in the remapped atlas table, and return its index in that table. */
    remap(vertex, usesUnquantizedPositions) {
        const vertIndex = usesUnquantizedPositions ? 3 : 2;
        this._32[0] = vertex[vertIndex];
        const oldIndex = this._8[3];
        let newIndex = this._remappedIndices.get(oldIndex);
        if (undefined === newIndex) {
            newIndex = this.materials.length / 4;
            this._remappedIndices.set(oldIndex, newIndex);
            let index = oldIndex * 4;
            this.materials.push(this._atlasTable[index++]);
            this.materials.push(this._atlasTable[index++]);
            this.materials.push(this._atlasTable[index++]);
            this.materials.push(this._atlasTable[index]);
        }
        this._8[3] = newIndex;
        vertex[vertIndex] = this._32[0];
    }
    unpackFloat(value) {
        this._32[0] = value;
        const valUint32 = this._32[0];
        const bias = 38.0;
        const temp = (valUint32 >>> 24) / 2.0;
        let exponent = Math.floor(temp);
        let sign = (temp - exponent) * 2.0;
        sign = -(sign * 2.0 - 1.0);
        const base = sign * (valUint32 & 0xffffff) / 16777216.0;
        exponent = exponent - bias;
        return base * Math.pow(10.0, exponent);
    }
    materialFromAtlasEntry(entry) {
        const rgbOverridden = (entry[1] & 0x1000000) !== 0;
        const alphaOverridden = (entry[1] & 0x2000000) !== 0;
        const args = {
            alpha: alphaOverridden ? (entry[0] >>> 24) / 255.0 : undefined,
            diffuse: {
                color: rgbOverridden ? core_common_1.ColorDef.fromTbgr(entry[0] & 0xffffff) : undefined,
                weight: ((entry[1] >>> 8) & 0xff) / 255.0,
            },
            specular: {
                color: core_common_1.ColorDef.fromTbgr(entry[2]),
                weight: ((entry[1] >>> 16) & 0xff) / 255.0,
                exponent: this.unpackFloat(entry[3]),
            },
        };
        const material = this._createMaterial(args);
        return (0, SurfaceParams_1.createSurfaceMaterial)(material);
    }
    /** Construct the finished color table. */
    buildAtlasTable() {
        (0, core_bentley_1.assert)(this.materials.length > 0);
        const m = new Uint32Array(this.materials);
        return this.materials.length > 4 ? m : this.materialFromAtlasEntry(m);
    }
}
/** A node in a split vertex table. Each node corresponds to one or more elements. */
class Node {
    /** `vertexTable` is the source table containing vertex data for all nodes, from which this node will extract the vertices belong to it. */
    constructor(vertexTable, atlas) {
        this.remappedIndices = new Map();
        this.indices = new IndexBuffer();
        this.vertices = new VertexBuffer(vertexTable);
        if (undefined === vertexTable.uniformColor)
            this.colors = new ColorTableRemapper(new Uint32Array(vertexTable.data.buffer, vertexTable.data.byteOffset + 4 * vertexTable.numVertices * vertexTable.numRgbaPerVertex));
        if (atlas) {
            const atlasOffset = (vertexTable.numVertices * vertexTable.numRgbaPerVertex + atlas.offset) * 4;
            this.atlas = new MaterialAtlasRemapper(new Uint32Array(vertexTable.data.buffer, vertexTable.data.byteOffset + atlasOffset), atlas.createMaterial);
        }
        this.usesUnquantizedPositions = vertexTable.usesUnquantizedPositions;
    }
    addVertex(originalIndex, vertex) {
        let newIndex = this.remappedIndices.get(originalIndex);
        if (undefined === newIndex) {
            newIndex = this.vertices.length;
            this.remappedIndices.set(originalIndex, newIndex);
            this.colors?.remap(vertex, this.usesUnquantizedPositions);
            this.atlas?.remap(vertex, this.usesUnquantizedPositions);
            this.vertices.push(vertex);
        }
        this.indices.push(newIndex);
    }
    buildOutput(maxDimension, surfaceMaterial) {
        const materialAtlas = this.atlas?.buildAtlasTable();
        let material;
        if (materialAtlas instanceof Uint32Array) {
            const colorTableOffset = undefined !== this.colors?.colors.length && this.colors?.colors.length > 1 ? this.colors?.colors.length : 0;
            material = {
                isAtlas: true,
                hasTranslucency: (surfaceMaterial?.isAtlas && surfaceMaterial?.hasTranslucency) ?? false,
                overridesAlpha: (surfaceMaterial?.isAtlas && surfaceMaterial?.overridesAlpha) ?? false,
                vertexTableOffset: colorTableOffset,
                numMaterials: materialAtlas.length / 4,
            };
        }
        else {
            material = materialAtlas;
        }
        return {
            indices: this.indices.toVertexIndices(),
            vertices: this.vertices.buildVertexTable(maxDimension, this.colors?.buildColorTable(), materialAtlas),
            material,
        };
    }
}
class VertexTableSplitter {
    constructor(input, computeNodeId) {
        this._nodes = new Map();
        this._input = input;
        this._computeNodeId = computeNodeId;
    }
    /** Split the source into one or more output nodes, returning a mapping of integer node Id to node. */
    static split(source, computeNodeId) {
        const splitter = new VertexTableSplitter(source, computeNodeId);
        splitter.split();
        return splitter._nodes;
    }
    split() {
        // Track the most recent feature and corresponding node to avoid repeated lookups - vertices for
        // individual features are largely contiguous.
        const curState = {
            featureIndex: -1,
            node: undefined,
        };
        const vertSize = this._input.vertices.numRgbaPerVertex;
        const vertex = new Uint32Array(vertSize);
        const vertexTable = new Uint32Array(this._input.vertices.data.buffer, this._input.vertices.data.byteOffset, this._input.vertices.numVertices * vertSize);
        let extractFeatureIndex;
        if (this._input.vertices.usesUnquantizedPositions) {
            const vertexBytes = new Uint8Array(vertex.buffer);
            extractFeatureIndex = () => {
                return vertexBytes[3]
                    | (vertexBytes[7] << 8)
                    | (vertexBytes[11] << 16);
            };
        }
        else {
            extractFeatureIndex = () => vertex[2] & 0x00ffffff;
        }
        for (const index of this._input.indices) {
            // Extract the data for this vertex without allocating new typed arrays.
            const vertexOffset = index * vertSize;
            for (let i = 0; i < vertex.length; i++)
                vertex[i] = vertexTable[vertexOffset + i];
            // Determine to which element the vertex belongs and find the corresponding Node.
            const featureIndex = extractFeatureIndex();
            if (curState.featureIndex !== featureIndex) {
                curState.featureIndex = featureIndex;
                const nodeId = this._computeNodeId(featureIndex);
                let node = this._nodes.get(nodeId);
                if (undefined === node)
                    this._nodes.set(nodeId, node = new Node(this._input.vertices, this._input.atlasInfo));
                curState.node = node;
            }
            // Add the vertex to the appropriate node.
            curState.node.addVertex(index, vertex);
        }
    }
}
/** Given a PointStringParams and a function that can associate a node Id with an element Id, produce a mapping of nodes to PointStringParams, splitting up
 * the input params as needed.
 * @internal
 */
function splitPointStringParams(args) {
    const nodes = VertexTableSplitter.split({
        indices: args.params.indices,
        vertices: args.params.vertices,
        featureTable: args.featureTable,
    }, args.computeNodeId);
    const result = new Map();
    for (const [id, node] of nodes) {
        const { vertices, indices } = node.buildOutput(args.maxDimension);
        result.set(id, { vertices, indices, weight: args.params.weight });
    }
    return result;
}
class RemappedPolylineEdges {
    constructor() {
        this.indices = new IndexBuffer();
        this.prevIndices = new IndexBuffer();
        this.nextIndicesAndParams = new core_bentley_1.Uint32ArrayBuilder();
    }
}
function remapIndex(out, srcIndex, nodes) {
    for (const [id, node] of nodes) {
        const index = node.remappedIndices.get(srcIndex);
        if (undefined !== index) {
            out.index = index;
            out.node = node;
            out.id = id;
            return true;
        }
    }
    (0, core_bentley_1.assert)(false);
    return false;
}
function remapSegmentEdges(type, source, nodes, edges) {
    const src = source[type];
    if (!src)
        return;
    const srcEndPts = new Uint32Array(src.endPointAndQuadIndices.buffer, src.endPointAndQuadIndices.byteOffset, src.endPointAndQuadIndices.length / 4);
    let srcNormalPairs;
    if (type === "silhouettes") {
        (0, core_bentley_1.assert)(undefined !== source.silhouettes);
        srcNormalPairs = new Uint32Array(source.silhouettes.normalPairs.buffer, source.silhouettes.normalPairs.byteOffset, source.silhouettes.normalPairs.length / 4);
    }
    let curIndexIndex = 0;
    const remappedIndex = {};
    for (const srcIndex of src.indices) {
        if (remapIndex(remappedIndex, srcIndex, nodes)) {
            let endPointAndQuad = srcEndPts[curIndexIndex];
            const otherIndex = (endPointAndQuad & 0x00ffffff) >>> 0;
            const newOtherIndex = remappedIndex.node.remappedIndices.get(otherIndex);
            (0, core_bentley_1.assert)(undefined !== newOtherIndex);
            endPointAndQuad = (endPointAndQuad & 0xff000000) | newOtherIndex;
            let entry = edges.get(remappedIndex.id);
            if (!entry)
                edges.set(remappedIndex.id, entry = {});
            if (srcNormalPairs) {
                if (!entry.silhouettes)
                    entry.silhouettes = { indices: new IndexBuffer(), endPointAndQuadIndices: new core_bentley_1.Uint32ArrayBuilder(), normalPairs: new core_bentley_1.Uint32ArrayBuilder() };
                entry.silhouettes.normalPairs.push(srcNormalPairs[curIndexIndex]);
            }
            else if (!entry.segments) {
                entry.segments = { indices: new IndexBuffer(), endPointAndQuadIndices: new core_bentley_1.Uint32ArrayBuilder() };
            }
            const segments = entry[type];
            (0, core_bentley_1.assert)(undefined !== segments);
            segments.indices.push(remappedIndex.index);
            segments.endPointAndQuadIndices.push(endPointAndQuad);
        }
        ++curIndexIndex;
    }
}
function remapPolylineEdges(src, nodes, edges) {
    const srcNextAndParam = new Uint32Array(src.nextIndicesAndParams.buffer, src.nextIndicesAndParams.byteOffset, src.nextIndicesAndParams.length / 4);
    const prevIter = src.prevIndices[Symbol.iterator]();
    let curIndexIndex = 0;
    const remappedIndex = {};
    for (const srcIndex of src.indices) {
        if (remapIndex(remappedIndex, srcIndex, nodes)) {
            const prevIndex = prevIter.next().value;
            (0, core_bentley_1.assert)(undefined !== prevIndex);
            const newPrevIndex = remappedIndex.node.remappedIndices.get(prevIndex);
            (0, core_bentley_1.assert)(undefined !== newPrevIndex);
            let nextAndParam = srcNextAndParam[curIndexIndex];
            const nextIndex = (nextAndParam & 0x00ffffff) >>> 0;
            const newNextIndex = remappedIndex.node.remappedIndices.get(nextIndex);
            (0, core_bentley_1.assert)(undefined !== newNextIndex);
            nextAndParam = (nextAndParam & 0xff000000) | newNextIndex;
            let entry = edges.get(remappedIndex.id);
            if (!entry)
                edges.set(remappedIndex.id, entry = {});
            if (!entry.polylines)
                entry.polylines = new RemappedPolylineEdges();
            entry.polylines.indices.push(remappedIndex.index);
            entry.polylines.prevIndices.push(newPrevIndex);
            entry.polylines.nextIndicesAndParams.push(nextAndParam);
        }
        ++curIndexIndex;
    }
}
function remapIndexedEdges(src, nodes, edges) {
    const srcEdgeData = src.edges.data;
    const numSegments = src.edges.numSegments;
    const silhouetteStartByteIndex = numSegments * 6 + src.edges.silhouettePadding;
    function getUint24EdgePair(byteIndex) {
        return [srcEdgeData[byteIndex + 0] | (srcEdgeData[byteIndex + 1] << 8) | srcEdgeData[byteIndex + 2] << 16,
            srcEdgeData[byteIndex + 3] | (srcEdgeData[byteIndex + 4] << 8) | srcEdgeData[byteIndex + 5] << 16];
    }
    function setUint24EdgePair(indEdges, value1, value2) {
        indEdges.edges.push(value1 & 0x0000ff);
        indEdges.edges.push((value1 & 0x00ff00) >>> 8);
        indEdges.edges.push((value1 & 0xff0000) >>> 16);
        indEdges.edges.push(value2 & 0x0000ff);
        indEdges.edges.push((value2 & 0x00ff00) >>> 8);
        indEdges.edges.push((value2 & 0xff0000) >>> 16);
    }
    function getUint24SilPair(byteIndex) {
        return [srcEdgeData[byteIndex + 0] | (srcEdgeData[byteIndex + 1] << 8) | srcEdgeData[byteIndex + 2] << 16,
            srcEdgeData[byteIndex + 3] | (srcEdgeData[byteIndex + 4] << 8) | srcEdgeData[byteIndex + 5] << 16,
            srcEdgeData[byteIndex + 6] | (srcEdgeData[byteIndex + 7] << 8), srcEdgeData[byteIndex + 8] | (srcEdgeData[byteIndex + 9] << 8)];
    }
    function setUint24SilPair(indSil, value1, value2, norm1, norm2) {
        indSil.silhouettes.push(value1 & 0x0000ff);
        indSil.silhouettes.push((value1 & 0x00ff00) >>> 8);
        indSil.silhouettes.push((value1 & 0xff0000) >>> 16);
        indSil.silhouettes.push(value2 & 0x0000ff);
        indSil.silhouettes.push((value2 & 0x00ff00) >>> 8);
        indSil.silhouettes.push((value2 & 0xff0000) >>> 16);
        indSil.silhouettes.push(norm1 & 0x0000ff);
        indSil.silhouettes.push((norm1 & 0x00ff00) >>> 8);
        indSil.silhouettes.push(norm2 & 0x0000ff);
        indSil.silhouettes.push((norm2 & 0x00ff00) >>> 8);
    }
    let maxIndex = 0;
    for (const srcIndex of src.indices)
        maxIndex = Math.max(srcIndex, maxIndex);
    const remappedIndex = {};
    let es1Index = 0, es2Index = 0, n1 = 0, n2 = 0;
    for (let curSegment = 0, byteIndex = 0; curSegment <= maxIndex; ++curSegment) {
        if (curSegment < numSegments) { // edges
            [es1Index, es2Index] = getUint24EdgePair(byteIndex);
            byteIndex += 6;
        }
        else { // silhouettes
            byteIndex = silhouetteStartByteIndex + (curSegment - numSegments) * 10;
            [es1Index, es2Index, n1, n2] = getUint24SilPair(byteIndex);
        }
        if (remapIndex(remappedIndex, es1Index, nodes)) {
            let entry = edges.get(remappedIndex.id);
            if (!entry)
                edges.set(remappedIndex.id, entry = {});
            if (!entry.indexed)
                entry.indexed = { edges: new core_bentley_1.Uint8ArrayBuilder(), silhouettes: new core_bentley_1.Uint8ArrayBuilder() };
            if (curSegment < numSegments) { // edges
                const newE1Index = remappedIndex.node.remappedIndices.get(es1Index);
                (0, core_bentley_1.assert)(undefined !== newE1Index);
                const newE2Index = remappedIndex.node.remappedIndices.get(es2Index);
                (0, core_bentley_1.assert)(undefined !== newE2Index);
                setUint24EdgePair(entry.indexed, newE1Index, newE2Index);
            }
            else { // silhouettes
                const newS1Index = remappedIndex.node.remappedIndices.get(es1Index);
                (0, core_bentley_1.assert)(undefined !== newS1Index);
                const newS2Index = remappedIndex.node.remappedIndices.get(es2Index);
                (0, core_bentley_1.assert)(undefined !== newS2Index);
                setUint24SilPair(entry.indexed, newS1Index, newS2Index, n1, n2);
            }
        }
    }
}
function splitEdges(source, nodes, maxDimension) {
    const edges = new Map();
    remapSegmentEdges("segments", source, nodes, edges);
    remapSegmentEdges("silhouettes", source, nodes, edges);
    if (source.polylines)
        remapPolylineEdges(source.polylines, nodes, edges);
    if (source.indexed)
        remapIndexedEdges(source.indexed, nodes, edges);
    const result = new Map();
    for (const [id, remappedEdges] of edges) {
        if (!remappedEdges.segments && !remappedEdges.silhouettes && !remappedEdges.indexed)
            continue;
        let edgeTable = {};
        let edgeIndices = {};
        if (remappedEdges.indexed) {
            const numSegmentEdges = remappedEdges.indexed.edges.length / 6;
            const numSilhouettes = remappedEdges.indexed.silhouettes.length / 10;
            const { width, height, silhouettePadding, silhouetteStartByteIndex } = (0, EdgeParams_1.calculateEdgeTableParams)(numSegmentEdges, numSilhouettes, maxDimension);
            const data = new Uint8Array(width * height * 4);
            data.set(remappedEdges.indexed.edges.toTypedArray(), 0);
            if (numSilhouettes > 0)
                data.set(remappedEdges.indexed.silhouettes.toTypedArray(), silhouetteStartByteIndex + silhouettePadding);
            const numTotalEdges = numSegmentEdges + numSilhouettes;
            edgeIndices = new VertexIndices_1.VertexIndices(new Uint8Array(numTotalEdges * 6 * 3));
            for (let i = 0; i < numTotalEdges; i++)
                for (let j = 0; j < 6; j++)
                    edgeIndices.setNthIndex(i * 6 + j, i);
            edgeTable = {
                data,
                width,
                height,
                numSegments: numSegmentEdges,
                silhouettePadding,
            };
        }
        result.set(id, {
            weight: source.weight,
            linePixels: source.linePixels,
            segments: remappedEdges.segments ? {
                indices: remappedEdges.segments.indices.toVertexIndices(),
                endPointAndQuadIndices: remappedEdges.segments.endPointAndQuadIndices.toUint8Array(),
            } : undefined,
            silhouettes: remappedEdges.silhouettes ? {
                indices: remappedEdges.silhouettes.indices.toVertexIndices(),
                endPointAndQuadIndices: remappedEdges.silhouettes.endPointAndQuadIndices.toUint8Array(),
                normalPairs: remappedEdges.silhouettes.normalPairs.toUint8Array(),
            } : undefined,
            polylines: remappedEdges.polylines ? {
                indices: remappedEdges.polylines.indices.toVertexIndices(),
                prevIndices: remappedEdges.polylines.prevIndices.toVertexIndices(),
                nextIndicesAndParams: remappedEdges.polylines.nextIndicesAndParams.toUint8Array(),
            } : undefined,
            indexed: remappedEdges.indexed ? {
                indices: edgeIndices,
                edges: edgeTable,
            } : undefined,
        });
    }
    return result;
}
/** @internal */
function splitMeshParams(args) {
    const result = new Map();
    const mat = args.params.surface.material;
    const atlasOffset = undefined !== mat && mat.isAtlas ? mat.vertexTableOffset : undefined;
    const atlasInfo = undefined !== atlasOffset ? { offset: atlasOffset, createMaterial: args.createMaterial } : undefined;
    const nodes = VertexTableSplitter.split({
        indices: args.params.surface.indices,
        vertices: args.params.vertices,
        featureTable: args.featureTable,
        atlasInfo,
    }, args.computeNodeId);
    const edges = args.params.edges ? splitEdges(args.params.edges, nodes, args.maxDimension) : undefined;
    for (const [id, node] of nodes) {
        const { vertices, indices, material } = node.buildOutput(args.maxDimension, args.params.surface.material);
        const params = {
            vertices,
            surface: {
                type: args.params.surface.type,
                indices,
                fillFlags: args.params.surface.fillFlags,
                hasBakedLighting: args.params.surface.hasBakedLighting,
                textureMapping: args.params.surface.textureMapping,
                material: material !== undefined ? material : args.params.surface.material,
            },
            edges: edges?.get(id),
            isPlanar: args.params.isPlanar,
            // ###TODO handle aux channels.......
            auxChannels: args.params.auxChannels,
        };
        result.set(id, params);
    }
    return result;
}
/** @internal */
function splitPolylineParams(args) {
    const nodes = VertexTableSplitter.split({
        indices: args.params.polyline.indices,
        vertices: args.params.vertices,
        featureTable: args.featureTable,
    }, args.computeNodeId);
    const src = args.params.polyline;
    const srcNextAndParam = new Uint32Array(src.nextIndicesAndParams.buffer, src.nextIndicesAndParams.byteOffset, src.nextIndicesAndParams.length / 4);
    let curIndexIndex = 0;
    const remappedIndex = {};
    for (const prevIndex of src.prevIndices) {
        if (remapIndex(remappedIndex, prevIndex, nodes)) {
            const node = remappedIndex.node;
            if (!node.prevIndices) {
                (0, core_bentley_1.assert)(undefined === node.nextIndicesAndParams);
                node.prevIndices = new IndexBuffer(node.indices.numIndices);
                node.nextIndicesAndParams = new core_bentley_1.Uint32ArrayBuilder({ initialCapacity: node.indices.numIndices });
            }
            else {
                (0, core_bentley_1.assert)(undefined !== node.nextIndicesAndParams);
            }
            node.prevIndices.push(remappedIndex.index);
            let nextAndParam = srcNextAndParam[curIndexIndex];
            const nextIndex = (nextAndParam & 0x00ffffff) >>> 0;
            const newNextIndex = remappedIndex.node.remappedIndices.get(nextIndex);
            (0, core_bentley_1.assert)(undefined !== newNextIndex);
            nextAndParam = (nextAndParam & 0xff000000) | newNextIndex;
            node.nextIndicesAndParams.push(nextAndParam);
        }
        ++curIndexIndex;
    }
    const result = new Map();
    for (const [id, node] of nodes) {
        (0, core_bentley_1.assert)(undefined !== node.prevIndices && undefined !== node.nextIndicesAndParams);
        const { vertices, indices } = node.buildOutput(args.maxDimension);
        const params = {
            ...args.params,
            vertices,
            polyline: {
                indices,
                prevIndices: node.prevIndices.toVertexIndices(),
                nextIndicesAndParams: node.nextIndicesAndParams.toUint8Array(),
            },
        };
        result.set(id, params);
    }
    return result;
}
//# sourceMappingURL=VertexTableSplitter.js.map