"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
 */
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PrimitiveBuilder = void 0;
const core_geometry_1 = require("@itwin/core-geometry");
const core_common_1 = require("@itwin/core-common");
const GraphicBuilder_1 = require("../../render/GraphicBuilder");
const GraphicBranch_1 = require("../../render/GraphicBranch");
const core_bentley_1 = require("@itwin/core-bentley");
const Symbols_1 = require("../../common/internal/Symbols");
const GraphicTemplate_1 = require("../../render/GraphicTemplate");
/** @internal */
class PrimitiveBuilder extends GraphicBuilder_1.GraphicBuilder {
    constructor(system, options) {
        super(options);
        this[_a] = undefined;
        this.primitives = [];
        this.system = system;
        this._options = options;
        this._viewIndependentOrigin = options.viewIndependentOrigin?.clone();
    }
    finish() {
        const template = this.toTemplate(false);
        const graphic = this.system.createGraphicFromTemplate({ template });
        return graphic ?? this.system.createGraphicList([]);
    }
    finishTemplate() {
        return this.toTemplate(true);
    }
    toTemplate(noDispose) {
        const accum = this[Symbols_1._accumulator];
        const tolerance = this.computeTolerance(accum);
        const result = this.saveToTemplate(this, tolerance, this.pickable, noDispose);
        accum.clear();
        return result ?? (0, GraphicTemplate_1.createGraphicTemplate)({ nodes: [], noDispose });
    }
    computeTolerance(accum) {
        return this._computeChordTolerance({
            graphic: this,
            computeRange: () => accum.geometries.computeRange(),
        });
    }
    resolveGradient(gradient) {
        return this.system.getGradientTexture(gradient, this.iModel);
    }
    /**
     * Populate a list of Graphic objects from the accumulated Geometry objects.
     * removed ViewContext
     */
    saveToGraphicList(graphics, options, tolerance, pickable) {
        const meshes = this[Symbols_1._accumulator].toMeshes(options, tolerance, pickable);
        if (0 === meshes.length)
            return undefined;
        // If the meshes contain quantized positions, they are all quantized to the same range. If that range is small relative to the distance
        // from the origin, quantization errors can produce display artifacts. Remove the translation from the quantization parameters and apply
        // it in the transform instead.
        //
        // If the positions are not quantized, they have already been transformed to be relative to the center of the meshes' range.
        // Apply the inverse translation to put them back into model space.
        const branch = new GraphicBranch_1.GraphicBranch(true);
        let transformOrigin;
        let meshesRangeOffset = false;
        for (const mesh of meshes) {
            const verts = mesh.points;
            if (branch.isEmpty) {
                if (verts instanceof core_common_1.QPoint3dList) {
                    transformOrigin = verts.params.origin.clone();
                    verts.params.origin.setZero();
                }
                else {
                    transformOrigin = verts.range.center;
                    // In this case we need to modify the qOrigin of the graphic that will get created later since we have translated the origin.
                    // We can't modify it directly, but if we temporarily modify the range of the mesh used to create it the qOrigin will get created properly.
                    // Range is shared (not cloned) by all meshes and the mesh list itself, so modifying the range of the meshlist will modify it for all meshes.
                    // We will then later add this offset back to the range once all of the graphics have been created because it is needed unmodified for locate.
                    if (!meshesRangeOffset) {
                        meshes.range?.low.subtractInPlace(transformOrigin);
                        meshes.range?.high.subtractInPlace(transformOrigin);
                        meshesRangeOffset = true;
                    }
                }
            }
            else {
                (0, core_bentley_1.assert)(undefined !== transformOrigin);
                if (verts instanceof core_common_1.QPoint3dList) {
                    (0, core_bentley_1.assert)(transformOrigin.isAlmostEqual(verts.params.origin));
                    verts.params.origin.setZero();
                }
                else {
                    (0, core_bentley_1.assert)(verts.range.center.isAlmostZero);
                }
            }
            const graphic = this.system.createMeshGraphics(mesh, this._viewIndependentOrigin);
            if (graphic)
                branch.add(graphic);
        }
        if (!branch.isEmpty) {
            (0, core_bentley_1.assert)(undefined !== transformOrigin);
            const transform = core_geometry_1.Transform.createTranslation(transformOrigin);
            graphics.push(this.system.createBranch(branch, transform));
            if (meshesRangeOffset) { // restore the meshes range that we modified earlier.
                meshes.range?.low.addInPlace(transformOrigin);
                meshes.range?.high.addInPlace(transformOrigin);
            }
        }
        return meshes;
    }
    saveToTemplate(options, tolerance, pickable, noDispose) {
        const meshes = this[Symbols_1._accumulator].toMeshes(options, tolerance, pickable);
        if (0 === meshes.length)
            return undefined;
        // If the meshes contain quantized positions, they are all quantized to the same range. If that range is small relative to the distance
        // from the origin, quantization errors can produce display artifacts. Remove the translation from the quantization parameters and apply
        // it in the transform instead.
        //
        // If the positions are not quantized, they have already been transformed to be relative to the center of the meshes' range.
        // Apply the inverse translation to put them back into model space.
        let transformOrigin;
        let meshesRangeOffset = false;
        const geometry = [];
        for (const mesh of meshes) {
            const verts = mesh.points;
            if (!transformOrigin) {
                if (verts instanceof core_common_1.QPoint3dList) {
                    transformOrigin = verts.params.origin.clone();
                    verts.params.origin.setZero();
                }
                else {
                    transformOrigin = verts.range.center;
                    // In this case we need to modify the qOrigin of the graphic that will get created later since we have translated the origin.
                    // We can't modify it directly, but if we temporarily modify the range of the mesh used to create it the qOrigin will get created properly.
                    // Range is shared (not cloned) by all meshes and the mesh list itself, so modifying the range of the meshlist will modify it for all meshes.
                    // We will then later add this offset back to the range once all of the graphics have been created because it is needed unmodified for locate.
                    if (!meshesRangeOffset) {
                        meshes.range?.low.subtractInPlace(transformOrigin);
                        meshes.range?.high.subtractInPlace(transformOrigin);
                        meshesRangeOffset = true;
                    }
                }
            }
            else {
                if (verts instanceof core_common_1.QPoint3dList) {
                    (0, core_bentley_1.assert)(transformOrigin.isAlmostEqual(verts.params.origin));
                    verts.params.origin.setZero();
                }
                else {
                    (0, core_bentley_1.assert)(verts.range.center.isAlmostZero);
                }
            }
            const geom = this.system.createGeometryFromMesh(mesh, this._viewIndependentOrigin);
            if (geom) {
                geometry.push(geom);
            }
        }
        let transform;
        if (transformOrigin) {
            transform = core_geometry_1.Transform.createTranslation(transformOrigin);
            if (meshesRangeOffset) { // restore the meshes range that we modified earlier.
                meshes.range?.low.addInPlace(transformOrigin);
                meshes.range?.high.addInPlace(transformOrigin);
            }
        }
        let batch;
        if (meshes.features?.anyDefined) {
            batch = {
                featureTable: core_common_1.PackedFeatureTable.pack(meshes.features),
                range: meshes.range ?? new core_geometry_1.Range3d(),
                options: this._options.pickable,
            };
        }
        return (0, GraphicTemplate_1.createGraphicTemplate)({
            batch,
            nodes: [{ geometry, transform }],
            noDispose,
        });
    }
}
exports.PrimitiveBuilder = PrimitiveBuilder;
_a = Symbols_1._implementationProhibited;
//# sourceMappingURL=PrimitiveBuilder.js.map