'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var Extensions = require('../../../../extensions/Extensions.js');
var BufferResource = require('../../shared/buffer/BufferResource.js');
var UniformGroup = require('../../shared/shader/UniformGroup.js');
var TextureSource = require('../../shared/texture/sources/TextureSource.js');
var TextureStyle = require('../../shared/texture/TextureStyle.js');
var generateProgram = require('./program/generateProgram.js');

const defaultSyncData = {
  textureCount: 0,
  blockIndex: 0
};
class GlShaderSystem {
  constructor(renderer) {
    this.activeProgram = null;
    this._programDataHash = /* @__PURE__ */ Object.create(null);
    this._nextIndex = 0;
    this._boundUniformsIdsToIndexHash = /* @__PURE__ */ Object.create(null);
    this._boundIndexToUniformsHash = /* @__PURE__ */ Object.create(null);
    this._renderer = renderer;
  }
  contextChange(gl) {
    this._gl = gl;
    this._maxBindings = gl.getParameter(gl.MAX_UNIFORM_BUFFER_BINDINGS);
  }
  bind(shader, skipSync) {
    this._setProgram(shader.glProgram);
    if (skipSync)
      return;
    defaultSyncData.textureCount = 0;
    defaultSyncData.blockIndex = 0;
    const gl = this._gl;
    const programData = this.getProgramData(shader.glProgram);
    for (const i in shader.groups) {
      const bindGroup = shader.groups[i];
      for (const j in bindGroup.resources) {
        const resource = bindGroup.resources[j];
        if (resource instanceof UniformGroup.UniformGroup) {
          if (resource.ubo) {
            this.bindUniformBlock(
              resource,
              shader.uniformBindMap[i][j],
              defaultSyncData.blockIndex++
            );
          } else {
            this._updateUniformGroup(resource);
          }
        } else if (resource instanceof BufferResource.BufferResource) {
          this.bindUniformBlock(
            resource,
            shader.uniformBindMap[i][j],
            defaultSyncData.blockIndex++
          );
        } else if (resource instanceof TextureSource.TextureSource) {
          this._renderer.texture.bind(resource, defaultSyncData.textureCount);
          const uniformName = shader.uniformBindMap[i][j];
          const uniformData = programData.uniformData[uniformName];
          if (uniformData) {
            if (uniformData.value !== defaultSyncData.textureCount) {
              gl.uniform1i(uniformData.location, defaultSyncData.textureCount);
            }
            defaultSyncData.textureCount++;
          }
        } else if (resource instanceof TextureStyle.TextureStyle) {
        }
      }
    }
  }
  _updateUniformGroup(uniformGroup) {
    this._renderer.uniformGroup.updateUniformGroup(uniformGroup, this.activeProgram, defaultSyncData);
  }
  bindUniformBlock(uniformGroup, name, index = 0) {
    const bufferSystem = this._renderer.buffer;
    const programData = this.getProgramData(this.activeProgram);
    const isBufferResource = uniformGroup.bufferResource;
    if (isBufferResource) {
      this._renderer.uniformBuffer.updateUniformGroup(uniformGroup);
    }
    bufferSystem.updateBuffer(uniformGroup.buffer);
    let boundIndex = this._boundUniformsIdsToIndexHash[uniformGroup.uid];
    if (boundIndex === void 0) {
      const nextIndex = this._nextIndex++ % this._maxBindings;
      const currentBoundUniformGroup = this._boundIndexToUniformsHash[nextIndex];
      if (currentBoundUniformGroup) {
        this._boundUniformsIdsToIndexHash[currentBoundUniformGroup.uid] = void 0;
      }
      boundIndex = this._boundUniformsIdsToIndexHash[uniformGroup.uid] = nextIndex;
      this._boundIndexToUniformsHash[nextIndex] = uniformGroup;
      if (isBufferResource) {
        bufferSystem.bindBufferRange(uniformGroup.buffer, nextIndex, uniformGroup.offset);
      } else {
        bufferSystem.bindBufferBase(uniformGroup.buffer, nextIndex);
      }
    }
    const gl = this._gl;
    const uniformBlockIndex = this.activeProgram.uniformBlockData[name].index;
    if (programData.uniformBlockBindings[index] === boundIndex)
      return;
    programData.uniformBlockBindings[index] = boundIndex;
    gl.uniformBlockBinding(programData.program, uniformBlockIndex, boundIndex);
  }
  _setProgram(program) {
    if (this.activeProgram === program)
      return;
    this.activeProgram = program;
    const programData = this.getProgramData(program);
    this._gl.useProgram(programData.program);
  }
  getProgramData(program) {
    return this._programDataHash[program.key] || this._createProgramData(program);
  }
  _createProgramData(program) {
    const key = program.key;
    this._programDataHash[key] = generateProgram.generateProgram(this._gl, program);
    return this._programDataHash[key];
  }
  destroy() {
    for (const key of Object.keys(this._programDataHash)) {
      const programData = this._programDataHash[key];
      programData.destroy();
      this._programDataHash[key] = null;
    }
    this._programDataHash = null;
    this._boundUniformsIdsToIndexHash = null;
  }
}
/** @ignore */
GlShaderSystem.extension = {
  type: [
    Extensions.ExtensionType.WebGLSystem
  ],
  name: "shader"
};

exports.GlShaderSystem = GlShaderSystem;
//# sourceMappingURL=GlShaderSystem.js.map
