/*---------------------------------------------------------------------------------------------
* 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
 */
import { assert } from "@itwin/core-bentley";
import { TextureUnit } from "../RenderFlags";
import { Texture2DHandle } from "../Texture";
import { addWindowToTexCoords, assignFragColor } from "./Fragment";
import { createViewportQuadBuilder } from "./ViewportQuad";
function addHiliteSettings(frag) {
    frag.addUniform("u_hilite_settings", 6 /* VariableType.Mat3 */, (prog) => {
        prog.addProgramUniform("u_hilite_settings", (uniform, params) => {
            params.target.uniforms.hilite.bindCompositeSettings(uniform);
        });
    });
    frag.addUniform("u_hilite_width", 3 /* VariableType.Vec2 */, (prog) => {
        prog.addProgramUniform("u_hilite_width", (uniform, params) => {
            params.target.uniforms.hilite.bindCompositeWidths(uniform);
        });
    });
}
const readEdgePixel = `
vec2 readEdgePixel(float xOffset, float yOffset) {
  vec2 t = windowCoordsToTexCoords(gl_FragCoord.xy + vec2(xOffset, yOffset));
  return TEXTURE(u_hilite, t).xy;
}
`;
const computeNearbyHilites = `
vec2 computeNearbyHilites() {
  float hiliteWidth = u_hilite_width.x;
  float emphWidth = u_hilite_width.y;
  float maxWidth = max(hiliteWidth, emphWidth);
  if (0.0 == maxWidth)
    return vec2(0.0);

  vec2 nearest = vec2(0.0, 0.0);
  for (int x = -1; x <= 1; x++)
    for (int y = -1; y <= 1; y++)
      if (0 != x || 0 != y)
        nearest = nearest + readEdgePixel(float(x), float(y));

  nearest = nearest * vec2(float(hiliteWidth > 0.0), float(emphWidth > 0.0));

  if ((0.0 == nearest.x && hiliteWidth > 1.0) || (0.0 == nearest.y && emphWidth > 1.0)) {
    vec2 farthest = vec2(0.0, 0.0);
    for (int i = -2; i <= 2; i++) {
      float f = float(i);
      farthest = farthest + readEdgePixel(f, -2.0) + readEdgePixel(-2.0, f) + readEdgePixel(f, 2.0) + readEdgePixel(2.0, f);
    }

    farthest = farthest * vec2(float(hiliteWidth > 1.0), float(emphWidth > 1.0));
    nearest = nearest + farthest;
  }

  return nearest;
}
`;
const computeOpaqueColor = `
vec4 computeOpaqueColor() {
  vec4 opaque = TEXTURE(u_opaque, v_texCoord);
  opaque.rgb *= computeAmbientOcclusion();
  return opaque;
}
`;
const computeDefaultAmbientOcclusion = `\nfloat computeAmbientOcclusion() { return 1.0; }\n`;
const computeAmbientOcclusion = `\nfloat computeAmbientOcclusion() { return TEXTURE(u_occlusion, v_texCoord).r; }\n`;
const computeHiliteColor = "\nvec4 computeColor() { return computeOpaqueColor(); }\n";
const computeHiliteBaseColor = `
  vec4 baseColor = computeColor();
  vec2 flags = TEXTURE(u_hilite, v_texCoord).rg;
  vec2 outline = computeNearbyHilites();
  if (u_hilite_width.y < u_hilite_width.x) { // check for emphasis outline first if it is thinner
    if (outline.y > 0.0 && flags.y == 0.0)
      return vec4(u_hilite_settings[1], 1.0);
    if (outline.x > 0.0 && flags.x == 0.0)
      return vec4(u_hilite_settings[0], 1.0);
  } else {
    if (outline.x > 0.0 && flags.x == 0.0)
      return vec4(u_hilite_settings[0], 1.0);
    if (outline.y > 0.0 && flags.y == 0.0)
      return vec4(u_hilite_settings[1], 1.0);
  }
  float hiliteMix = flags.x * u_hilite_settings[2][0];
  float emphasisMix = flags.y * u_hilite_settings[2][1];
  baseColor.rgb *= (1.0 - (hiliteMix + emphasisMix));
  baseColor.rgb += u_hilite_settings[0] * hiliteMix;
  baseColor.rgb += u_hilite_settings[1] * emphasisMix;
  return baseColor;
`;
const computeTranslucentColor = `
vec4 computeColor() {
  vec4 opaque = computeOpaqueColor();
  vec4 accum = TEXTURE(u_accumulation, v_texCoord);
  vec2 rg = TEXTURE(u_revealage, v_texCoord).rg;

  vec4 transparent = vec4(accum.rgb / clamp(rg.r, 1e-4, 5e4), accum.a);
  vec4 col = mix((1.0 - transparent.a) * transparent + transparent.a * opaque, vec4(u_clipIntersection.rgb, 1.0), rg.g);
  return col;
}
`;
const computeTranslucentBaseColor = "return computeColor();";
const computeAmbientOcclusionBaseColor = "return computeOpaqueColor();";
/** @internal */
export function createCompositeProgram(flags, context) {
    assert(0 /* CompositeFlags.None */ !== flags);
    const wantHilite = 0 /* CompositeFlags.None */ !== (flags & 2 /* CompositeFlags.Hilite */);
    const wantTranslucent = 0 /* CompositeFlags.None */ !== (flags & 1 /* CompositeFlags.Translucent */);
    const wantOcclusion = 0 /* CompositeFlags.None */ !== (flags & 4 /* CompositeFlags.AmbientOcclusion */);
    const builder = createViewportQuadBuilder(true);
    const frag = builder.frag;
    frag.addFunction(wantOcclusion ? computeAmbientOcclusion : computeDefaultAmbientOcclusion);
    frag.addFunction(computeOpaqueColor);
    frag.set(17 /* FragmentShaderComponent.AssignFragData */, assignFragColor);
    frag.addUniform("u_opaque", 8 /* VariableType.Sampler2D */, (prog) => {
        prog.addGraphicUniform("u_opaque", (uniform, params) => {
            Texture2DHandle.bindSampler(uniform, params.geometry.opaque, TextureUnit.Zero);
        });
    });
    if (wantHilite) {
        addHiliteSettings(frag);
        addWindowToTexCoords(frag);
        frag.addFunction(readEdgePixel);
        frag.addFunction(computeNearbyHilites);
        frag.addUniform("u_hilite", 8 /* VariableType.Sampler2D */, (prog) => {
            prog.addGraphicUniform("u_hilite", (uniform, params) => {
                Texture2DHandle.bindSampler(uniform, params.geometry.hilite, TextureUnit.Three);
            });
        });
        frag.set(1 /* FragmentShaderComponent.ComputeBaseColor */, computeHiliteBaseColor);
        if (!wantTranslucent) {
            frag.addFunction(computeHiliteColor);
        }
    }
    if (wantTranslucent) {
        frag.addUniform("u_accumulation", 8 /* VariableType.Sampler2D */, (prog) => {
            prog.addGraphicUniform("u_accumulation", (uniform, params) => {
                Texture2DHandle.bindSampler(uniform, params.geometry.accum, TextureUnit.One);
            });
        });
        frag.addUniform("u_revealage", 8 /* VariableType.Sampler2D */, (prog) => {
            prog.addGraphicUniform("u_revealage", (uniform, params) => {
                Texture2DHandle.bindSampler(uniform, params.geometry.reveal, TextureUnit.Two);
            });
        });
        builder.frag.addUniform("u_clipIntersection", 5 /* VariableType.Vec4 */, (program) => {
            program.addGraphicUniform("u_clipIntersection", (uniform, params) => {
                params.target.uniforms.branch.clipStack.intersectionStyle.bind(uniform);
            });
        });
        frag.addFunction(computeTranslucentColor);
        if (!wantHilite) {
            frag.set(1 /* FragmentShaderComponent.ComputeBaseColor */, computeTranslucentBaseColor);
        }
    }
    if (wantOcclusion) {
        frag.addUniform("u_occlusion", 8 /* VariableType.Sampler2D */, (prog) => {
            prog.addGraphicUniform("u_occlusion", (uniform, params) => {
                Texture2DHandle.bindSampler(uniform, params.geometry.occlusion, TextureUnit.Four);
            });
        });
        if (!wantHilite && !wantTranslucent)
            frag.set(1 /* FragmentShaderComponent.ComputeBaseColor */, computeAmbientOcclusionBaseColor);
    }
    const flagString = (wantHilite ? "-Hilite" : "") + (wantTranslucent ? "-Translucent" : "") + (wantOcclusion ? "-Occlusion" : "");
    builder.vert.headerComment = `//!V! CombineTextures${flagString}`;
    builder.frag.headerComment = `//!F! CombineTextures${flagString}`;
    return builder.buildProgram(context);
}
//# sourceMappingURL=Composite.js.map