'use strict';

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

var Extensions = require('../../../extensions/Extensions.js');
var PoolGroup = require('../../../utils/pool/PoolGroup.js');
var BatchGeometry = require('../../batcher/gpu/BatchGeometry.js');
var getTextureBatchBindGroup = require('../../batcher/gpu/getTextureBatchBindGroup.js');
var Batcher = require('../../batcher/shared/Batcher.js');
var InstructionSet = require('../../renderers/shared/instructions/InstructionSet.js');
var buildContextBatches = require('./utils/buildContextBatches.js');

class GpuGraphicsContext {
}
class GraphicsContextRenderData {
  constructor() {
    this.geometry = new BatchGeometry.BatchGeometry();
    this.instructions = new InstructionSet.InstructionSet();
  }
  init() {
    this.geometry.reset();
    this.instructions.reset();
  }
}
class GraphicsContextSystem {
  constructor() {
    // the root context batches, used to either make a batch or geometry
    // all graphics use this as a base
    this._activeBatchers = [];
    this._gpuContextHash = {};
    // used for non-batchable graphics
    this._graphicsDataContextHash = /* @__PURE__ */ Object.create(null);
    this._needsContextNeedsRebuild = [];
  }
  prerender() {
    this._returnActiveBatchers();
  }
  getContextRenderData(context) {
    return this._graphicsDataContextHash[context.uid] || this._initContextRenderData(context);
  }
  // Context management functions
  updateGpuContext(context) {
    let gpuContext = this._gpuContextHash[context.uid] || this._initContext(context);
    if (context.dirty) {
      if (gpuContext) {
        this._cleanGraphicsContextData(context);
      } else {
        gpuContext = this._initContext(context);
      }
      const contextBatches = buildContextBatches.buildContextBatches(context);
      let size = 0;
      const batchMode = context.batchMode;
      let isBatchable = true;
      if (context.customShader || batchMode === "no-batch") {
        isBatchable = false;
      } else if (batchMode === "auto") {
        for (let i = 0; i < contextBatches.length; i++) {
          size += contextBatches[i].vertexSize;
          if (size > 400) {
            isBatchable = false;
            break;
          }
        }
      }
      gpuContext = this._gpuContextHash[context.uid] = {
        isBatchable,
        batches: contextBatches
      };
      context.dirty = false;
    }
    return gpuContext;
  }
  getGpuContext(context) {
    return this._gpuContextHash[context.uid] || this._initContext(context);
  }
  _returnActiveBatchers() {
    for (let i = 0; i < this._activeBatchers.length; i++) {
      PoolGroup.BigPool.return(this._activeBatchers[i]);
    }
    this._activeBatchers.length = 0;
  }
  _initContextRenderData(context) {
    const graphicsData = PoolGroup.BigPool.get(GraphicsContextRenderData);
    const batches = this._gpuContextHash[context.uid].batches;
    let vertexSize = 0;
    let indexSize = 0;
    batches.forEach((batch) => {
      batch.applyTransform = false;
      vertexSize += batch.geometryData.vertices.length;
      indexSize += batch.geometryData.indices.length;
    });
    const batcher = PoolGroup.BigPool.get(Batcher.Batcher);
    this._activeBatchers.push(batcher);
    batcher.ensureAttributeBuffer(vertexSize);
    batcher.ensureIndexBuffer(indexSize);
    batcher.begin();
    for (let i = 0; i < batches.length; i++) {
      const batch = batches[i];
      batcher.add(batch);
    }
    batcher.finish(graphicsData.instructions);
    const geometry = graphicsData.geometry;
    geometry.indexBuffer.data = batcher.indexBuffer;
    geometry.buffers[0].data = batcher.attributeBuffer.float32View;
    geometry.indexBuffer.update(batcher.indexSize * 4);
    geometry.buffers[0].update(batcher.attributeSize * 4);
    const drawBatches = batcher.batches;
    for (let i = 0; i < drawBatches.length; i++) {
      const batch = drawBatches[i];
      batch.bindGroup = getTextureBatchBindGroup.getTextureBatchBindGroup(batch.textures.textures, batch.textures.count);
    }
    this._graphicsDataContextHash[context.uid] = graphicsData;
    return graphicsData;
  }
  _initContext(context) {
    const gpuContext = new GpuGraphicsContext();
    this._gpuContextHash[context.uid] = gpuContext;
    context.on("update", this.onGraphicsContextUpdate, this);
    context.on("destroy", this.onGraphicsContextDestroy, this);
    return this._gpuContextHash[context.uid];
  }
  onGraphicsContextUpdate(context) {
    this._needsContextNeedsRebuild.push(context);
  }
  onGraphicsContextDestroy(context) {
    this._cleanGraphicsContextData(context);
    this._gpuContextHash[context.uid] = null;
  }
  _cleanGraphicsContextData(context) {
    const gpuContext = this._gpuContextHash[context.uid];
    if (!gpuContext.isBatchable) {
      if (this._graphicsDataContextHash[context.uid]) {
        PoolGroup.BigPool.return(this.getContextRenderData(context));
        this._graphicsDataContextHash[context.uid] = null;
      }
    }
    if (gpuContext.batches) {
      gpuContext.batches.forEach((batch) => {
        PoolGroup.BigPool.return(batch);
      });
    }
  }
  destroy() {
    for (const context of this._needsContextNeedsRebuild) {
      this._cleanGraphicsContextData(context);
      this._gpuContextHash[context.uid] = null;
    }
    this._needsContextNeedsRebuild.length = 0;
  }
}
/** @ignore */
GraphicsContextSystem.extension = {
  type: [
    Extensions.ExtensionType.WebGLSystem,
    Extensions.ExtensionType.WebGPUSystem,
    Extensions.ExtensionType.CanvasSystem
  ],
  name: "graphicsContext"
};

exports.GpuGraphicsContext = GpuGraphicsContext;
exports.GraphicsContextRenderData = GraphicsContextRenderData;
exports.GraphicsContextSystem = GraphicsContextSystem;
//# sourceMappingURL=GraphicsContextSystem.js.map
