/* eslint-disable @typescript-eslint/naming-convention */
import { Vector3 } from "../../Maths/math.vector.js";
import { _CreationDataStorage, Mesh } from "../mesh.js";
import { VertexData } from "../mesh.vertexData.js";
import { LinesMesh } from "../../Meshes/linesMesh.js";
import { VertexBuffer } from "../../Buffers/buffer.js";
import { Logger } from "../../Misc/logger.js";
/**
 * Creates the VertexData of the LineSystem
 * @param options an object used to set the following optional parameters for the LineSystem, required but can be empty
 *  - lines an array of lines, each line being an array of successive Vector3
 *  - colors an array of line colors, each of the line colors being an array of successive Color4, one per line point
 * @returns the VertexData of the LineSystem
 */
export function CreateLineSystemVertexData(options) {
    const indices = [];
    const positions = [];
    const lines = options.lines;
    const colors = options.colors;
    const vertexColors = [];
    let idx = 0;
    for (let l = 0; l < lines.length; l++) {
        const points = lines[l];
        for (let index = 0; index < points.length; index++) {
            const { x, y, z } = points[index];
            positions.push(x, y, z);
            if (colors) {
                const color = colors[l];
                const { r, g, b, a } = color[index];
                vertexColors.push(r, g, b, a);
            }
            if (index > 0) {
                indices.push(idx - 1);
                indices.push(idx);
            }
            idx++;
        }
    }
    const vertexData = new VertexData();
    vertexData.indices = indices;
    vertexData.positions = positions;
    if (colors) {
        vertexData.colors = vertexColors;
    }
    return vertexData;
}
/**
 * Create the VertexData for a DashedLines
 * @param options an object used to set the following optional parameters for the DashedLines, required but can be empty
 *  - points an array successive Vector3
 *  - dashSize the size of the dashes relative to the dash number, optional, default 3
 *  - gapSize the size of the gap between two successive dashes relative to the dash number, optional, default 1
 *  - dashNb the intended total number of dashes, optional, default 200
 * @returns the VertexData for the DashedLines
 */
export function CreateDashedLinesVertexData(options) {
    const dashSize = options.dashSize || 3;
    const gapSize = options.gapSize || 1;
    const dashNb = options.dashNb || 200;
    const points = options.points;
    const positions = [];
    const indices = [];
    const curvect = Vector3.Zero();
    let lg = 0;
    let nb = 0;
    let shft = 0;
    let dashshft = 0;
    let curshft = 0;
    let idx = 0;
    let i = 0;
    for (i = 0; i < points.length - 1; i++) {
        points[i + 1].subtractToRef(points[i], curvect);
        lg += curvect.length();
    }
    shft = lg / dashNb;
    dashshft = (dashSize * shft) / (dashSize + gapSize);
    for (i = 0; i < points.length - 1; i++) {
        points[i + 1].subtractToRef(points[i], curvect);
        nb = Math.floor(curvect.length() / shft);
        curvect.normalize();
        for (let j = 0; j < nb; j++) {
            curshft = shft * j;
            positions.push(points[i].x + curshft * curvect.x, points[i].y + curshft * curvect.y, points[i].z + curshft * curvect.z);
            positions.push(points[i].x + (curshft + dashshft) * curvect.x, points[i].y + (curshft + dashshft) * curvect.y, points[i].z + (curshft + dashshft) * curvect.z);
            indices.push(idx, idx + 1);
            idx += 2;
        }
    }
    // Result
    const vertexData = new VertexData();
    vertexData.positions = positions;
    vertexData.indices = indices;
    return vertexData;
}
/**
 * Creates a line system mesh. A line system is a pool of many lines gathered in a single mesh
 * * A line system mesh is considered as a parametric shape since it has no predefined original shape. Its shape is determined by the passed array of lines as an input parameter
 * * Like every other parametric shape, it is dynamically updatable by passing an existing instance of LineSystem to this static function
 * * The parameter `lines` is an array of lines, each line being an array of successive Vector3
 * * The optional parameter `instance` is an instance of an existing LineSystem object to be updated with the passed `lines` parameter
 * * The optional parameter `colors` is an array of line colors, each line colors being an array of successive Color4, one per line point
 * * The optional parameter `useVertexAlpha` is to be set to `false` (default `true`) when you don't need the alpha blending (faster)
 * * The optional parameter `material` is the material to use to draw the lines if provided. If not, a default material will be created
 * * Updating a simple Line mesh, you just need to update every line in the `lines` array : https://doc.babylonjs.com/features/featuresDeepDive/mesh/dynamicMeshMorph#lines-and-dashedlines
 * * When updating an instance, remember that only line point positions can change, not the number of points, neither the number of lines
 * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created
 * @see https://doc.babylonjs.com/features/featuresDeepDive/mesh/creation/param#line-system
 * @param name defines the name of the new line system
 * @param options defines the options used to create the line system
 * @param scene defines the hosting scene
 * @returns a new line system mesh
 */
