import { BufferTransform } from '@luma.gl/engine';
import { GL } from '@luma.gl/constants';
import Attribute from '../lib/attribute/attribute';
import { getAttributeTypeFromSize, getAttributeBufferLength, cycleBuffers, padBuffer, getFloat32VertexFormat } from '../lib/attribute/attribute-transition-utils';
import Transition from './transition';
export default class GPUInterpolationTransition {
  constructor({
    device,
    attribute,
    timeline
  }) {
    this.device = void 0;
    this.type = 'interpolation';
    this.attributeInTransition = void 0;
    this.settings = void 0;
    this.attribute = void 0;
    this.transition = void 0;
    this.currentStartIndices = void 0;
    this.currentLength = void 0;
    this.transform = void 0;
    this.buffers = void 0;
    this.device = device;
    this.transition = new Transition(timeline);
    this.attribute = attribute;
    this.attributeInTransition = new Attribute(device, attribute.settings);

    if (ArrayBuffer.isView(attribute.value)) {
      this.attributeInTransition.setData(attribute.value);
    }

    this.currentStartIndices = attribute.startIndices;
    this.currentLength = 0;
    this.transform = getTransform(device, attribute);
    const bufferOpts = {
      byteLength: attribute.buffer.byteLength,
      usage: 35050
    };
    this.buffers = [device.createBuffer(bufferOpts), device.createBuffer(bufferOpts)];
  }

  get inProgress() {
    return this.transition.inProgress;
  }

  start(transitionSettings, numInstances) {
    if (transitionSettings.duration <= 0) {
      this.transition.cancel();
      return;
    }

    this.settings = transitionSettings;
    const {
      buffers,
      attribute
    } = this;
    cycleBuffers(buffers);
    const padBufferOpts = {
      numInstances,
      attribute,
      fromLength: this.currentLength,
      fromStartIndices: this.currentStartIndices,
      getData: transitionSettings.enter
    };

    for (const [index, buffer] of buffers.entries()) {
      const paddedBuffer = padBuffer({
        buffer,
        ...padBufferOpts
      });

      if (buffer !== paddedBuffer) {
        buffer.destroy();
        buffers[index] = paddedBuffer;
        console.warn(`[GPUInterpolationTransition] Replaced buffer ${buffer.id} (${buffer.byteLength} bytes) → ` + `${paddedBuffer.id} (${paddedBuffer.byteLength} bytes)`);
      }
    }

    this.currentStartIndices = attribute.startIndices;
    this.currentLength = getAttributeBufferLength(attribute, numInstances);
    this.attributeInTransition.setData({
      buffer: buffers[1],
      value: attribute.value
    });
    this.transition.start(transitionSettings);
    this.transform.model.setVertexCount(Math.floor(this.currentLength / attribute.size));
    this.transform.model.setAttributes(attribute.getBuffer() ? {
      aFrom: buffers[0],
      aTo: attribute.getBuffer()
    } : {
      aFrom: buffers[0]
    });
    this.transform.transformFeedback.setBuffers({
      vCurrent: buffers[1]
    });
  }

  update() {
    const updated = this.transition.update();

    if (updated) {
      const {
        duration,
        easing
      } = this.settings;
      const {
        time
      } = this.transition;
      let t = time / duration;

      if (easing) {
        t = easing(t);
      }

      this.transform.model.setUniforms({
        time: t
      });
      this.transform.run();
    }

    return updated;
  }

  cancel() {
    this.transition.cancel();
    this.transform.delete();

    for (const buffer of this.buffers) {
      buffer.delete();
    }

    this.buffers.length = 0;
  }

}
const vs = `\
#version 300 es
#define SHADER_NAME interpolation-transition-vertex-shader

uniform float time;
in ATTRIBUTE_TYPE aFrom;
in ATTRIBUTE_TYPE aTo;
out ATTRIBUTE_TYPE vCurrent;

void main(void) {
  vCurrent = mix(aFrom, aTo, time);
  gl_Position = vec4(0.0);
}
`;

function getTransform(device, attribute) {
  const attributeType = getAttributeTypeFromSize(attribute.size);
  const format = getFloat32VertexFormat(attribute.size);
  return new BufferTransform(device, {
    vs,
    bufferLayout: [{
      name: 'aFrom',
      format
    }, {
      name: 'aTo',
      format
    }],
    defines: {
      ATTRIBUTE_TYPE: attributeType
    },
    varyings: ['vCurrent']
  });
}
//# sourceMappingURL=gpu-interpolation-transition.js.map