applyUniforms(frameState) {
    const gl = this.gl_;

    let value;
    let textureSlot = 0;
    this.uniforms_.forEach((uniform) => {
      value =
        typeof uniform.value === 'function'
          ? uniform.value(frameState)
          : uniform.value;

      // apply value based on type
      if (
        value instanceof HTMLCanvasElement ||
        value instanceof HTMLImageElement ||
        value instanceof ImageData ||
        value instanceof WebGLTexture
      ) {
        // create a texture & put data
        if (value instanceof WebGLTexture && !uniform.texture) {
          uniform.prevValue = undefined;
          uniform.texture = value;
        } else if (!uniform.texture) {
          uniform.prevValue = undefined;
          uniform.texture = gl.createTexture();
        }
        this.bindTexture(uniform.texture, textureSlot, uniform.name);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

        const imageReady =
          !(value instanceof HTMLImageElement) ||
          /** @type {HTMLImageElement} */ (value).complete;
        if (
          !(value instanceof WebGLTexture) &&
          imageReady &&
          uniform.prevValue !== value
        ) {
          uniform.prevValue = value;
          gl.texImage2D(
            gl.TEXTURE_2D,
            0,
            gl.RGBA,
            gl.RGBA,
            gl.UNSIGNED_BYTE,
            value,
          );
        }
        textureSlot++;
      } else if (Array.isArray(value) && value.length === 6) {
        this.setUniformMatrixValue(
          uniform.name,
          fromTransform(this.tmpMat4_, value),
        );
      } else if (Array.isArray(value) && value.length <= 4) {
        switch (value.length) {
          case 2:
            gl.uniform2f(
              this.getUniformLocation(uniform.name),
              value[0],
              value[1],
            );
            return;
          case 3:
            gl.uniform3f(
              this.getUniformLocation(uniform.name),
              value[0],
              value[1],
              value[2],
            );
            return;
          case 4:
            gl.uniform4f(
              this.getUniformLocation(uniform.name),
              value[0],
              value[1],
              value[2],
              value[3],
            );
            return;
          default:
            return;
        }
      } else if (typeof value === 'number') {
        gl.uniform1f(this.getUniformLocation(uniform.name), value);
      }
    });
  }
Sets the custom uniforms based on what was given in the constructor. This is called internally in `prepareDraw`.
@param {import("../Map.js").FrameState} frameState Frame state.