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

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

  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; }

  /**
   * https://github.com/gkjohnson/ply-exporter-js
   *
   * Usage:
   *  const exporter = new PLYExporter();
   *
   *  // second argument is a list of options
   *  exporter.parse(mesh, data => console.log(data), { binary: true, excludeAttributes: [ 'color' ], littleEndian: true });
   *
   * Format Definition:
   * http://paulbourke.net/dataformats/ply/
   */
  var PLYExporter = /*#__PURE__*/function () {
    function PLYExporter() {
      _classCallCheck(this, PLYExporter);
    }

    _createClass(PLYExporter, [{
      key: "parse",
      value: function parse(object, onDone, options) {
        if (onDone && typeof onDone === 'object') {
          console.warn('THREE.PLYExporter: The options parameter is now the third argument to the "parse" function. See the documentation for the new API.');
          options = onDone;
          onDone = undefined;
        } // Iterate over the valid meshes in the object


        function traverseMeshes(cb) {
          object.traverse(function (child) {
            if (child.isMesh === true) {
              var mesh = child;
              var geometry = mesh.geometry;

              if (geometry.isBufferGeometry !== true) {
                throw new Error('THREE.PLYExporter: Geometry is not of type THREE.BufferGeometry.');
              }

              if (geometry.hasAttribute('position') === true) {
                cb(mesh, geometry);
              }
            }
          });
        } // Default options


        var defaultOptions = {
          binary: false,
          excludeAttributes: [],
          // normal, uv, color, index
          littleEndian: false
        };
        options = Object.assign(defaultOptions, options);
        var excludeAttributes = options.excludeAttributes;
        var includeNormals = false;
        var includeColors = false;
        var includeUVs = false; // count the vertices, check which properties are used,
        // and cache the BufferGeometry

        var vertexCount = 0;
        var faceCount = 0;
        object.traverse(function (child) {
          if (child.isMesh === true) {
            var mesh = child;
            var geometry = mesh.geometry;

            if (geometry.isBufferGeometry !== true) {
              throw new Error('THREE.PLYExporter: Geometry is not of type THREE.BufferGeometry.');
            }

            var vertices = geometry.getAttribute('position');
            var normals = geometry.getAttribute('normal');
            var uvs = geometry.getAttribute('uv');
            var colors = geometry.getAttribute('color');
            var indices = geometry.getIndex();

            if (vertices === undefined) {
              return;
            }

            vertexCount += vertices.count;
            faceCount += indices ? indices.count / 3 : vertices.count / 3;
            if (normals !== undefined) includeNormals = true;
            if (uvs !== undefined) includeUVs = true;
            if (colors !== undefined) includeColors = true;
          }
        });
        var includeIndices = excludeAttributes.indexOf('index') === -1;
        includeNormals = includeNormals && excludeAttributes.indexOf('normal') === -1;
        includeColors = includeColors && excludeAttributes.indexOf('color') === -1;
        includeUVs = includeUVs && excludeAttributes.indexOf('uv') === -1;

        if (includeIndices && faceCount !== Math.floor(faceCount)) {
          // point cloud meshes will not have an index array and may not have a
          // number of vertices that is divisble by 3 (and therefore representable
          // as triangles)
          console.error('PLYExporter: Failed to generate a valid PLY file with triangle indices because the ' + 'number of indices is not divisible by 3.');
          return null;
        }

        var indexByteCount = 4;
        var header = 'ply\n' + "format ".concat(options.binary ? options.littleEndian ? 'binary_little_endian' : 'binary_big_endian' : 'ascii', " 1.0\n") + "element vertex ".concat(vertexCount, "\n") + // position
        'property float x\n' + 'property float y\n' + 'property float z\n';

        if (includeNormals === true) {
          // normal
          header += 'property float nx\n' + 'property float ny\n' + 'property float nz\n';
        }

        if (includeUVs === true) {
          // uvs
          header += 'property float s\n' + 'property float t\n';
        }

        if (includeColors === true) {
          // colors
          header += 'property uchar red\n' + 'property uchar green\n' + 'property uchar blue\n';
        }

        if (includeIndices === true) {
          // faces
          header += "element face ".concat(faceCount, "\n") + 'property list uchar int vertex_index\n';
        }

        header += 'end_header\n'; // Generate attribute data

        var vertex = new _three.Vector3();
        var normalMatrixWorld = new _three.Matrix3();
        var result = null;

        if (options.binary === true) {
          // Binary File Generation
          var headerBin = new TextEncoder().encode(header); // 3 position values at 4 bytes
          // 3 normal values at 4 bytes
          // 3 color channels with 1 byte
          // 2 uv values at 4 bytes

          var vertexListLength = vertexCount * (4 * 3 + (includeNormals ? 4 * 3 : 0) + (includeColors ? 3 : 0) + (includeUVs ? 4 * 2 : 0)); // 1 byte shape desciptor
          // 3 vertex indices at ${indexByteCount} bytes

          var faceListLength = includeIndices ? faceCount * (indexByteCount * 3 + 1) : 0;
          var output = new DataView(new ArrayBuffer(headerBin.length + vertexListLength + faceListLength));
          new Uint8Array(output.buffer).set(headerBin, 0);
          var vOffset = headerBin.length;
          var fOffset = headerBin.length + vertexListLength;
          var writtenVertices = 0;
          traverseMeshes(function (mesh, geometry) {
            var vertices = geometry.getAttribute('position');
            var normals = geometry.getAttribute('normal');
            var uvs = geometry.getAttribute('uv');
            var colors = geometry.getAttribute('color');
            var indices = geometry.getIndex();
            normalMatrixWorld.getNormalMatrix(mesh.matrixWorld);

            for (var i = 0, l = vertices.count; i < l; i++) {
              vertex.x = vertices.getX(i);
              vertex.y = vertices.getY(i);
              vertex.z = vertices.getZ(i);
              vertex.applyMatrix4(mesh.matrixWorld); // Position information

              output.setFloat32(vOffset, vertex.x, options.littleEndian);
              vOffset += 4;
              output.setFloat32(vOffset, vertex.y, options.littleEndian);
              vOffset += 4;
              output.setFloat32(vOffset, vertex.z, options.littleEndian);
              vOffset += 4; // Normal information

              if (includeNormals === true) {
                if (normals != null) {
                  vertex.x = normals.getX(i);
                  vertex.y = normals.getY(i);
                  vertex.z = normals.getZ(i);
                  vertex.applyMatrix3(normalMatrixWorld).normalize();
                  output.setFloat32(vOffset, vertex.x, options.littleEndian);
                  vOffset += 4;
                  output.setFloat32(vOffset, vertex.y, options.littleEndian);
                  vOffset += 4;
                  output.setFloat32(vOffset, vertex.z, options.littleEndian);
                  vOffset += 4;
                } else {
                  output.setFloat32(vOffset, 0, options.littleEndian);
                  vOffset += 4;
                  output.setFloat32(vOffset, 0, options.littleEndian);
                  vOffset += 4;
                  output.setFloat32(vOffset, 0, options.littleEndian);
                  vOffset += 4;
                }
              } // UV information


              if (includeUVs === true) {
                if (uvs != null) {
                  output.setFloat32(vOffset, uvs.getX(i), options.littleEndian);
                  vOffset += 4;
                  output.setFloat32(vOffset, uvs.getY(i), options.littleEndian);
                  vOffset += 4;
                } else if (includeUVs !== false) {
                  output.setFloat32(vOffset, 0, options.littleEndian);
                  vOffset += 4;
                  output.setFloat32(vOffset, 0, options.littleEndian);
                  vOffset += 4;
                }
              } // Color information


              if (includeColors === true) {
                if (colors != null) {
                  output.setUint8(vOffset, Math.floor(colors.getX(i) * 255));
                  vOffset += 1;
                  output.setUint8(vOffset, Math.floor(colors.getY(i) * 255));
                  vOffset += 1;
                  output.setUint8(vOffset, Math.floor(colors.getZ(i) * 255));
                  vOffset += 1;
                } else {
                  output.setUint8(vOffset, 255);
                  vOffset += 1;
                  output.setUint8(vOffset, 255);
                  vOffset += 1;
                  output.setUint8(vOffset, 255);
                  vOffset += 1;
                }
              }
            }

            if (includeIndices === true) {
              // Create the face list
              if (indices !== null) {
                for (var _i = 0, _l = indices.count; _i < _l; _i += 3) {
                  output.setUint8(fOffset, 3);
                  fOffset += 1;
                  output.setUint32(fOffset, indices.getX(_i + 0) + writtenVertices, options.littleEndian);
                  fOffset += indexByteCount;
                  output.setUint32(fOffset, indices.getX(_i + 1) + writtenVertices, options.littleEndian);
                  fOffset += indexByteCount;
                  output.setUint32(fOffset, indices.getX(_i + 2) + writtenVertices, options.littleEndian);
                  fOffset += indexByteCount;
                }
              } else {
                for (var _i2 = 0, _l2 = vertices.count; _i2 < _l2; _i2 += 3) {
                  output.setUint8(fOffset, 3);
                  fOffset += 1;
                  output.setUint32(fOffset, writtenVertices + _i2, options.littleEndian);
                  fOffset += indexByteCount;
                  output.setUint32(fOffset, writtenVertices + _i2 + 1, options.littleEndian);
                  fOffset += indexByteCount;
                  output.setUint32(fOffset, writtenVertices + _i2 + 2, options.littleEndian);
                  fOffset += indexByteCount;
                }
              }
            } // Save the amount of verts we've already written so we can offset
            // the face index on the next mesh


            writtenVertices += vertices.count;
          });
          result = output.buffer;
        } else {
          // Ascii File Generation
          // count the number of vertices
          var _writtenVertices = 0;
          var vertexList = '';
          var faceList = '';
          traverseMeshes(function (mesh, geometry) {
            var vertices = geometry.getAttribute('position');
            var normals = geometry.getAttribute('normal');
            var uvs = geometry.getAttribute('uv');
            var colors = geometry.getAttribute('color');
            var indices = geometry.getIndex();
            normalMatrixWorld.getNormalMatrix(mesh.matrixWorld); // form each line

            for (var i = 0, l = vertices.count; i < l; i++) {
              vertex.x = vertices.getX(i);
              vertex.y = vertices.getY(i);
              vertex.z = vertices.getZ(i);
              vertex.applyMatrix4(mesh.matrixWorld); // Position information

              var line = vertex.x + ' ' + vertex.y + ' ' + vertex.z; // Normal information

              if (includeNormals === true) {
                if (normals != null) {
                  vertex.x = normals.getX(i);
                  vertex.y = normals.getY(i);
                  vertex.z = normals.getZ(i);
                  vertex.applyMatrix3(normalMatrixWorld).normalize();
                  line += ' ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z;
                } else {
                  line += ' 0 0 0';
                }
              } // UV information


              if (includeUVs === true) {
                if (uvs != null) {
                  line += ' ' + uvs.getX(i) + ' ' + uvs.getY(i);
                } else if (includeUVs !== false) {
                  line += ' 0 0';
                }
              } // Color information


              if (includeColors === true) {
                if (colors != null) {
                  line += ' ' + Math.floor(colors.getX(i) * 255) + ' ' + Math.floor(colors.getY(i) * 255) + ' ' + Math.floor(colors.getZ(i) * 255);
                } else {
                  line += ' 255 255 255';
                }
              }

              vertexList += line + '\n';
            } // Create the face list


            if (includeIndices === true) {
              if (indices !== null) {
                for (var _i3 = 0, _l3 = indices.count; _i3 < _l3; _i3 += 3) {
                  faceList += "3 ".concat(indices.getX(_i3 + 0) + _writtenVertices);
                  faceList += " ".concat(indices.getX(_i3 + 1) + _writtenVertices);
                  faceList += " ".concat(indices.getX(_i3 + 2) + _writtenVertices, "\n");
                }
              } else {
                for (var _i4 = 0, _l4 = vertices.count; _i4 < _l4; _i4 += 3) {
                  faceList += "3 ".concat(_writtenVertices + _i4, " ").concat(_writtenVertices + _i4 + 1, " ").concat(_writtenVertices + _i4 + 2, "\n");
                }
              }

              faceCount += indices ? indices.count / 3 : vertices.count / 3;
            }

            _writtenVertices += vertices.count;
          });
          result = "".concat(header).concat(vertexList).concat(includeIndices ? "".concat(faceList, "\n") : '\n');
        }

        if (typeof onDone === 'function') requestAnimationFrame(function () {
          return onDone(result);
        });
        return result;
      }
    }]);

    return PLYExporter;
  }();

  _exports.PLYExporter = PLYExporter;
});