minerender 2.1.0-alpha.49 → 2.1.0-alpha.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3487,7 +3487,7 @@ var init_SceneObject = __esm({
3487
3487
  });
3488
3488
 
3489
3489
  // src/model/ModelCulling.ts
3490
- import { Vector3 as Vector36 } from "three";
3490
+ import { Vector3 as Vector39 } from "three";
3491
3491
  var ModelCulling;
3492
3492
  var init_ModelCulling = __esm({
3493
3493
  "src/model/ModelCulling.ts"() {
@@ -3496,7 +3496,7 @@ var init_ModelCulling = __esm({
3496
3496
  static toLocalMask(worldMask, rotation) {
3497
3497
  let localMask = 0;
3498
3498
  for (const [localFace, offset] of CUBE_FACE_OFFSETS.entries()) {
3499
- const normal = new Vector36(...offset).applyEuler(rotation);
3499
+ const normal = new Vector39(...offset).applyEuler(rotation);
3500
3500
  const worldFace = CUBE_FACE_OFFSETS.findIndex(([x, y, z]) => Math.abs(normal.x - x) < 1e-6 && Math.abs(normal.y - y) < 1e-6 && Math.abs(normal.z - z) < 1e-6);
3501
3501
  if (worldFace < 0) return 0;
3502
3502
  if (worldMask & 1 << worldFace) localMask |= 1 << localFace;
@@ -3530,15 +3530,15 @@ var init_ModelCulling = __esm({
3530
3530
 
3531
3531
  // src/three/BufferGeometryUtils.js
3532
3532
  import {
3533
- BufferAttribute as BufferAttribute3,
3534
- BufferGeometry,
3535
- Float32BufferAttribute as Float32BufferAttribute3,
3533
+ BufferAttribute as BufferAttribute4,
3534
+ BufferGeometry as BufferGeometry2,
3535
+ Float32BufferAttribute as Float32BufferAttribute4,
3536
3536
  InterleavedBuffer,
3537
3537
  InterleavedBufferAttribute,
3538
3538
  TriangleFanDrawMode,
3539
3539
  TriangleStripDrawMode,
3540
3540
  TrianglesDrawMode,
3541
- Vector3 as Vector37
3541
+ Vector3 as Vector310
3542
3542
  } from "three";
3543
3543
  function computeTangents(geometry) {
3544
3544
  geometry.computeTangents();
@@ -3551,7 +3551,7 @@ function mergeBufferGeometries(geometries, useGroups = false) {
3551
3551
  const attributes = {};
3552
3552
  const morphAttributes = {};
3553
3553
  const morphTargetsRelative = geometries[0].morphTargetsRelative;
3554
- const mergedGeometry = new BufferGeometry();
3554
+ const mergedGeometry = new BufferGeometry2();
3555
3555
  let offset = 0;
3556
3556
  for (let i = 0; i < geometries.length; ++i) {
3557
3557
  const geometry = geometries[i];
@@ -3675,7 +3675,7 @@ function mergeBufferAttributes(attributes) {
3675
3675
  array.set(attributes[i].array, offset);
3676
3676
  offset += attributes[i].array.length;
3677
3677
  }
3678
- return new BufferAttribute3(array, itemSize, normalized);
3678
+ return new BufferAttribute4(array, itemSize, normalized);
3679
3679
  }
3680
3680
  function interleaveAttributes(attributes) {
3681
3681
  let TypedArray;
@@ -3784,13 +3784,13 @@ function mergeVertices(geometry, tolerance = 1e-4) {
3784
3784
  const name = attributeNames[i];
3785
3785
  const oldAttribute = geometry.getAttribute(name);
3786
3786
  const buffer = new oldAttribute.array.constructor(attrArrays[name]);
3787
- const attribute = new BufferAttribute3(buffer, oldAttribute.itemSize, oldAttribute.normalized);
3787
+ const attribute = new BufferAttribute4(buffer, oldAttribute.itemSize, oldAttribute.normalized);
3788
3788
  result.setAttribute(name, attribute);
3789
3789
  if (name in morphAttrsArrays) {
3790
3790
  for (let j = 0; j < morphAttrsArrays[name].length; j++) {
3791
3791
  const oldMorphAttribute = geometry.morphAttributes[name][j];
3792
3792
  const buffer2 = new oldMorphAttribute.array.constructor(morphAttrsArrays[name][j]);
3793
- const morphAttribute = new BufferAttribute3(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
3793
+ const morphAttribute = new BufferAttribute4(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
3794
3794
  result.morphAttributes[name][j] = morphAttribute;
3795
3795
  }
3796
3796
  }
@@ -3857,15 +3857,15 @@ function computeMorphedAttributes(object) {
3857
3857
  console.error("THREE.BufferGeometryUtils: Geometry is not of type BufferGeometry.");
3858
3858
  return null;
3859
3859
  }
3860
- const _vA = new Vector37();
3861
- const _vB = new Vector37();
3862
- const _vC = new Vector37();
3863
- const _tempA = new Vector37();
3864
- const _tempB = new Vector37();
3865
- const _tempC = new Vector37();
3866
- const _morphA = new Vector37();
3867
- const _morphB = new Vector37();
3868
- const _morphC = new Vector37();
3860
+ const _vA = new Vector310();
3861
+ const _vB = new Vector310();
3862
+ const _vC = new Vector310();
3863
+ const _tempA = new Vector310();
3864
+ const _tempB = new Vector310();
3865
+ const _tempC = new Vector310();
3866
+ const _morphA = new Vector310();
3867
+ const _morphB = new Vector310();
3868
+ const _morphC = new Vector310();
3869
3869
  function _calculateMorphedAttributeData(object2, material2, attribute, morphAttribute, morphTargetsRelative2, a2, b2, c2, modifiedAttributeArray) {
3870
3870
  _vA.fromBufferAttribute(attribute, a2);
3871
3871
  _vB.fromBufferAttribute(attribute, b2);
@@ -4060,8 +4060,8 @@ function computeMorphedAttributes(object) {
4060
4060
  }
4061
4061
  }
4062
4062
  }
4063
- const morphedPositionAttribute = new Float32BufferAttribute3(modifiedPosition, 3);
4064
- const morphedNormalAttribute = new Float32BufferAttribute3(modifiedNormal, 3);
4063
+ const morphedPositionAttribute = new Float32BufferAttribute4(modifiedPosition, 3);
4064
+ const morphedNormalAttribute = new Float32BufferAttribute4(modifiedNormal, 3);
4065
4065
  return {
4066
4066
  positionAttribute,
4067
4067
  normalAttribute,
@@ -4075,7 +4075,7 @@ var init_BufferGeometryUtils = __esm({
4075
4075
  });
4076
4076
 
4077
4077
  // src/model/scene/ModelObject.ts
4078
- import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute4, Color as Color3, Euler as Euler6, Matrix4 as Matrix44 } from "three";
4078
+ import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute5, Color as Color7, Euler as Euler6, Matrix4 as Matrix46 } from "three";
4079
4079
  function isModelObject(obj) {
4080
4080
  return obj.isModelObject;
4081
4081
  }
@@ -4151,19 +4151,19 @@ var init_ModelObject = __esm({
4151
4151
  if (tintIndex === void 0 || tintIndex < 0) continue;
4152
4152
  const tint = this.options.tints[tintIndex];
4153
4153
  if (tint === void 0) continue;
4154
- const color = new Color3(tint);
4154
+ const color = new Color7(tint);
4155
4155
  for (let vertex = 0; vertex < 4; vertex++) {
4156
4156
  color.toArray(colors, (faceIndex * 4 + vertex) * 3);
4157
4157
  }
4158
4158
  }
4159
- elGeo.setAttribute("color", new BufferAttribute4(colors, 3));
4159
+ elGeo.setAttribute("color", new BufferAttribute5(colors, 3));
4160
4160
  }
4161
- elGeo.applyMatrix4(new Matrix44().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));
4162
- elGeo.applyMatrix4(new Matrix44().makeTranslation(el.from[0], el.from[1], el.from[2]));
4161
+ elGeo.applyMatrix4(new Matrix46().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));
4162
+ elGeo.applyMatrix4(new Matrix46().makeTranslation(el.from[0], el.from[1], el.from[2]));
4163
4163
  if (el.rotation) {
4164
4164
  applyElementRotation(el.rotation, elGeo);
4165
4165
  }
4166
- elGeo.applyMatrix4(new Matrix44().makeTranslation(-8, -8, -8));
4166
+ elGeo.applyMatrix4(new Matrix46().makeTranslation(-8, -8, -8));
4167
4167
  if (displayTransform) DisplayTransforms.apply(elGeo, displayTransform);
4168
4168
  if (this.options.mergeMeshes) {
4169
4169
  allGeos.push(elGeo);
@@ -4276,7 +4276,7 @@ var init_fluidBlocks = __esm({
4276
4276
  });
4277
4277
 
4278
4278
  // src/model/fluid/FluidGeometry.ts
4279
- import { BufferGeometry as BufferGeometry2, Float32BufferAttribute as Float32BufferAttribute4 } from "three";
4279
+ import { BufferGeometry as BufferGeometry3, Float32BufferAttribute as Float32BufferAttribute5 } from "three";
4280
4280
  function getBlockFluidState(key, state) {
4281
4281
  const rule = key && fluidRules[key.toNamespacedString()];
4282
4282
  if (rule) return {
@@ -4294,7 +4294,7 @@ function ownHeight(sample) {
4294
4294
  return (level === 0 || level >= 8 ? 8 : 8 - level) / 9;
4295
4295
  }
4296
4296
  function createFluidGeometry(kind, sample) {
4297
- const geometry = new BufferGeometry2();
4297
+ const geometry = new BufferGeometry3();
4298
4298
  const positions = [], normals = [], uvs = [], indices = [];
4299
4299
  const self = sample(0, 0, 0);
4300
4300
  const height = (x, z) => {
@@ -4393,9 +4393,9 @@ function createFluidGeometry(kind, sample) {
4393
4393
  1
4394
4394
  );
4395
4395
  }
4396
- geometry.setAttribute("position", new Float32BufferAttribute4(positions, 3));
4397
- geometry.setAttribute("normal", new Float32BufferAttribute4(normals, 3));
4398
- geometry.setAttribute("uv", new Float32BufferAttribute4(uvs, 2));
4396
+ geometry.setAttribute("position", new Float32BufferAttribute5(positions, 3));
4397
+ geometry.setAttribute("normal", new Float32BufferAttribute5(normals, 3));
4398
+ geometry.setAttribute("uv", new Float32BufferAttribute5(uvs, 2));
4399
4399
  geometry.setIndex(indices);
4400
4400
  return geometry;
4401
4401
  }
@@ -4415,7 +4415,7 @@ __export(FluidModelObject_exports, {
4415
4415
  FluidModelObject: () => FluidModelObject,
4416
4416
  sampleFluid: () => sampleFluid
4417
4417
  });
4418
- import { BufferAttribute as BufferAttribute5, Color as Color4, DoubleSide as DoubleSide2 } from "three";
4418
+ import { BufferAttribute as BufferAttribute6, Color as Color8, DoubleSide as DoubleSide3 } from "three";
4419
4419
  function sampleFluid(kind, sample) {
4420
4420
  const cells = [];
4421
4421
  const key = [];
@@ -4466,10 +4466,10 @@ var init_FluidModelObject = __esm({
4466
4466
  }
4467
4467
  }
4468
4468
  geometry.clearGroups();
4469
- const color = new Color4(this.options.tints?.[0] ?? (this.kind === "water" ? 4159204 : 16777215));
4469
+ const color = new Color8(this.options.tints?.[0] ?? (this.kind === "water" ? 4159204 : 16777215));
4470
4470
  const colors = new Float32Array(geometry.getAttribute("position").count * 3);
4471
4471
  for (let i = 0; i < colors.length; i += 3) color.toArray(colors, i);
4472
- geometry.setAttribute("color", new BufferAttribute5(colors, 3));
4472
+ geometry.setAttribute("color", new BufferAttribute6(colors, 3));
4473
4473
  geometry.computeBoundingBox();
4474
4474
  geometry.computeBoundingSphere();
4475
4475
  if (this.options.instanceMeshes) {
@@ -4483,7 +4483,7 @@ var init_FluidModelObject = __esm({
4483
4483
  super.applyTextures();
4484
4484
  this.iterateAllMeshes((mesh) => {
4485
4485
  const material = mesh.material;
4486
- material.side = DoubleSide2;
4486
+ material.side = DoubleSide3;
4487
4487
  material.forceSinglePass = true;
4488
4488
  material.depthWrite = !material.transparent;
4489
4489
  });
@@ -4835,6 +4835,37 @@ init_PersistentCache();
4835
4835
  init_CanvasCompat();
4836
4836
  init_CanvasImage();
4837
4837
 
4838
+ // src/canvas/trimCanvas.ts
4839
+ init_CanvasCompat();
4840
+ function trimCanvas(source) {
4841
+ if (source.width === 0 || source.height === 0) return createCanvas2(1, 1);
4842
+ const canvas = createCanvas2(source.width, source.height);
4843
+ const context = canvas.getContext("2d");
4844
+ if (!context) throw new Error("Image export requires a 2D canvas context");
4845
+ context.drawImage(source, 0, 0);
4846
+ const pixels = context.getImageData(0, 0, canvas.width, canvas.height).data;
4847
+ let left = canvas.width, top = canvas.height, right = -1, bottom = -1;
4848
+ for (let y = 0; y < canvas.height; y++) {
4849
+ for (let x = 0; x < canvas.width; x++) {
4850
+ if (pixels[(y * canvas.width + x) * 4 + 3] === 0) continue;
4851
+ left = Math.min(left, x);
4852
+ top = Math.min(top, y);
4853
+ right = Math.max(right, x);
4854
+ bottom = Math.max(bottom, y);
4855
+ }
4856
+ }
4857
+ if (right < left) {
4858
+ canvas.width = canvas.height = 1;
4859
+ return canvas;
4860
+ }
4861
+ const width = right - left + 1, height = bottom - top + 1;
4862
+ const cropped = context.getImageData(left, top, width, height);
4863
+ canvas.width = width;
4864
+ canvas.height = height;
4865
+ context.putImageData(cropped, 0, 0);
4866
+ return canvas;
4867
+ }
4868
+
4838
4869
  // src/entity/scene/EntityObject.ts
4839
4870
  init_SceneObject();
4840
4871
  init_Caching();
@@ -4957,6 +4988,2555 @@ function isEntityObject(obj) {
4957
4988
  // src/error/index.ts
4958
4989
  init_MineRenderError();
4959
4990
 
4991
+ // src/export/SceneExporter.ts
4992
+ import { ClampToEdgeWrapping as ClampToEdgeWrapping2, Color as Color6, Float32BufferAttribute as Float32BufferAttribute3, Matrix4 as Matrix45, Mesh as Mesh5, MeshBasicMaterial as MeshBasicMaterial2, NearestFilter as NearestFilter3, RGBAFormat as RGBAFormat3, Scene as Scene4, Source as Source2, Texture as Texture4, UnsignedByteType } from "three";
4993
+
4994
+ // ../../node_modules/three/examples/jsm/exporters/OBJExporter.js
4995
+ import {
4996
+ Color as Color3,
4997
+ Matrix3,
4998
+ Vector2 as Vector22,
4999
+ Vector3 as Vector36
5000
+ } from "three";
5001
+ var OBJExporter = class {
5002
+ parse(object) {
5003
+ let output = "";
5004
+ let indexVertex = 0;
5005
+ let indexVertexUvs = 0;
5006
+ let indexNormals = 0;
5007
+ const vertex = new Vector36();
5008
+ const color = new Color3();
5009
+ const normal = new Vector36();
5010
+ const uv = new Vector22();
5011
+ const face = [];
5012
+ function parseMesh(mesh) {
5013
+ let nbVertex = 0;
5014
+ let nbNormals = 0;
5015
+ let nbVertexUvs = 0;
5016
+ const geometry = mesh.geometry;
5017
+ const normalMatrixWorld = new Matrix3();
5018
+ const vertices = geometry.getAttribute("position");
5019
+ const normals = geometry.getAttribute("normal");
5020
+ const uvs = geometry.getAttribute("uv");
5021
+ const indices = geometry.getIndex();
5022
+ output += "o " + mesh.name + "\n";
5023
+ if (mesh.material && mesh.material.name) {
5024
+ output += "usemtl " + mesh.material.name + "\n";
5025
+ }
5026
+ if (vertices !== void 0) {
5027
+ for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
5028
+ vertex.fromBufferAttribute(vertices, i);
5029
+ vertex.applyMatrix4(mesh.matrixWorld);
5030
+ output += "v " + vertex.x + " " + vertex.y + " " + vertex.z + "\n";
5031
+ }
5032
+ }
5033
+ if (uvs !== void 0) {
5034
+ for (let i = 0, l = uvs.count; i < l; i++, nbVertexUvs++) {
5035
+ uv.fromBufferAttribute(uvs, i);
5036
+ output += "vt " + uv.x + " " + uv.y + "\n";
5037
+ }
5038
+ }
5039
+ if (normals !== void 0) {
5040
+ normalMatrixWorld.getNormalMatrix(mesh.matrixWorld);
5041
+ for (let i = 0, l = normals.count; i < l; i++, nbNormals++) {
5042
+ normal.fromBufferAttribute(normals, i);
5043
+ normal.applyMatrix3(normalMatrixWorld).normalize();
5044
+ output += "vn " + normal.x + " " + normal.y + " " + normal.z + "\n";
5045
+ }
5046
+ }
5047
+ if (indices !== null) {
5048
+ for (let i = 0, l = indices.count; i < l; i += 3) {
5049
+ for (let m = 0; m < 3; m++) {
5050
+ const j = indices.getX(i + m) + 1;
5051
+ face[m] = indexVertex + j + (normals || uvs ? "/" + (uvs ? indexVertexUvs + j : "") + (normals ? "/" + (indexNormals + j) : "") : "");
5052
+ }
5053
+ output += "f " + face.join(" ") + "\n";
5054
+ }
5055
+ } else {
5056
+ for (let i = 0, l = vertices.count; i < l; i += 3) {
5057
+ for (let m = 0; m < 3; m++) {
5058
+ const j = i + m + 1;
5059
+ face[m] = indexVertex + j + (normals || uvs ? "/" + (uvs ? indexVertexUvs + j : "") + (normals ? "/" + (indexNormals + j) : "") : "");
5060
+ }
5061
+ output += "f " + face.join(" ") + "\n";
5062
+ }
5063
+ }
5064
+ indexVertex += nbVertex;
5065
+ indexVertexUvs += nbVertexUvs;
5066
+ indexNormals += nbNormals;
5067
+ }
5068
+ function parseLine(line) {
5069
+ let nbVertex = 0;
5070
+ const geometry = line.geometry;
5071
+ const type = line.type;
5072
+ const vertices = geometry.getAttribute("position");
5073
+ output += "o " + line.name + "\n";
5074
+ if (vertices !== void 0) {
5075
+ for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
5076
+ vertex.fromBufferAttribute(vertices, i);
5077
+ vertex.applyMatrix4(line.matrixWorld);
5078
+ output += "v " + vertex.x + " " + vertex.y + " " + vertex.z + "\n";
5079
+ }
5080
+ }
5081
+ if (type === "Line") {
5082
+ output += "l ";
5083
+ for (let j = 1, l = vertices.count; j <= l; j++) {
5084
+ output += indexVertex + j + " ";
5085
+ }
5086
+ output += "\n";
5087
+ }
5088
+ if (type === "LineSegments") {
5089
+ for (let j = 1, k = j + 1, l = vertices.count; j < l; j += 2, k = j + 1) {
5090
+ output += "l " + (indexVertex + j) + " " + (indexVertex + k) + "\n";
5091
+ }
5092
+ }
5093
+ indexVertex += nbVertex;
5094
+ }
5095
+ function parsePoints(points) {
5096
+ let nbVertex = 0;
5097
+ const geometry = points.geometry;
5098
+ const vertices = geometry.getAttribute("position");
5099
+ const colors = geometry.getAttribute("color");
5100
+ output += "o " + points.name + "\n";
5101
+ if (vertices !== void 0) {
5102
+ for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
5103
+ vertex.fromBufferAttribute(vertices, i);
5104
+ vertex.applyMatrix4(points.matrixWorld);
5105
+ output += "v " + vertex.x + " " + vertex.y + " " + vertex.z;
5106
+ if (colors !== void 0) {
5107
+ color.fromBufferAttribute(colors, i).convertLinearToSRGB();
5108
+ output += " " + color.r + " " + color.g + " " + color.b;
5109
+ }
5110
+ output += "\n";
5111
+ }
5112
+ output += "p ";
5113
+ for (let j = 1, l = vertices.count; j <= l; j++) {
5114
+ output += indexVertex + j + " ";
5115
+ }
5116
+ output += "\n";
5117
+ }
5118
+ indexVertex += nbVertex;
5119
+ }
5120
+ object.traverse(function(child) {
5121
+ if (child.isMesh === true) {
5122
+ parseMesh(child);
5123
+ }
5124
+ if (child.isLine === true) {
5125
+ parseLine(child);
5126
+ }
5127
+ if (child.isPoints === true) {
5128
+ parsePoints(child);
5129
+ }
5130
+ });
5131
+ return output;
5132
+ }
5133
+ };
5134
+
5135
+ // ../../node_modules/three/examples/jsm/exporters/PLYExporter.js
5136
+ import {
5137
+ Matrix3 as Matrix32,
5138
+ Vector3 as Vector37,
5139
+ Color as Color4
5140
+ } from "three";
5141
+ var PLYExporter = class {
5142
+ parse(object, onDone, options = {}) {
5143
+ function traverseMeshes(cb) {
5144
+ object.traverse(function(child) {
5145
+ if (child.isMesh === true || child.isPoints) {
5146
+ const mesh = child;
5147
+ const geometry = mesh.geometry;
5148
+ if (geometry.hasAttribute("position") === true) {
5149
+ cb(mesh, geometry);
5150
+ }
5151
+ }
5152
+ });
5153
+ }
5154
+ const defaultOptions = {
5155
+ binary: false,
5156
+ excludeAttributes: [],
5157
+ // normal, uv, color, index
5158
+ littleEndian: false
5159
+ };
5160
+ options = Object.assign(defaultOptions, options);
5161
+ const excludeAttributes = options.excludeAttributes;
5162
+ let includeIndices = true;
5163
+ let includeNormals = false;
5164
+ let includeColors = false;
5165
+ let includeUVs = false;
5166
+ let vertexCount = 0;
5167
+ let faceCount = 0;
5168
+ object.traverse(function(child) {
5169
+ if (child.isMesh === true) {
5170
+ const mesh = child;
5171
+ const geometry = mesh.geometry;
5172
+ const vertices = geometry.getAttribute("position");
5173
+ const normals = geometry.getAttribute("normal");
5174
+ const uvs = geometry.getAttribute("uv");
5175
+ const colors = geometry.getAttribute("color");
5176
+ const indices = geometry.getIndex();
5177
+ if (vertices === void 0) {
5178
+ return;
5179
+ }
5180
+ vertexCount += vertices.count;
5181
+ faceCount += indices ? indices.count / 3 : vertices.count / 3;
5182
+ if (normals !== void 0) includeNormals = true;
5183
+ if (uvs !== void 0) includeUVs = true;
5184
+ if (colors !== void 0) includeColors = true;
5185
+ } else if (child.isPoints) {
5186
+ const mesh = child;
5187
+ const geometry = mesh.geometry;
5188
+ const vertices = geometry.getAttribute("position");
5189
+ const normals = geometry.getAttribute("normal");
5190
+ const colors = geometry.getAttribute("color");
5191
+ vertexCount += vertices.count;
5192
+ if (normals !== void 0) includeNormals = true;
5193
+ if (colors !== void 0) includeColors = true;
5194
+ includeIndices = false;
5195
+ }
5196
+ });
5197
+ const tempColor = new Color4();
5198
+ includeIndices = includeIndices && excludeAttributes.indexOf("index") === -1;
5199
+ includeNormals = includeNormals && excludeAttributes.indexOf("normal") === -1;
5200
+ includeColors = includeColors && excludeAttributes.indexOf("color") === -1;
5201
+ includeUVs = includeUVs && excludeAttributes.indexOf("uv") === -1;
5202
+ if (includeIndices && faceCount !== Math.floor(faceCount)) {
5203
+ console.error(
5204
+ "PLYExporter: Failed to generate a valid PLY file with triangle indices because the number of indices is not divisible by 3."
5205
+ );
5206
+ return null;
5207
+ }
5208
+ const indexByteCount = 4;
5209
+ let header = `ply
5210
+ format ${options.binary ? options.littleEndian ? "binary_little_endian" : "binary_big_endian" : "ascii"} 1.0
5211
+ element vertex ${vertexCount}
5212
+ property float x
5213
+ property float y
5214
+ property float z
5215
+ `;
5216
+ if (includeNormals === true) {
5217
+ header += "property float nx\nproperty float ny\nproperty float nz\n";
5218
+ }
5219
+ if (includeUVs === true) {
5220
+ header += "property float s\nproperty float t\n";
5221
+ }
5222
+ if (includeColors === true) {
5223
+ header += "property uchar red\nproperty uchar green\nproperty uchar blue\n";
5224
+ }
5225
+ if (includeIndices === true) {
5226
+ header += `element face ${faceCount}
5227
+ property list uchar int vertex_index
5228
+ `;
5229
+ }
5230
+ header += "end_header\n";
5231
+ const vertex = new Vector37();
5232
+ const normalMatrixWorld = new Matrix32();
5233
+ let result = null;
5234
+ if (options.binary === true) {
5235
+ const headerBin = new TextEncoder().encode(header);
5236
+ const vertexListLength = vertexCount * (4 * 3 + (includeNormals ? 4 * 3 : 0) + (includeColors ? 3 : 0) + (includeUVs ? 4 * 2 : 0));
5237
+ const faceListLength = includeIndices ? faceCount * (indexByteCount * 3 + 1) : 0;
5238
+ const output = new DataView(new ArrayBuffer(headerBin.length + vertexListLength + faceListLength));
5239
+ new Uint8Array(output.buffer).set(headerBin, 0);
5240
+ let vOffset = headerBin.length;
5241
+ let fOffset = headerBin.length + vertexListLength;
5242
+ let writtenVertices = 0;
5243
+ traverseMeshes(function(mesh, geometry) {
5244
+ const vertices = geometry.getAttribute("position");
5245
+ const normals = geometry.getAttribute("normal");
5246
+ const uvs = geometry.getAttribute("uv");
5247
+ const colors = geometry.getAttribute("color");
5248
+ const indices = geometry.getIndex();
5249
+ normalMatrixWorld.getNormalMatrix(mesh.matrixWorld);
5250
+ for (let i = 0, l = vertices.count; i < l; i++) {
5251
+ vertex.fromBufferAttribute(vertices, i);
5252
+ vertex.applyMatrix4(mesh.matrixWorld);
5253
+ output.setFloat32(vOffset, vertex.x, options.littleEndian);
5254
+ vOffset += 4;
5255
+ output.setFloat32(vOffset, vertex.y, options.littleEndian);
5256
+ vOffset += 4;
5257
+ output.setFloat32(vOffset, vertex.z, options.littleEndian);
5258
+ vOffset += 4;
5259
+ if (includeNormals === true) {
5260
+ if (normals != null) {
5261
+ vertex.fromBufferAttribute(normals, i);
5262
+ vertex.applyMatrix3(normalMatrixWorld).normalize();
5263
+ output.setFloat32(vOffset, vertex.x, options.littleEndian);
5264
+ vOffset += 4;
5265
+ output.setFloat32(vOffset, vertex.y, options.littleEndian);
5266
+ vOffset += 4;
5267
+ output.setFloat32(vOffset, vertex.z, options.littleEndian);
5268
+ vOffset += 4;
5269
+ } else {
5270
+ output.setFloat32(vOffset, 0, options.littleEndian);
5271
+ vOffset += 4;
5272
+ output.setFloat32(vOffset, 0, options.littleEndian);
5273
+ vOffset += 4;
5274
+ output.setFloat32(vOffset, 0, options.littleEndian);
5275
+ vOffset += 4;
5276
+ }
5277
+ }
5278
+ if (includeUVs === true) {
5279
+ if (uvs != null) {
5280
+ output.setFloat32(vOffset, uvs.getX(i), options.littleEndian);
5281
+ vOffset += 4;
5282
+ output.setFloat32(vOffset, uvs.getY(i), options.littleEndian);
5283
+ vOffset += 4;
5284
+ } else {
5285
+ output.setFloat32(vOffset, 0, options.littleEndian);
5286
+ vOffset += 4;
5287
+ output.setFloat32(vOffset, 0, options.littleEndian);
5288
+ vOffset += 4;
5289
+ }
5290
+ }
5291
+ if (includeColors === true) {
5292
+ if (colors != null) {
5293
+ tempColor.fromBufferAttribute(colors, i).convertLinearToSRGB();
5294
+ output.setUint8(vOffset, Math.floor(tempColor.r * 255));
5295
+ vOffset += 1;
5296
+ output.setUint8(vOffset, Math.floor(tempColor.g * 255));
5297
+ vOffset += 1;
5298
+ output.setUint8(vOffset, Math.floor(tempColor.b * 255));
5299
+ vOffset += 1;
5300
+ } else {
5301
+ output.setUint8(vOffset, 255);
5302
+ vOffset += 1;
5303
+ output.setUint8(vOffset, 255);
5304
+ vOffset += 1;
5305
+ output.setUint8(vOffset, 255);
5306
+ vOffset += 1;
5307
+ }
5308
+ }
5309
+ }
5310
+ if (includeIndices === true) {
5311
+ if (indices !== null) {
5312
+ for (let i = 0, l = indices.count; i < l; i += 3) {
5313
+ output.setUint8(fOffset, 3);
5314
+ fOffset += 1;
5315
+ output.setUint32(fOffset, indices.getX(i + 0) + writtenVertices, options.littleEndian);
5316
+ fOffset += indexByteCount;
5317
+ output.setUint32(fOffset, indices.getX(i + 1) + writtenVertices, options.littleEndian);
5318
+ fOffset += indexByteCount;
5319
+ output.setUint32(fOffset, indices.getX(i + 2) + writtenVertices, options.littleEndian);
5320
+ fOffset += indexByteCount;
5321
+ }
5322
+ } else {
5323
+ for (let i = 0, l = vertices.count; i < l; i += 3) {
5324
+ output.setUint8(fOffset, 3);
5325
+ fOffset += 1;
5326
+ output.setUint32(fOffset, writtenVertices + i, options.littleEndian);
5327
+ fOffset += indexByteCount;
5328
+ output.setUint32(fOffset, writtenVertices + i + 1, options.littleEndian);
5329
+ fOffset += indexByteCount;
5330
+ output.setUint32(fOffset, writtenVertices + i + 2, options.littleEndian);
5331
+ fOffset += indexByteCount;
5332
+ }
5333
+ }
5334
+ }
5335
+ writtenVertices += vertices.count;
5336
+ });
5337
+ result = output.buffer;
5338
+ } else {
5339
+ let writtenVertices = 0;
5340
+ let vertexList = "";
5341
+ let faceList = "";
5342
+ traverseMeshes(function(mesh, geometry) {
5343
+ const vertices = geometry.getAttribute("position");
5344
+ const normals = geometry.getAttribute("normal");
5345
+ const uvs = geometry.getAttribute("uv");
5346
+ const colors = geometry.getAttribute("color");
5347
+ const indices = geometry.getIndex();
5348
+ normalMatrixWorld.getNormalMatrix(mesh.matrixWorld);
5349
+ for (let i = 0, l = vertices.count; i < l; i++) {
5350
+ vertex.fromBufferAttribute(vertices, i);
5351
+ vertex.applyMatrix4(mesh.matrixWorld);
5352
+ let line = vertex.x + " " + vertex.y + " " + vertex.z;
5353
+ if (includeNormals === true) {
5354
+ if (normals != null) {
5355
+ vertex.fromBufferAttribute(normals, i);
5356
+ vertex.applyMatrix3(normalMatrixWorld).normalize();
5357
+ line += " " + vertex.x + " " + vertex.y + " " + vertex.z;
5358
+ } else {
5359
+ line += " 0 0 0";
5360
+ }
5361
+ }
5362
+ if (includeUVs === true) {
5363
+ if (uvs != null) {
5364
+ line += " " + uvs.getX(i) + " " + uvs.getY(i);
5365
+ } else {
5366
+ line += " 0 0";
5367
+ }
5368
+ }
5369
+ if (includeColors === true) {
5370
+ if (colors != null) {
5371
+ tempColor.fromBufferAttribute(colors, i).convertLinearToSRGB();
5372
+ line += " " + Math.floor(tempColor.r * 255) + " " + Math.floor(tempColor.g * 255) + " " + Math.floor(tempColor.b * 255);
5373
+ } else {
5374
+ line += " 255 255 255";
5375
+ }
5376
+ }
5377
+ vertexList += line + "\n";
5378
+ }
5379
+ if (includeIndices === true) {
5380
+ if (indices !== null) {
5381
+ for (let i = 0, l = indices.count; i < l; i += 3) {
5382
+ faceList += `3 ${indices.getX(i + 0) + writtenVertices}`;
5383
+ faceList += ` ${indices.getX(i + 1) + writtenVertices}`;
5384
+ faceList += ` ${indices.getX(i + 2) + writtenVertices}
5385
+ `;
5386
+ }
5387
+ } else {
5388
+ for (let i = 0, l = vertices.count; i < l; i += 3) {
5389
+ faceList += `3 ${writtenVertices + i} ${writtenVertices + i + 1} ${writtenVertices + i + 2}
5390
+ `;
5391
+ }
5392
+ }
5393
+ faceCount += indices ? indices.count / 3 : vertices.count / 3;
5394
+ }
5395
+ writtenVertices += vertices.count;
5396
+ });
5397
+ result = `${header}${vertexList}${includeIndices ? `${faceList}
5398
+ ` : "\n"}`;
5399
+ }
5400
+ if (typeof onDone === "function") requestAnimationFrame(() => onDone(result));
5401
+ return result;
5402
+ }
5403
+ };
5404
+
5405
+ // ../../node_modules/three/examples/jsm/exporters/GLTFExporter.js
5406
+ import {
5407
+ BufferAttribute as BufferAttribute3,
5408
+ ClampToEdgeWrapping,
5409
+ Color as Color5,
5410
+ DoubleSide as DoubleSide2,
5411
+ InterpolateDiscrete,
5412
+ InterpolateLinear,
5413
+ NoColorSpace,
5414
+ LinearFilter,
5415
+ LinearMipmapLinearFilter,
5416
+ LinearMipmapNearestFilter,
5417
+ MathUtils as MathUtils2,
5418
+ Matrix4 as Matrix44,
5419
+ MirroredRepeatWrapping,
5420
+ NearestFilter as NearestFilter2,
5421
+ NearestMipmapLinearFilter,
5422
+ NearestMipmapNearestFilter,
5423
+ PropertyBinding,
5424
+ RGBAFormat as RGBAFormat2,
5425
+ RepeatWrapping,
5426
+ Scene as Scene3,
5427
+ Source,
5428
+ SRGBColorSpace as SRGBColorSpace4,
5429
+ CompressedTexture,
5430
+ Vector3 as Vector38,
5431
+ Quaternion as Quaternion4
5432
+ } from "three";
5433
+
5434
+ // ../../node_modules/three/examples/jsm/utils/TextureUtils.js
5435
+ import {
5436
+ PlaneGeometry,
5437
+ ShaderMaterial as ShaderMaterial2,
5438
+ Uniform,
5439
+ Mesh as Mesh4,
5440
+ PerspectiveCamera,
5441
+ Scene as Scene2,
5442
+ WebGLRenderer,
5443
+ Texture as Texture3,
5444
+ SRGBColorSpace as SRGBColorSpace3
5445
+ } from "three";
5446
+ var _renderer;
5447
+ var fullscreenQuadGeometry;
5448
+ var fullscreenQuadMaterial;
5449
+ var fullscreenQuad;
5450
+ function decompress(texture, maxTextureSize = Infinity, renderer = null) {
5451
+ if (!fullscreenQuadGeometry) fullscreenQuadGeometry = new PlaneGeometry(2, 2, 1, 1);
5452
+ if (!fullscreenQuadMaterial) fullscreenQuadMaterial = new ShaderMaterial2({
5453
+ uniforms: { blitTexture: new Uniform(texture) },
5454
+ vertexShader: `
5455
+ varying vec2 vUv;
5456
+ void main(){
5457
+ vUv = uv;
5458
+ gl_Position = vec4(position.xy * 1.0,0.,.999999);
5459
+ }`,
5460
+ fragmentShader: `
5461
+ uniform sampler2D blitTexture;
5462
+ varying vec2 vUv;
5463
+
5464
+ void main(){
5465
+ gl_FragColor = vec4(vUv.xy, 0, 1);
5466
+
5467
+ #ifdef IS_SRGB
5468
+ gl_FragColor = LinearTosRGB( texture2D( blitTexture, vUv) );
5469
+ #else
5470
+ gl_FragColor = texture2D( blitTexture, vUv);
5471
+ #endif
5472
+ }`
5473
+ });
5474
+ fullscreenQuadMaterial.uniforms.blitTexture.value = texture;
5475
+ fullscreenQuadMaterial.defines.IS_SRGB = texture.colorSpace == SRGBColorSpace3;
5476
+ fullscreenQuadMaterial.needsUpdate = true;
5477
+ if (!fullscreenQuad) {
5478
+ fullscreenQuad = new Mesh4(fullscreenQuadGeometry, fullscreenQuadMaterial);
5479
+ fullscreenQuad.frustrumCulled = false;
5480
+ }
5481
+ const _camera = new PerspectiveCamera();
5482
+ const _scene = new Scene2();
5483
+ _scene.add(fullscreenQuad);
5484
+ if (!renderer) {
5485
+ renderer = _renderer = new WebGLRenderer({ antialias: false });
5486
+ }
5487
+ renderer.setSize(Math.min(texture.image.width, maxTextureSize), Math.min(texture.image.height, maxTextureSize));
5488
+ renderer.clear();
5489
+ renderer.render(_scene, _camera);
5490
+ const readableTexture = new Texture3(renderer.domElement);
5491
+ readableTexture.minFilter = texture.minFilter;
5492
+ readableTexture.magFilter = texture.magFilter;
5493
+ readableTexture.wrapS = texture.wrapS;
5494
+ readableTexture.wrapT = texture.wrapT;
5495
+ readableTexture.name = texture.name;
5496
+ if (_renderer) {
5497
+ _renderer.dispose();
5498
+ _renderer = null;
5499
+ }
5500
+ return readableTexture;
5501
+ }
5502
+
5503
+ // ../../node_modules/three/examples/jsm/exporters/GLTFExporter.js
5504
+ var KHR_mesh_quantization_ExtraAttrTypes = {
5505
+ POSITION: [
5506
+ "byte",
5507
+ "byte normalized",
5508
+ "unsigned byte",
5509
+ "unsigned byte normalized",
5510
+ "short",
5511
+ "short normalized",
5512
+ "unsigned short",
5513
+ "unsigned short normalized"
5514
+ ],
5515
+ NORMAL: [
5516
+ "byte normalized",
5517
+ "short normalized"
5518
+ ],
5519
+ TANGENT: [
5520
+ "byte normalized",
5521
+ "short normalized"
5522
+ ],
5523
+ TEXCOORD: [
5524
+ "byte",
5525
+ "byte normalized",
5526
+ "unsigned byte",
5527
+ "short",
5528
+ "short normalized",
5529
+ "unsigned short"
5530
+ ]
5531
+ };
5532
+ var GLTFExporter = class {
5533
+ constructor() {
5534
+ this.pluginCallbacks = [];
5535
+ this.register(function(writer) {
5536
+ return new GLTFLightExtension(writer);
5537
+ });
5538
+ this.register(function(writer) {
5539
+ return new GLTFMaterialsUnlitExtension(writer);
5540
+ });
5541
+ this.register(function(writer) {
5542
+ return new GLTFMaterialsTransmissionExtension(writer);
5543
+ });
5544
+ this.register(function(writer) {
5545
+ return new GLTFMaterialsVolumeExtension(writer);
5546
+ });
5547
+ this.register(function(writer) {
5548
+ return new GLTFMaterialsIorExtension(writer);
5549
+ });
5550
+ this.register(function(writer) {
5551
+ return new GLTFMaterialsSpecularExtension(writer);
5552
+ });
5553
+ this.register(function(writer) {
5554
+ return new GLTFMaterialsClearcoatExtension(writer);
5555
+ });
5556
+ this.register(function(writer) {
5557
+ return new GLTFMaterialsIridescenceExtension(writer);
5558
+ });
5559
+ this.register(function(writer) {
5560
+ return new GLTFMaterialsSheenExtension(writer);
5561
+ });
5562
+ this.register(function(writer) {
5563
+ return new GLTFMaterialsAnisotropyExtension(writer);
5564
+ });
5565
+ this.register(function(writer) {
5566
+ return new GLTFMaterialsEmissiveStrengthExtension(writer);
5567
+ });
5568
+ this.register(function(writer) {
5569
+ return new GLTFMeshGpuInstancing(writer);
5570
+ });
5571
+ }
5572
+ register(callback) {
5573
+ if (this.pluginCallbacks.indexOf(callback) === -1) {
5574
+ this.pluginCallbacks.push(callback);
5575
+ }
5576
+ return this;
5577
+ }
5578
+ unregister(callback) {
5579
+ if (this.pluginCallbacks.indexOf(callback) !== -1) {
5580
+ this.pluginCallbacks.splice(this.pluginCallbacks.indexOf(callback), 1);
5581
+ }
5582
+ return this;
5583
+ }
5584
+ /**
5585
+ * Parse scenes and generate GLTF output
5586
+ * @param {Scene or [THREE.Scenes]} input Scene or Array of THREE.Scenes
5587
+ * @param {Function} onDone Callback on completed
5588
+ * @param {Function} onError Callback on errors
5589
+ * @param {Object} options options
5590
+ */
5591
+ parse(input, onDone, onError, options) {
5592
+ const writer = new GLTFWriter();
5593
+ const plugins = [];
5594
+ for (let i = 0, il = this.pluginCallbacks.length; i < il; i++) {
5595
+ plugins.push(this.pluginCallbacks[i](writer));
5596
+ }
5597
+ writer.setPlugins(plugins);
5598
+ writer.write(input, onDone, options).catch(onError);
5599
+ }
5600
+ parseAsync(input, options) {
5601
+ const scope = this;
5602
+ return new Promise(function(resolve, reject) {
5603
+ scope.parse(input, resolve, reject, options);
5604
+ });
5605
+ }
5606
+ };
5607
+ var WEBGL_CONSTANTS = {
5608
+ POINTS: 0,
5609
+ LINES: 1,
5610
+ LINE_LOOP: 2,
5611
+ LINE_STRIP: 3,
5612
+ TRIANGLES: 4,
5613
+ TRIANGLE_STRIP: 5,
5614
+ TRIANGLE_FAN: 6,
5615
+ BYTE: 5120,
5616
+ UNSIGNED_BYTE: 5121,
5617
+ SHORT: 5122,
5618
+ UNSIGNED_SHORT: 5123,
5619
+ INT: 5124,
5620
+ UNSIGNED_INT: 5125,
5621
+ FLOAT: 5126,
5622
+ ARRAY_BUFFER: 34962,
5623
+ ELEMENT_ARRAY_BUFFER: 34963,
5624
+ NEAREST: 9728,
5625
+ LINEAR: 9729,
5626
+ NEAREST_MIPMAP_NEAREST: 9984,
5627
+ LINEAR_MIPMAP_NEAREST: 9985,
5628
+ NEAREST_MIPMAP_LINEAR: 9986,
5629
+ LINEAR_MIPMAP_LINEAR: 9987,
5630
+ CLAMP_TO_EDGE: 33071,
5631
+ MIRRORED_REPEAT: 33648,
5632
+ REPEAT: 10497
5633
+ };
5634
+ var KHR_MESH_QUANTIZATION = "KHR_mesh_quantization";
5635
+ var THREE_TO_WEBGL = {};
5636
+ THREE_TO_WEBGL[NearestFilter2] = WEBGL_CONSTANTS.NEAREST;
5637
+ THREE_TO_WEBGL[NearestMipmapNearestFilter] = WEBGL_CONSTANTS.NEAREST_MIPMAP_NEAREST;
5638
+ THREE_TO_WEBGL[NearestMipmapLinearFilter] = WEBGL_CONSTANTS.NEAREST_MIPMAP_LINEAR;
5639
+ THREE_TO_WEBGL[LinearFilter] = WEBGL_CONSTANTS.LINEAR;
5640
+ THREE_TO_WEBGL[LinearMipmapNearestFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_NEAREST;
5641
+ THREE_TO_WEBGL[LinearMipmapLinearFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_LINEAR;
5642
+ THREE_TO_WEBGL[ClampToEdgeWrapping] = WEBGL_CONSTANTS.CLAMP_TO_EDGE;
5643
+ THREE_TO_WEBGL[RepeatWrapping] = WEBGL_CONSTANTS.REPEAT;
5644
+ THREE_TO_WEBGL[MirroredRepeatWrapping] = WEBGL_CONSTANTS.MIRRORED_REPEAT;
5645
+ var PATH_PROPERTIES = {
5646
+ scale: "scale",
5647
+ position: "translation",
5648
+ quaternion: "rotation",
5649
+ morphTargetInfluences: "weights"
5650
+ };
5651
+ var DEFAULT_SPECULAR_COLOR = new Color5();
5652
+ var GLB_HEADER_BYTES = 12;
5653
+ var GLB_HEADER_MAGIC = 1179937895;
5654
+ var GLB_VERSION = 2;
5655
+ var GLB_CHUNK_PREFIX_BYTES = 8;
5656
+ var GLB_CHUNK_TYPE_JSON = 1313821514;
5657
+ var GLB_CHUNK_TYPE_BIN = 5130562;
5658
+ function equalArray(array1, array2) {
5659
+ return array1.length === array2.length && array1.every(function(element, index) {
5660
+ return element === array2[index];
5661
+ });
5662
+ }
5663
+ function stringToArrayBuffer(text) {
5664
+ return new TextEncoder().encode(text).buffer;
5665
+ }
5666
+ function isIdentityMatrix(matrix) {
5667
+ return equalArray(matrix.elements, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
5668
+ }
5669
+ function getMinMax(attribute, start, count) {
5670
+ const output = {
5671
+ min: new Array(attribute.itemSize).fill(Number.POSITIVE_INFINITY),
5672
+ max: new Array(attribute.itemSize).fill(Number.NEGATIVE_INFINITY)
5673
+ };
5674
+ for (let i = start; i < start + count; i++) {
5675
+ for (let a = 0; a < attribute.itemSize; a++) {
5676
+ let value;
5677
+ if (attribute.itemSize > 4) {
5678
+ value = attribute.array[i * attribute.itemSize + a];
5679
+ } else {
5680
+ if (a === 0) value = attribute.getX(i);
5681
+ else if (a === 1) value = attribute.getY(i);
5682
+ else if (a === 2) value = attribute.getZ(i);
5683
+ else if (a === 3) value = attribute.getW(i);
5684
+ if (attribute.normalized === true) {
5685
+ value = MathUtils2.normalize(value, attribute.array);
5686
+ }
5687
+ }
5688
+ output.min[a] = Math.min(output.min[a], value);
5689
+ output.max[a] = Math.max(output.max[a], value);
5690
+ }
5691
+ }
5692
+ return output;
5693
+ }
5694
+ function getPaddedBufferSize(bufferSize) {
5695
+ return Math.ceil(bufferSize / 4) * 4;
5696
+ }
5697
+ function getPaddedArrayBuffer(arrayBuffer, paddingByte = 0) {
5698
+ const paddedLength = getPaddedBufferSize(arrayBuffer.byteLength);
5699
+ if (paddedLength !== arrayBuffer.byteLength) {
5700
+ const array = new Uint8Array(paddedLength);
5701
+ array.set(new Uint8Array(arrayBuffer));
5702
+ if (paddingByte !== 0) {
5703
+ for (let i = arrayBuffer.byteLength; i < paddedLength; i++) {
5704
+ array[i] = paddingByte;
5705
+ }
5706
+ }
5707
+ return array.buffer;
5708
+ }
5709
+ return arrayBuffer;
5710
+ }
5711
+ function getCanvas() {
5712
+ if (typeof document === "undefined" && typeof OffscreenCanvas !== "undefined") {
5713
+ return new OffscreenCanvas(1, 1);
5714
+ }
5715
+ return document.createElement("canvas");
5716
+ }
5717
+ function getToBlobPromise(canvas, mimeType) {
5718
+ if (canvas.toBlob !== void 0) {
5719
+ return new Promise((resolve) => canvas.toBlob(resolve, mimeType));
5720
+ }
5721
+ let quality;
5722
+ if (mimeType === "image/jpeg") {
5723
+ quality = 0.92;
5724
+ } else if (mimeType === "image/webp") {
5725
+ quality = 0.8;
5726
+ }
5727
+ return canvas.convertToBlob({
5728
+ type: mimeType,
5729
+ quality
5730
+ });
5731
+ }
5732
+ var GLTFWriter = class {
5733
+ constructor() {
5734
+ this.plugins = [];
5735
+ this.options = {};
5736
+ this.pending = [];
5737
+ this.buffers = [];
5738
+ this.byteOffset = 0;
5739
+ this.buffers = [];
5740
+ this.nodeMap = /* @__PURE__ */ new Map();
5741
+ this.skins = [];
5742
+ this.extensionsUsed = {};
5743
+ this.extensionsRequired = {};
5744
+ this.uids = /* @__PURE__ */ new Map();
5745
+ this.uid = 0;
5746
+ this.json = {
5747
+ asset: {
5748
+ version: "2.0",
5749
+ generator: "THREE.GLTFExporter"
5750
+ }
5751
+ };
5752
+ this.cache = {
5753
+ meshes: /* @__PURE__ */ new Map(),
5754
+ attributes: /* @__PURE__ */ new Map(),
5755
+ attributesNormalized: /* @__PURE__ */ new Map(),
5756
+ materials: /* @__PURE__ */ new Map(),
5757
+ textures: /* @__PURE__ */ new Map(),
5758
+ images: /* @__PURE__ */ new Map()
5759
+ };
5760
+ }
5761
+ setPlugins(plugins) {
5762
+ this.plugins = plugins;
5763
+ }
5764
+ /**
5765
+ * Parse scenes and generate GLTF output
5766
+ * @param {Scene or [THREE.Scenes]} input Scene or Array of THREE.Scenes
5767
+ * @param {Function} onDone Callback on completed
5768
+ * @param {Object} options options
5769
+ */
5770
+ async write(input, onDone, options = {}) {
5771
+ this.options = Object.assign({
5772
+ // default options
5773
+ binary: false,
5774
+ trs: false,
5775
+ onlyVisible: true,
5776
+ maxTextureSize: Infinity,
5777
+ animations: [],
5778
+ includeCustomExtensions: false
5779
+ }, options);
5780
+ if (this.options.animations.length > 0) {
5781
+ this.options.trs = true;
5782
+ }
5783
+ this.processInput(input);
5784
+ await Promise.all(this.pending);
5785
+ const writer = this;
5786
+ const buffers = writer.buffers;
5787
+ const json = writer.json;
5788
+ options = writer.options;
5789
+ const extensionsUsed = writer.extensionsUsed;
5790
+ const extensionsRequired = writer.extensionsRequired;
5791
+ const blob = new Blob(buffers, { type: "application/octet-stream" });
5792
+ const extensionsUsedList = Object.keys(extensionsUsed);
5793
+ const extensionsRequiredList = Object.keys(extensionsRequired);
5794
+ if (extensionsUsedList.length > 0) json.extensionsUsed = extensionsUsedList;
5795
+ if (extensionsRequiredList.length > 0) json.extensionsRequired = extensionsRequiredList;
5796
+ if (json.buffers && json.buffers.length > 0) json.buffers[0].byteLength = blob.size;
5797
+ if (options.binary === true) {
5798
+ const reader = new FileReader();
5799
+ reader.readAsArrayBuffer(blob);
5800
+ reader.onloadend = function() {
5801
+ const binaryChunk = getPaddedArrayBuffer(reader.result);
5802
+ const binaryChunkPrefix = new DataView(new ArrayBuffer(GLB_CHUNK_PREFIX_BYTES));
5803
+ binaryChunkPrefix.setUint32(0, binaryChunk.byteLength, true);
5804
+ binaryChunkPrefix.setUint32(4, GLB_CHUNK_TYPE_BIN, true);
5805
+ const jsonChunk = getPaddedArrayBuffer(stringToArrayBuffer(JSON.stringify(json)), 32);
5806
+ const jsonChunkPrefix = new DataView(new ArrayBuffer(GLB_CHUNK_PREFIX_BYTES));
5807
+ jsonChunkPrefix.setUint32(0, jsonChunk.byteLength, true);
5808
+ jsonChunkPrefix.setUint32(4, GLB_CHUNK_TYPE_JSON, true);
5809
+ const header = new ArrayBuffer(GLB_HEADER_BYTES);
5810
+ const headerView = new DataView(header);
5811
+ headerView.setUint32(0, GLB_HEADER_MAGIC, true);
5812
+ headerView.setUint32(4, GLB_VERSION, true);
5813
+ const totalByteLength = GLB_HEADER_BYTES + jsonChunkPrefix.byteLength + jsonChunk.byteLength + binaryChunkPrefix.byteLength + binaryChunk.byteLength;
5814
+ headerView.setUint32(8, totalByteLength, true);
5815
+ const glbBlob = new Blob([
5816
+ header,
5817
+ jsonChunkPrefix,
5818
+ jsonChunk,
5819
+ binaryChunkPrefix,
5820
+ binaryChunk
5821
+ ], { type: "application/octet-stream" });
5822
+ const glbReader = new FileReader();
5823
+ glbReader.readAsArrayBuffer(glbBlob);
5824
+ glbReader.onloadend = function() {
5825
+ onDone(glbReader.result);
5826
+ };
5827
+ };
5828
+ } else {
5829
+ if (json.buffers && json.buffers.length > 0) {
5830
+ const reader = new FileReader();
5831
+ reader.readAsDataURL(blob);
5832
+ reader.onloadend = function() {
5833
+ const base64data = reader.result;
5834
+ json.buffers[0].uri = base64data;
5835
+ onDone(json);
5836
+ };
5837
+ } else {
5838
+ onDone(json);
5839
+ }
5840
+ }
5841
+ }
5842
+ /**
5843
+ * Serializes a userData.
5844
+ *
5845
+ * @param {THREE.Object3D|THREE.Material} object
5846
+ * @param {Object} objectDef
5847
+ */
5848
+ serializeUserData(object, objectDef) {
5849
+ if (Object.keys(object.userData).length === 0) return;
5850
+ const options = this.options;
5851
+ const extensionsUsed = this.extensionsUsed;
5852
+ try {
5853
+ const json = JSON.parse(JSON.stringify(object.userData));
5854
+ if (options.includeCustomExtensions && json.gltfExtensions) {
5855
+ if (objectDef.extensions === void 0) objectDef.extensions = {};
5856
+ for (const extensionName in json.gltfExtensions) {
5857
+ objectDef.extensions[extensionName] = json.gltfExtensions[extensionName];
5858
+ extensionsUsed[extensionName] = true;
5859
+ }
5860
+ delete json.gltfExtensions;
5861
+ }
5862
+ if (Object.keys(json).length > 0) objectDef.extras = json;
5863
+ } catch (error) {
5864
+ console.warn("THREE.GLTFExporter: userData of '" + object.name + "' won't be serialized because of JSON.stringify error - " + error.message);
5865
+ }
5866
+ }
5867
+ /**
5868
+ * Returns ids for buffer attributes.
5869
+ * @param {Object} object
5870
+ * @return {Integer}
5871
+ */
5872
+ getUID(attribute, isRelativeCopy = false) {
5873
+ if (this.uids.has(attribute) === false) {
5874
+ const uids2 = /* @__PURE__ */ new Map();
5875
+ uids2.set(true, this.uid++);
5876
+ uids2.set(false, this.uid++);
5877
+ this.uids.set(attribute, uids2);
5878
+ }
5879
+ const uids = this.uids.get(attribute);
5880
+ return uids.get(isRelativeCopy);
5881
+ }
5882
+ /**
5883
+ * Checks if normal attribute values are normalized.
5884
+ *
5885
+ * @param {BufferAttribute} normal
5886
+ * @returns {Boolean}
5887
+ */
5888
+ isNormalizedNormalAttribute(normal) {
5889
+ const cache = this.cache;
5890
+ if (cache.attributesNormalized.has(normal)) return false;
5891
+ const v = new Vector38();
5892
+ for (let i = 0, il = normal.count; i < il; i++) {
5893
+ if (Math.abs(v.fromBufferAttribute(normal, i).length() - 1) > 5e-4) return false;
5894
+ }
5895
+ return true;
5896
+ }
5897
+ /**
5898
+ * Creates normalized normal buffer attribute.
5899
+ *
5900
+ * @param {BufferAttribute} normal
5901
+ * @returns {BufferAttribute}
5902
+ *
5903
+ */
5904
+ createNormalizedNormalAttribute(normal) {
5905
+ const cache = this.cache;
5906
+ if (cache.attributesNormalized.has(normal)) return cache.attributesNormalized.get(normal);
5907
+ const attribute = normal.clone();
5908
+ const v = new Vector38();
5909
+ for (let i = 0, il = attribute.count; i < il; i++) {
5910
+ v.fromBufferAttribute(attribute, i);
5911
+ if (v.x === 0 && v.y === 0 && v.z === 0) {
5912
+ v.setX(1);
5913
+ } else {
5914
+ v.normalize();
5915
+ }
5916
+ attribute.setXYZ(i, v.x, v.y, v.z);
5917
+ }
5918
+ cache.attributesNormalized.set(normal, attribute);
5919
+ return attribute;
5920
+ }
5921
+ /**
5922
+ * Applies a texture transform, if present, to the map definition. Requires
5923
+ * the KHR_texture_transform extension.
5924
+ *
5925
+ * @param {Object} mapDef
5926
+ * @param {THREE.Texture} texture
5927
+ */
5928
+ applyTextureTransform(mapDef, texture) {
5929
+ let didTransform = false;
5930
+ const transformDef = {};
5931
+ if (texture.offset.x !== 0 || texture.offset.y !== 0) {
5932
+ transformDef.offset = texture.offset.toArray();
5933
+ didTransform = true;
5934
+ }
5935
+ if (texture.rotation !== 0) {
5936
+ transformDef.rotation = texture.rotation;
5937
+ didTransform = true;
5938
+ }
5939
+ if (texture.repeat.x !== 1 || texture.repeat.y !== 1) {
5940
+ transformDef.scale = texture.repeat.toArray();
5941
+ didTransform = true;
5942
+ }
5943
+ if (didTransform) {
5944
+ mapDef.extensions = mapDef.extensions || {};
5945
+ mapDef.extensions["KHR_texture_transform"] = transformDef;
5946
+ this.extensionsUsed["KHR_texture_transform"] = true;
5947
+ }
5948
+ }
5949
+ buildMetalRoughTexture(metalnessMap, roughnessMap) {
5950
+ if (metalnessMap === roughnessMap) return metalnessMap;
5951
+ function getEncodingConversion(map) {
5952
+ if (map.colorSpace === SRGBColorSpace4) {
5953
+ return function SRGBToLinear(c) {
5954
+ return c < 0.04045 ? c * 0.0773993808 : Math.pow(c * 0.9478672986 + 0.0521327014, 2.4);
5955
+ };
5956
+ }
5957
+ return function LinearToLinear(c) {
5958
+ return c;
5959
+ };
5960
+ }
5961
+ console.warn("THREE.GLTFExporter: Merged metalnessMap and roughnessMap textures.");
5962
+ if (metalnessMap instanceof CompressedTexture) {
5963
+ metalnessMap = decompress(metalnessMap);
5964
+ }
5965
+ if (roughnessMap instanceof CompressedTexture) {
5966
+ roughnessMap = decompress(roughnessMap);
5967
+ }
5968
+ const metalness = metalnessMap ? metalnessMap.image : null;
5969
+ const roughness = roughnessMap ? roughnessMap.image : null;
5970
+ const width = Math.max(metalness ? metalness.width : 0, roughness ? roughness.width : 0);
5971
+ const height = Math.max(metalness ? metalness.height : 0, roughness ? roughness.height : 0);
5972
+ const canvas = getCanvas();
5973
+ canvas.width = width;
5974
+ canvas.height = height;
5975
+ const context = canvas.getContext("2d");
5976
+ context.fillStyle = "#00ffff";
5977
+ context.fillRect(0, 0, width, height);
5978
+ const composite = context.getImageData(0, 0, width, height);
5979
+ if (metalness) {
5980
+ context.drawImage(metalness, 0, 0, width, height);
5981
+ const convert = getEncodingConversion(metalnessMap);
5982
+ const data = context.getImageData(0, 0, width, height).data;
5983
+ for (let i = 2; i < data.length; i += 4) {
5984
+ composite.data[i] = convert(data[i] / 256) * 256;
5985
+ }
5986
+ }
5987
+ if (roughness) {
5988
+ context.drawImage(roughness, 0, 0, width, height);
5989
+ const convert = getEncodingConversion(roughnessMap);
5990
+ const data = context.getImageData(0, 0, width, height).data;
5991
+ for (let i = 1; i < data.length; i += 4) {
5992
+ composite.data[i] = convert(data[i] / 256) * 256;
5993
+ }
5994
+ }
5995
+ context.putImageData(composite, 0, 0);
5996
+ const reference = metalnessMap || roughnessMap;
5997
+ const texture = reference.clone();
5998
+ texture.source = new Source(canvas);
5999
+ texture.colorSpace = NoColorSpace;
6000
+ texture.channel = (metalnessMap || roughnessMap).channel;
6001
+ if (metalnessMap && roughnessMap && metalnessMap.channel !== roughnessMap.channel) {
6002
+ console.warn("THREE.GLTFExporter: UV channels for metalnessMap and roughnessMap textures must match.");
6003
+ }
6004
+ return texture;
6005
+ }
6006
+ /**
6007
+ * Process a buffer to append to the default one.
6008
+ * @param {ArrayBuffer} buffer
6009
+ * @return {Integer}
6010
+ */
6011
+ processBuffer(buffer) {
6012
+ const json = this.json;
6013
+ const buffers = this.buffers;
6014
+ if (!json.buffers) json.buffers = [{ byteLength: 0 }];
6015
+ buffers.push(buffer);
6016
+ return 0;
6017
+ }
6018
+ /**
6019
+ * Process and generate a BufferView
6020
+ * @param {BufferAttribute} attribute
6021
+ * @param {number} componentType
6022
+ * @param {number} start
6023
+ * @param {number} count
6024
+ * @param {number} target (Optional) Target usage of the BufferView
6025
+ * @return {Object}
6026
+ */
6027
+ processBufferView(attribute, componentType, start, count, target) {
6028
+ const json = this.json;
6029
+ if (!json.bufferViews) json.bufferViews = [];
6030
+ let componentSize;
6031
+ switch (componentType) {
6032
+ case WEBGL_CONSTANTS.BYTE:
6033
+ case WEBGL_CONSTANTS.UNSIGNED_BYTE:
6034
+ componentSize = 1;
6035
+ break;
6036
+ case WEBGL_CONSTANTS.SHORT:
6037
+ case WEBGL_CONSTANTS.UNSIGNED_SHORT:
6038
+ componentSize = 2;
6039
+ break;
6040
+ default:
6041
+ componentSize = 4;
6042
+ }
6043
+ const byteLength = getPaddedBufferSize(count * attribute.itemSize * componentSize);
6044
+ const dataView = new DataView(new ArrayBuffer(byteLength));
6045
+ let offset = 0;
6046
+ for (let i = start; i < start + count; i++) {
6047
+ for (let a = 0; a < attribute.itemSize; a++) {
6048
+ let value;
6049
+ if (attribute.itemSize > 4) {
6050
+ value = attribute.array[i * attribute.itemSize + a];
6051
+ } else {
6052
+ if (a === 0) value = attribute.getX(i);
6053
+ else if (a === 1) value = attribute.getY(i);
6054
+ else if (a === 2) value = attribute.getZ(i);
6055
+ else if (a === 3) value = attribute.getW(i);
6056
+ if (attribute.normalized === true) {
6057
+ value = MathUtils2.normalize(value, attribute.array);
6058
+ }
6059
+ }
6060
+ if (componentType === WEBGL_CONSTANTS.FLOAT) {
6061
+ dataView.setFloat32(offset, value, true);
6062
+ } else if (componentType === WEBGL_CONSTANTS.INT) {
6063
+ dataView.setInt32(offset, value, true);
6064
+ } else if (componentType === WEBGL_CONSTANTS.UNSIGNED_INT) {
6065
+ dataView.setUint32(offset, value, true);
6066
+ } else if (componentType === WEBGL_CONSTANTS.SHORT) {
6067
+ dataView.setInt16(offset, value, true);
6068
+ } else if (componentType === WEBGL_CONSTANTS.UNSIGNED_SHORT) {
6069
+ dataView.setUint16(offset, value, true);
6070
+ } else if (componentType === WEBGL_CONSTANTS.BYTE) {
6071
+ dataView.setInt8(offset, value);
6072
+ } else if (componentType === WEBGL_CONSTANTS.UNSIGNED_BYTE) {
6073
+ dataView.setUint8(offset, value);
6074
+ }
6075
+ offset += componentSize;
6076
+ }
6077
+ }
6078
+ const bufferViewDef = {
6079
+ buffer: this.processBuffer(dataView.buffer),
6080
+ byteOffset: this.byteOffset,
6081
+ byteLength
6082
+ };
6083
+ if (target !== void 0) bufferViewDef.target = target;
6084
+ if (target === WEBGL_CONSTANTS.ARRAY_BUFFER) {
6085
+ bufferViewDef.byteStride = attribute.itemSize * componentSize;
6086
+ }
6087
+ this.byteOffset += byteLength;
6088
+ json.bufferViews.push(bufferViewDef);
6089
+ const output = {
6090
+ id: json.bufferViews.length - 1,
6091
+ byteLength: 0
6092
+ };
6093
+ return output;
6094
+ }
6095
+ /**
6096
+ * Process and generate a BufferView from an image Blob.
6097
+ * @param {Blob} blob
6098
+ * @return {Promise<Integer>}
6099
+ */
6100
+ processBufferViewImage(blob) {
6101
+ const writer = this;
6102
+ const json = writer.json;
6103
+ if (!json.bufferViews) json.bufferViews = [];
6104
+ return new Promise(function(resolve) {
6105
+ const reader = new FileReader();
6106
+ reader.readAsArrayBuffer(blob);
6107
+ reader.onloadend = function() {
6108
+ const buffer = getPaddedArrayBuffer(reader.result);
6109
+ const bufferViewDef = {
6110
+ buffer: writer.processBuffer(buffer),
6111
+ byteOffset: writer.byteOffset,
6112
+ byteLength: buffer.byteLength
6113
+ };
6114
+ writer.byteOffset += buffer.byteLength;
6115
+ resolve(json.bufferViews.push(bufferViewDef) - 1);
6116
+ };
6117
+ });
6118
+ }
6119
+ /**
6120
+ * Process attribute to generate an accessor
6121
+ * @param {BufferAttribute} attribute Attribute to process
6122
+ * @param {THREE.BufferGeometry} geometry (Optional) Geometry used for truncated draw range
6123
+ * @param {Integer} start (Optional)
6124
+ * @param {Integer} count (Optional)
6125
+ * @return {Integer|null} Index of the processed accessor on the "accessors" array
6126
+ */
6127
+ processAccessor(attribute, geometry, start, count) {
6128
+ const json = this.json;
6129
+ const types = {
6130
+ 1: "SCALAR",
6131
+ 2: "VEC2",
6132
+ 3: "VEC3",
6133
+ 4: "VEC4",
6134
+ 9: "MAT3",
6135
+ 16: "MAT4"
6136
+ };
6137
+ let componentType;
6138
+ if (attribute.array.constructor === Float32Array) {
6139
+ componentType = WEBGL_CONSTANTS.FLOAT;
6140
+ } else if (attribute.array.constructor === Int32Array) {
6141
+ componentType = WEBGL_CONSTANTS.INT;
6142
+ } else if (attribute.array.constructor === Uint32Array) {
6143
+ componentType = WEBGL_CONSTANTS.UNSIGNED_INT;
6144
+ } else if (attribute.array.constructor === Int16Array) {
6145
+ componentType = WEBGL_CONSTANTS.SHORT;
6146
+ } else if (attribute.array.constructor === Uint16Array) {
6147
+ componentType = WEBGL_CONSTANTS.UNSIGNED_SHORT;
6148
+ } else if (attribute.array.constructor === Int8Array) {
6149
+ componentType = WEBGL_CONSTANTS.BYTE;
6150
+ } else if (attribute.array.constructor === Uint8Array) {
6151
+ componentType = WEBGL_CONSTANTS.UNSIGNED_BYTE;
6152
+ } else {
6153
+ throw new Error("THREE.GLTFExporter: Unsupported bufferAttribute component type: " + attribute.array.constructor.name);
6154
+ }
6155
+ if (start === void 0) start = 0;
6156
+ if (count === void 0 || count === Infinity) count = attribute.count;
6157
+ if (count === 0) return null;
6158
+ const minMax = getMinMax(attribute, start, count);
6159
+ let bufferViewTarget;
6160
+ if (geometry !== void 0) {
6161
+ bufferViewTarget = attribute === geometry.index ? WEBGL_CONSTANTS.ELEMENT_ARRAY_BUFFER : WEBGL_CONSTANTS.ARRAY_BUFFER;
6162
+ }
6163
+ const bufferView = this.processBufferView(attribute, componentType, start, count, bufferViewTarget);
6164
+ const accessorDef = {
6165
+ bufferView: bufferView.id,
6166
+ byteOffset: bufferView.byteOffset,
6167
+ componentType,
6168
+ count,
6169
+ max: minMax.max,
6170
+ min: minMax.min,
6171
+ type: types[attribute.itemSize]
6172
+ };
6173
+ if (attribute.normalized === true) accessorDef.normalized = true;
6174
+ if (!json.accessors) json.accessors = [];
6175
+ return json.accessors.push(accessorDef) - 1;
6176
+ }
6177
+ /**
6178
+ * Process image
6179
+ * @param {Image} image to process
6180
+ * @param {Integer} format of the image (RGBAFormat)
6181
+ * @param {Boolean} flipY before writing out the image
6182
+ * @param {String} mimeType export format
6183
+ * @return {Integer} Index of the processed texture in the "images" array
6184
+ */
6185
+ processImage(image, format, flipY, mimeType = "image/png") {
6186
+ if (image !== null) {
6187
+ const writer = this;
6188
+ const cache = writer.cache;
6189
+ const json = writer.json;
6190
+ const options = writer.options;
6191
+ const pending = writer.pending;
6192
+ if (!cache.images.has(image)) cache.images.set(image, {});
6193
+ const cachedImages = cache.images.get(image);
6194
+ const key = mimeType + ":flipY/" + flipY.toString();
6195
+ if (cachedImages[key] !== void 0) return cachedImages[key];
6196
+ if (!json.images) json.images = [];
6197
+ const imageDef = { mimeType };
6198
+ const canvas = getCanvas();
6199
+ canvas.width = Math.min(image.width, options.maxTextureSize);
6200
+ canvas.height = Math.min(image.height, options.maxTextureSize);
6201
+ const ctx = canvas.getContext("2d");
6202
+ if (flipY === true) {
6203
+ ctx.translate(0, canvas.height);
6204
+ ctx.scale(1, -1);
6205
+ }
6206
+ if (image.data !== void 0) {
6207
+ if (format !== RGBAFormat2) {
6208
+ console.error("GLTFExporter: Only RGBAFormat is supported.", format);
6209
+ }
6210
+ if (image.width > options.maxTextureSize || image.height > options.maxTextureSize) {
6211
+ console.warn("GLTFExporter: Image size is bigger than maxTextureSize", image);
6212
+ }
6213
+ const data = new Uint8ClampedArray(image.height * image.width * 4);
6214
+ for (let i = 0; i < data.length; i += 4) {
6215
+ data[i + 0] = image.data[i + 0];
6216
+ data[i + 1] = image.data[i + 1];
6217
+ data[i + 2] = image.data[i + 2];
6218
+ data[i + 3] = image.data[i + 3];
6219
+ }
6220
+ ctx.putImageData(new ImageData(data, image.width, image.height), 0, 0);
6221
+ } else {
6222
+ ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
6223
+ }
6224
+ if (options.binary === true) {
6225
+ pending.push(
6226
+ getToBlobPromise(canvas, mimeType).then((blob) => writer.processBufferViewImage(blob)).then((bufferViewIndex) => {
6227
+ imageDef.bufferView = bufferViewIndex;
6228
+ })
6229
+ );
6230
+ } else {
6231
+ if (canvas.toDataURL !== void 0) {
6232
+ imageDef.uri = canvas.toDataURL(mimeType);
6233
+ } else {
6234
+ pending.push(
6235
+ getToBlobPromise(canvas, mimeType).then((blob) => new FileReader().readAsDataURL(blob)).then((dataURL) => {
6236
+ imageDef.uri = dataURL;
6237
+ })
6238
+ );
6239
+ }
6240
+ }
6241
+ const index = json.images.push(imageDef) - 1;
6242
+ cachedImages[key] = index;
6243
+ return index;
6244
+ } else {
6245
+ throw new Error("THREE.GLTFExporter: No valid image data found. Unable to process texture.");
6246
+ }
6247
+ }
6248
+ /**
6249
+ * Process sampler
6250
+ * @param {Texture} map Texture to process
6251
+ * @return {Integer} Index of the processed texture in the "samplers" array
6252
+ */
6253
+ processSampler(map) {
6254
+ const json = this.json;
6255
+ if (!json.samplers) json.samplers = [];
6256
+ const samplerDef = {
6257
+ magFilter: THREE_TO_WEBGL[map.magFilter],
6258
+ minFilter: THREE_TO_WEBGL[map.minFilter],
6259
+ wrapS: THREE_TO_WEBGL[map.wrapS],
6260
+ wrapT: THREE_TO_WEBGL[map.wrapT]
6261
+ };
6262
+ return json.samplers.push(samplerDef) - 1;
6263
+ }
6264
+ /**
6265
+ * Process texture
6266
+ * @param {Texture} map Map to process
6267
+ * @return {Integer} Index of the processed texture in the "textures" array
6268
+ */
6269
+ processTexture(map) {
6270
+ const writer = this;
6271
+ const options = writer.options;
6272
+ const cache = this.cache;
6273
+ const json = this.json;
6274
+ if (cache.textures.has(map)) return cache.textures.get(map);
6275
+ if (!json.textures) json.textures = [];
6276
+ if (map instanceof CompressedTexture) {
6277
+ map = decompress(map, options.maxTextureSize);
6278
+ }
6279
+ let mimeType = map.userData.mimeType;
6280
+ if (mimeType === "image/webp") mimeType = "image/png";
6281
+ const textureDef = {
6282
+ sampler: this.processSampler(map),
6283
+ source: this.processImage(map.image, map.format, map.flipY, mimeType)
6284
+ };
6285
+ if (map.name) textureDef.name = map.name;
6286
+ this._invokeAll(function(ext) {
6287
+ ext.writeTexture && ext.writeTexture(map, textureDef);
6288
+ });
6289
+ const index = json.textures.push(textureDef) - 1;
6290
+ cache.textures.set(map, index);
6291
+ return index;
6292
+ }
6293
+ /**
6294
+ * Process material
6295
+ * @param {THREE.Material} material Material to process
6296
+ * @return {Integer|null} Index of the processed material in the "materials" array
6297
+ */
6298
+ processMaterial(material) {
6299
+ const cache = this.cache;
6300
+ const json = this.json;
6301
+ if (cache.materials.has(material)) return cache.materials.get(material);
6302
+ if (material.isShaderMaterial) {
6303
+ console.warn("GLTFExporter: THREE.ShaderMaterial not supported.");
6304
+ return null;
6305
+ }
6306
+ if (!json.materials) json.materials = [];
6307
+ const materialDef = { pbrMetallicRoughness: {} };
6308
+ if (material.isMeshStandardMaterial !== true && material.isMeshBasicMaterial !== true) {
6309
+ console.warn("GLTFExporter: Use MeshStandardMaterial or MeshBasicMaterial for best results.");
6310
+ }
6311
+ const color = material.color.toArray().concat([material.opacity]);
6312
+ if (!equalArray(color, [1, 1, 1, 1])) {
6313
+ materialDef.pbrMetallicRoughness.baseColorFactor = color;
6314
+ }
6315
+ if (material.isMeshStandardMaterial) {
6316
+ materialDef.pbrMetallicRoughness.metallicFactor = material.metalness;
6317
+ materialDef.pbrMetallicRoughness.roughnessFactor = material.roughness;
6318
+ } else {
6319
+ materialDef.pbrMetallicRoughness.metallicFactor = 0.5;
6320
+ materialDef.pbrMetallicRoughness.roughnessFactor = 0.5;
6321
+ }
6322
+ if (material.metalnessMap || material.roughnessMap) {
6323
+ const metalRoughTexture = this.buildMetalRoughTexture(material.metalnessMap, material.roughnessMap);
6324
+ const metalRoughMapDef = {
6325
+ index: this.processTexture(metalRoughTexture),
6326
+ channel: metalRoughTexture.channel
6327
+ };
6328
+ this.applyTextureTransform(metalRoughMapDef, metalRoughTexture);
6329
+ materialDef.pbrMetallicRoughness.metallicRoughnessTexture = metalRoughMapDef;
6330
+ }
6331
+ if (material.map) {
6332
+ const baseColorMapDef = {
6333
+ index: this.processTexture(material.map),
6334
+ texCoord: material.map.channel
6335
+ };
6336
+ this.applyTextureTransform(baseColorMapDef, material.map);
6337
+ materialDef.pbrMetallicRoughness.baseColorTexture = baseColorMapDef;
6338
+ }
6339
+ if (material.emissive) {
6340
+ const emissive = material.emissive;
6341
+ const maxEmissiveComponent = Math.max(emissive.r, emissive.g, emissive.b);
6342
+ if (maxEmissiveComponent > 0) {
6343
+ materialDef.emissiveFactor = material.emissive.toArray();
6344
+ }
6345
+ if (material.emissiveMap) {
6346
+ const emissiveMapDef = {
6347
+ index: this.processTexture(material.emissiveMap),
6348
+ texCoord: material.emissiveMap.channel
6349
+ };
6350
+ this.applyTextureTransform(emissiveMapDef, material.emissiveMap);
6351
+ materialDef.emissiveTexture = emissiveMapDef;
6352
+ }
6353
+ }
6354
+ if (material.normalMap) {
6355
+ const normalMapDef = {
6356
+ index: this.processTexture(material.normalMap),
6357
+ texCoord: material.normalMap.channel
6358
+ };
6359
+ if (material.normalScale && material.normalScale.x !== 1) {
6360
+ normalMapDef.scale = material.normalScale.x;
6361
+ }
6362
+ this.applyTextureTransform(normalMapDef, material.normalMap);
6363
+ materialDef.normalTexture = normalMapDef;
6364
+ }
6365
+ if (material.aoMap) {
6366
+ const occlusionMapDef = {
6367
+ index: this.processTexture(material.aoMap),
6368
+ texCoord: material.aoMap.channel
6369
+ };
6370
+ if (material.aoMapIntensity !== 1) {
6371
+ occlusionMapDef.strength = material.aoMapIntensity;
6372
+ }
6373
+ this.applyTextureTransform(occlusionMapDef, material.aoMap);
6374
+ materialDef.occlusionTexture = occlusionMapDef;
6375
+ }
6376
+ if (material.transparent) {
6377
+ materialDef.alphaMode = "BLEND";
6378
+ } else {
6379
+ if (material.alphaTest > 0) {
6380
+ materialDef.alphaMode = "MASK";
6381
+ materialDef.alphaCutoff = material.alphaTest;
6382
+ }
6383
+ }
6384
+ if (material.side === DoubleSide2) materialDef.doubleSided = true;
6385
+ if (material.name !== "") materialDef.name = material.name;
6386
+ this.serializeUserData(material, materialDef);
6387
+ this._invokeAll(function(ext) {
6388
+ ext.writeMaterial && ext.writeMaterial(material, materialDef);
6389
+ });
6390
+ const index = json.materials.push(materialDef) - 1;
6391
+ cache.materials.set(material, index);
6392
+ return index;
6393
+ }
6394
+ /**
6395
+ * Process mesh
6396
+ * @param {THREE.Mesh} mesh Mesh to process
6397
+ * @return {Integer|null} Index of the processed mesh in the "meshes" array
6398
+ */
6399
+ processMesh(mesh) {
6400
+ const cache = this.cache;
6401
+ const json = this.json;
6402
+ const meshCacheKeyParts = [mesh.geometry.uuid];
6403
+ if (Array.isArray(mesh.material)) {
6404
+ for (let i = 0, l = mesh.material.length; i < l; i++) {
6405
+ meshCacheKeyParts.push(mesh.material[i].uuid);
6406
+ }
6407
+ } else {
6408
+ meshCacheKeyParts.push(mesh.material.uuid);
6409
+ }
6410
+ const meshCacheKey = meshCacheKeyParts.join(":");
6411
+ if (cache.meshes.has(meshCacheKey)) return cache.meshes.get(meshCacheKey);
6412
+ const geometry = mesh.geometry;
6413
+ let mode;
6414
+ if (mesh.isLineSegments) {
6415
+ mode = WEBGL_CONSTANTS.LINES;
6416
+ } else if (mesh.isLineLoop) {
6417
+ mode = WEBGL_CONSTANTS.LINE_LOOP;
6418
+ } else if (mesh.isLine) {
6419
+ mode = WEBGL_CONSTANTS.LINE_STRIP;
6420
+ } else if (mesh.isPoints) {
6421
+ mode = WEBGL_CONSTANTS.POINTS;
6422
+ } else {
6423
+ mode = mesh.material.wireframe ? WEBGL_CONSTANTS.LINES : WEBGL_CONSTANTS.TRIANGLES;
6424
+ }
6425
+ const meshDef = {};
6426
+ const attributes = {};
6427
+ const primitives = [];
6428
+ const targets = [];
6429
+ const nameConversion = {
6430
+ uv: "TEXCOORD_0",
6431
+ uv1: "TEXCOORD_1",
6432
+ uv2: "TEXCOORD_2",
6433
+ uv3: "TEXCOORD_3",
6434
+ color: "COLOR_0",
6435
+ skinWeight: "WEIGHTS_0",
6436
+ skinIndex: "JOINTS_0"
6437
+ };
6438
+ const originalNormal = geometry.getAttribute("normal");
6439
+ if (originalNormal !== void 0 && !this.isNormalizedNormalAttribute(originalNormal)) {
6440
+ console.warn("THREE.GLTFExporter: Creating normalized normal attribute from the non-normalized one.");
6441
+ geometry.setAttribute("normal", this.createNormalizedNormalAttribute(originalNormal));
6442
+ }
6443
+ let modifiedAttribute = null;
6444
+ for (let attributeName in geometry.attributes) {
6445
+ if (attributeName.slice(0, 5) === "morph") continue;
6446
+ const attribute = geometry.attributes[attributeName];
6447
+ attributeName = nameConversion[attributeName] || attributeName.toUpperCase();
6448
+ const validVertexAttributes = /^(POSITION|NORMAL|TANGENT|TEXCOORD_\d+|COLOR_\d+|JOINTS_\d+|WEIGHTS_\d+)$/;
6449
+ if (!validVertexAttributes.test(attributeName)) attributeName = "_" + attributeName;
6450
+ if (cache.attributes.has(this.getUID(attribute))) {
6451
+ attributes[attributeName] = cache.attributes.get(this.getUID(attribute));
6452
+ continue;
6453
+ }
6454
+ modifiedAttribute = null;
6455
+ const array = attribute.array;
6456
+ if (attributeName === "JOINTS_0" && !(array instanceof Uint16Array) && !(array instanceof Uint8Array)) {
6457
+ console.warn('GLTFExporter: Attribute "skinIndex" converted to type UNSIGNED_SHORT.');
6458
+ modifiedAttribute = new BufferAttribute3(new Uint16Array(array), attribute.itemSize, attribute.normalized);
6459
+ }
6460
+ const accessor = this.processAccessor(modifiedAttribute || attribute, geometry);
6461
+ if (accessor !== null) {
6462
+ if (!attributeName.startsWith("_")) {
6463
+ this.detectMeshQuantization(attributeName, attribute);
6464
+ }
6465
+ attributes[attributeName] = accessor;
6466
+ cache.attributes.set(this.getUID(attribute), accessor);
6467
+ }
6468
+ }
6469
+ if (originalNormal !== void 0) geometry.setAttribute("normal", originalNormal);
6470
+ if (Object.keys(attributes).length === 0) return null;
6471
+ if (mesh.morphTargetInfluences !== void 0 && mesh.morphTargetInfluences.length > 0) {
6472
+ const weights = [];
6473
+ const targetNames = [];
6474
+ const reverseDictionary = {};
6475
+ if (mesh.morphTargetDictionary !== void 0) {
6476
+ for (const key in mesh.morphTargetDictionary) {
6477
+ reverseDictionary[mesh.morphTargetDictionary[key]] = key;
6478
+ }
6479
+ }
6480
+ for (let i = 0; i < mesh.morphTargetInfluences.length; ++i) {
6481
+ const target = {};
6482
+ let warned = false;
6483
+ for (const attributeName in geometry.morphAttributes) {
6484
+ if (attributeName !== "position" && attributeName !== "normal") {
6485
+ if (!warned) {
6486
+ console.warn("GLTFExporter: Only POSITION and NORMAL morph are supported.");
6487
+ warned = true;
6488
+ }
6489
+ continue;
6490
+ }
6491
+ const attribute = geometry.morphAttributes[attributeName][i];
6492
+ const gltfAttributeName = attributeName.toUpperCase();
6493
+ const baseAttribute = geometry.attributes[attributeName];
6494
+ if (cache.attributes.has(this.getUID(attribute, true))) {
6495
+ target[gltfAttributeName] = cache.attributes.get(this.getUID(attribute, true));
6496
+ continue;
6497
+ }
6498
+ const relativeAttribute = attribute.clone();
6499
+ if (!geometry.morphTargetsRelative) {
6500
+ for (let j = 0, jl = attribute.count; j < jl; j++) {
6501
+ for (let a = 0; a < attribute.itemSize; a++) {
6502
+ if (a === 0) relativeAttribute.setX(j, attribute.getX(j) - baseAttribute.getX(j));
6503
+ if (a === 1) relativeAttribute.setY(j, attribute.getY(j) - baseAttribute.getY(j));
6504
+ if (a === 2) relativeAttribute.setZ(j, attribute.getZ(j) - baseAttribute.getZ(j));
6505
+ if (a === 3) relativeAttribute.setW(j, attribute.getW(j) - baseAttribute.getW(j));
6506
+ }
6507
+ }
6508
+ }
6509
+ target[gltfAttributeName] = this.processAccessor(relativeAttribute, geometry);
6510
+ cache.attributes.set(this.getUID(baseAttribute, true), target[gltfAttributeName]);
6511
+ }
6512
+ targets.push(target);
6513
+ weights.push(mesh.morphTargetInfluences[i]);
6514
+ if (mesh.morphTargetDictionary !== void 0) targetNames.push(reverseDictionary[i]);
6515
+ }
6516
+ meshDef.weights = weights;
6517
+ if (targetNames.length > 0) {
6518
+ meshDef.extras = {};
6519
+ meshDef.extras.targetNames = targetNames;
6520
+ }
6521
+ }
6522
+ const isMultiMaterial = Array.isArray(mesh.material);
6523
+ if (isMultiMaterial && geometry.groups.length === 0) return null;
6524
+ const materials = isMultiMaterial ? mesh.material : [mesh.material];
6525
+ const groups = isMultiMaterial ? geometry.groups : [{ materialIndex: 0, start: void 0, count: void 0 }];
6526
+ for (let i = 0, il = groups.length; i < il; i++) {
6527
+ const primitive = {
6528
+ mode,
6529
+ attributes
6530
+ };
6531
+ this.serializeUserData(geometry, primitive);
6532
+ if (targets.length > 0) primitive.targets = targets;
6533
+ if (geometry.index !== null) {
6534
+ let cacheKey = this.getUID(geometry.index);
6535
+ if (groups[i].start !== void 0 || groups[i].count !== void 0) {
6536
+ cacheKey += ":" + groups[i].start + ":" + groups[i].count;
6537
+ }
6538
+ if (cache.attributes.has(cacheKey)) {
6539
+ primitive.indices = cache.attributes.get(cacheKey);
6540
+ } else {
6541
+ primitive.indices = this.processAccessor(geometry.index, geometry, groups[i].start, groups[i].count);
6542
+ cache.attributes.set(cacheKey, primitive.indices);
6543
+ }
6544
+ if (primitive.indices === null) delete primitive.indices;
6545
+ }
6546
+ const material = this.processMaterial(materials[groups[i].materialIndex]);
6547
+ if (material !== null) primitive.material = material;
6548
+ primitives.push(primitive);
6549
+ }
6550
+ meshDef.primitives = primitives;
6551
+ if (!json.meshes) json.meshes = [];
6552
+ this._invokeAll(function(ext) {
6553
+ ext.writeMesh && ext.writeMesh(mesh, meshDef);
6554
+ });
6555
+ const index = json.meshes.push(meshDef) - 1;
6556
+ cache.meshes.set(meshCacheKey, index);
6557
+ return index;
6558
+ }
6559
+ /**
6560
+ * If a vertex attribute with a
6561
+ * [non-standard data type](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#meshes-overview)
6562
+ * is used, it is checked whether it is a valid data type according to the
6563
+ * [KHR_mesh_quantization](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_mesh_quantization/README.md)
6564
+ * extension.
6565
+ * In this case the extension is automatically added to the list of used extensions.
6566
+ *
6567
+ * @param {string} attributeName
6568
+ * @param {THREE.BufferAttribute} attribute
6569
+ */
6570
+ detectMeshQuantization(attributeName, attribute) {
6571
+ if (this.extensionsUsed[KHR_MESH_QUANTIZATION]) return;
6572
+ let attrType = void 0;
6573
+ switch (attribute.array.constructor) {
6574
+ case Int8Array:
6575
+ attrType = "byte";
6576
+ break;
6577
+ case Uint8Array:
6578
+ attrType = "unsigned byte";
6579
+ break;
6580
+ case Int16Array:
6581
+ attrType = "short";
6582
+ break;
6583
+ case Uint16Array:
6584
+ attrType = "unsigned short";
6585
+ break;
6586
+ default:
6587
+ return;
6588
+ }
6589
+ if (attribute.normalized) attrType += " normalized";
6590
+ const attrNamePrefix = attributeName.split("_", 1)[0];
6591
+ if (KHR_mesh_quantization_ExtraAttrTypes[attrNamePrefix] && KHR_mesh_quantization_ExtraAttrTypes[attrNamePrefix].includes(attrType)) {
6592
+ this.extensionsUsed[KHR_MESH_QUANTIZATION] = true;
6593
+ this.extensionsRequired[KHR_MESH_QUANTIZATION] = true;
6594
+ }
6595
+ }
6596
+ /**
6597
+ * Process camera
6598
+ * @param {THREE.Camera} camera Camera to process
6599
+ * @return {Integer} Index of the processed mesh in the "camera" array
6600
+ */
6601
+ processCamera(camera) {
6602
+ const json = this.json;
6603
+ if (!json.cameras) json.cameras = [];
6604
+ const isOrtho = camera.isOrthographicCamera;
6605
+ const cameraDef = {
6606
+ type: isOrtho ? "orthographic" : "perspective"
6607
+ };
6608
+ if (isOrtho) {
6609
+ cameraDef.orthographic = {
6610
+ xmag: camera.right * 2,
6611
+ ymag: camera.top * 2,
6612
+ zfar: camera.far <= 0 ? 1e-3 : camera.far,
6613
+ znear: camera.near < 0 ? 0 : camera.near
6614
+ };
6615
+ } else {
6616
+ cameraDef.perspective = {
6617
+ aspectRatio: camera.aspect,
6618
+ yfov: MathUtils2.degToRad(camera.fov),
6619
+ zfar: camera.far <= 0 ? 1e-3 : camera.far,
6620
+ znear: camera.near < 0 ? 0 : camera.near
6621
+ };
6622
+ }
6623
+ if (camera.name !== "") cameraDef.name = camera.type;
6624
+ return json.cameras.push(cameraDef) - 1;
6625
+ }
6626
+ /**
6627
+ * Creates glTF animation entry from AnimationClip object.
6628
+ *
6629
+ * Status:
6630
+ * - Only properties listed in PATH_PROPERTIES may be animated.
6631
+ *
6632
+ * @param {THREE.AnimationClip} clip
6633
+ * @param {THREE.Object3D} root
6634
+ * @return {number|null}
6635
+ */
6636
+ processAnimation(clip, root) {
6637
+ const json = this.json;
6638
+ const nodeMap = this.nodeMap;
6639
+ if (!json.animations) json.animations = [];
6640
+ clip = GLTFExporter.Utils.mergeMorphTargetTracks(clip.clone(), root);
6641
+ const tracks = clip.tracks;
6642
+ const channels = [];
6643
+ const samplers = [];
6644
+ for (let i = 0; i < tracks.length; ++i) {
6645
+ const track = tracks[i];
6646
+ const trackBinding = PropertyBinding.parseTrackName(track.name);
6647
+ let trackNode = PropertyBinding.findNode(root, trackBinding.nodeName);
6648
+ const trackProperty = PATH_PROPERTIES[trackBinding.propertyName];
6649
+ if (trackBinding.objectName === "bones") {
6650
+ if (trackNode.isSkinnedMesh === true) {
6651
+ trackNode = trackNode.skeleton.getBoneByName(trackBinding.objectIndex);
6652
+ } else {
6653
+ trackNode = void 0;
6654
+ }
6655
+ }
6656
+ if (!trackNode || !trackProperty) {
6657
+ console.warn('THREE.GLTFExporter: Could not export animation track "%s".', track.name);
6658
+ return null;
6659
+ }
6660
+ const inputItemSize = 1;
6661
+ let outputItemSize = track.values.length / track.times.length;
6662
+ if (trackProperty === PATH_PROPERTIES.morphTargetInfluences) {
6663
+ outputItemSize /= trackNode.morphTargetInfluences.length;
6664
+ }
6665
+ let interpolation;
6666
+ if (track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline === true) {
6667
+ interpolation = "CUBICSPLINE";
6668
+ outputItemSize /= 3;
6669
+ } else if (track.getInterpolation() === InterpolateDiscrete) {
6670
+ interpolation = "STEP";
6671
+ } else {
6672
+ interpolation = "LINEAR";
6673
+ }
6674
+ samplers.push({
6675
+ input: this.processAccessor(new BufferAttribute3(track.times, inputItemSize)),
6676
+ output: this.processAccessor(new BufferAttribute3(track.values, outputItemSize)),
6677
+ interpolation
6678
+ });
6679
+ channels.push({
6680
+ sampler: samplers.length - 1,
6681
+ target: {
6682
+ node: nodeMap.get(trackNode),
6683
+ path: trackProperty
6684
+ }
6685
+ });
6686
+ }
6687
+ json.animations.push({
6688
+ name: clip.name || "clip_" + json.animations.length,
6689
+ samplers,
6690
+ channels
6691
+ });
6692
+ return json.animations.length - 1;
6693
+ }
6694
+ /**
6695
+ * @param {THREE.Object3D} object
6696
+ * @return {number|null}
6697
+ */
6698
+ processSkin(object) {
6699
+ const json = this.json;
6700
+ const nodeMap = this.nodeMap;
6701
+ const node = json.nodes[nodeMap.get(object)];
6702
+ const skeleton = object.skeleton;
6703
+ if (skeleton === void 0) return null;
6704
+ const rootJoint = object.skeleton.bones[0];
6705
+ if (rootJoint === void 0) return null;
6706
+ const joints = [];
6707
+ const inverseBindMatrices = new Float32Array(skeleton.bones.length * 16);
6708
+ const temporaryBoneInverse = new Matrix44();
6709
+ for (let i = 0; i < skeleton.bones.length; ++i) {
6710
+ joints.push(nodeMap.get(skeleton.bones[i]));
6711
+ temporaryBoneInverse.copy(skeleton.boneInverses[i]);
6712
+ temporaryBoneInverse.multiply(object.bindMatrix).toArray(inverseBindMatrices, i * 16);
6713
+ }
6714
+ if (json.skins === void 0) json.skins = [];
6715
+ json.skins.push({
6716
+ inverseBindMatrices: this.processAccessor(new BufferAttribute3(inverseBindMatrices, 16)),
6717
+ joints,
6718
+ skeleton: nodeMap.get(rootJoint)
6719
+ });
6720
+ const skinIndex = node.skin = json.skins.length - 1;
6721
+ return skinIndex;
6722
+ }
6723
+ /**
6724
+ * Process Object3D node
6725
+ * @param {THREE.Object3D} node Object3D to processNode
6726
+ * @return {Integer} Index of the node in the nodes list
6727
+ */
6728
+ processNode(object) {
6729
+ const json = this.json;
6730
+ const options = this.options;
6731
+ const nodeMap = this.nodeMap;
6732
+ if (!json.nodes) json.nodes = [];
6733
+ const nodeDef = {};
6734
+ if (options.trs) {
6735
+ const rotation = object.quaternion.toArray();
6736
+ const position = object.position.toArray();
6737
+ const scale = object.scale.toArray();
6738
+ if (!equalArray(rotation, [0, 0, 0, 1])) {
6739
+ nodeDef.rotation = rotation;
6740
+ }
6741
+ if (!equalArray(position, [0, 0, 0])) {
6742
+ nodeDef.translation = position;
6743
+ }
6744
+ if (!equalArray(scale, [1, 1, 1])) {
6745
+ nodeDef.scale = scale;
6746
+ }
6747
+ } else {
6748
+ if (object.matrixAutoUpdate) {
6749
+ object.updateMatrix();
6750
+ }
6751
+ if (isIdentityMatrix(object.matrix) === false) {
6752
+ nodeDef.matrix = object.matrix.elements;
6753
+ }
6754
+ }
6755
+ if (object.name !== "") nodeDef.name = String(object.name);
6756
+ this.serializeUserData(object, nodeDef);
6757
+ if (object.isMesh || object.isLine || object.isPoints) {
6758
+ const meshIndex = this.processMesh(object);
6759
+ if (meshIndex !== null) nodeDef.mesh = meshIndex;
6760
+ } else if (object.isCamera) {
6761
+ nodeDef.camera = this.processCamera(object);
6762
+ }
6763
+ if (object.isSkinnedMesh) this.skins.push(object);
6764
+ if (object.children.length > 0) {
6765
+ const children = [];
6766
+ for (let i = 0, l = object.children.length; i < l; i++) {
6767
+ const child = object.children[i];
6768
+ if (child.visible || options.onlyVisible === false) {
6769
+ const nodeIndex2 = this.processNode(child);
6770
+ if (nodeIndex2 !== null) children.push(nodeIndex2);
6771
+ }
6772
+ }
6773
+ if (children.length > 0) nodeDef.children = children;
6774
+ }
6775
+ this._invokeAll(function(ext) {
6776
+ ext.writeNode && ext.writeNode(object, nodeDef);
6777
+ });
6778
+ const nodeIndex = json.nodes.push(nodeDef) - 1;
6779
+ nodeMap.set(object, nodeIndex);
6780
+ return nodeIndex;
6781
+ }
6782
+ /**
6783
+ * Process Scene
6784
+ * @param {Scene} node Scene to process
6785
+ */
6786
+ processScene(scene) {
6787
+ const json = this.json;
6788
+ const options = this.options;
6789
+ if (!json.scenes) {
6790
+ json.scenes = [];
6791
+ json.scene = 0;
6792
+ }
6793
+ const sceneDef = {};
6794
+ if (scene.name !== "") sceneDef.name = scene.name;
6795
+ json.scenes.push(sceneDef);
6796
+ const nodes = [];
6797
+ for (let i = 0, l = scene.children.length; i < l; i++) {
6798
+ const child = scene.children[i];
6799
+ if (child.visible || options.onlyVisible === false) {
6800
+ const nodeIndex = this.processNode(child);
6801
+ if (nodeIndex !== null) nodes.push(nodeIndex);
6802
+ }
6803
+ }
6804
+ if (nodes.length > 0) sceneDef.nodes = nodes;
6805
+ this.serializeUserData(scene, sceneDef);
6806
+ }
6807
+ /**
6808
+ * Creates a Scene to hold a list of objects and parse it
6809
+ * @param {Array} objects List of objects to process
6810
+ */
6811
+ processObjects(objects) {
6812
+ const scene = new Scene3();
6813
+ scene.name = "AuxScene";
6814
+ for (let i = 0; i < objects.length; i++) {
6815
+ scene.children.push(objects[i]);
6816
+ }
6817
+ this.processScene(scene);
6818
+ }
6819
+ /**
6820
+ * @param {THREE.Object3D|Array<THREE.Object3D>} input
6821
+ */
6822
+ processInput(input) {
6823
+ const options = this.options;
6824
+ input = input instanceof Array ? input : [input];
6825
+ this._invokeAll(function(ext) {
6826
+ ext.beforeParse && ext.beforeParse(input);
6827
+ });
6828
+ const objectsWithoutScene = [];
6829
+ for (let i = 0; i < input.length; i++) {
6830
+ if (input[i] instanceof Scene3) {
6831
+ this.processScene(input[i]);
6832
+ } else {
6833
+ objectsWithoutScene.push(input[i]);
6834
+ }
6835
+ }
6836
+ if (objectsWithoutScene.length > 0) this.processObjects(objectsWithoutScene);
6837
+ for (let i = 0; i < this.skins.length; ++i) {
6838
+ this.processSkin(this.skins[i]);
6839
+ }
6840
+ for (let i = 0; i < options.animations.length; ++i) {
6841
+ this.processAnimation(options.animations[i], input[0]);
6842
+ }
6843
+ this._invokeAll(function(ext) {
6844
+ ext.afterParse && ext.afterParse(input);
6845
+ });
6846
+ }
6847
+ _invokeAll(func) {
6848
+ for (let i = 0, il = this.plugins.length; i < il; i++) {
6849
+ func(this.plugins[i]);
6850
+ }
6851
+ }
6852
+ };
6853
+ var GLTFLightExtension = class {
6854
+ constructor(writer) {
6855
+ this.writer = writer;
6856
+ this.name = "KHR_lights_punctual";
6857
+ }
6858
+ writeNode(light, nodeDef) {
6859
+ if (!light.isLight) return;
6860
+ if (!light.isDirectionalLight && !light.isPointLight && !light.isSpotLight) {
6861
+ console.warn("THREE.GLTFExporter: Only directional, point, and spot lights are supported.", light);
6862
+ return;
6863
+ }
6864
+ const writer = this.writer;
6865
+ const json = writer.json;
6866
+ const extensionsUsed = writer.extensionsUsed;
6867
+ const lightDef = {};
6868
+ if (light.name) lightDef.name = light.name;
6869
+ lightDef.color = light.color.toArray();
6870
+ lightDef.intensity = light.intensity;
6871
+ if (light.isDirectionalLight) {
6872
+ lightDef.type = "directional";
6873
+ } else if (light.isPointLight) {
6874
+ lightDef.type = "point";
6875
+ if (light.distance > 0) lightDef.range = light.distance;
6876
+ } else if (light.isSpotLight) {
6877
+ lightDef.type = "spot";
6878
+ if (light.distance > 0) lightDef.range = light.distance;
6879
+ lightDef.spot = {};
6880
+ lightDef.spot.innerConeAngle = (1 - light.penumbra) * light.angle;
6881
+ lightDef.spot.outerConeAngle = light.angle;
6882
+ }
6883
+ if (light.decay !== void 0 && light.decay !== 2) {
6884
+ console.warn("THREE.GLTFExporter: Light decay may be lost. glTF is physically-based, and expects light.decay=2.");
6885
+ }
6886
+ if (light.target && (light.target.parent !== light || light.target.position.x !== 0 || light.target.position.y !== 0 || light.target.position.z !== -1)) {
6887
+ console.warn("THREE.GLTFExporter: Light direction may be lost. For best results, make light.target a child of the light with position 0,0,-1.");
6888
+ }
6889
+ if (!extensionsUsed[this.name]) {
6890
+ json.extensions = json.extensions || {};
6891
+ json.extensions[this.name] = { lights: [] };
6892
+ extensionsUsed[this.name] = true;
6893
+ }
6894
+ const lights = json.extensions[this.name].lights;
6895
+ lights.push(lightDef);
6896
+ nodeDef.extensions = nodeDef.extensions || {};
6897
+ nodeDef.extensions[this.name] = { light: lights.length - 1 };
6898
+ }
6899
+ };
6900
+ var GLTFMaterialsUnlitExtension = class {
6901
+ constructor(writer) {
6902
+ this.writer = writer;
6903
+ this.name = "KHR_materials_unlit";
6904
+ }
6905
+ writeMaterial(material, materialDef) {
6906
+ if (!material.isMeshBasicMaterial) return;
6907
+ const writer = this.writer;
6908
+ const extensionsUsed = writer.extensionsUsed;
6909
+ materialDef.extensions = materialDef.extensions || {};
6910
+ materialDef.extensions[this.name] = {};
6911
+ extensionsUsed[this.name] = true;
6912
+ materialDef.pbrMetallicRoughness.metallicFactor = 0;
6913
+ materialDef.pbrMetallicRoughness.roughnessFactor = 0.9;
6914
+ }
6915
+ };
6916
+ var GLTFMaterialsClearcoatExtension = class {
6917
+ constructor(writer) {
6918
+ this.writer = writer;
6919
+ this.name = "KHR_materials_clearcoat";
6920
+ }
6921
+ writeMaterial(material, materialDef) {
6922
+ if (!material.isMeshPhysicalMaterial || material.clearcoat === 0) return;
6923
+ const writer = this.writer;
6924
+ const extensionsUsed = writer.extensionsUsed;
6925
+ const extensionDef = {};
6926
+ extensionDef.clearcoatFactor = material.clearcoat;
6927
+ if (material.clearcoatMap) {
6928
+ const clearcoatMapDef = {
6929
+ index: writer.processTexture(material.clearcoatMap),
6930
+ texCoord: material.clearcoatMap.channel
6931
+ };
6932
+ writer.applyTextureTransform(clearcoatMapDef, material.clearcoatMap);
6933
+ extensionDef.clearcoatTexture = clearcoatMapDef;
6934
+ }
6935
+ extensionDef.clearcoatRoughnessFactor = material.clearcoatRoughness;
6936
+ if (material.clearcoatRoughnessMap) {
6937
+ const clearcoatRoughnessMapDef = {
6938
+ index: writer.processTexture(material.clearcoatRoughnessMap),
6939
+ texCoord: material.clearcoatRoughnessMap.channel
6940
+ };
6941
+ writer.applyTextureTransform(clearcoatRoughnessMapDef, material.clearcoatRoughnessMap);
6942
+ extensionDef.clearcoatRoughnessTexture = clearcoatRoughnessMapDef;
6943
+ }
6944
+ if (material.clearcoatNormalMap) {
6945
+ const clearcoatNormalMapDef = {
6946
+ index: writer.processTexture(material.clearcoatNormalMap),
6947
+ texCoord: material.clearcoatNormalMap.channel
6948
+ };
6949
+ writer.applyTextureTransform(clearcoatNormalMapDef, material.clearcoatNormalMap);
6950
+ extensionDef.clearcoatNormalTexture = clearcoatNormalMapDef;
6951
+ }
6952
+ materialDef.extensions = materialDef.extensions || {};
6953
+ materialDef.extensions[this.name] = extensionDef;
6954
+ extensionsUsed[this.name] = true;
6955
+ }
6956
+ };
6957
+ var GLTFMaterialsIridescenceExtension = class {
6958
+ constructor(writer) {
6959
+ this.writer = writer;
6960
+ this.name = "KHR_materials_iridescence";
6961
+ }
6962
+ writeMaterial(material, materialDef) {
6963
+ if (!material.isMeshPhysicalMaterial || material.iridescence === 0) return;
6964
+ const writer = this.writer;
6965
+ const extensionsUsed = writer.extensionsUsed;
6966
+ const extensionDef = {};
6967
+ extensionDef.iridescenceFactor = material.iridescence;
6968
+ if (material.iridescenceMap) {
6969
+ const iridescenceMapDef = {
6970
+ index: writer.processTexture(material.iridescenceMap),
6971
+ texCoord: material.iridescenceMap.channel
6972
+ };
6973
+ writer.applyTextureTransform(iridescenceMapDef, material.iridescenceMap);
6974
+ extensionDef.iridescenceTexture = iridescenceMapDef;
6975
+ }
6976
+ extensionDef.iridescenceIor = material.iridescenceIOR;
6977
+ extensionDef.iridescenceThicknessMinimum = material.iridescenceThicknessRange[0];
6978
+ extensionDef.iridescenceThicknessMaximum = material.iridescenceThicknessRange[1];
6979
+ if (material.iridescenceThicknessMap) {
6980
+ const iridescenceThicknessMapDef = {
6981
+ index: writer.processTexture(material.iridescenceThicknessMap),
6982
+ texCoord: material.iridescenceThicknessMap.channel
6983
+ };
6984
+ writer.applyTextureTransform(iridescenceThicknessMapDef, material.iridescenceThicknessMap);
6985
+ extensionDef.iridescenceThicknessTexture = iridescenceThicknessMapDef;
6986
+ }
6987
+ materialDef.extensions = materialDef.extensions || {};
6988
+ materialDef.extensions[this.name] = extensionDef;
6989
+ extensionsUsed[this.name] = true;
6990
+ }
6991
+ };
6992
+ var GLTFMaterialsTransmissionExtension = class {
6993
+ constructor(writer) {
6994
+ this.writer = writer;
6995
+ this.name = "KHR_materials_transmission";
6996
+ }
6997
+ writeMaterial(material, materialDef) {
6998
+ if (!material.isMeshPhysicalMaterial || material.transmission === 0) return;
6999
+ const writer = this.writer;
7000
+ const extensionsUsed = writer.extensionsUsed;
7001
+ const extensionDef = {};
7002
+ extensionDef.transmissionFactor = material.transmission;
7003
+ if (material.transmissionMap) {
7004
+ const transmissionMapDef = {
7005
+ index: writer.processTexture(material.transmissionMap),
7006
+ texCoord: material.transmissionMap.channel
7007
+ };
7008
+ writer.applyTextureTransform(transmissionMapDef, material.transmissionMap);
7009
+ extensionDef.transmissionTexture = transmissionMapDef;
7010
+ }
7011
+ materialDef.extensions = materialDef.extensions || {};
7012
+ materialDef.extensions[this.name] = extensionDef;
7013
+ extensionsUsed[this.name] = true;
7014
+ }
7015
+ };
7016
+ var GLTFMaterialsVolumeExtension = class {
7017
+ constructor(writer) {
7018
+ this.writer = writer;
7019
+ this.name = "KHR_materials_volume";
7020
+ }
7021
+ writeMaterial(material, materialDef) {
7022
+ if (!material.isMeshPhysicalMaterial || material.transmission === 0) return;
7023
+ const writer = this.writer;
7024
+ const extensionsUsed = writer.extensionsUsed;
7025
+ const extensionDef = {};
7026
+ extensionDef.thicknessFactor = material.thickness;
7027
+ if (material.thicknessMap) {
7028
+ const thicknessMapDef = {
7029
+ index: writer.processTexture(material.thicknessMap),
7030
+ texCoord: material.thicknessMap.channel
7031
+ };
7032
+ writer.applyTextureTransform(thicknessMapDef, material.thicknessMap);
7033
+ extensionDef.thicknessTexture = thicknessMapDef;
7034
+ }
7035
+ extensionDef.attenuationDistance = material.attenuationDistance;
7036
+ extensionDef.attenuationColor = material.attenuationColor.toArray();
7037
+ materialDef.extensions = materialDef.extensions || {};
7038
+ materialDef.extensions[this.name] = extensionDef;
7039
+ extensionsUsed[this.name] = true;
7040
+ }
7041
+ };
7042
+ var GLTFMaterialsIorExtension = class {
7043
+ constructor(writer) {
7044
+ this.writer = writer;
7045
+ this.name = "KHR_materials_ior";
7046
+ }
7047
+ writeMaterial(material, materialDef) {
7048
+ if (!material.isMeshPhysicalMaterial || material.ior === 1.5) return;
7049
+ const writer = this.writer;
7050
+ const extensionsUsed = writer.extensionsUsed;
7051
+ const extensionDef = {};
7052
+ extensionDef.ior = material.ior;
7053
+ materialDef.extensions = materialDef.extensions || {};
7054
+ materialDef.extensions[this.name] = extensionDef;
7055
+ extensionsUsed[this.name] = true;
7056
+ }
7057
+ };
7058
+ var GLTFMaterialsSpecularExtension = class {
7059
+ constructor(writer) {
7060
+ this.writer = writer;
7061
+ this.name = "KHR_materials_specular";
7062
+ }
7063
+ writeMaterial(material, materialDef) {
7064
+ if (!material.isMeshPhysicalMaterial || material.specularIntensity === 1 && material.specularColor.equals(DEFAULT_SPECULAR_COLOR) && !material.specularIntensityMap && !material.specularColorTexture) return;
7065
+ const writer = this.writer;
7066
+ const extensionsUsed = writer.extensionsUsed;
7067
+ const extensionDef = {};
7068
+ if (material.specularIntensityMap) {
7069
+ const specularIntensityMapDef = {
7070
+ index: writer.processTexture(material.specularIntensityMap),
7071
+ texCoord: material.specularIntensityMap.channel
7072
+ };
7073
+ writer.applyTextureTransform(specularIntensityMapDef, material.specularIntensityMap);
7074
+ extensionDef.specularTexture = specularIntensityMapDef;
7075
+ }
7076
+ if (material.specularColorMap) {
7077
+ const specularColorMapDef = {
7078
+ index: writer.processTexture(material.specularColorMap),
7079
+ texCoord: material.specularColorMap.channel
7080
+ };
7081
+ writer.applyTextureTransform(specularColorMapDef, material.specularColorMap);
7082
+ extensionDef.specularColorTexture = specularColorMapDef;
7083
+ }
7084
+ extensionDef.specularFactor = material.specularIntensity;
7085
+ extensionDef.specularColorFactor = material.specularColor.toArray();
7086
+ materialDef.extensions = materialDef.extensions || {};
7087
+ materialDef.extensions[this.name] = extensionDef;
7088
+ extensionsUsed[this.name] = true;
7089
+ }
7090
+ };
7091
+ var GLTFMaterialsSheenExtension = class {
7092
+ constructor(writer) {
7093
+ this.writer = writer;
7094
+ this.name = "KHR_materials_sheen";
7095
+ }
7096
+ writeMaterial(material, materialDef) {
7097
+ if (!material.isMeshPhysicalMaterial || material.sheen == 0) return;
7098
+ const writer = this.writer;
7099
+ const extensionsUsed = writer.extensionsUsed;
7100
+ const extensionDef = {};
7101
+ if (material.sheenRoughnessMap) {
7102
+ const sheenRoughnessMapDef = {
7103
+ index: writer.processTexture(material.sheenRoughnessMap),
7104
+ texCoord: material.sheenRoughnessMap.channel
7105
+ };
7106
+ writer.applyTextureTransform(sheenRoughnessMapDef, material.sheenRoughnessMap);
7107
+ extensionDef.sheenRoughnessTexture = sheenRoughnessMapDef;
7108
+ }
7109
+ if (material.sheenColorMap) {
7110
+ const sheenColorMapDef = {
7111
+ index: writer.processTexture(material.sheenColorMap),
7112
+ texCoord: material.sheenColorMap.channel
7113
+ };
7114
+ writer.applyTextureTransform(sheenColorMapDef, material.sheenColorMap);
7115
+ extensionDef.sheenColorTexture = sheenColorMapDef;
7116
+ }
7117
+ extensionDef.sheenRoughnessFactor = material.sheenRoughness;
7118
+ extensionDef.sheenColorFactor = material.sheenColor.toArray();
7119
+ materialDef.extensions = materialDef.extensions || {};
7120
+ materialDef.extensions[this.name] = extensionDef;
7121
+ extensionsUsed[this.name] = true;
7122
+ }
7123
+ };
7124
+ var GLTFMaterialsAnisotropyExtension = class {
7125
+ constructor(writer) {
7126
+ this.writer = writer;
7127
+ this.name = "KHR_materials_anisotropy";
7128
+ }
7129
+ writeMaterial(material, materialDef) {
7130
+ if (!material.isMeshPhysicalMaterial || material.anisotropy == 0) return;
7131
+ const writer = this.writer;
7132
+ const extensionsUsed = writer.extensionsUsed;
7133
+ const extensionDef = {};
7134
+ if (material.anisotropyMap) {
7135
+ const anisotropyMapDef = { index: writer.processTexture(material.anisotropyMap) };
7136
+ writer.applyTextureTransform(anisotropyMapDef, material.anisotropyMap);
7137
+ extensionDef.anisotropyTexture = anisotropyMapDef;
7138
+ }
7139
+ extensionDef.anisotropyStrength = material.anisotropy;
7140
+ extensionDef.anisotropyRotation = material.anisotropyRotation;
7141
+ materialDef.extensions = materialDef.extensions || {};
7142
+ materialDef.extensions[this.name] = extensionDef;
7143
+ extensionsUsed[this.name] = true;
7144
+ }
7145
+ };
7146
+ var GLTFMaterialsEmissiveStrengthExtension = class {
7147
+ constructor(writer) {
7148
+ this.writer = writer;
7149
+ this.name = "KHR_materials_emissive_strength";
7150
+ }
7151
+ writeMaterial(material, materialDef) {
7152
+ if (!material.isMeshStandardMaterial || material.emissiveIntensity === 1) return;
7153
+ const writer = this.writer;
7154
+ const extensionsUsed = writer.extensionsUsed;
7155
+ const extensionDef = {};
7156
+ extensionDef.emissiveStrength = material.emissiveIntensity;
7157
+ materialDef.extensions = materialDef.extensions || {};
7158
+ materialDef.extensions[this.name] = extensionDef;
7159
+ extensionsUsed[this.name] = true;
7160
+ }
7161
+ };
7162
+ var GLTFMeshGpuInstancing = class {
7163
+ constructor(writer) {
7164
+ this.writer = writer;
7165
+ this.name = "EXT_mesh_gpu_instancing";
7166
+ }
7167
+ writeNode(object, nodeDef) {
7168
+ if (!object.isInstancedMesh) return;
7169
+ const writer = this.writer;
7170
+ const mesh = object;
7171
+ const translationAttr = new Float32Array(mesh.count * 3);
7172
+ const rotationAttr = new Float32Array(mesh.count * 4);
7173
+ const scaleAttr = new Float32Array(mesh.count * 3);
7174
+ const matrix = new Matrix44();
7175
+ const position = new Vector38();
7176
+ const quaternion = new Quaternion4();
7177
+ const scale = new Vector38();
7178
+ for (let i = 0; i < mesh.count; i++) {
7179
+ mesh.getMatrixAt(i, matrix);
7180
+ matrix.decompose(position, quaternion, scale);
7181
+ position.toArray(translationAttr, i * 3);
7182
+ quaternion.toArray(rotationAttr, i * 4);
7183
+ scale.toArray(scaleAttr, i * 3);
7184
+ }
7185
+ const attributes = {
7186
+ TRANSLATION: writer.processAccessor(new BufferAttribute3(translationAttr, 3)),
7187
+ ROTATION: writer.processAccessor(new BufferAttribute3(rotationAttr, 4)),
7188
+ SCALE: writer.processAccessor(new BufferAttribute3(scaleAttr, 3))
7189
+ };
7190
+ if (mesh.instanceColor)
7191
+ attributes._COLOR_0 = writer.processAccessor(mesh.instanceColor);
7192
+ nodeDef.extensions = nodeDef.extensions || {};
7193
+ nodeDef.extensions[this.name] = { attributes };
7194
+ writer.extensionsUsed[this.name] = true;
7195
+ writer.extensionsRequired[this.name] = true;
7196
+ }
7197
+ };
7198
+ GLTFExporter.Utils = {
7199
+ insertKeyframe: function(track, time) {
7200
+ const tolerance = 1e-3;
7201
+ const valueSize = track.getValueSize();
7202
+ const times = new track.TimeBufferType(track.times.length + 1);
7203
+ const values = new track.ValueBufferType(track.values.length + valueSize);
7204
+ const interpolant = track.createInterpolant(new track.ValueBufferType(valueSize));
7205
+ let index;
7206
+ if (track.times.length === 0) {
7207
+ times[0] = time;
7208
+ for (let i = 0; i < valueSize; i++) {
7209
+ values[i] = 0;
7210
+ }
7211
+ index = 0;
7212
+ } else if (time < track.times[0]) {
7213
+ if (Math.abs(track.times[0] - time) < tolerance) return 0;
7214
+ times[0] = time;
7215
+ times.set(track.times, 1);
7216
+ values.set(interpolant.evaluate(time), 0);
7217
+ values.set(track.values, valueSize);
7218
+ index = 0;
7219
+ } else if (time > track.times[track.times.length - 1]) {
7220
+ if (Math.abs(track.times[track.times.length - 1] - time) < tolerance) {
7221
+ return track.times.length - 1;
7222
+ }
7223
+ times[times.length - 1] = time;
7224
+ times.set(track.times, 0);
7225
+ values.set(track.values, 0);
7226
+ values.set(interpolant.evaluate(time), track.values.length);
7227
+ index = times.length - 1;
7228
+ } else {
7229
+ for (let i = 0; i < track.times.length; i++) {
7230
+ if (Math.abs(track.times[i] - time) < tolerance) return i;
7231
+ if (track.times[i] < time && track.times[i + 1] > time) {
7232
+ times.set(track.times.slice(0, i + 1), 0);
7233
+ times[i + 1] = time;
7234
+ times.set(track.times.slice(i + 1), i + 2);
7235
+ values.set(track.values.slice(0, (i + 1) * valueSize), 0);
7236
+ values.set(interpolant.evaluate(time), (i + 1) * valueSize);
7237
+ values.set(track.values.slice((i + 1) * valueSize), (i + 2) * valueSize);
7238
+ index = i + 1;
7239
+ break;
7240
+ }
7241
+ }
7242
+ }
7243
+ track.times = times;
7244
+ track.values = values;
7245
+ return index;
7246
+ },
7247
+ mergeMorphTargetTracks: function(clip, root) {
7248
+ const tracks = [];
7249
+ const mergedTracks = {};
7250
+ const sourceTracks = clip.tracks;
7251
+ for (let i = 0; i < sourceTracks.length; ++i) {
7252
+ let sourceTrack = sourceTracks[i];
7253
+ const sourceTrackBinding = PropertyBinding.parseTrackName(sourceTrack.name);
7254
+ const sourceTrackNode = PropertyBinding.findNode(root, sourceTrackBinding.nodeName);
7255
+ if (sourceTrackBinding.propertyName !== "morphTargetInfluences" || sourceTrackBinding.propertyIndex === void 0) {
7256
+ tracks.push(sourceTrack);
7257
+ continue;
7258
+ }
7259
+ if (sourceTrack.createInterpolant !== sourceTrack.InterpolantFactoryMethodDiscrete && sourceTrack.createInterpolant !== sourceTrack.InterpolantFactoryMethodLinear) {
7260
+ if (sourceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline) {
7261
+ throw new Error("THREE.GLTFExporter: Cannot merge tracks with glTF CUBICSPLINE interpolation.");
7262
+ }
7263
+ console.warn("THREE.GLTFExporter: Morph target interpolation mode not yet supported. Using LINEAR instead.");
7264
+ sourceTrack = sourceTrack.clone();
7265
+ sourceTrack.setInterpolation(InterpolateLinear);
7266
+ }
7267
+ const targetCount = sourceTrackNode.morphTargetInfluences.length;
7268
+ const targetIndex = sourceTrackNode.morphTargetDictionary[sourceTrackBinding.propertyIndex];
7269
+ if (targetIndex === void 0) {
7270
+ throw new Error("THREE.GLTFExporter: Morph target name not found: " + sourceTrackBinding.propertyIndex);
7271
+ }
7272
+ let mergedTrack;
7273
+ if (mergedTracks[sourceTrackNode.uuid] === void 0) {
7274
+ mergedTrack = sourceTrack.clone();
7275
+ const values = new mergedTrack.ValueBufferType(targetCount * mergedTrack.times.length);
7276
+ for (let j = 0; j < mergedTrack.times.length; j++) {
7277
+ values[j * targetCount + targetIndex] = mergedTrack.values[j];
7278
+ }
7279
+ mergedTrack.name = (sourceTrackBinding.nodeName || "") + ".morphTargetInfluences";
7280
+ mergedTrack.values = values;
7281
+ mergedTracks[sourceTrackNode.uuid] = mergedTrack;
7282
+ tracks.push(mergedTrack);
7283
+ continue;
7284
+ }
7285
+ const sourceInterpolant = sourceTrack.createInterpolant(new sourceTrack.ValueBufferType(1));
7286
+ mergedTrack = mergedTracks[sourceTrackNode.uuid];
7287
+ for (let j = 0; j < mergedTrack.times.length; j++) {
7288
+ mergedTrack.values[j * targetCount + targetIndex] = sourceInterpolant.evaluate(mergedTrack.times[j]);
7289
+ }
7290
+ for (let j = 0; j < sourceTrack.times.length; j++) {
7291
+ const keyframeIndex = this.insertKeyframe(mergedTrack, sourceTrack.times[j]);
7292
+ mergedTrack.values[keyframeIndex * targetCount + targetIndex] = sourceTrack.values[j];
7293
+ }
7294
+ }
7295
+ clip.tracks = tracks;
7296
+ return clip;
7297
+ }
7298
+ };
7299
+
7300
+ // src/export/SceneExporter.ts
7301
+ init_MineRenderError();
7302
+ init_DisplayTransforms();
7303
+ init_CanvasCompat();
7304
+ var SceneExporter = class {
7305
+ /** Returns OBJ geometry with normals and UVs; material files and textures are not included. */
7306
+ static toObj(root) {
7307
+ const snapshot = createSnapshot(root, false);
7308
+ try {
7309
+ return new OBJExporter().parse(snapshot.scene);
7310
+ } finally {
7311
+ snapshot.dispose();
7312
+ }
7313
+ }
7314
+ /** Returns PLY geometry with vertex colors and UVs; texture images are not included. */
7315
+ static toPLY(root, options) {
7316
+ const snapshot = createSnapshot(root, false, true);
7317
+ try {
7318
+ const result = new PLYExporter().parse(snapshot.scene, void 0, options);
7319
+ if (result === null) throw new MineRenderError("The scene could not be exported as PLY");
7320
+ return result;
7321
+ } finally {
7322
+ snapshot.dispose();
7323
+ }
7324
+ }
7325
+ /**
7326
+ * Exports a static glTF/GLB snapshot in a browser. Atlas textures and vertex tints are retained;
7327
+ * MineRender's custom directional lighting is not baked into the exported materials.
7328
+ */
7329
+ static async toGLTF(root, options = {}) {
7330
+ if (typeof document === "undefined" || typeof FileReader === "undefined") {
7331
+ throw new MineRenderError("glTF export requires a browser with canvas and FileReader support");
7332
+ }
7333
+ if (options.maxTextureSize !== void 0 && !(options.maxTextureSize >= 1)) {
7334
+ throw new MineRenderError("maxTextureSize must be at least 1 pixel");
7335
+ }
7336
+ const snapshot = createSnapshot(root, true);
7337
+ try {
7338
+ return await new GLTFExporter().parseAsync(snapshot.scene, {
7339
+ binary: options.binary ?? false,
7340
+ maxTextureSize: options.maxTextureSize ?? Infinity
7341
+ });
7342
+ } finally {
7343
+ snapshot.dispose();
7344
+ }
7345
+ }
7346
+ };
7347
+ function localMatrix(object) {
7348
+ return object.matrixAutoUpdate ? new Matrix45().compose(object.position, object.quaternion, object.scale) : object.matrix.clone();
7349
+ }
7350
+ function createSnapshot(root, gltf, bakeColors = false) {
7351
+ const scene = new Scene4();
7352
+ const geometries = [];
7353
+ const materials = [];
7354
+ const textures = [];
7355
+ const textureCopies = /* @__PURE__ */ new Map();
7356
+ const dispose = () => {
7357
+ for (const geometry of geometries) geometry.dispose();
7358
+ for (const material of materials) material.dispose();
7359
+ for (const texture of textures) texture.dispose();
7360
+ };
7361
+ const copyMaterial = (source, geometry) => {
7362
+ let material;
7363
+ const shader = source;
7364
+ if (shader.isShaderMaterial && gltf) {
7365
+ const uniforms = shader.uniforms;
7366
+ if (!uniforms.map?.value?.isTexture || !uniforms.SHADE || !uniforms.BRIGHTNESS || !uniforms.EMISSIVE) {
7367
+ throw new MineRenderError("glTF export does not support this custom ShaderMaterial");
7368
+ }
7369
+ material = new MeshBasicMaterial2({
7370
+ map: uniforms.map.value,
7371
+ vertexColors: source.vertexColors,
7372
+ transparent: source.transparent,
7373
+ side: source.side,
7374
+ alphaTest: 0.01,
7375
+ depthWrite: source.depthWrite
7376
+ });
7377
+ material.name = source.name;
7378
+ } else if (shader.isShaderMaterial) {
7379
+ material = new MeshBasicMaterial2({ vertexColors: source.vertexColors });
7380
+ material.name = source.name;
7381
+ } else {
7382
+ const copySource = Object.create(source);
7383
+ copySource.userData = {};
7384
+ material = source.clone.call(copySource);
7385
+ }
7386
+ materials.push(material);
7387
+ if (gltf) {
7388
+ selectAlphaMode(material, geometry);
7389
+ for (const [key, value] of Object.entries(material)) {
7390
+ if (value?.isDataTexture) {
7391
+ let texture = textureCopies.get(value);
7392
+ if (!texture) {
7393
+ texture = copyDataTexture(value);
7394
+ textureCopies.set(value, texture);
7395
+ textures.push(texture);
7396
+ }
7397
+ material[key] = texture;
7398
+ }
7399
+ }
7400
+ }
7401
+ return material;
7402
+ };
7403
+ const addMesh = (mesh, world, instanceColor) => {
7404
+ if (world.determinant() === 0 || !mesh.geometry.getAttribute("position")) return;
7405
+ const source = mesh.geometry;
7406
+ const count = source.index?.count ?? source.getAttribute("position").count;
7407
+ const groups = Array.isArray(mesh.material) ? source.groups : [{ start: 0, count, materialIndex: 0 }];
7408
+ for (const group of groups) {
7409
+ const sourceMaterial = Array.isArray(mesh.material) ? mesh.material[group.materialIndex ?? 0] : mesh.material;
7410
+ if (!sourceMaterial?.visible) continue;
7411
+ const start = Math.max(group.start, source.drawRange.start);
7412
+ const end = Math.min(count, group.start + group.count, source.drawRange.start + source.drawRange.count);
7413
+ const indices = [];
7414
+ for (let i = start; i + 2 < end; i += 3) {
7415
+ for (let corner = 0; corner < 3; corner++) indices.push(source.index?.getX(i + corner) ?? i + corner);
7416
+ }
7417
+ if (!indices.length) continue;
7418
+ let geometry = source.clone();
7419
+ geometry.setIndex(indices);
7420
+ if (new Set(indices).size < geometry.getAttribute("position").count) {
7421
+ const compact = geometry.toNonIndexed();
7422
+ geometry.dispose();
7423
+ geometry = compact;
7424
+ }
7425
+ geometries.push(geometry);
7426
+ geometry.userData = {};
7427
+ geometry.clearGroups();
7428
+ geometry.setDrawRange(0, Infinity);
7429
+ DisplayTransforms.apply(geometry, world);
7430
+ const material = copyMaterial(sourceMaterial, geometry);
7431
+ if (!sourceMaterial.vertexColors) geometry.deleteAttribute("color");
7432
+ if (bakeColors || instanceColor) {
7433
+ const tint = (material.color ?? new Color6()).clone();
7434
+ if (instanceColor) tint.multiply(instanceColor);
7435
+ if (bakeColors) {
7436
+ const original = geometry.getAttribute("color");
7437
+ const colors = new Float32BufferAttribute3(new Float32Array(geometry.getAttribute("position").count * 3), 3);
7438
+ for (let i = 0; i < colors.count; i++) {
7439
+ colors.setXYZ(i, (original?.getX(i) ?? 1) * tint.r, (original?.getY(i) ?? 1) * tint.g, (original?.getZ(i) ?? 1) * tint.b);
7440
+ }
7441
+ geometry.setAttribute("color", colors);
7442
+ } else if (material.color) {
7443
+ material.color.copy(tint);
7444
+ }
7445
+ }
7446
+ const copy = new Mesh5(geometry, material);
7447
+ copy.name = mesh.name;
7448
+ copy.renderOrder = mesh.renderOrder;
7449
+ scene.add(copy);
7450
+ }
7451
+ };
7452
+ const visit = (object, parentWorld) => {
7453
+ if (!object.visible) return;
7454
+ const world = parentWorld.clone().multiply(localMatrix(object));
7455
+ const mesh = object;
7456
+ if (mesh.isMesh) {
7457
+ const instanced = mesh;
7458
+ if (instanced.isInstancedMesh) {
7459
+ for (let i = 0; i < instanced.count; i++) {
7460
+ const matrix = new Matrix45();
7461
+ instanced.getMatrixAt(i, matrix);
7462
+ const color = instanced.instanceColor ? new Color6().fromBufferAttribute(instanced.instanceColor, i) : void 0;
7463
+ addMesh(mesh, world.clone().multiply(matrix), color);
7464
+ }
7465
+ } else {
7466
+ addMesh(mesh, world);
7467
+ }
7468
+ }
7469
+ for (const child of object.children) visit(child, world);
7470
+ };
7471
+ try {
7472
+ const ancestors = [];
7473
+ for (let parent = root.parent; parent; parent = parent.parent) ancestors.unshift(parent);
7474
+ const world = new Matrix45();
7475
+ for (const ancestor of ancestors) {
7476
+ if (!ancestor.visible) return { scene, dispose };
7477
+ world.multiply(localMatrix(ancestor));
7478
+ }
7479
+ visit(root, world);
7480
+ return { scene, dispose };
7481
+ } catch (error) {
7482
+ dispose();
7483
+ throw error;
7484
+ }
7485
+ }
7486
+ function selectAlphaMode(material, geometry) {
7487
+ const texture = material.map;
7488
+ if (material.type !== "MeshBasicMaterial" || !material.transparent || !material.depthWrite || material.opacity !== 1 || material.alphaMap || !texture?.isDataTexture || texture.format !== RGBAFormat3 || texture.type !== UnsignedByteType || texture.wrapS !== ClampToEdgeWrapping2 || texture.wrapT !== ClampToEdgeWrapping2 || texture.magFilter !== NearestFilter3 || texture.minFilter !== NearestFilter3 || texture.anisotropy > 1 || texture.offset.x !== 0 || texture.offset.y !== 0 || texture.repeat.x !== 1 || texture.repeat.y !== 1 || texture.rotation !== 0 || !texture.matrixAutoUpdate && !texture.matrix.elements.every((value, i) => value === (i % 4 === 0 ? 1 : 0))) return;
7489
+ const uv = geometry.getAttribute(texture.channel === 0 ? "uv" : `uv${texture.channel}`);
7490
+ const colors = geometry.getAttribute("color");
7491
+ if (!uv || material.vertexColors && colors?.itemSize === 4) return;
7492
+ const { data, width, height } = texture.image;
7493
+ if (!data || width < 1 || height < 1 || data.length < width * height * 4) return;
7494
+ const count = geometry.index?.count ?? uv.count;
7495
+ let holes = false;
7496
+ for (let i = 0; i + 2 < count; i += 3) {
7497
+ let minU = Infinity, maxU = -Infinity, minV = Infinity, maxV = -Infinity;
7498
+ for (let corner = 0; corner < 3; corner++) {
7499
+ const index = geometry.index?.getX(i + corner) ?? i + corner;
7500
+ const u = uv.getX(index), v = texture.flipY ? 1 - uv.getY(index) : uv.getY(index);
7501
+ if (!Number.isFinite(u) || !Number.isFinite(v)) return;
7502
+ minU = Math.min(minU, u);
7503
+ maxU = Math.max(maxU, u);
7504
+ minV = Math.min(minV, v);
7505
+ maxV = Math.max(maxV, v);
7506
+ }
7507
+ const minX = Math.max(0, Math.min(width - 1, Math.floor(minU * width)));
7508
+ const maxX = Math.max(minX, Math.min(width - 1, Math.ceil(maxU * width) - 1));
7509
+ const minY = Math.max(0, Math.min(height - 1, Math.floor(minV * height)));
7510
+ const maxY = Math.max(minY, Math.min(height - 1, Math.ceil(maxV * height) - 1));
7511
+ for (let y = minY; y <= maxY; y++) {
7512
+ for (let x = minX; x <= maxX; x++) {
7513
+ const alpha = data[(y * width + x) * 4 + 3];
7514
+ if (alpha === 255) continue;
7515
+ if (alpha !== 0 && alpha / 255 >= material.alphaTest) return;
7516
+ holes = true;
7517
+ }
7518
+ }
7519
+ }
7520
+ material.transparent = false;
7521
+ if (holes && material.alphaTest === 0) material.alphaTest = 1 / 255;
7522
+ }
7523
+ function copyDataTexture(source) {
7524
+ const image = source.image;
7525
+ if (source.format !== RGBAFormat3 || source.type !== UnsignedByteType) {
7526
+ throw new MineRenderError("glTF export requires RGBA unsigned-byte data textures");
7527
+ }
7528
+ const canvas = createCanvas2(image.width, image.height);
7529
+ const context = canvas.getContext("2d");
7530
+ if (!context) throw new MineRenderError("glTF export could not create a 2D canvas context");
7531
+ const pixels = context.createImageData(image.width, image.height);
7532
+ pixels.data.set(image.data);
7533
+ context.putImageData(pixels, 0, 0);
7534
+ const copySource = Object.create(source);
7535
+ copySource.userData = {};
7536
+ copySource.source = new Source2(canvas);
7537
+ return new Texture4().copy(copySource);
7538
+ }
7539
+
4960
7540
  // src/gui/GuiHelper.ts
4961
7541
  var GuiHelper = class {
4962
7542
  static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
@@ -4971,7 +7551,7 @@ init_ModelTextures();
4971
7551
  init_Caching();
4972
7552
  init_SceneObject();
4973
7553
  init_Materials();
4974
- import { Box2, Mesh as Mesh4, PlaneGeometry, Vector2 as Vector22 } from "three";
7554
+ import { Box2, Mesh as Mesh6, PlaneGeometry as PlaneGeometry2, Vector2 as Vector23 } from "three";
4975
7555
  var GuiObject = class extends SceneObject {
4976
7556
  constructor(textureLayers, options) {
4977
7557
  super({ ...options, instanceMeshes: false, mergeMeshes: false });
@@ -4993,7 +7573,7 @@ var GuiObject = class extends SceneObject {
4993
7573
  const [cropX, cropY, cropWidth, cropHeight] = layer.crop ?? [0, 0, image.width, image.height];
4994
7574
  const [width, height] = layer.size ?? [cropWidth, cropHeight];
4995
7575
  const [x, y] = layer.position ?? [0, 0];
4996
- const geometry = new PlaneGeometry(width, height);
7576
+ const geometry = new PlaneGeometry2(width, height);
4997
7577
  this.geometries.add(geometry);
4998
7578
  const uv = geometry.getAttribute("uv");
4999
7579
  for (let i = 0; i < uv.count; i++) {
@@ -5003,13 +7583,13 @@ var GuiObject = class extends SceneObject {
5003
7583
  1 - (cropY + (1 - uv.getY(i)) * cropHeight) / image.height
5004
7584
  );
5005
7585
  }
5006
- const mesh = new Mesh4(geometry, material);
7586
+ const mesh = new Mesh6(geometry, material);
5007
7587
  mesh.name = `mesh:${layer.name ?? index}`;
5008
7588
  mesh.position.set(x + width / 2, -y - height / 2, 0);
5009
7589
  mesh.renderOrder = index;
5010
7590
  this.add(mesh);
5011
- this.bounds.expandByPoint(new Vector22(x, y));
5012
- this.bounds.expandByPoint(new Vector22(x + width, y + height));
7591
+ this.bounds.expandByPoint(new Vector23(x, y));
7592
+ this.bounds.expandByPoint(new Vector23(x + width, y + height));
5013
7593
  }
5014
7594
  this.initialized = true;
5015
7595
  this.notifyDirty();
@@ -5058,7 +7638,7 @@ init_image();
5058
7638
  // src/inspector/SceneInspector.ts
5059
7639
  init_SceneObject();
5060
7640
  init_util();
5061
- import { Raycaster, Vector2 as Vector23 } from "three";
7641
+ import { Raycaster, Vector2 as Vector24 } from "three";
5062
7642
  init_log();
5063
7643
  init_three();
5064
7644
  var p7 = prefix("SceneInspector");
@@ -5066,7 +7646,7 @@ var help = "<span>Ctrl/Cmd+Click to Select<br/></span><br/>";
5066
7646
  var SceneInspector = class {
5067
7647
  constructor(renderer) {
5068
7648
  this.renderer = renderer;
5069
- this.mouse = new Vector23();
7649
+ this.mouse = new Vector24();
5070
7650
  this.listeners = new AbortController();
5071
7651
  this.objectInfoContainer = document.createElement("div");
5072
7652
  this.objectControlsContainer = document.createElement("div");
@@ -5674,7 +8254,7 @@ var import_ts_deepmerge6 = __toESM(require_dist());
5674
8254
  init_MineRenderError();
5675
8255
  init_InstanceReference();
5676
8256
  init_AssetKey();
5677
- import { Euler as Euler7, Matrix4 as Matrix45, Quaternion as Quaternion4, Vector3 as Vector38 } from "three";
8257
+ import { Euler as Euler7, Matrix4 as Matrix47, Quaternion as Quaternion5, Vector3 as Vector311 } from "three";
5678
8258
  init_ModelCulling();
5679
8259
  init_FluidGeometry();
5680
8260
  var BlockObject = class _BlockObject extends SceneObject {
@@ -5740,11 +8320,11 @@ var BlockObject = class _BlockObject extends SceneObject {
5740
8320
  getModelCullMask(model, worldMask) {
5741
8321
  const object = isInstanceReference(model) ? model.instanceable : model;
5742
8322
  if (object.options.displayPosition) return 0;
5743
- const position = new Vector38();
5744
- const rotation = new Quaternion4();
5745
- const scale = new Vector38();
8323
+ const position = new Vector311();
8324
+ const rotation = new Quaternion5();
8325
+ const scale = new Vector311();
5746
8326
  this.getModelMatrix(model).decompose(position, rotation, scale);
5747
- if (position.distanceToSquared(this.position) > 1e-10 || scale.distanceToSquared(new Vector38(1, 1, 1)) > 1e-10) return 0;
8327
+ if (position.distanceToSquared(this.position) > 1e-10 || scale.distanceToSquared(new Vector311(1, 1, 1)) > 1e-10) return 0;
5748
8328
  return ModelCulling.toLocalMask(worldMask, new Euler7().setFromQuaternion(rotation));
5749
8329
  }
5750
8330
  async setCullMask(worldMask) {
@@ -5807,7 +8387,7 @@ var BlockObject = class _BlockObject extends SceneObject {
5807
8387
  () => new FluidModelObject2(kind, surface.sample, this.blockState.key, this.options)
5808
8388
  );
5809
8389
  const previous = this._fluidModel;
5810
- const matrix = previous ? this.getModelMatrix(previous) : new Matrix45().makeTranslation(...this.position.toArray());
8390
+ const matrix = previous ? this.getModelMatrix(previous) : new Matrix47().makeTranslation(...this.position.toArray());
5811
8391
  if (isInstanceReference(replacement)) replacement.setMatrix(matrix);
5812
8392
  else matrix.decompose(replacement.position, replacement.quaternion, replacement.scale);
5813
8393
  this._models = this._models.filter((model) => model !== previous);
@@ -5938,7 +8518,7 @@ var BlockObject = class _BlockObject extends SceneObject {
5938
8518
  setPositionRotationScaleAt(index, position, rotation, scale) {
5939
8519
  super.setPositionRotationScaleAt(index, position, rotation, scale);
5940
8520
  }
5941
- getMatrixAt(index, matrix = new Matrix45()) {
8521
+ getMatrixAt(index, matrix = new Matrix47()) {
5942
8522
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
5943
8523
  const child = this._models[0];
5944
8524
  if (child && isModelObject(child)) {
@@ -7807,7 +10387,7 @@ init_nbt();
7807
10387
  init_SceneObject();
7808
10388
  var import_ts_deepmerge8 = __toESM(require_dist());
7809
10389
  init_ModelObject();
7810
- import { Scene as Scene2 } from "three";
10390
+ import { Scene as Scene5 } from "three";
7811
10391
 
7812
10392
  // src/skin/scene/SkinObject.ts
7813
10393
  init_SceneObject();
@@ -8540,7 +11120,7 @@ init_util();
8540
11120
  init_Caching();
8541
11121
  init_CacheKey();
8542
11122
  init_MineRenderError();
8543
- import { DataTexture, DoubleSide as DoubleSide3, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial4, SRGBColorSpace as SRGBColorSpace3 } from "three";
11123
+ import { DataTexture as DataTexture2, DoubleSide as DoubleSide4, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial5, SRGBColorSpace as SRGBColorSpace5 } from "three";
8544
11124
 
8545
11125
  // src/skin/SkinImage.ts
8546
11126
  init_Caching();
@@ -8621,11 +11201,11 @@ var SkinTextures = class {
8621
11201
  });
8622
11202
  }
8623
11203
  static createMaterial(pixels, width, height, transparent = true) {
8624
- const texture = Textures.initTextureProps(new DataTexture(pixels, width, height));
8625
- texture.colorSpace = SRGBColorSpace3;
11204
+ const texture = Textures.initTextureProps(new DataTexture2(pixels, width, height));
11205
+ texture.colorSpace = SRGBColorSpace5;
8626
11206
  texture.flipY = true;
8627
11207
  texture.needsUpdate = true;
8628
- return new MeshBasicMaterial4({ map: texture, transparent, side: transparent ? DoubleSide3 : FrontSide2, alphaTest: transparent ? 0.1 : 0 });
11208
+ return new MeshBasicMaterial5({ map: texture, transparent, side: transparent ? DoubleSide4 : FrontSide2, alphaTest: transparent ? 0.1 : 0 });
8629
11209
  }
8630
11210
  static isSlim(image, scale) {
8631
11211
  for (const [x, y] of [[46, 52], [54, 20]]) {
@@ -8852,7 +11432,7 @@ var SkinObject = class extends SceneObject {
8852
11432
  };
8853
11433
 
8854
11434
  // src/renderer/MineRenderScene.ts
8855
- var MineRenderScene = class _MineRenderScene extends Scene2 {
11435
+ var MineRenderScene = class _MineRenderScene extends Scene5 {
8856
11436
  constructor(options) {
8857
11437
  super();
8858
11438
  this.isMineRenderScene = true;
@@ -8985,7 +11565,7 @@ function isMineRenderScene(obj) {
8985
11565
  }
8986
11566
 
8987
11567
  // src/renderer/Renderer.ts
8988
- import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace4, Vector3 as Vector310, WebGLRenderer } from "three";
11568
+ import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera as PerspectiveCamera2, SRGBColorSpace as SRGBColorSpace6, Vector3 as Vector313, WebGLRenderer as WebGLRenderer2 } from "three";
8989
11569
  var import_ts_deepmerge9 = __toESM(require_dist());
8990
11570
  init_util();
8991
11571
  import Stats from "stats.js";
@@ -8996,11 +11576,11 @@ init_three();
8996
11576
  import {
8997
11577
  EventDispatcher,
8998
11578
  MOUSE,
8999
- Quaternion as Quaternion5,
11579
+ Quaternion as Quaternion6,
9000
11580
  Spherical,
9001
11581
  TOUCH,
9002
- Vector2 as Vector24,
9003
- Vector3 as Vector39
11582
+ Vector2 as Vector25,
11583
+ Vector3 as Vector312
9004
11584
  } from "three";
9005
11585
  var _changeEvent = { type: "change" };
9006
11586
  var _startEvent = { type: "start" };
@@ -9014,7 +11594,7 @@ var OrbitControls = class extends EventDispatcher {
9014
11594
  this.domElement = domElement;
9015
11595
  this.domElement.style.touchAction = "none";
9016
11596
  this.enabled = true;
9017
- this.target = new Vector39();
11597
+ this.target = new Vector312();
9018
11598
  this.minDistance = 0;
9019
11599
  this.maxDistance = Infinity;
9020
11600
  this.minZoom = 0;
@@ -9066,11 +11646,11 @@ var OrbitControls = class extends EventDispatcher {
9066
11646
  state = STATE.NONE;
9067
11647
  };
9068
11648
  this.update = function() {
9069
- const offset = new Vector39();
9070
- const quat = new Quaternion5().setFromUnitVectors(object.up, new Vector39(0, 1, 0));
11649
+ const offset = new Vector312();
11650
+ const quat = new Quaternion6().setFromUnitVectors(object.up, new Vector312(0, 1, 0));
9071
11651
  const quatInverse = quat.clone().invert();
9072
- const lastPosition = new Vector39();
9073
- const lastQuaternion = new Quaternion5();
11652
+ const lastPosition = new Vector312();
11653
+ const lastQuaternion = new Quaternion6();
9074
11654
  const twoPI = 2 * Math.PI;
9075
11655
  return function update() {
9076
11656
  const position = scope.object.position;
@@ -9159,17 +11739,17 @@ var OrbitControls = class extends EventDispatcher {
9159
11739
  const spherical = new Spherical();
9160
11740
  const sphericalDelta = new Spherical();
9161
11741
  let scale = 1;
9162
- const panOffset = new Vector39();
11742
+ const panOffset = new Vector312();
9163
11743
  let zoomChanged = false;
9164
- const rotateStart = new Vector24();
9165
- const rotateEnd = new Vector24();
9166
- const rotateDelta = new Vector24();
9167
- const panStart = new Vector24();
9168
- const panEnd = new Vector24();
9169
- const panDelta = new Vector24();
9170
- const dollyStart = new Vector24();
9171
- const dollyEnd = new Vector24();
9172
- const dollyDelta = new Vector24();
11744
+ const rotateStart = new Vector25();
11745
+ const rotateEnd = new Vector25();
11746
+ const rotateDelta = new Vector25();
11747
+ const panStart = new Vector25();
11748
+ const panEnd = new Vector25();
11749
+ const panDelta = new Vector25();
11750
+ const dollyStart = new Vector25();
11751
+ const dollyEnd = new Vector25();
11752
+ const dollyDelta = new Vector25();
9173
11753
  const pointers = [];
9174
11754
  const pointerPositions = {};
9175
11755
  function getAutoRotationAngle() {
@@ -9185,7 +11765,7 @@ var OrbitControls = class extends EventDispatcher {
9185
11765
  sphericalDelta.phi -= angle;
9186
11766
  }
9187
11767
  const panLeft = function() {
9188
- const v = new Vector39();
11768
+ const v = new Vector312();
9189
11769
  return function panLeft2(distance, objectMatrix) {
9190
11770
  v.setFromMatrixColumn(objectMatrix, 0);
9191
11771
  v.multiplyScalar(-distance);
@@ -9193,7 +11773,7 @@ var OrbitControls = class extends EventDispatcher {
9193
11773
  };
9194
11774
  }();
9195
11775
  const panUp = function() {
9196
- const v = new Vector39();
11776
+ const v = new Vector312();
9197
11777
  return function panUp2(distance, objectMatrix) {
9198
11778
  if (scope.screenSpacePanning === true) {
9199
11779
  v.setFromMatrixColumn(objectMatrix, 1);
@@ -9206,7 +11786,7 @@ var OrbitControls = class extends EventDispatcher {
9206
11786
  };
9207
11787
  }();
9208
11788
  const pan = function() {
9209
- const offset = new Vector39();
11789
+ const offset = new Vector312();
9210
11790
  return function pan2(deltaX, deltaY) {
9211
11791
  const element = scope.domElement;
9212
11792
  if (scope.object.isPerspectiveCamera) {
@@ -9615,7 +12195,7 @@ var OrbitControls = class extends EventDispatcher {
9615
12195
  function trackPointer(event) {
9616
12196
  let position = pointerPositions[event.pointerId];
9617
12197
  if (position === void 0) {
9618
- position = new Vector24();
12198
+ position = new Vector25();
9619
12199
  pointerPositions[event.pointerId] = position;
9620
12200
  }
9621
12201
  position.set(event.pageX, event.pageY);
@@ -9687,8 +12267,8 @@ var Renderer = class _Renderer {
9687
12267
  top: void 0,
9688
12268
  bottom: void 0
9689
12269
  },
9690
- position: new Vector310(50, 50, 50),
9691
- lookingAt: new Vector310(0, 0, 0)
12270
+ position: new Vector313(50, 50, 50),
12271
+ lookingAt: new Vector313(0, 0, 0)
9692
12272
  },
9693
12273
  render: {
9694
12274
  fpsLimit: 60,
@@ -9719,7 +12299,7 @@ var Renderer = class _Renderer {
9719
12299
  switch (this.options.camera.type) {
9720
12300
  case "perspective":
9721
12301
  default:
9722
- return new PerspectiveCamera(
12302
+ return new PerspectiveCamera2(
9723
12303
  this.options.camera.perspective.fov,
9724
12304
  this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
9725
12305
  this.options.camera.near,
@@ -9737,7 +12317,7 @@ var Renderer = class _Renderer {
9737
12317
  }
9738
12318
  }
9739
12319
  createRenderer() {
9740
- const renderer = new WebGLRenderer({
12320
+ const renderer = new WebGLRenderer2({
9741
12321
  antialias: this.options.render.antialias,
9742
12322
  alpha: true,
9743
12323
  powerPreference: "high-performance",
@@ -9746,7 +12326,7 @@ var Renderer = class _Renderer {
9746
12326
  renderer.setClearColor(0, 0);
9747
12327
  renderer.shadowMap.enabled = true;
9748
12328
  renderer.shadowMap.type = PCFSoftShadowMap;
9749
- renderer.outputColorSpace = SRGBColorSpace4;
12329
+ renderer.outputColorSpace = SRGBColorSpace6;
9750
12330
  renderer.setPixelRatio(this.options.render.pixelRatio ?? 1);
9751
12331
  renderer.setSize(this.viewWidth, this.viewHeight);
9752
12332
  return renderer;
@@ -9938,6 +12518,9 @@ var Renderer = class _Renderer {
9938
12518
  if (next !== void 0 && t + 0.1 < next) return;
9939
12519
  this._nextFrameTime = next !== void 0 && t - next < interval ? next + interval : t + interval;
9940
12520
  }
12521
+ this.drawFrame();
12522
+ }
12523
+ drawFrame() {
9941
12524
  if (this._stats) {
9942
12525
  this._stats.begin();
9943
12526
  }
@@ -9952,8 +12535,28 @@ var Renderer = class _Renderer {
9952
12535
  }
9953
12536
  }
9954
12537
  //</editor-fold>
9955
- toImage() {
9956
- return this.renderer.domElement.toDataURL();
12538
+ /**
12539
+ * Renders a fresh frame and returns an image data URL, including while the animation loop is stopped.
12540
+ * Trimming removes transparent borders; an empty image becomes one transparent pixel.
12541
+ * MIME type support and lossy quality (0–1) follow the canvas encoder.
12542
+ */
12543
+ toImage(trim = false, mime = "image/png", quality) {
12544
+ if (this._disposed) throw new Error("Cannot export an image from a disposed renderer");
12545
+ if (this._controls?.enabled) {
12546
+ this._controls.update();
12547
+ }
12548
+ this.drawFrame();
12549
+ const canvas = trim ? trimCanvas(this.renderer.domElement) : this.renderer.domElement;
12550
+ return canvas.toDataURL(mime, quality);
12551
+ }
12552
+ toObj() {
12553
+ return SceneExporter.toObj(this.scene);
12554
+ }
12555
+ toPLY(options) {
12556
+ return SceneExporter.toPLY(this.scene, options);
12557
+ }
12558
+ toGLTF(options) {
12559
+ return SceneExporter.toGLTF(this.scene, options);
9957
12560
  }
9958
12561
  ///
9959
12562
  get attachedToBody() {
@@ -10424,12 +13027,12 @@ var AnvilParser = class {
10424
13027
  };
10425
13028
 
10426
13029
  // src/world/Chunk.ts
10427
- import { Vector3 as Vector313 } from "three";
13030
+ import { Vector3 as Vector316 } from "three";
10428
13031
  init_BlockStates();
10429
13032
  init_AssetKey();
10430
13033
 
10431
13034
  // src/world/MineRenderWorld.ts
10432
- import { Vector3 as Vector312 } from "three";
13035
+ import { Vector3 as Vector315 } from "three";
10433
13036
  init_BatchedExecutor();
10434
13037
  init_AssetKey();
10435
13038
  init_BlockStates();
@@ -10439,7 +13042,7 @@ init_CubeFace();
10439
13042
  init_AssetKey();
10440
13043
  init_Models();
10441
13044
  init_CubeFace();
10442
- import { Matrix4 as Matrix46, Vector3 as Vector311 } from "three";
13045
+ import { Matrix4 as Matrix48, Vector3 as Vector314 } from "three";
10443
13046
  init_ModelCulling();
10444
13047
  init_ModelObject();
10445
13048
  init_UVMapper();
@@ -10502,12 +13105,12 @@ var SectionModels = class {
10502
13105
  });
10503
13106
  await object.init();
10504
13107
  const geometry = object.children[0].geometry;
10505
- geometry.applyMatrix4(new Matrix46().makeRotationFromEuler(rotation));
13108
+ geometry.applyMatrix4(new Matrix48().makeRotationFromEuler(rotation));
10506
13109
  object.clear();
10507
13110
  const cullFaces = CUBE_FACES.map((face) => {
10508
13111
  const local = CUBE_FACES.findIndex((name) => name === atlas.model.elements[0].faces[face]?.cullface);
10509
13112
  if (local < 0) return 0;
10510
- const normal = new Vector311(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
13113
+ const normal = new Vector314(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
10511
13114
  const world = CUBE_FACE_OFFSETS.findIndex(([x, y, z]) => Math.abs(normal.x - x) < 1e-6 && Math.abs(normal.y - y) < 1e-6 && Math.abs(normal.z - z) < 1e-6);
10512
13115
  return 1 << world;
10513
13116
  });
@@ -10537,20 +13140,20 @@ var MineRenderWorld = class {
10537
13140
  }
10538
13141
  getBlockAt(posOrX, y, z) {
10539
13142
  if (typeof posOrX == "number") {
10540
- return this.getBlockAt(new Vector312(posOrX, y, z));
13143
+ return this.getBlockAt(new Vector315(posOrX, y, z));
10541
13144
  }
10542
13145
  if (isTripleArray(posOrX)) {
10543
- return this.getBlockAt(new Vector312(posOrX[0], posOrX[1], posOrX[2]));
13146
+ return this.getBlockAt(new Vector315(posOrX[0], posOrX[1], posOrX[2]));
10544
13147
  }
10545
13148
  this.validatePosBounds(posOrX);
10546
13149
  return this.getChunkAt(posOrX)?.getBlockAt(posOrX);
10547
13150
  }
10548
13151
  async setBlockAt(posOrX, yOrBlock, z, block) {
10549
13152
  if (typeof posOrX == "number") {
10550
- return this.setBlockAt(new Vector312(posOrX, yOrBlock, z), block);
13153
+ return this.setBlockAt(new Vector315(posOrX, yOrBlock, z), block);
10551
13154
  }
10552
13155
  if (isTripleArray(posOrX)) {
10553
- return this.setBlockAt(new Vector312(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
13156
+ return this.setBlockAt(new Vector315(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
10554
13157
  }
10555
13158
  return this.placeBlock(posOrX, yOrBlock);
10556
13159
  }
@@ -10571,7 +13174,7 @@ var MineRenderWorld = class {
10571
13174
  const collect = async (positions2) => {
10572
13175
  for (const pos of positions2) changes.set(pos.toArray().join(","), pos);
10573
13176
  };
10574
- const place = (block) => this.placeBlock(new Vector312(...block.position), block, collect);
13177
+ const place = (block) => this.placeBlock(new Vector315(...block.position), block, collect);
10575
13178
  const keys = /* @__PURE__ */ new Map();
10576
13179
  for (const block of multiblock.blocks) {
10577
13180
  if (Chunk.isAir(block)) continue;
@@ -10649,13 +13252,13 @@ var MineRenderWorld = class {
10649
13252
  for (const pos of positions) {
10650
13253
  this.pendingCulling.set(pos.toArray().join(","), pos.clone());
10651
13254
  for (const offset of CUBE_FACE_OFFSETS) {
10652
- const neighbor = pos.clone().add(new Vector312(...offset));
13255
+ const neighbor = pos.clone().add(new Vector315(...offset));
10653
13256
  this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
10654
13257
  }
10655
13258
  for (let y = -1; y <= 1; y++) {
10656
13259
  for (let z = -1; z <= 1; z++) {
10657
13260
  for (let x = -1; x <= 1; x++) {
10658
- const neighbor = pos.clone().add(new Vector312(x, y, z));
13261
+ const neighbor = pos.clone().add(new Vector315(x, y, z));
10659
13262
  if (this.getBlockAt(neighbor)?.object?.fluidKind) {
10660
13263
  this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
10661
13264
  }
@@ -10677,7 +13280,7 @@ var MineRenderWorld = class {
10677
13280
  if (!block) continue;
10678
13281
  if (block.object?.fluidKind) {
10679
13282
  await block.object.updateFluid((x, y, z) => {
10680
- const neighbor = pos.clone().add(new Vector312(x, y, z));
13283
+ const neighbor = pos.clone().add(new Vector315(x, y, z));
10681
13284
  const section = this.getChunkAt(neighbor);
10682
13285
  const object = section?.getBlockAt(neighbor)?.object;
10683
13286
  return {
@@ -10689,7 +13292,7 @@ var MineRenderWorld = class {
10689
13292
  }
10690
13293
  let mask = 0;
10691
13294
  for (const [face, offset] of CUBE_FACE_OFFSETS.entries()) {
10692
- const neighbor = pos.clone().add(new Vector312(...offset));
13295
+ const neighbor = pos.clone().add(new Vector315(...offset));
10693
13296
  if (this.getChunkAt(neighbor)?.isOccludingAt(neighbor)) {
10694
13297
  mask |= 1 << face;
10695
13298
  }
@@ -10723,14 +13326,14 @@ var MineRenderWorld = class {
10723
13326
  return this._chunks.get(this.worldPosToChunkKey(pos));
10724
13327
  }
10725
13328
  static worldToScenePosition(pos) {
10726
- return new Vector312(
13329
+ return new Vector315(
10727
13330
  pos.x * 16,
10728
13331
  pos.y * 16,
10729
13332
  pos.z * 16
10730
13333
  );
10731
13334
  }
10732
13335
  static sceneToWorldPosition(pos) {
10733
- return new Vector312(
13336
+ return new Vector315(
10734
13337
  pos.x / 16,
10735
13338
  pos.y / 16,
10736
13339
  pos.z / 16
@@ -10752,7 +13355,7 @@ var MineRenderWorld = class {
10752
13355
  // src/world/SectionMesh.ts
10753
13356
  init_CanvasCompat();
10754
13357
  init_Materials();
10755
- import { BufferGeometry as BufferGeometry4, Float32BufferAttribute as Float32BufferAttribute5, Group, Mesh as Mesh8 } from "three";
13358
+ import { BufferGeometry as BufferGeometry5, Float32BufferAttribute as Float32BufferAttribute6, Group, Mesh as Mesh10 } from "three";
10756
13359
  var SectionMesh = class _SectionMesh extends Group {
10757
13360
  constructor() {
10758
13361
  super(...arguments);
@@ -10826,18 +13429,18 @@ var SectionMesh = class _SectionMesh extends Group {
10826
13429
  for (let corner = 0; corner < 6; corner++) indices.push(start + sourceIndices.getX(face * 6 + corner) - face * 4);
10827
13430
  }
10828
13431
  }
10829
- const geometry = new BufferGeometry4();
10830
- geometry.setAttribute("position", new Float32BufferAttribute5(positions, 3));
10831
- geometry.setAttribute("normal", new Float32BufferAttribute5(normals, 3));
10832
- geometry.setAttribute("uv", new Float32BufferAttribute5(uvs, 2));
10833
- geometry.setAttribute("color", new Float32BufferAttribute5(colors, 3));
13432
+ const geometry = new BufferGeometry5();
13433
+ geometry.setAttribute("position", new Float32BufferAttribute6(positions, 3));
13434
+ geometry.setAttribute("normal", new Float32BufferAttribute6(normals, 3));
13435
+ geometry.setAttribute("uv", new Float32BufferAttribute6(uvs, 2));
13436
+ geometry.setAttribute("color", new Float32BufferAttribute6(colors, 3));
10834
13437
  geometry.setIndex(indices);
10835
13438
  geometry.computeBoundingBox();
10836
13439
  geometry.computeBoundingSphere();
10837
13440
  const material = Materials.createShadedCanvasMaterial(canvas, false);
10838
13441
  material.vertexColors = true;
10839
13442
  const texture = material.uniforms?.map?.value ?? material.map;
10840
- const mesh = new Mesh8(geometry, material);
13443
+ const mesh = new Mesh10(geometry, material);
10841
13444
  section.add(mesh);
10842
13445
  section.ownedMeshes.push({ mesh, texture });
10843
13446
  }
@@ -10871,10 +13474,10 @@ var Chunk = class _Chunk {
10871
13474
  }
10872
13475
  getBlockAt(posOrX, y, z) {
10873
13476
  if (typeof posOrX == "number") {
10874
- return this.getBlockAt(new Vector313(posOrX, y, z));
13477
+ return this.getBlockAt(new Vector316(posOrX, y, z));
10875
13478
  }
10876
13479
  if (isTripleArray(posOrX)) {
10877
- return this.getBlockAt(new Vector313(posOrX[0], posOrX[1], posOrX[2]));
13480
+ return this.getBlockAt(new Vector316(posOrX[0], posOrX[1], posOrX[2]));
10878
13481
  }
10879
13482
  const pos = this.worldPosToChunkPos(posOrX);
10880
13483
  const index = _Chunk.chunkPosToBlockIndex(pos);
@@ -10882,10 +13485,10 @@ var Chunk = class _Chunk {
10882
13485
  }
10883
13486
  async setBlockAt(posOrX, yOrBlock, z, block) {
10884
13487
  if (typeof posOrX == "number") {
10885
- return this.setBlockAt(new Vector313(posOrX, yOrBlock, z), block);
13488
+ return this.setBlockAt(new Vector316(posOrX, yOrBlock, z), block);
10886
13489
  }
10887
13490
  if (isTripleArray(posOrX)) {
10888
- return this.setBlockAt(new Vector313(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
13491
+ return this.setBlockAt(new Vector316(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
10889
13492
  }
10890
13493
  const worldPos = posOrX;
10891
13494
  const pos = this.worldPosToChunkPos(worldPos);
@@ -10970,7 +13573,7 @@ var Chunk = class _Chunk {
10970
13573
  }
10971
13574
  async clear(onBlocksChanged = this.onBlocksChanged) {
10972
13575
  const positions = [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
10973
- new Vector313(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
13576
+ new Vector316(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
10974
13577
  ));
10975
13578
  for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
10976
13579
  this.sectionBlocks.clear();
@@ -10994,14 +13597,14 @@ var Chunk = class _Chunk {
10994
13597
  return pos.y * 16 * 16 + pos.z * 16 + pos.x;
10995
13598
  }
10996
13599
  worldPosToChunkPos(pos) {
10997
- return new Vector313(
13600
+ return new Vector316(
10998
13601
  pos.x - this.x * 16,
10999
13602
  pos.y - this.y * 16,
11000
13603
  pos.z - this.z * 16
11001
13604
  );
11002
13605
  }
11003
13606
  chunkPosToWorldPos(pos) {
11004
- return new Vector313(
13607
+ return new Vector316(
11005
13608
  this.x * 16 + pos.x,
11006
13609
  this.y * 16 + pos.y,
11007
13610
  this.z * 16 + pos.z
@@ -11080,6 +13683,7 @@ export {
11080
13683
  RequestError,
11081
13684
  Requests,
11082
13685
  SKIN_PARTS,
13686
+ SceneExporter,
11083
13687
  SceneInspector,
11084
13688
  SceneObject,
11085
13689
  SceneStats,
@@ -11168,6 +13772,7 @@ export {
11168
13772
  timingStart,
11169
13773
  toDegrees,
11170
13774
  toRadians,
11171
- toTrianglesDrawMode
13775
+ toTrianglesDrawMode,
13776
+ trimCanvas
11172
13777
  };
11173
13778
  //# sourceMappingURL=index.mjs.map