"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.createPointCloudHiliter = exports.createPointCloudBuilder = void 0;
const core_bentley_1 = require("@itwin/core-bentley");
const AttributeMap_1 = require("../AttributeMap");
const ShaderBuilder_1 = require("../ShaderBuilder");
const FeatureSymbology_1 = require("./FeatureSymbology");
const PlanarClassification_1 = require("./PlanarClassification");
const Vertex_1 = require("./Vertex");
const Viewport_1 = require("./Viewport");
const Thematic_1 = require("./Thematic");
const Surface_1 = require("./Surface");
const Fragment_1 = require("./Fragment");
// Revert components if color format is BGR instead of RGB.
const computeColor = `
  return u_pointCloud.y == 1.0 ? vec4(a_color.b, a_color.g, a_color.r, 1.0) : vec4(a_color, 1.0);
`;
const computeBaseColor = "return v_color;";
// Round the point unless drawing square points.
const roundPointDiscard = `
  if (u_pointCloudSettings.w == 1.0)
    return false;

  vec2 pointXY = (2.0 * gl_PointCoord - 1.0);
  return dot(pointXY, pointXY) > 1.0;
`;
const checkForClassifiedDiscard = "return baseColor.a == 0.0;";
const computePosition = `
  gl_PointSize = 1.0;
  vec4 pos = MAT_MVP * rawPos;
  if (u_pointCloudSettings.x > 0.0) {
    // Size is specified in pixels.
    gl_PointSize = u_pointCloudSettings.x;
    return pos;
  }

  // Point size is in meters (voxel size).
  if (pos.w <= 0.0) {
    // Cannot perform perspective divide below.
    return pos;
  }

  // Convert voxel size in meters into pixel size, then compute pixel size, taking perspective into account.
  mat4 toView = u_viewportTransformation * MAT_MVP;
  float scale = length(toView[0].xyz);
  gl_PointSize = -u_pointCloudSettings.x * clamp(u_pointCloud.x * scale / pos.w, u_pointCloudSettings.y, u_pointCloudSettings.z);
  return pos;
`;
function createBuilder() {
    const builder = new ShaderBuilder_1.ProgramBuilder(AttributeMap_1.AttributeMap.findAttributeMap(2 /* TechniqueId.PointCloud */, false));
    const vert = builder.vert;
    (0, Viewport_1.addViewportTransformation)(vert);
    vert.set(10 /* VertexShaderComponent.ComputePosition */, computePosition);
    (0, Vertex_1.addModelViewProjectionMatrix)(vert);
    builder.frag.set(0 /* FragmentShaderComponent.CheckForEarlyDiscard */, roundPointDiscard);
    // Uniforms based on the PointCloudDisplaySettings.
    builder.addUniform("u_pointCloudSettings", 5 /* VariableType.Vec4 */, (prog) => {
        prog.addGraphicUniform("u_pointCloudSettings", (uniform, params) => {
            params.target.uniforms.realityModel.pointCloud.bind(uniform);
        });
    });
    // Uniforms based on the PointCloudGeometry.
    builder.vert.addUniform("u_pointCloud", 3 /* VariableType.Vec2 */, (prog) => {
        prog.addGraphicUniform("u_pointCloud", (uniform, params) => {
            (0, core_bentley_1.assert)(params.geometry.asPointCloud !== undefined);
            scratchPointCloud[0] = params.geometry.asPointCloud.voxelSize;
            scratchPointCloud[1] = params.geometry.asPointCloud.colorIsBgr ? 1 : 0;
            uniform.setUniform2fv(scratchPointCloud);
        });
    });
    return builder;
}
const scratchPointCloud = new Float32Array([0, 0]);
/** @internal */
function createPointCloudBuilder(classified, featureMode, thematic) {
    const builder = createBuilder();
    builder.addVarying("v_color", 5 /* VariableType.Vec4 */);
    builder.vert.set(5 /* VertexShaderComponent.ComputeBaseColor */, computeColor);
    builder.frag.set(1 /* FragmentShaderComponent.ComputeBaseColor */, computeBaseColor);
    if (classified) {
        (0, PlanarClassification_1.addColorPlanarClassifier)(builder, false, thematic);
        builder.frag.set(4 /* FragmentShaderComponent.CheckForDiscard */, checkForClassifiedDiscard);
        if (0 /* FeatureMode.None */ !== featureMode)
            (0, PlanarClassification_1.addFeaturePlanarClassifier)(builder);
    }
    if (1 /* IsThematic.Yes */ === thematic) {
        (0, Thematic_1.addThematicDisplay)(builder, true);
        (0, Surface_1.addTexture)(builder, 0 /* IsAnimated.No */, 1 /* IsThematic.Yes */, true, false);
    }
    return builder;
}
exports.createPointCloudBuilder = createPointCloudBuilder;
/** @internal */
function createPointCloudHiliter(classified) {
    const builder = createBuilder();
    if (classified) {
        (0, PlanarClassification_1.addHilitePlanarClassifier)(builder, false);
        builder.frag.set(16 /* FragmentShaderComponent.AssignFragData */, Fragment_1.assignFragColor);
    }
    else {
        (0, FeatureSymbology_1.addUniformHiliter)(builder);
    }
    return builder;
}
exports.createPointCloudHiliter = createPointCloudHiliter;
//# sourceMappingURL=PointCloud.js.map