export function CreateLineSystem(name, options, scene = null) {
    const instance = options.instance;
    const lines = options.lines;
    const colors = options.colors;
    if (instance) {
        if (options.updateVertexData) {
            const vertexData = CreateLineSystemVertexData(options);
            vertexData.applyToMesh(instance, options.updatable);
            instance.refreshBoundingInfo();
            return instance;
        }
        // lines update
        const indices = [];
        const positions = instance.getVerticesData(VertexBuffer.PositionKind);
        let vertexColor;
        let lineColors;
        if (colors) {
            vertexColor = instance.getVerticesData(VertexBuffer.ColorKind);
        }
        let i = 0;
        let c = 0;
        let idx = 0;
        for (let l = 0; l < lines.length; l++) {
            const points = lines[l];
            for (let p = 0; p < points.length; p++) {
                positions[i] = points[p].x;
                positions[i + 1] = points[p].y;
                positions[i + 2] = points[p].z;
                if (colors && vertexColor) {
                    lineColors = colors[l];
                    vertexColor[c] = lineColors[p].r;
                    vertexColor[c + 1] = lineColors[p].g;
                    vertexColor[c + 2] = lineColors[p].b;
                    vertexColor[c + 3] = lineColors[p].a;
                    c += 4;
                }
                i += 3;
                if (p > 0) {
                    indices.push(idx - 1);
                    indices.push(idx);
                }
                idx++;
            }
        }
        const originIndices = instance.getIndices();
        if (!originIndices || originIndices.length !== indices.length) {
            instance.setIndices(indices, null, options.updatable);
        }
        instance.updateVerticesData(VertexBuffer.PositionKind, positions, false, false);
        if (colors && vertexColor) {
            instance.updateVerticesData(VertexBuffer.ColorKind, vertexColor, false, false);
        }
        instance.refreshBoundingInfo();
        return instance;
    }
    // line system creation
    const useVertexColor = colors ? true : false;
    const lineSystem = new LinesMesh(name, scene, null, undefined, undefined, useVertexColor, options.useVertexAlpha, options.material);
    const vertexData = CreateLineSystemVertexData(options);
    vertexData.applyToMesh(lineSystem, options.updatable);
    return lineSystem;
}
/**
 * Creates a line mesh
 * A line mesh is considered as a parametric shape since it has no predefined original shape. Its shape is determined by the passed array of points as an input parameter
 * * Like every other parametric shape, it is dynamically updatable by passing an existing instance of LineMesh to this static function
 * * The parameter `points` is an array successive Vector3
 * * The optional parameter `instance` is an instance of an existing LineMesh object to be updated with the passed `points` parameter : https://doc.babylonjs.com/features/featuresDeepDive/mesh/dynamicMeshMorph#lines-and-dashedlines
 * * The optional parameter `colors` is an array of successive Color4, one per line point
 * * The optional parameter `useVertexAlpha` is to be set to `false` (default `true`) when you don't need alpha blending (faster)
 * * The optional parameter `material` is the material to use to draw the lines if provided. If not, a default material will be created
 * * When updating an instance, remember that only point positions can change, not the number of points
 * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created
 * @see https://doc.babylonjs.com/features/featuresDeepDive/mesh/creation/param#lines
 * @param name defines the name of the new line system
 * @param options defines the options used to create the line system
 * @param scene defines the hosting scene
 * @returns a new line mesh
 */
