/**
 * A batch shader generator that could handle extra uniforms during initialization.
 * @param {string} vertexSrc              The vertex shader source
 * @param {string} fragTemplate           The fragment shader source template
 * @param {object | (maxTextures: number) => object} [uniforms]    Additional uniforms
 */
class BatchShaderGenerator extends PIXI.BatchShaderGenerator {
  constructor(vertexSrc, fragTemplate, uniforms={}) {
    super(vertexSrc, fragTemplate);
    this.#uniforms = uniforms;
  }

  /**
   * Extra uniforms used to create the batch shader.
   * @type {object | (maxTextures: number) => object}
   */
  #uniforms;

  /* -------------------------------------------- */

  /** @override */
  generateShader(maxTextures) {
    if ( !this.programCache[maxTextures] ) {
      const sampleValues = Int32Array.from({length: maxTextures}, (n, i) => i);
      this.defaultGroupCache[maxTextures] = PIXI.UniformGroup.from({uSamplers: sampleValues}, true);
      let fragmentSrc = this.fragTemplate;
      fragmentSrc = fragmentSrc.replace(/%count%/gi, `${maxTextures}`);
      fragmentSrc = fragmentSrc.replace(/%forloop%/gi, this.generateSampleSrc(maxTextures));
      this.programCache[maxTextures] = new PIXI.Program(this.vertexSrc, fragmentSrc);
    }
    let uniforms = this.#uniforms;
    if ( typeof uniforms === "function" ) uniforms = uniforms.call(this, maxTextures);
    else uniforms = foundry.utils.deepClone(uniforms);
    return new PIXI.Shader(this.programCache[maxTextures], {
      ...uniforms,
      tint: new Float32Array([1, 1, 1, 1]),
      translationMatrix: new PIXI.Matrix(),
      default: this.defaultGroupCache[maxTextures]
    });
  }
}
