import { SimpleMeshLayer } from "@deck.gl/mesh-layers";
import { COORDINATE_SYSTEM } from "@deck.gl/core";
import fsShader from "./terrainmap.fs.glsl";
import GL from "@luma.gl/constants";
import { Texture2D } from "@luma.gl/core";
import { rgbValues } from "@emerson-eps/color-tables/";
import { createPropertyData } from "../utils/layerTools";
const DEFAULT_TEXTURE_PARAMETERS = {
    [GL.TEXTURE_MIN_FILTER]: GL.LINEAR_MIPMAP_LINEAR,
    [GL.TEXTURE_MAG_FILTER]: GL.LINEAR,
    [GL.TEXTURE_WRAP_S]: GL.CLAMP_TO_EDGE,
    [GL.TEXTURE_WRAP_T]: GL.CLAMP_TO_EDGE,
};
export const DECODER = {
    rScaler: 256 * 256,
    gScaler: 256,
    bScaler: 1,
    offset: 0,
};
function getImageData(colorMapName, colorTables) {
    const data = new Uint8Array(256 * 3);
    for (let i = 0; i < 256; i++) {
        const value = i / 255.0;
        const rgb = rgbValues(value, colorMapName, colorTables);
        let color = [];
        if (rgb != undefined) {
            if (Array.isArray(rgb)) {
                color = rgb;
            }
            else {
                color = [rgb.r, rgb.g, rgb.b];
            }
        }
        data[3 * i + 0] = color[0];
        data[3 * i + 1] = color[1];
        data[3 * i + 2] = color[2];
    }
    return data;
}
const defaultProps = {
    data: [{ position: [0, 0], angle: 0, color: [255, 0, 0, 0] }],
    getPosition: (d) => d.position,
    getColor: (d) => d.color,
    getOrientation: (d) => [0, d.angle, 0],
    contours: [-1, -1],
    colorMapName: "",
    propertyValueRange: [0.0, 1.0],
    isReadoutDepth: false,
    isContoursDepth: true,
    coordinateSystem: COORDINATE_SYSTEM.CARTESIAN,
};
// This is a private layer used only by the composite Map3DLayer.
// It is an extension of SimpleMeshLayer but with modified fragment shader
// so that the texture pixel values can be used as lookup in  a supplied color map.
export default class TerrainMapLayer extends SimpleMeshLayer {
    // Signature from the base class, eslint doesn't like the any type.
    // eslint-disable-next-line
    draw({ uniforms, context }) {
        var _a, _b, _c, _d, _e, _f, _g, _h;
        const contourReferencePoint = (_a = this.props.contours[0]) !== null && _a !== void 0 ? _a : -1.0;
        const contourInterval = (_b = this.props.contours[1]) !== null && _b !== void 0 ? _b : -1.0;
        const isReadoutDepth = this.props.isReadoutDepth;
        const isContoursDepth = this.props.isContoursDepth;
        const valueRangeMin = (_c = this.props.propertyValueRange[0]) !== null && _c !== void 0 ? _c : 0.0;
        const valueRangeMax = (_d = this.props.propertyValueRange[1]) !== null && _d !== void 0 ? _d : 1.0;
        // If specified color map will extend from colorMapRangeMin to colorMapRangeMax.
        // Otherwise it will extend from valueRangeMin to valueRangeMax.
        const colorMapRangeMin = (_f = (_e = this.props.colorMapRange) === null || _e === void 0 ? void 0 : _e[0]) !== null && _f !== void 0 ? _f : valueRangeMin;
        const colorMapRangeMax = (_h = (_g = this.props.colorMapRange) === null || _g === void 0 ? void 0 : _g[1]) !== null && _h !== void 0 ? _h : valueRangeMax;
        const isClampColor = this.props.colorMapClampColor !== undefined;
        let colorMapClampColor = isClampColor
            ? this.props.colorMapClampColor
            : [0, 0, 0, 0];
        // Normalize to [0,1] range.
        colorMapClampColor = colorMapClampColor.map((x) => (x !== null && x !== void 0 ? x : 0) / 255);
        super.draw({
            uniforms: Object.assign(Object.assign({}, uniforms), { colormap: new Texture2D(context.gl, {
                    width: 256,
                    height: 1,
                    format: GL.RGB,
                    data: getImageData(this.props.colorMapName, this.context.userData
                        .colorTables),
                    parameters: DEFAULT_TEXTURE_PARAMETERS,
                }), valueRangeMin,
                valueRangeMax,
                colorMapRangeMin,
                colorMapRangeMax,
                contourReferencePoint,
                contourInterval,
                isReadoutDepth,
                isContoursDepth,
                colorMapClampColor,
                isClampColor }),
        });
    }
    getShaders() {
        const parentShaders = super.getShaders();
        // Overwrite the default fragment shader with ours.
        parentShaders.fs = fsShader;
        return Object.assign(Object.assign({}, parentShaders), { 
            // Inject this into vertex shader. Vi want to export vertex world position to
            // fragment shader for making contour lines.
            inject: {
                "vs:#decl": `
                  out vec3 worldPos;
                `,
                "vs:#main-start": `
                   worldPos = positions;
                `,
            } });
    }
    decodePickingColor() {
        return 0;
    }
    // For now, use `any` for the picking types.
    //eslint-disable-next-line
    getPickingInfo({ info }) {
        if (!info.color) {
            return info;
        }
        // Note these colors are in the  0-255 range.
        const r = info.color[0] * DECODER.rScaler;
        const g = info.color[1] * DECODER.gScaler;
        const b = info.color[2] * DECODER.bScaler;
        const value = r + g + b;
        let depth = undefined;
        const layer_properties = [];
        // Either map properties or map depths are encoded here.
        if (this.props.isReadoutDepth)
            depth = value.toFixed(2);
        else
            layer_properties.push(getMapProperty(value, this.props.propertyValueRange));
        return Object.assign(Object.assign({}, info), { properties: layer_properties, propertyValue: depth });
    }
}
TerrainMapLayer.layerName = "TerrainMapLayer";
TerrainMapLayer.defaultProps = defaultProps;
//================= Local help functions. ==================
function getMapProperty(value, value_range) {
    // Remap the [0, 1] decoded value to property value range.
    const [min, max] = value_range;
    const floatScaler = 1.0 / (256.0 * 256.0 * 256.0 - 1.0);
    const scaled_value = value * floatScaler;
    value = scaled_value * (max - min) + min;
    return createPropertyData("Property", value);
}
//# sourceMappingURL=terrainMapLayer.js.map