export function CreateLines(name, options, scene = null) {
    const colors = options.colors ? [options.colors] : null;
    const lines = CreateLineSystem(name, { lines: [options.points], updatable: options.updatable, instance: options.instance, colors: colors, useVertexAlpha: options.useVertexAlpha, material: options.material }, scene);
    return lines;
}
/**
 * Creates a dashed line mesh
 * * A dashed line mesh is considered as a parametric shape since it has no predefined original shape. Its shape is determined by the passed array of points as an input parameter
 * * Like every other parametric shape, it is dynamically updatable by passing an existing instance of LineMesh to this static function
 * * The parameter `points` is an array successive Vector3
 * * The parameter `dashNb` is the intended total number of dashes (positive integer, default 200)
 * * The parameter `dashSize` is the size of the dashes relatively the dash number (positive float, default 3)
 * * The parameter `gapSize` is the size of the gap between two successive dashes relatively the dash number (positive float, default 1)
 * * The optional parameter `instance` is an instance of an existing LineMesh object to be updated with the passed `points` parameter : https://doc.babylonjs.com/features/featuresDeepDive/mesh/dynamicMeshMorph#lines-and-dashedlines
 * * The optional parameter `useVertexAlpha` is to be set to `false` (default `true`) when you don't need the alpha blending (faster)
 * * The optional parameter `material` is the material to use to draw the lines if provided. If not, a default material will be created
 * * When updating an instance, remember that only point positions can change, not the number of points
 * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created
 * @param name defines the name of the mesh
 * @param options defines the options used to create the mesh
 * @param scene defines the hosting scene
 * @returns the dashed line mesh
 * @see https://doc.babylonjs.com/features/featuresDeepDive/mesh/creation/param#dashed-lines
 */
export function CreateDashedLines(name, options, scene = null) {
    const points = options.points;
    const instance = options.instance;
    const gapSize = options.gapSize || 1;
    const dashSize = options.dashSize || 3;
    if (instance) {
        //  dashed lines update
        const positionFunction = (positions) => {
            const curvect = Vector3.Zero();
            const nbSeg = positions.length / 6;
            let lg = 0;
            let nb = 0;
            let shft = 0;
            let dashshft = 0;
            let curshft = 0;
            let p = 0;
            let i = 0;
            let j = 0;
            for (i = 0; i < points.length - 1; i++) {
                points[i + 1].subtractToRef(points[i], curvect);
                lg += curvect.length();
            }
            shft = lg / nbSeg;
            const dashSize = instance._creationDataStorage.dashSize;
            const gapSize = instance._creationDataStorage.gapSize;
            dashshft = (dashSize * shft) / (dashSize + gapSize);
            for (i = 0; i < points.length - 1; i++) {
                points[i + 1].subtractToRef(points[i], curvect);
                nb = Math.floor(curvect.length() / shft);
                curvect.normalize();
                j = 0;
                while (j < nb && p < positions.length) {
                    curshft = shft * j;
                    positions[p] = points[i].x + curshft * curvect.x;
                    positions[p + 1] = points[i].y + curshft * curvect.y;
                    positions[p + 2] = points[i].z + curshft * curvect.z;
                    positions[p + 3] = points[i].x + (curshft + dashshft) * curvect.x;
                    positions[p + 4] = points[i].y + (curshft + dashshft) * curvect.y;
                    positions[p + 5] = points[i].z + (curshft + dashshft) * curvect.z;
                    p += 6;
                    j++;
                }
            }
            while (p < positions.length) {
                positions[p] = points[i].x;
                positions[p + 1] = points[i].y;
                positions[p + 2] = points[i].z;
                p += 3;
            }
        };
        if (options.dashNb || options.dashSize || options.gapSize || options.useVertexAlpha || options.material) {
            Logger.Warn("You have used an option other than points with the instance option. Please be aware that these other options will be ignored.");
        }
        instance.updateMeshPositions(positionFunction, false);
        return instance;
    }
    // dashed lines creation
    const dashedLines = new LinesMesh(name, scene, null, undefined, undefined, undefined, options.useVertexAlpha, options.material);
    const vertexData = CreateDashedLinesVertexData(options);
    vertexData.applyToMesh(dashedLines, options.updatable);
    dashedLines._creationDataStorage = new _CreationDataStorage();
    dashedLines._creationDataStorage.dashSize = dashSize;
    dashedLines._creationDataStorage.gapSize = gapSize;
    return dashedLines;
}
/**
 * Class containing static functions to help procedurally build meshes
 * @deprecated use the functions directly from the module
 */
export const LinesBuilder = {
    CreateDashedLines,
    CreateLineSystem,
    CreateLines,
};
VertexData.CreateLineSystem = CreateLineSystemVertexData;
VertexData.CreateDashedLines = CreateDashedLinesVertexData;
Mesh.CreateLines = (name, points, scene = null, updatable = false, instance = null) => {
    const options = {
        points,
        updatable,
        instance,
    };
    return CreateLines(name, options, scene);
};
Mesh.CreateDashedLines = (name, points, dashSize, gapSize, dashNb, scene = null, updatable, instance) => {
    const options = {
        points,
        dashSize,
        gapSize,
        dashNb,
        updatable,
        instance,
    };
    return CreateDashedLines(name, options, scene);
};
//# sourceMappingURL=linesBuilder.js.map