(function (global, factory) {
  if (typeof define === "function" && define.amd) {
    define(["exports", "./constants.js", "three"], factory);
  } else if (typeof exports !== "undefined") {
    factory(exports, require("./constants.js"), require("three"));
  } else {
    var mod = {
      exports: {}
    };
    factory(mod.exports, global.constants, global.three);
    global.WebGPURenderPipeline = mod.exports;
  }
})(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, _constants, _three) {
  "use strict";

  Object.defineProperty(_exports, "__esModule", {
    value: true
  });
  _exports.default = void 0;

  function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }

  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }

  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

  function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }

  var WebGPURenderPipeline = /*#__PURE__*/function () {
    function WebGPURenderPipeline(device, renderer, sampleCount) {
      _classCallCheck(this, WebGPURenderPipeline);

      this.cacheKey = null;
      this.shaderAttributes = null;
      this.stageVertex = null;
      this.stageFragment = null;
      this.usedTimes = 0;
      this._device = device;
      this._renderer = renderer;
      this._sampleCount = sampleCount;
    }

    _createClass(WebGPURenderPipeline, [{
      key: "init",
      value: function init(cacheKey, stageVertex, stageFragment, object, nodeBuilder) {
        var material = object.material;
        var geometry = object.geometry; // determine shader attributes

        var shaderAttributes = this._getShaderAttributes(nodeBuilder, geometry); // vertex buffers


        var vertexBuffers = [];

        var _iterator = _createForOfIteratorHelper(shaderAttributes),
            _step;

        try {
          for (_iterator.s(); !(_step = _iterator.n()).done;) {
            var attribute = _step.value;
            var name = attribute.name;
            var geometryAttribute = geometry.getAttribute(name);
            var stepMode = geometryAttribute !== undefined && geometryAttribute.isInstancedBufferAttribute ? _constants.GPUInputStepMode.Instance : _constants.GPUInputStepMode.Vertex;
            vertexBuffers.push({
              arrayStride: attribute.arrayStride,
              attributes: [{
                shaderLocation: attribute.slot,
                offset: 0,
                format: attribute.format
              }],
              stepMode: stepMode
            });
          }
        } catch (err) {
          _iterator.e(err);
        } finally {
          _iterator.f();
        }

        this.cacheKey = cacheKey;
        this.shaderAttributes = shaderAttributes;
        this.stageVertex = stageVertex;
        this.stageFragment = stageFragment; // blending

        var alphaBlend = {};
        var colorBlend = {};

        if (material.transparent === true && material.blending !== _three.NoBlending) {
          alphaBlend = this._getAlphaBlend(material);
          colorBlend = this._getColorBlend(material);
        } // stencil


        var stencilFront = {};

        if (material.stencilWrite === true) {
          stencilFront = {
            compare: this._getStencilCompare(material),
            failOp: this._getStencilOperation(material.stencilFail),
            depthFailOp: this._getStencilOperation(material.stencilZFail),
            passOp: this._getStencilOperation(material.stencilZPass)
          };
        } //


        var primitiveState = this._getPrimitiveState(object, material);

        var colorWriteMask = this._getColorWriteMask(material);

        var depthCompare = this._getDepthCompare(material);

        var colorFormat = this._renderer.getCurrentColorFormat();

        var depthStencilFormat = this._renderer.getCurrentDepthStencilFormat();

        this.pipeline = this._device.createRenderPipeline({
          vertex: Object.assign({}, stageVertex.stage, {
            buffers: vertexBuffers
          }),
          fragment: Object.assign({}, stageFragment.stage, {
            targets: [{
              format: colorFormat,
              blend: {
                alpha: alphaBlend,
                color: colorBlend
              },
              writeMask: colorWriteMask
            }]
          }),
          primitive: primitiveState,
          depthStencil: {
            format: depthStencilFormat,
            depthWriteEnabled: material.depthWrite,
            depthCompare: depthCompare,
            stencilFront: stencilFront,
            stencilBack: {},
            // three.js does not provide an API to configure the back function (gl.stencilFuncSeparate() was never used)
            stencilReadMask: material.stencilFuncMask,
            stencilWriteMask: material.stencilWriteMask
          },
          multisample: {
            count: this._sampleCount
          }
        });
      }
    }, {
      key: "_getArrayStride",
      value: function _getArrayStride(type, bytesPerElement) {
        // @TODO: This code is GLSL specific. We need to update when we switch to WGSL.
        if (type === 'float' || type === 'int' || type === 'uint') return bytesPerElement;
        if (type === 'vec2' || type === 'ivec2' || type === 'uvec2') return bytesPerElement * 2;
        if (type === 'vec3' || type === 'ivec3' || type === 'uvec3') return bytesPerElement * 3;
        if (type === 'vec4' || type === 'ivec4' || type === 'uvec4') return bytesPerElement * 4;
        console.error('THREE.WebGPURenderer: Shader variable type not supported yet.', type);
      }
    }, {
      key: "_getAlphaBlend",
      value: function _getAlphaBlend(material) {
        var blending = material.blending;
        var premultipliedAlpha = material.premultipliedAlpha;
        var alphaBlend = undefined;

        switch (blending) {
          case _three.NormalBlending:
            if (premultipliedAlpha === false) {
              alphaBlend = {
                srcFactor: _constants.GPUBlendFactor.One,
                dstFactor: _constants.GPUBlendFactor.OneMinusSrcAlpha,
                operation: _constants.GPUBlendOperation.Add
              };
            }

            break;

          case _three.AdditiveBlending:
            // no alphaBlend settings
            break;

          case _three.SubtractiveBlending:
            if (premultipliedAlpha === true) {
              alphaBlend = {
                srcFactor: _constants.GPUBlendFactor.OneMinusSrcColor,
                dstFactor: _constants.GPUBlendFactor.OneMinusSrcAlpha,
                operation: _constants.GPUBlendOperation.Add
              };
            }

            break;

          case _three.MultiplyBlending:
            if (premultipliedAlpha === true) {
              alphaBlend = {
                srcFactor: _constants.GPUBlendFactor.Zero,
                dstFactor: _constants.GPUBlendFactor.SrcAlpha,
                operation: _constants.GPUBlendOperation.Add
              };
            }

            break;

          case _three.CustomBlending:
            var blendSrcAlpha = material.blendSrcAlpha;
            var blendDstAlpha = material.blendDstAlpha;
            var blendEquationAlpha = material.blendEquationAlpha;

            if (blendSrcAlpha !== null && blendDstAlpha !== null && blendEquationAlpha !== null) {
              alphaBlend = {
                srcFactor: this._getBlendFactor(blendSrcAlpha),
                dstFactor: this._getBlendFactor(blendDstAlpha),
                operation: this._getBlendOperation(blendEquationAlpha)
              };
            }

            break;

          default:
            console.error('THREE.WebGPURenderer: Blending not supported.', blending);
        }

        return alphaBlend;
      }
    }, {
      key: "_getBlendFactor",
      value: function _getBlendFactor(blend) {
        var blendFactor;

        switch (blend) {
          case _three.ZeroFactor:
            blendFactor = _constants.GPUBlendFactor.Zero;
            break;

          case _three.OneFactor:
            blendFactor = _constants.GPUBlendFactor.One;
            break;

          case _three.SrcColorFactor:
            blendFactor = _constants.GPUBlendFactor.SrcColor;
            break;

          case _three.OneMinusSrcColorFactor:
            blendFactor = _constants.GPUBlendFactor.OneMinusSrcColor;
            break;

          case _three.SrcAlphaFactor:
            blendFactor = _constants.GPUBlendFactor.SrcAlpha;
            break;

          case _three.OneMinusSrcAlphaFactor:
            blendFactor = _constants.GPUBlendFactor.OneMinusSrcAlpha;
            break;

          case _three.DstColorFactor:
            blendFactor = _constants.GPUBlendFactor.DstColor;
            break;

          case _three.OneMinusDstColorFactor:
            blendFactor = _constants.GPUBlendFactor.OneMinusDstColor;
            break;

          case _three.DstAlphaFactor:
            blendFactor = _constants.GPUBlendFactor.DstAlpha;
            break;

          case _three.OneMinusDstAlphaFactor:
            blendFactor = _constants.GPUBlendFactor.OneMinusDstAlpha;
            break;

          case _three.SrcAlphaSaturateFactor:
            blendFactor = _constants.GPUBlendFactor.SrcAlphaSaturated;
            break;

          case _constants.BlendColorFactor:
            blendFactor = _constants.GPUBlendFactor.BlendColor;
            break;

          case _constants.OneMinusBlendColorFactor:
            blendFactor = _constants.GPUBlendFactor.OneMinusBlendColor;
            break;

          default:
            console.error('THREE.WebGPURenderer: Blend factor not supported.', blend);
        }

        return blendFactor;
      }
    }, {
      key: "_getBlendOperation",
      value: function _getBlendOperation(blendEquation) {
        var blendOperation;

        switch (blendEquation) {
          case _three.AddEquation:
            blendOperation = _constants.GPUBlendOperation.Add;
            break;

          case _three.SubtractEquation:
            blendOperation = _constants.GPUBlendOperation.Subtract;
            break;

          case _three.ReverseSubtractEquation:
            blendOperation = _constants.GPUBlendOperation.ReverseSubtract;
            break;

          case _three.MinEquation:
            blendOperation = _constants.GPUBlendOperation.Min;
            break;

          case _three.MaxEquation:
            blendOperation = _constants.GPUBlendOperation.Max;
            break;

          default:
            console.error('THREE.WebGPURenderer: Blend equation not supported.', blendEquation);
        }

        return blendOperation;
      }
    }, {
      key: "_getColorBlend",
      value: function _getColorBlend(material) {
        var blending = material.blending;
        var premultipliedAlpha = material.premultipliedAlpha;
        var colorBlend = {
          srcFactor: null,
          dstFactor: null,
          operation: null
        };

        switch (blending) {
          case _three.NormalBlending:
            colorBlend.srcFactor = premultipliedAlpha === true ? _constants.GPUBlendFactor.One : _constants.GPUBlendFactor.SrcAlpha;
            colorBlend.dstFactor = _constants.GPUBlendFactor.OneMinusSrcAlpha;
            colorBlend.operation = _constants.GPUBlendOperation.Add;
            break;

          case _three.AdditiveBlending:
            colorBlend.srcFactor = premultipliedAlpha === true ? _constants.GPUBlendFactor.One : _constants.GPUBlendFactor.SrcAlpha;
            colorBlend.operation = _constants.GPUBlendOperation.Add;
            break;

          case _three.SubtractiveBlending:
            colorBlend.srcFactor = _constants.GPUBlendFactor.Zero;
            colorBlend.dstFactor = premultipliedAlpha === true ? _constants.GPUBlendFactor.Zero : _constants.GPUBlendFactor.OneMinusSrcColor;
            colorBlend.operation = _constants.GPUBlendOperation.Add;
            break;

          case _three.MultiplyBlending:
            colorBlend.srcFactor = _constants.GPUBlendFactor.Zero;
            colorBlend.dstFactor = _constants.GPUBlendFactor.SrcColor;
            colorBlend.operation = _constants.GPUBlendOperation.Add;
            break;

          case _three.CustomBlending:
            colorBlend.srcFactor = this._getBlendFactor(material.blendSrc);
            colorBlend.dstFactor = this._getBlendFactor(material.blendDst);
            colorBlend.operation = this._getBlendOperation(material.blendEquation);
            break;

          default:
            console.error('THREE.WebGPURenderer: Blending not supported.', blending);
        }

        return colorBlend;
      }
    }, {
      key: "_getColorWriteMask",
      value: function _getColorWriteMask(material) {
        return material.colorWrite === true ? _constants.GPUColorWriteFlags.All : _constants.GPUColorWriteFlags.None;
      }
    }, {
      key: "_getDepthCompare",
      value: function _getDepthCompare(material) {
        var depthCompare;

        if (material.depthTest === false) {
          depthCompare = _constants.GPUCompareFunction.Always;
        } else {
          var depthFunc = material.depthFunc;

          switch (depthFunc) {
            case _three.NeverDepth:
              depthCompare = _constants.GPUCompareFunction.Never;
              break;

            case _three.AlwaysDepth:
              depthCompare = _constants.GPUCompareFunction.Always;
              break;

            case _three.LessDepth:
              depthCompare = _constants.GPUCompareFunction.Less;
              break;

            case _three.LessEqualDepth:
              depthCompare = _constants.GPUCompareFunction.LessEqual;
              break;

            case _three.EqualDepth:
              depthCompare = _constants.GPUCompareFunction.Equal;
              break;

            case _three.GreaterEqualDepth:
              depthCompare = _constants.GPUCompareFunction.GreaterEqual;
              break;

            case _three.GreaterDepth:
              depthCompare = _constants.GPUCompareFunction.Greater;
              break;

            case _three.NotEqualDepth:
              depthCompare = _constants.GPUCompareFunction.NotEqual;
              break;

            default:
              console.error('THREE.WebGPURenderer: Invalid depth function.', depthFunc);
          }
        }

        return depthCompare;
      }
    }, {
      key: "_getPrimitiveState",
      value: function _getPrimitiveState(object, material) {
        var descriptor = {};
        descriptor.topology = this._getPrimitiveTopology(object);

        if (object.isLine === true && object.isLineSegments !== true) {
          var geometry = object.geometry;
          var count = geometry.index ? geometry.index.count : geometry.attributes.position.count;
          descriptor.stripIndexFormat = count > 65535 ? _constants.GPUIndexFormat.Uint32 : _constants.GPUIndexFormat.Uint16; // define data type for primitive restart value
        }

        switch (material.side) {
          case _three.FrontSide:
            descriptor.frontFace = _constants.GPUFrontFace.CCW;
            descriptor.cullMode = _constants.GPUCullMode.Back;
            break;

          case _three.BackSide:
            descriptor.frontFace = _constants.GPUFrontFace.CW;
            descriptor.cullMode = _constants.GPUCullMode.Back;
            break;

          case _three.DoubleSide:
            descriptor.frontFace = _constants.GPUFrontFace.CCW;
            descriptor.cullMode = _constants.GPUCullMode.None;
            break;

          default:
            console.error('THREE.WebGPURenderer: Unknown Material.side value.', material.side);
            break;
        }

        return descriptor;
      }
    }, {
      key: "_getPrimitiveTopology",
      value: function _getPrimitiveTopology(object) {
        if (object.isMesh) return _constants.GPUPrimitiveTopology.TriangleList;else if (object.isPoints) return _constants.GPUPrimitiveTopology.PointList;else if (object.isLineSegments) return _constants.GPUPrimitiveTopology.LineList;else if (object.isLine) return _constants.GPUPrimitiveTopology.LineStrip;
      }
    }, {
      key: "_getStencilCompare",
      value: function _getStencilCompare(material) {
        var stencilCompare;
        var stencilFunc = material.stencilFunc;

        switch (stencilFunc) {
          case _three.NeverStencilFunc:
            stencilCompare = _constants.GPUCompareFunction.Never;
            break;

          case _three.AlwaysStencilFunc:
            stencilCompare = _constants.GPUCompareFunction.Always;
            break;

          case _three.LessStencilFunc:
            stencilCompare = _constants.GPUCompareFunction.Less;
            break;

          case _three.LessEqualStencilFunc:
            stencilCompare = _constants.GPUCompareFunction.LessEqual;
            break;

          case _three.EqualStencilFunc:
            stencilCompare = _constants.GPUCompareFunction.Equal;
            break;

          case _three.GreaterEqualStencilFunc:
            stencilCompare = _constants.GPUCompareFunction.GreaterEqual;
            break;

          case _three.GreaterStencilFunc:
            stencilCompare = _constants.GPUCompareFunction.Greater;
            break;

          case _three.NotEqualStencilFunc:
            stencilCompare = _constants.GPUCompareFunction.NotEqual;
            break;

          default:
            console.error('THREE.WebGPURenderer: Invalid stencil function.', stencilFunc);
        }

        return stencilCompare;
      }
    }, {
      key: "_getStencilOperation",
      value: function _getStencilOperation(op) {
        var stencilOperation;

        switch (op) {
          case _three.KeepStencilOp:
            stencilOperation = _constants.GPUStencilOperation.Keep;
            break;

          case _three.ZeroStencilOp:
            stencilOperation = _constants.GPUStencilOperation.Zero;
            break;

          case _three.ReplaceStencilOp:
            stencilOperation = _constants.GPUStencilOperation.Replace;
            break;

          case _three.InvertStencilOp:
            stencilOperation = _constants.GPUStencilOperation.Invert;
            break;

          case _three.IncrementStencilOp:
            stencilOperation = _constants.GPUStencilOperation.IncrementClamp;
            break;

          case _three.DecrementStencilOp:
            stencilOperation = _constants.GPUStencilOperation.DecrementClamp;
            break;

          case _three.IncrementWrapStencilOp:
            stencilOperation = _constants.GPUStencilOperation.IncrementWrap;
            break;

          case _three.DecrementWrapStencilOp:
            stencilOperation = _constants.GPUStencilOperation.DecrementWrap;
            break;

          default:
            console.error('THREE.WebGPURenderer: Invalid stencil operation.', stencilOperation);
        }

        return stencilOperation;
      }
    }, {
      key: "_getVertexFormat",
      value: function _getVertexFormat(type, bytesPerElement) {
        // float
        if (type === 'float') return _constants.GPUVertexFormat.Float32;

        if (type === 'vec2') {
          if (bytesPerElement === 2) {
            return _constants.GPUVertexFormat.Float16x2;
          } else {
            return _constants.GPUVertexFormat.Float32x2;
          }
        }

        if (type === 'vec3') return _constants.GPUVertexFormat.Float32x3;

        if (type === 'vec4') {
          if (bytesPerElement === 2) {
            return _constants.GPUVertexFormat.Float16x4;
          } else {
            return _constants.GPUVertexFormat.Float32x4;
          }
        } // int


        if (type === 'int') return _constants.GPUVertexFormat.Sint32;

        if (type === 'ivec2') {
          if (bytesPerElement === 1) {
            return _constants.GPUVertexFormat.Sint8x2;
          } else if (bytesPerElement === 2) {
            return _constants.GPUVertexFormat.Sint16x2;
          } else {
            return _constants.GPUVertexFormat.Sint32x2;
          }
        }

        if (type === 'ivec3') return _constants.GPUVertexFormat.Sint32x3;

        if (type === 'ivec4') {
          if (bytesPerElement === 1) {
            return _constants.GPUVertexFormat.Sint8x4;
          } else if (bytesPerElement === 2) {
            return _constants.GPUVertexFormat.Sint16x4;
          } else {
            return _constants.GPUVertexFormat.Sint32x4;
          }
        } // uint


        if (type === 'uint') return _constants.GPUVertexFormat.Uint32;

        if (type === 'uvec2') {
          if (bytesPerElement === 1) {
            return _constants.GPUVertexFormat.Uint8x2;
          } else if (bytesPerElement === 2) {
            return _constants.GPUVertexFormat.Uint16x2;
          } else {
            return _constants.GPUVertexFormat.Uint32x2;
          }
        }

        if (type === 'uvec3') return _constants.GPUVertexFormat.Uint32x3;

        if (type === 'uvec4') {
          if (bytesPerElement === 1) {
            return _constants.GPUVertexFormat.Uint8x4;
          } else if (bytesPerElement === 2) {
            return _constants.GPUVertexFormat.Uint16x4;
          } else {
            return _constants.GPUVertexFormat.Uint32x4;
          }
        }

        console.error('THREE.WebGPURenderer: Shader variable type not supported yet.', type);
      }
    }, {
      key: "_getShaderAttributes",
      value: function _getShaderAttributes(nodeBuilder, geometry) {
        var nodeAttributes = nodeBuilder.attributes;
        var attributes = [];

        for (var slot = 0; slot < nodeAttributes.length; slot++) {
          var nodeAttribute = nodeAttributes[slot];
          var name = nodeAttribute.name;
          var type = nodeAttribute.type;
          var geometryAttribute = geometry.getAttribute(name);
          var bytesPerElement = geometryAttribute !== undefined ? geometryAttribute.array.BYTES_PER_ELEMENT : 4;

          var arrayStride = this._getArrayStride(type, bytesPerElement);

          var format = this._getVertexFormat(type, bytesPerElement);

          attributes.push({
            name: name,
            arrayStride: arrayStride,
            format: format,
            slot: slot
          });
        }

        return attributes;
      }
    }]);

    return WebGPURenderPipeline;
  }();

  var _default = WebGPURenderPipeline;
  _exports.default = _default;
});