"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.I3dmReader = void 0;
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module Tiles
 */
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 internal_1 = require("./internal");
function setTransform(transforms, index, rotation, origin) {
    const i = index * 12;
    let rot = rotation.coffs;
    const ignoreRotation = false;
    if (ignoreRotation)
        rot = new Float64Array([1, 0, 0, 0, 1, 0, 0, 0, 1]);
    const ignoreOrigin = false;
    if (ignoreOrigin)
        origin.x = origin.y = origin.z = 0;
    transforms[i + 0] = rot[0];
    transforms[i + 1] = rot[1];
    transforms[i + 2] = rot[2];
    transforms[i + 3] = origin.x;
    transforms[i + 4] = rot[3];
    transforms[i + 5] = rot[4];
    transforms[i + 6] = rot[5];
    transforms[i + 7] = origin.y;
    transforms[i + 8] = rot[6];
    transforms[i + 9] = rot[7];
    transforms[i + 10] = rot[8];
    transforms[i + 11] = origin.z;
}
/**
 * Deserializes a tile in [i3dm](https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification/TileFormats/Instanced3DModel) format.
 * @internal
 */
class I3dmReader extends internal_1.GltfReader {
    static create(stream, iModel, modelId, is3d, range, system, yAxisUp, isLeaf, isCanceled, idMap, deduplicateVertices = false) {
        const header = new core_common_1.I3dmHeader(stream);
        if (!header.isValid)
            return undefined;
        const props = internal_1.GltfReaderProps.create(stream.nextBytes(header.length - stream.curPos), yAxisUp);
        if (undefined === props)
            return undefined;
        stream.curPos = header.featureTableJsonPosition;
        const featureStr = (0, core_bentley_1.utf8ToString)(stream.nextBytes(header.featureTableJsonLength));
        if (undefined === featureStr)
            return undefined;
        const featureBinary = new Uint8Array(stream.arrayBuffer, header.featureTableJsonPosition + header.featureTableJsonLength, header.featureTableBinaryLength);
        return new I3dmReader(featureBinary, JSON.parse(featureStr), header.batchTableJson, props, iModel, modelId, is3d, system, range, isLeaf, isCanceled, idMap, deduplicateVertices);
    }
    constructor(_featureBinary, _featureJson, _batchTableJson, props, iModel, modelId, is3d, system, _range, _isLeaf, shouldAbort, _idMap, deduplicateVertices = false) {
        super({
            props, iModel, system, shouldAbort, deduplicateVertices,
            is2d: !is3d, idMap: _idMap,
        });
        this._featureBinary = _featureBinary;
        this._featureJson = _featureJson;
        this._batchTableJson = _batchTableJson;
        this._range = _range;
        this._isLeaf = _isLeaf;
        this._instanceCount = 0;
        this._modelId = modelId;
    }
    async read() {
        this._instanceCount = core_bentley_1.JsonUtils.asInt(this._featureJson.INSTANCES_LENGTH, 0);
        // NB: For reality models with no batch table, we want the model ID in the feature table
        this._featureTable = new core_common_1.FeatureTable(undefined === this._batchTableJson ? this._instanceCount : 1, this._modelId, this._type);
        if (this._idMap !== undefined && this._batchTableJson !== undefined) {
            for (let i = 0; i < this._instanceCount; i++) {
                const feature = {};
                for (const key in this._batchTableJson) // eslint-disable-line guard-for-in
                    feature[key] = this._batchTableJson[key][i];
                this._featureTable.insert(new core_common_1.Feature(this._idMap.getBatchId(feature)));
            }
        }
        else {
            // NB: For reality models with no batch table, we want the model ID in the feature table
            const feature = new core_common_1.Feature(this._modelId);
            this._featureTable.insert(feature);
        }
        await this.resolveResources();
        if (this._isCanceled)
            return { readStatus: core_common_1.TileReadStatus.Canceled, isLeaf: this._isLeaf };
        const instances = this.readInstances();
        if (undefined === instances)
            return { readStatus: core_common_1.TileReadStatus.InvalidTileData, isLeaf: this._isLeaf };
        return this.readGltfAndCreateGraphics(this._isLeaf, this._featureTable, this._range, undefined, undefined, instances);
    }
    readFeatures(_features, _json) {
        return false;
    }
    readInstances() {
        const count = core_bentley_1.JsonUtils.asInt(this._featureJson.INSTANCES_LENGTH, 0);
        if (count <= 0)
            return undefined;
        const json = this._featureJson;
        const binary = this._featureBinary;
        const batchIds = json.BATCH_ID ? new Int32Array(binary.buffer, binary.byteOffset + json.BATCH_ID.byteOffset, count) : undefined;
        const positions = json.POSITION ? new Float32Array(binary.buffer, binary.byteOffset + json.POSITION.byteOffset, count * 3) : undefined;
        const upNormals = json.NORMAL_UP ? new Float32Array(binary.buffer, binary.byteOffset + json.NORMAL_UP.byteOffset, count * 3) : undefined;
        const rightNormals = json.NORMAL_RIGHT ? new Float32Array(binary.buffer, binary.byteOffset + json.NORMAL_RIGHT.byteOffset, count * 3) : undefined;
        const scales = json.SCALE ? new Float32Array(binary.buffer, binary.byteOffset + json.SCALE.byteOffset, count) : undefined;
        const nonUniformScales = json.SCALE_NON_UNIFORM ? new Float32Array(binary.buffer, binary.byteOffset + json.SCALE_NON_UNIFORM.byteOffset, count * 3) : undefined;
        const matrix = core_geometry_1.Matrix3d.createIdentity();
        const position = core_geometry_1.Point3d.createZero();
        const upNormal = core_geometry_1.Vector3d.create(0, 0, 1);
        const rightNormal = core_geometry_1.Vector3d.create(1, 0, 0);
        const scale = core_geometry_1.Vector3d.create(1, 1, 1);
        const transformCenter = this._range.center;
        const transforms = new Float32Array(12 * count);
        for (let i = 0; i < count; i++) {
            const index = i * 3;
            if (positions)
                position.set(positions[index] - transformCenter.x, positions[index + 1] - transformCenter.y, positions[index + 2] - transformCenter.z);
            if (upNormals || rightNormals) {
                if (upNormals)
                    upNormal.set(upNormals[index], upNormals[index + 1], upNormals[index + 2]);
                if (rightNormals)
                    rightNormal.set(rightNormals[index], rightNormals[index + 1], rightNormals[index + 2]);
                if (scales)
                    scale.x = scale.y = scale.z = scales[i];
                if (nonUniformScales) {
                    scale.x *= nonUniformScales[index + 0];
                    scale.y *= nonUniformScales[index + 1];
                    scale.z *= nonUniformScales[index + 2];
                }
                core_geometry_1.Matrix3d.createRigidFromColumns(rightNormal, upNormal, core_geometry_1.AxisOrder.XYZ, matrix);
                if (scales || nonUniformScales)
                    matrix.scaleColumnsInPlace(scale.x, scale.y, scale.z);
                setTransform(transforms, i, matrix, position);
            }
        }
        let featureIds;
        if (undefined !== batchIds) {
            featureIds = new Uint8Array(3 * batchIds.length);
            for (let i = 0, j = 0; i < batchIds.length; i++) {
                const batchId = batchIds[i];
                featureIds[j++] = batchId & 0x000000ff;
                featureIds[j++] = (batchId & 0x0000ff00) >> 8;
                featureIds[j++] = (batchId & 0x00ff0000) >> 16;
            }
        }
        const symbologyOverrides = undefined;
        return { count, transforms, symbologyOverrides, featureIds, transformCenter };
    }
}
exports.I3dmReader = I3dmReader;
//# sourceMappingURL=I3dmReader.js.map