"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.OctEncodedNormalPair = exports.OctEncodedNormal = void 0;
const core_geometry_1 = require("@itwin/core-geometry");
const scratchUInt16 = new Uint16Array(1);
function clamp(val, minVal, maxVal) {
    return val < minVal ? minVal : (val > maxVal ? maxVal : val);
}
function clampUint8(val) {
    return roundUint16(0.5 + (clamp(val, -1, 1) * 0.5 + 0.5) * 255);
}
function roundUint16(val) {
    scratchUInt16[0] = val;
    return scratchUInt16[0];
}
function signNotZero(val) {
    return val < 0.0 ? -1.0 : 1.0;
}
/** Represents a 3d normal vector compressed into a single 16-bit integer using [oct-encoding](http://jcgt.org/published/0003/02/01/paper.pdf).
 * These are chiefly used to reduce the space required to store normal vectors for [RenderGraphic]($frontend)s.
 * @public
 */
class OctEncodedNormal {
    /** The encoded normal. */
    value;
    /** Construct directly from a 16-bit encoded value.
     * @see [[encode]] to compute the encoded value.
     * @see [[fromVector]] to construct from a vector.
     */
    constructor(val) {
        this.value = roundUint16(val);
    }
    /** Compute the encoded 16-bit value of the supplied normalized vector. */
    static encode(vec) {
        return this.encodeXYZ(vec.x, vec.y, vec.z);
    }
    /** Compute the encoded 16-bit value of the supplied normalized vector components. */
    static encodeXYZ(nx, ny, nz) {
        const denom = Math.abs(nx) + Math.abs(ny) + Math.abs(nz);
        let rx = nx / denom;
        let ry = ny / denom;
        if (nz < 0) {
            const x = rx;
            const y = ry;
            rx = (1 - Math.abs(y)) * signNotZero(x);
            ry = (1 - Math.abs(x)) * signNotZero(y);
        }
        return clampUint8(ry) << 8 | clampUint8(rx);
    }
    /** Create an OctEncodedNormal from a normalized vector. */
    static fromVector(val) {
        return new OctEncodedNormal(this.encode(val));
    }
    /** Decode this oct-encoded normal into a normalized vector. */
    decode() {
        return OctEncodedNormal.decodeValue(this.value);
    }
    /** Decode a 16-bit encoded value into a normalized vector. */
    static decodeValue(val, result) {
        let ex = val & 0xff;
        let ey = val >> 8;
        ex = ex / 255.0 * 2.0 - 1.0;
        ey = ey / 255.0 * 2.0 - 1.0;
        const ez = 1 - (Math.abs(ex) + Math.abs(ey));
        let n;
        if (result === undefined) {
            n = new core_geometry_1.Vector3d(ex, ey, ez);
        }
        else {
            n = result;
            n.x = ex;
            n.y = ey;
            n.z = ez;
        }
        if (n.z < 0) {
            const x = n.x;
            const y = n.y;
            n.x = (1 - Math.abs(y)) * signNotZero(x);
            n.y = (1 - Math.abs(x)) * signNotZero(y);
        }
        n.normalizeInPlace();
        return n;
    }
}
exports.OctEncodedNormal = OctEncodedNormal;
/** @internal */
class OctEncodedNormalPair {
    first;
    second;
    constructor(first, second) {
        this.first = first;
        this.second = second;
    }
}
exports.OctEncodedNormalPair = OctEncodedNormalPair;
//# sourceMappingURL=OctEncodedNormal.js.map