"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.DisplayParams = void 0;
const core_bentley_1 = require("@itwin/core-bentley");
const core_common_1 = require("@itwin/core-common");
function compareMaterials(lhs, rhs) {
    return (0, core_bentley_1.comparePossiblyUndefined)((lh, rh) => lh.compare(rh), lhs, rhs);
}
function compareTextureMappings(lhs, rhs) {
    return (0, core_bentley_1.comparePossiblyUndefined)((lh, rh) => lh.compare(rh), lhs, rhs);
}
/** This class is used to determine if things can be batched together for display.
 * @internal
 */
class DisplayParams {
    constructor(type, lineColor, fillColor, width = 0, linePixels = core_common_1.LinePixels.Solid, fillFlags = core_common_1.FillFlags.None, material, gradient, ignoreLighting = false, textureMapping) {
        this.type = DisplayParams.Type.Mesh;
        this.type = type;
        this.material = material;
        this.gradient = gradient;
        this.lineColor = DisplayParams.adjustTransparency(lineColor);
        this.fillColor = DisplayParams.adjustTransparency(fillColor);
        this.width = width;
        this.linePixels = linePixels;
        this.fillFlags = fillFlags;
        this.ignoreLighting = ignoreLighting;
        this._textureMapping = textureMapping;
        (0, core_bentley_1.assert)(undefined === material || undefined === textureMapping);
    }
    /** Creates a DisplayParams object for a particular type (mesh, linear, text) based on the specified GraphicParams. */
    static createForType(type, gf, resolveGradient, ignoreLighting = false) {
        const lineColor = DisplayParams.adjustTransparency(gf.lineColor);
        switch (type) {
            case DisplayParams.Type.Mesh: {
                let gradientMapping;
                if (undefined !== gf.gradient && undefined !== resolveGradient) {
                    const gradientTexture = resolveGradient(gf.gradient);
                    if (undefined !== gradientTexture)
                        gradientMapping = new core_common_1.TextureMapping(gradientTexture, new core_common_1.TextureMapping.Params());
                }
                return new DisplayParams(type, lineColor, DisplayParams.adjustTransparency(gf.fillColor), gf.rasterWidth, gf.linePixels, gf.fillFlags, gf.material, gf.gradient, ignoreLighting, gradientMapping);
            }
            case DisplayParams.Type.Linear:
                return new DisplayParams(type, lineColor, lineColor, gf.rasterWidth, gf.linePixels);
            default: // DisplayParams.Type.Text
                return new DisplayParams(type, lineColor, lineColor, 0, core_common_1.LinePixels.Solid, core_common_1.FillFlags.Always, undefined, undefined, true);
        }
    }
    /** Creates a DisplayParams object that describes mesh geometry based on the specified GraphicParams. */
    static createForMesh(gf, ignoreLighting, resolveGradient) {
        return DisplayParams.createForType(DisplayParams.Type.Mesh, gf, resolveGradient, ignoreLighting);
    }
    /** Creates a DisplayParams object that describes linear geometry based on the specified GraphicParams. */
    static createForLinear(gf) {
        return DisplayParams.createForType(DisplayParams.Type.Linear, gf);
    }
    /** Creates a DisplayParams object that describes text geometry based on the specified GraphicParams. */
    static createForText(gf) {
        return DisplayParams.createForType(DisplayParams.Type.Text, gf);
    }
    get regionEdgeType() {
        if (this.hasBlankingFill)
            return DisplayParams.RegionEdgeType.None;
        if (this.gradient !== undefined && undefined !== this.gradient.flags) {
            // Even if the gradient is not outlined, produce an outline to be displayed as the region's edges when fill ViewFlag is off.
            const gradFlags = this.gradient.flags;
            if (0 !== (gradFlags & core_common_1.Gradient.Flags.Outline) || core_common_1.FillFlags.None === (this.fillFlags & core_common_1.FillFlags.Always))
                return DisplayParams.RegionEdgeType.Outline;
            return DisplayParams.RegionEdgeType.None;
        }
        return (!this.fillColor.equals(this.lineColor)) ? DisplayParams.RegionEdgeType.Outline : DisplayParams.RegionEdgeType.Default;
    }
    get wantRegionOutline() {
        return DisplayParams.RegionEdgeType.Outline === this.regionEdgeType;
    }
    get hasBlankingFill() { return core_common_1.FillFlags.Blanking === (this.fillFlags & core_common_1.FillFlags.Blanking); }
    get hasFillTransparency() { return 255 !== this.fillColor.getAlpha(); }
    get hasLineTransparency() { return 255 !== this.lineColor.getAlpha(); }
    get textureMapping() { return undefined !== this.material ? this.material.textureMapping : this._textureMapping; }
    get isTextured() { return undefined !== this.textureMapping; }
    /** Determines if the properties of this DisplayParams object are equal to those of another DisplayParams object.  */
    equals(rhs, purpose = DisplayParams.ComparePurpose.Strict) {
        if (DisplayParams.ComparePurpose.Merge === purpose)
            return 0 === this.compareForMerge(rhs);
        else if (rhs === this)
            return true;
        if (this.type !== rhs.type)
            return false;
        if (this.ignoreLighting !== rhs.ignoreLighting)
            return false;
        if (this.width !== rhs.width)
            return false;
        if (this.linePixels !== rhs.linePixels)
            return false;
        if (this.fillFlags !== rhs.fillFlags)
            return false;
        if (this.wantRegionOutline !== rhs.wantRegionOutline)
            return false;
        if (this.material !== rhs.material)
            return false;
        if (this.textureMapping !== rhs.textureMapping)
            return false;
        if (!this.fillColor.equals(rhs.fillColor))
            return false;
        if (!this.lineColor.equals(rhs.lineColor))
            return false;
        return true;
    }
    compareForMerge(rhs) {
        if (rhs === this)
            return 0;
        let diff = (0, core_bentley_1.compareNumbers)(this.type, rhs.type);
        if (0 === diff) {
            diff = (0, core_bentley_1.compareBooleans)(this.ignoreLighting, rhs.ignoreLighting);
            if (0 === diff) {
                diff = (0, core_bentley_1.compareNumbers)(this.width, rhs.width);
                if (0 === diff) {
                    diff = (0, core_bentley_1.compareNumbers)(this.linePixels, rhs.linePixels);
                    if (0 === diff) {
                        diff = (0, core_bentley_1.compareNumbers)(this.fillFlags, rhs.fillFlags);
                        if (0 === diff) {
                            diff = (0, core_bentley_1.compareBooleans)(this.wantRegionOutline, rhs.wantRegionOutline);
                            if (0 === diff) {
                                diff = (0, core_bentley_1.compareBooleans)(this.hasFillTransparency, rhs.hasFillTransparency);
                                if (0 === diff) {
                                    diff = (0, core_bentley_1.compareBooleans)(this.hasLineTransparency, rhs.hasLineTransparency);
                                    if (0 === diff) {
                                        diff = compareMaterials(this.material, rhs.material);
                                        if (0 === diff && undefined === this.material && this.isTextured) {
                                            diff = compareTextureMappings(this.textureMapping, rhs.textureMapping);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return diff;
    }
    /**
     * Given a ColorDef object, check its transparency and if it falls below the minimum, mark the color as fully opaque.
     * @return The original reference to the color provided, which has possibly been modified.
     */
    static adjustTransparency(color) {
        return (color.colors.t < DisplayParams.minTransparency) ? color.withTransparency(0) : color;
    }
}
exports.DisplayParams = DisplayParams;
DisplayParams.minTransparency = 15; // Threshold below which we consider a color fully opaque
/** @internal */
(function (DisplayParams) {
    let Type;
    (function (Type) {
        Type[Type["Mesh"] = 0] = "Mesh";
        Type[Type["Linear"] = 1] = "Linear";
        Type[Type["Text"] = 2] = "Text";
    })(Type = DisplayParams.Type || (DisplayParams.Type = {}));
    let RegionEdgeType;
    (function (RegionEdgeType) {
        RegionEdgeType[RegionEdgeType["None"] = 0] = "None";
        RegionEdgeType[RegionEdgeType["Default"] = 1] = "Default";
        RegionEdgeType[RegionEdgeType["Outline"] = 2] = "Outline";
    })(RegionEdgeType = DisplayParams.RegionEdgeType || (DisplayParams.RegionEdgeType = {}));
    let ComparePurpose;
    (function (ComparePurpose) {
        ComparePurpose[ComparePurpose["Merge"] = 0] = "Merge";
        ComparePurpose[ComparePurpose["Strict"] = 1] = "Strict";
    })(ComparePurpose = DisplayParams.ComparePurpose || (DisplayParams.ComparePurpose = {}));
})(DisplayParams || (exports.DisplayParams = DisplayParams = {}));
//# sourceMappingURL=DisplayParams.js.map