"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 WebGL
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.PlanarGridGeometry = void 0;
const core_bentley_1 = require("@itwin/core-bentley");
const core_geometry_1 = require("@itwin/core-geometry");
const core_common_1 = require("@itwin/core-common");
const GraphicBranch_1 = require("../GraphicBranch");
const AttributeBuffers_1 = require("./AttributeBuffers");
const AttributeMap_1 = require("./AttributeMap");
const CachedGeometry_1 = require("./CachedGeometry");
const GL_1 = require("./GL");
const Primitive_1 = require("./Primitive");
class PlanarGridGeometryParams extends CachedGeometry_1.IndexedGeometryParams {
    constructor(positions, uvParams, indices, numIndices, props) {
        super(positions, indices, numIndices);
        this.props = props;
        const attrParams = AttributeMap_1.AttributeMap.findAttribute("a_uvParam", 8 /* TechniqueId.PlanarGrid */, false);
        (0, core_bentley_1.assert)(attrParams !== undefined);
        this.buffers.addBuffer(uvParams, [AttributeBuffers_1.BufferParameters.create(attrParams.location, 2, GL_1.GL.DataType.UnsignedShort, false, 0, 0, false)]);
        this.uvParams = uvParams;
    }
}
class PlanarGridGeometry extends CachedGeometry_1.IndexedGeometry {
    get techniqueId() { return 8 /* TechniqueId.PlanarGrid */; }
    getPass() { return "translucent"; }
    collectStatistics(_stats) { }
    get renderOrder() { return 3 /* RenderOrder.UnlitSurface */; }
    get asPlanarGrid() { return this; }
    constructor(params) {
        super(params);
        this.uvParams = params.uvParams;
        this.props = params.props;
    }
    static create(frustum, grid, system) {
        const plane = core_geometry_1.Plane3dByOriginAndUnitNormal.create(grid.origin, grid.rMatrix.rowZ());
        const polygon = frustum.getIntersectionWithPlane(plane);
        if (!polygon || polygon.length < 3)
            return undefined;
        const xVector = grid.rMatrix.rowX();
        const yVector = grid.rMatrix.rowY();
        const gridsPerRef = Math.max(1, grid.gridsPerRef);
        const xOrigin = xVector.dotProduct(grid.origin);
        const yOrigin = yVector.dotProduct(grid.origin);
        const params = [];
        for (const polygonPoint of polygon) {
            const x = (xVector.dotProduct(polygonPoint) - xOrigin) / grid.spacing.x;
            const y = (yVector.dotProduct(polygonPoint) - yOrigin) / grid.spacing.y;
            params.push(core_geometry_1.Point2d.create(x, y));
        }
        const qPoints = core_common_1.QPoint3dList.fromPoints(polygon);
        const qParams = core_common_1.QPoint2dList.fromPoints(params);
        qParams.params.origin.x = qParams.params.origin.x % gridsPerRef;
        qParams.params.origin.y = qParams.params.origin.y % gridsPerRef;
        let transform;
        // If the grid is far from the origin, create a branch to avoid large coordinate accuracy issues. (Reality models).
        if (qPoints.params.origin.magnitude() > 1.0E4) {
            transform = core_geometry_1.Transform.createTranslationXYZ(qPoints.params.origin.x, qPoints.params.origin.y, qPoints.params.origin.z);
            qPoints.params.origin.setZero();
        }
        const nTriangles = polygon.length - 2;
        const indices = new Uint32Array(3 * nTriangles);
        for (let i = 0, j = 0; i < nTriangles; i++) {
            indices[j++] = 0;
            indices[j++] = i + 1;
            indices[j++] = i + 2;
        }
        const pointBuffer = AttributeBuffers_1.QBufferHandle3d.create(qPoints.params, qPoints.toTypedArray());
        const paramBuffer = AttributeBuffers_1.QBufferHandle2d.create(qParams.params, qParams.toTypedArray());
        const indBuffer = AttributeBuffers_1.BufferHandle.createBuffer(GL_1.GL.Buffer.Target.ElementArrayBuffer, indices);
        if (!pointBuffer || !paramBuffer || !indBuffer)
            return undefined;
        const geomParams = new PlanarGridGeometryParams(pointBuffer, paramBuffer, indBuffer, indices.length, grid);
        if (!geomParams)
            return undefined;
        const geom = new PlanarGridGeometry(geomParams);
        let graphic = Primitive_1.Primitive.create(geom);
        if (transform && graphic) {
            const branch = new GraphicBranch_1.GraphicBranch(true);
            branch.add(graphic);
            graphic = system.createBranch(branch, transform);
        }
        return graphic;
    }
}
exports.PlanarGridGeometry = PlanarGridGeometry;
//# sourceMappingURL=PlanarGrid.js.map