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.
@@ -3404,7 +3404,7 @@ var init_SceneObject = __esm({
3404
3404
  });
3405
3405
 
3406
3406
  // src/model/ModelCulling.ts
3407
- import { Vector3 as Vector36 } from "three";
3407
+ import { Vector3 as Vector39 } from "three";
3408
3408
  var ModelCulling;
3409
3409
  var init_ModelCulling = __esm({
3410
3410
  "src/model/ModelCulling.ts"() {
@@ -3413,7 +3413,7 @@ var init_ModelCulling = __esm({
3413
3413
  static toLocalMask(worldMask, rotation) {
3414
3414
  let localMask = 0;
3415
3415
  for (const [localFace, offset] of CUBE_FACE_OFFSETS.entries()) {
3416
- const normal = new Vector36(...offset).applyEuler(rotation);
3416
+ const normal = new Vector39(...offset).applyEuler(rotation);
3417
3417
  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);
3418
3418
  if (worldFace < 0) return 0;
3419
3419
  if (worldMask & 1 << worldFace) localMask |= 1 << localFace;
@@ -3447,15 +3447,15 @@ var init_ModelCulling = __esm({
3447
3447
 
3448
3448
  // src/three/BufferGeometryUtils.js
3449
3449
  import {
3450
- BufferAttribute as BufferAttribute3,
3451
- BufferGeometry,
3452
- Float32BufferAttribute as Float32BufferAttribute3,
3450
+ BufferAttribute as BufferAttribute4,
3451
+ BufferGeometry as BufferGeometry2,
3452
+ Float32BufferAttribute as Float32BufferAttribute4,
3453
3453
  InterleavedBuffer,
3454
3454
  InterleavedBufferAttribute,
3455
3455
  TriangleFanDrawMode,
3456
3456
  TriangleStripDrawMode,
3457
3457
  TrianglesDrawMode,
3458
- Vector3 as Vector37
3458
+ Vector3 as Vector310
3459
3459
  } from "three";
3460
3460
  function computeTangents(geometry) {
3461
3461
  geometry.computeTangents();
@@ -3468,7 +3468,7 @@ function mergeBufferGeometries(geometries, useGroups = false) {
3468
3468
  const attributes = {};
3469
3469
  const morphAttributes = {};
3470
3470
  const morphTargetsRelative = geometries[0].morphTargetsRelative;
3471
- const mergedGeometry = new BufferGeometry();
3471
+ const mergedGeometry = new BufferGeometry2();
3472
3472
  let offset = 0;
3473
3473
  for (let i = 0; i < geometries.length; ++i) {
3474
3474
  const geometry = geometries[i];
@@ -3592,7 +3592,7 @@ function mergeBufferAttributes(attributes) {
3592
3592
  array.set(attributes[i].array, offset);
3593
3593
  offset += attributes[i].array.length;
3594
3594
  }
3595
- return new BufferAttribute3(array, itemSize, normalized);
3595
+ return new BufferAttribute4(array, itemSize, normalized);
3596
3596
  }
3597
3597
  function interleaveAttributes(attributes) {
3598
3598
  let TypedArray;
@@ -3701,13 +3701,13 @@ function mergeVertices(geometry, tolerance = 1e-4) {
3701
3701
  const name = attributeNames[i];
3702
3702
  const oldAttribute = geometry.getAttribute(name);
3703
3703
  const buffer = new oldAttribute.array.constructor(attrArrays[name]);
3704
- const attribute = new BufferAttribute3(buffer, oldAttribute.itemSize, oldAttribute.normalized);
3704
+ const attribute = new BufferAttribute4(buffer, oldAttribute.itemSize, oldAttribute.normalized);
3705
3705
  result.setAttribute(name, attribute);
3706
3706
  if (name in morphAttrsArrays) {
3707
3707
  for (let j = 0; j < morphAttrsArrays[name].length; j++) {
3708
3708
  const oldMorphAttribute = geometry.morphAttributes[name][j];
3709
3709
  const buffer2 = new oldMorphAttribute.array.constructor(morphAttrsArrays[name][j]);
3710
- const morphAttribute = new BufferAttribute3(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
3710
+ const morphAttribute = new BufferAttribute4(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
3711
3711
  result.morphAttributes[name][j] = morphAttribute;
3712
3712
  }
3713
3713
  }
@@ -3774,15 +3774,15 @@ function computeMorphedAttributes(object) {
3774
3774
  console.error("THREE.BufferGeometryUtils: Geometry is not of type BufferGeometry.");
3775
3775
  return null;
3776
3776
  }
3777
- const _vA = new Vector37();
3778
- const _vB = new Vector37();
3779
- const _vC = new Vector37();
3780
- const _tempA = new Vector37();
3781
- const _tempB = new Vector37();
3782
- const _tempC = new Vector37();
3783
- const _morphA = new Vector37();
3784
- const _morphB = new Vector37();
3785
- const _morphC = new Vector37();
3777
+ const _vA = new Vector310();
3778
+ const _vB = new Vector310();
3779
+ const _vC = new Vector310();
3780
+ const _tempA = new Vector310();
3781
+ const _tempB = new Vector310();
3782
+ const _tempC = new Vector310();
3783
+ const _morphA = new Vector310();
3784
+ const _morphB = new Vector310();
3785
+ const _morphC = new Vector310();
3786
3786
  function _calculateMorphedAttributeData(object2, material2, attribute, morphAttribute, morphTargetsRelative2, a2, b2, c2, modifiedAttributeArray) {
3787
3787
  _vA.fromBufferAttribute(attribute, a2);
3788
3788
  _vB.fromBufferAttribute(attribute, b2);
@@ -3977,8 +3977,8 @@ function computeMorphedAttributes(object) {
3977
3977
  }
3978
3978
  }
3979
3979
  }
3980
- const morphedPositionAttribute = new Float32BufferAttribute3(modifiedPosition, 3);
3981
- const morphedNormalAttribute = new Float32BufferAttribute3(modifiedNormal, 3);
3980
+ const morphedPositionAttribute = new Float32BufferAttribute4(modifiedPosition, 3);
3981
+ const morphedNormalAttribute = new Float32BufferAttribute4(modifiedNormal, 3);
3982
3982
  return {
3983
3983
  positionAttribute,
3984
3984
  normalAttribute,
@@ -3992,7 +3992,7 @@ var init_BufferGeometryUtils = __esm({
3992
3992
  });
3993
3993
 
3994
3994
  // src/model/scene/ModelObject.ts
3995
- import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute4, Color as Color3, Euler as Euler6, Matrix4 as Matrix44 } from "three";
3995
+ import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute5, Color as Color7, Euler as Euler6, Matrix4 as Matrix46 } from "three";
3996
3996
  function isModelObject(obj) {
3997
3997
  return obj.isModelObject;
3998
3998
  }
@@ -4065,19 +4065,19 @@ var init_ModelObject = __esm({
4065
4065
  if (tintIndex === void 0 || tintIndex < 0) continue;
4066
4066
  const tint = this.options.tints[tintIndex];
4067
4067
  if (tint === void 0) continue;
4068
- const color = new Color3(tint);
4068
+ const color = new Color7(tint);
4069
4069
  for (let vertex = 0; vertex < 4; vertex++) {
4070
4070
  color.toArray(colors, (faceIndex * 4 + vertex) * 3);
4071
4071
  }
4072
4072
  }
4073
- elGeo.setAttribute("color", new BufferAttribute4(colors, 3));
4073
+ elGeo.setAttribute("color", new BufferAttribute5(colors, 3));
4074
4074
  }
4075
- 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));
4076
- elGeo.applyMatrix4(new Matrix44().makeTranslation(el.from[0], el.from[1], el.from[2]));
4075
+ 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));
4076
+ elGeo.applyMatrix4(new Matrix46().makeTranslation(el.from[0], el.from[1], el.from[2]));
4077
4077
  if (el.rotation) {
4078
4078
  applyElementRotation(el.rotation, elGeo);
4079
4079
  }
4080
- elGeo.applyMatrix4(new Matrix44().makeTranslation(-8, -8, -8));
4080
+ elGeo.applyMatrix4(new Matrix46().makeTranslation(-8, -8, -8));
4081
4081
  if (displayTransform) DisplayTransforms.apply(elGeo, displayTransform);
4082
4082
  if (this.options.mergeMeshes) {
4083
4083
  allGeos.push(elGeo);
@@ -4192,7 +4192,7 @@ var init_fluidBlocks = __esm({
4192
4192
  });
4193
4193
 
4194
4194
  // src/model/fluid/FluidGeometry.ts
4195
- import { BufferGeometry as BufferGeometry2, Float32BufferAttribute as Float32BufferAttribute4 } from "three";
4195
+ import { BufferGeometry as BufferGeometry3, Float32BufferAttribute as Float32BufferAttribute5 } from "three";
4196
4196
  function getBlockFluidState(key, state) {
4197
4197
  const rule = key && fluidRules[key.toNamespacedString()];
4198
4198
  if (rule) return {
@@ -4210,7 +4210,7 @@ function ownHeight(sample) {
4210
4210
  return (level === 0 || level >= 8 ? 8 : 8 - level) / 9;
4211
4211
  }
4212
4212
  function createFluidGeometry(kind, sample) {
4213
- const geometry = new BufferGeometry2();
4213
+ const geometry = new BufferGeometry3();
4214
4214
  const positions = [], normals = [], uvs = [], indices = [];
4215
4215
  const self = sample(0, 0, 0);
4216
4216
  const height = (x, z) => {
@@ -4309,9 +4309,9 @@ function createFluidGeometry(kind, sample) {
4309
4309
  1
4310
4310
  );
4311
4311
  }
4312
- geometry.setAttribute("position", new Float32BufferAttribute4(positions, 3));
4313
- geometry.setAttribute("normal", new Float32BufferAttribute4(normals, 3));
4314
- geometry.setAttribute("uv", new Float32BufferAttribute4(uvs, 2));
4312
+ geometry.setAttribute("position", new Float32BufferAttribute5(positions, 3));
4313
+ geometry.setAttribute("normal", new Float32BufferAttribute5(normals, 3));
4314
+ geometry.setAttribute("uv", new Float32BufferAttribute5(uvs, 2));
4315
4315
  geometry.setIndex(indices);
4316
4316
  return geometry;
4317
4317
  }
@@ -4331,7 +4331,7 @@ __export(FluidModelObject_exports, {
4331
4331
  FluidModelObject: () => FluidModelObject,
4332
4332
  sampleFluid: () => sampleFluid
4333
4333
  });
4334
- import { BufferAttribute as BufferAttribute5, Color as Color4, DoubleSide as DoubleSide2 } from "three";
4334
+ import { BufferAttribute as BufferAttribute6, Color as Color8, DoubleSide as DoubleSide3 } from "three";
4335
4335
  function sampleFluid(kind, sample) {
4336
4336
  const cells = [];
4337
4337
  const key = [];
@@ -4382,10 +4382,10 @@ var init_FluidModelObject = __esm({
4382
4382
  }
4383
4383
  }
4384
4384
  geometry.clearGroups();
4385
- const color = new Color4(this.options.tints?.[0] ?? (this.kind === "water" ? 4159204 : 16777215));
4385
+ const color = new Color8(this.options.tints?.[0] ?? (this.kind === "water" ? 4159204 : 16777215));
4386
4386
  const colors = new Float32Array(geometry.getAttribute("position").count * 3);
4387
4387
  for (let i = 0; i < colors.length; i += 3) color.toArray(colors, i);
4388
- geometry.setAttribute("color", new BufferAttribute5(colors, 3));
4388
+ geometry.setAttribute("color", new BufferAttribute6(colors, 3));
4389
4389
  geometry.computeBoundingBox();
4390
4390
  geometry.computeBoundingSphere();
4391
4391
  if (this.options.instanceMeshes) {
@@ -4399,7 +4399,7 @@ var init_FluidModelObject = __esm({
4399
4399
  super.applyTextures();
4400
4400
  this.iterateAllMeshes((mesh) => {
4401
4401
  const material = mesh.material;
4402
- material.side = DoubleSide2;
4402
+ material.side = DoubleSide3;
4403
4403
  material.forceSinglePass = true;
4404
4404
  material.depthWrite = !material.transparent;
4405
4405
  });
@@ -4789,6 +4789,37 @@ init_PersistentCache();
4789
4789
  init_CanvasCompat();
4790
4790
  init_CanvasImage();
4791
4791
 
4792
+ // src/canvas/trimCanvas.ts
4793
+ init_CanvasCompat();
4794
+ function trimCanvas(source) {
4795
+ if (source.width === 0 || source.height === 0) return createCanvas(1, 1);
4796
+ const canvas = createCanvas(source.width, source.height);
4797
+ const context = canvas.getContext("2d");
4798
+ if (!context) throw new Error("Image export requires a 2D canvas context");
4799
+ context.drawImage(source, 0, 0);
4800
+ const pixels = context.getImageData(0, 0, canvas.width, canvas.height).data;
4801
+ let left = canvas.width, top = canvas.height, right = -1, bottom = -1;
4802
+ for (let y = 0; y < canvas.height; y++) {
4803
+ for (let x = 0; x < canvas.width; x++) {
4804
+ if (pixels[(y * canvas.width + x) * 4 + 3] === 0) continue;
4805
+ left = Math.min(left, x);
4806
+ top = Math.min(top, y);
4807
+ right = Math.max(right, x);
4808
+ bottom = Math.max(bottom, y);
4809
+ }
4810
+ }
4811
+ if (right < left) {
4812
+ canvas.width = canvas.height = 1;
4813
+ return canvas;
4814
+ }
4815
+ const width = right - left + 1, height = bottom - top + 1;
4816
+ const cropped = context.getImageData(left, top, width, height);
4817
+ canvas.width = width;
4818
+ canvas.height = height;
4819
+ context.putImageData(cropped, 0, 0);
4820
+ return canvas;
4821
+ }
4822
+
4792
4823
  // src/entity/scene/EntityObject.ts
4793
4824
  init_SceneObject();
4794
4825
  init_Caching();
@@ -4910,6 +4941,2555 @@ function isEntityObject(obj) {
4910
4941
  // src/error/index.ts
4911
4942
  init_MineRenderError();
4912
4943
 
4944
+ // src/export/SceneExporter.ts
4945
+ 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";
4946
+
4947
+ // ../../node_modules/three/examples/jsm/exporters/OBJExporter.js
4948
+ import {
4949
+ Color as Color3,
4950
+ Matrix3,
4951
+ Vector2 as Vector22,
4952
+ Vector3 as Vector36
4953
+ } from "three";
4954
+ var OBJExporter = class {
4955
+ parse(object) {
4956
+ let output = "";
4957
+ let indexVertex = 0;
4958
+ let indexVertexUvs = 0;
4959
+ let indexNormals = 0;
4960
+ const vertex = new Vector36();
4961
+ const color = new Color3();
4962
+ const normal = new Vector36();
4963
+ const uv = new Vector22();
4964
+ const face = [];
4965
+ function parseMesh(mesh) {
4966
+ let nbVertex = 0;
4967
+ let nbNormals = 0;
4968
+ let nbVertexUvs = 0;
4969
+ const geometry = mesh.geometry;
4970
+ const normalMatrixWorld = new Matrix3();
4971
+ const vertices = geometry.getAttribute("position");
4972
+ const normals = geometry.getAttribute("normal");
4973
+ const uvs = geometry.getAttribute("uv");
4974
+ const indices = geometry.getIndex();
4975
+ output += "o " + mesh.name + "\n";
4976
+ if (mesh.material && mesh.material.name) {
4977
+ output += "usemtl " + mesh.material.name + "\n";
4978
+ }
4979
+ if (vertices !== void 0) {
4980
+ for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
4981
+ vertex.fromBufferAttribute(vertices, i);
4982
+ vertex.applyMatrix4(mesh.matrixWorld);
4983
+ output += "v " + vertex.x + " " + vertex.y + " " + vertex.z + "\n";
4984
+ }
4985
+ }
4986
+ if (uvs !== void 0) {
4987
+ for (let i = 0, l = uvs.count; i < l; i++, nbVertexUvs++) {
4988
+ uv.fromBufferAttribute(uvs, i);
4989
+ output += "vt " + uv.x + " " + uv.y + "\n";
4990
+ }
4991
+ }
4992
+ if (normals !== void 0) {
4993
+ normalMatrixWorld.getNormalMatrix(mesh.matrixWorld);
4994
+ for (let i = 0, l = normals.count; i < l; i++, nbNormals++) {
4995
+ normal.fromBufferAttribute(normals, i);
4996
+ normal.applyMatrix3(normalMatrixWorld).normalize();
4997
+ output += "vn " + normal.x + " " + normal.y + " " + normal.z + "\n";
4998
+ }
4999
+ }
5000
+ if (indices !== null) {
5001
+ for (let i = 0, l = indices.count; i < l; i += 3) {
5002
+ for (let m = 0; m < 3; m++) {
5003
+ const j = indices.getX(i + m) + 1;
5004
+ face[m] = indexVertex + j + (normals || uvs ? "/" + (uvs ? indexVertexUvs + j : "") + (normals ? "/" + (indexNormals + j) : "") : "");
5005
+ }
5006
+ output += "f " + face.join(" ") + "\n";
5007
+ }
5008
+ } else {
5009
+ for (let i = 0, l = vertices.count; i < l; i += 3) {
5010
+ for (let m = 0; m < 3; m++) {
5011
+ const j = i + m + 1;
5012
+ face[m] = indexVertex + j + (normals || uvs ? "/" + (uvs ? indexVertexUvs + j : "") + (normals ? "/" + (indexNormals + j) : "") : "");
5013
+ }
5014
+ output += "f " + face.join(" ") + "\n";
5015
+ }
5016
+ }
5017
+ indexVertex += nbVertex;
5018
+ indexVertexUvs += nbVertexUvs;
5019
+ indexNormals += nbNormals;
5020
+ }
5021
+ function parseLine(line) {
5022
+ let nbVertex = 0;
5023
+ const geometry = line.geometry;
5024
+ const type = line.type;
5025
+ const vertices = geometry.getAttribute("position");
5026
+ output += "o " + line.name + "\n";
5027
+ if (vertices !== void 0) {
5028
+ for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
5029
+ vertex.fromBufferAttribute(vertices, i);
5030
+ vertex.applyMatrix4(line.matrixWorld);
5031
+ output += "v " + vertex.x + " " + vertex.y + " " + vertex.z + "\n";
5032
+ }
5033
+ }
5034
+ if (type === "Line") {
5035
+ output += "l ";
5036
+ for (let j = 1, l = vertices.count; j <= l; j++) {
5037
+ output += indexVertex + j + " ";
5038
+ }
5039
+ output += "\n";
5040
+ }
5041
+ if (type === "LineSegments") {
5042
+ for (let j = 1, k = j + 1, l = vertices.count; j < l; j += 2, k = j + 1) {
5043
+ output += "l " + (indexVertex + j) + " " + (indexVertex + k) + "\n";
5044
+ }
5045
+ }
5046
+ indexVertex += nbVertex;
5047
+ }
5048
+ function parsePoints(points) {
5049
+ let nbVertex = 0;
5050
+ const geometry = points.geometry;
5051
+ const vertices = geometry.getAttribute("position");
5052
+ const colors = geometry.getAttribute("color");
5053
+ output += "o " + points.name + "\n";
5054
+ if (vertices !== void 0) {
5055
+ for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
5056
+ vertex.fromBufferAttribute(vertices, i);
5057
+ vertex.applyMatrix4(points.matrixWorld);
5058
+ output += "v " + vertex.x + " " + vertex.y + " " + vertex.z;
5059
+ if (colors !== void 0) {
5060
+ color.fromBufferAttribute(colors, i).convertLinearToSRGB();
5061
+ output += " " + color.r + " " + color.g + " " + color.b;
5062
+ }
5063
+ output += "\n";
5064
+ }
5065
+ output += "p ";
5066
+ for (let j = 1, l = vertices.count; j <= l; j++) {
5067
+ output += indexVertex + j + " ";
5068
+ }
5069
+ output += "\n";
5070
+ }
5071
+ indexVertex += nbVertex;
5072
+ }
5073
+ object.traverse(function(child) {
5074
+ if (child.isMesh === true) {
5075
+ parseMesh(child);
5076
+ }
5077
+ if (child.isLine === true) {
5078
+ parseLine(child);
5079
+ }
5080
+ if (child.isPoints === true) {
5081
+ parsePoints(child);
5082
+ }
5083
+ });
5084
+ return output;
5085
+ }
5086
+ };
5087
+
5088
+ // ../../node_modules/three/examples/jsm/exporters/PLYExporter.js
5089
+ import {
5090
+ Matrix3 as Matrix32,
5091
+ Vector3 as Vector37,
5092
+ Color as Color4
5093
+ } from "three";
5094
+ var PLYExporter = class {
5095
+ parse(object, onDone, options = {}) {
5096
+ function traverseMeshes(cb) {
5097
+ object.traverse(function(child) {
5098
+ if (child.isMesh === true || child.isPoints) {
5099
+ const mesh = child;
5100
+ const geometry = mesh.geometry;
5101
+ if (geometry.hasAttribute("position") === true) {
5102
+ cb(mesh, geometry);
5103
+ }
5104
+ }
5105
+ });
5106
+ }
5107
+ const defaultOptions = {
5108
+ binary: false,
5109
+ excludeAttributes: [],
5110
+ // normal, uv, color, index
5111
+ littleEndian: false
5112
+ };
5113
+ options = Object.assign(defaultOptions, options);
5114
+ const excludeAttributes = options.excludeAttributes;
5115
+ let includeIndices = true;
5116
+ let includeNormals = false;
5117
+ let includeColors = false;
5118
+ let includeUVs = false;
5119
+ let vertexCount = 0;
5120
+ let faceCount = 0;
5121
+ object.traverse(function(child) {
5122
+ if (child.isMesh === true) {
5123
+ const mesh = child;
5124
+ const geometry = mesh.geometry;
5125
+ const vertices = geometry.getAttribute("position");
5126
+ const normals = geometry.getAttribute("normal");
5127
+ const uvs = geometry.getAttribute("uv");
5128
+ const colors = geometry.getAttribute("color");
5129
+ const indices = geometry.getIndex();
5130
+ if (vertices === void 0) {
5131
+ return;
5132
+ }
5133
+ vertexCount += vertices.count;
5134
+ faceCount += indices ? indices.count / 3 : vertices.count / 3;
5135
+ if (normals !== void 0) includeNormals = true;
5136
+ if (uvs !== void 0) includeUVs = true;
5137
+ if (colors !== void 0) includeColors = true;
5138
+ } else if (child.isPoints) {
5139
+ const mesh = child;
5140
+ const geometry = mesh.geometry;
5141
+ const vertices = geometry.getAttribute("position");
5142
+ const normals = geometry.getAttribute("normal");
5143
+ const colors = geometry.getAttribute("color");
5144
+ vertexCount += vertices.count;
5145
+ if (normals !== void 0) includeNormals = true;
5146
+ if (colors !== void 0) includeColors = true;
5147
+ includeIndices = false;
5148
+ }
5149
+ });
5150
+ const tempColor = new Color4();
5151
+ includeIndices = includeIndices && excludeAttributes.indexOf("index") === -1;
5152
+ includeNormals = includeNormals && excludeAttributes.indexOf("normal") === -1;
5153
+ includeColors = includeColors && excludeAttributes.indexOf("color") === -1;
5154
+ includeUVs = includeUVs && excludeAttributes.indexOf("uv") === -1;
5155
+ if (includeIndices && faceCount !== Math.floor(faceCount)) {
5156
+ console.error(
5157
+ "PLYExporter: Failed to generate a valid PLY file with triangle indices because the number of indices is not divisible by 3."
5158
+ );
5159
+ return null;
5160
+ }
5161
+ const indexByteCount = 4;
5162
+ let header = `ply
5163
+ format ${options.binary ? options.littleEndian ? "binary_little_endian" : "binary_big_endian" : "ascii"} 1.0
5164
+ element vertex ${vertexCount}
5165
+ property float x
5166
+ property float y
5167
+ property float z
5168
+ `;
5169
+ if (includeNormals === true) {
5170
+ header += "property float nx\nproperty float ny\nproperty float nz\n";
5171
+ }
5172
+ if (includeUVs === true) {
5173
+ header += "property float s\nproperty float t\n";
5174
+ }
5175
+ if (includeColors === true) {
5176
+ header += "property uchar red\nproperty uchar green\nproperty uchar blue\n";
5177
+ }
5178
+ if (includeIndices === true) {
5179
+ header += `element face ${faceCount}
5180
+ property list uchar int vertex_index
5181
+ `;
5182
+ }
5183
+ header += "end_header\n";
5184
+ const vertex = new Vector37();
5185
+ const normalMatrixWorld = new Matrix32();
5186
+ let result = null;
5187
+ if (options.binary === true) {
5188
+ const headerBin = new TextEncoder().encode(header);
5189
+ const vertexListLength = vertexCount * (4 * 3 + (includeNormals ? 4 * 3 : 0) + (includeColors ? 3 : 0) + (includeUVs ? 4 * 2 : 0));
5190
+ const faceListLength = includeIndices ? faceCount * (indexByteCount * 3 + 1) : 0;
5191
+ const output = new DataView(new ArrayBuffer(headerBin.length + vertexListLength + faceListLength));
5192
+ new Uint8Array(output.buffer).set(headerBin, 0);
5193
+ let vOffset = headerBin.length;
5194
+ let fOffset = headerBin.length + vertexListLength;
5195
+ let writtenVertices = 0;
5196
+ traverseMeshes(function(mesh, geometry) {
5197
+ const vertices = geometry.getAttribute("position");
5198
+ const normals = geometry.getAttribute("normal");
5199
+ const uvs = geometry.getAttribute("uv");
5200
+ const colors = geometry.getAttribute("color");
5201
+ const indices = geometry.getIndex();
5202
+ normalMatrixWorld.getNormalMatrix(mesh.matrixWorld);
5203
+ for (let i = 0, l = vertices.count; i < l; i++) {
5204
+ vertex.fromBufferAttribute(vertices, i);
5205
+ vertex.applyMatrix4(mesh.matrixWorld);
5206
+ output.setFloat32(vOffset, vertex.x, options.littleEndian);
5207
+ vOffset += 4;
5208
+ output.setFloat32(vOffset, vertex.y, options.littleEndian);
5209
+ vOffset += 4;
5210
+ output.setFloat32(vOffset, vertex.z, options.littleEndian);
5211
+ vOffset += 4;
5212
+ if (includeNormals === true) {
5213
+ if (normals != null) {
5214
+ vertex.fromBufferAttribute(normals, i);
5215
+ vertex.applyMatrix3(normalMatrixWorld).normalize();
5216
+ output.setFloat32(vOffset, vertex.x, options.littleEndian);
5217
+ vOffset += 4;
5218
+ output.setFloat32(vOffset, vertex.y, options.littleEndian);
5219
+ vOffset += 4;
5220
+ output.setFloat32(vOffset, vertex.z, options.littleEndian);
5221
+ vOffset += 4;
5222
+ } else {
5223
+ output.setFloat32(vOffset, 0, options.littleEndian);
5224
+ vOffset += 4;
5225
+ output.setFloat32(vOffset, 0, options.littleEndian);
5226
+ vOffset += 4;
5227
+ output.setFloat32(vOffset, 0, options.littleEndian);
5228
+ vOffset += 4;
5229
+ }
5230
+ }
5231
+ if (includeUVs === true) {
5232
+ if (uvs != null) {
5233
+ output.setFloat32(vOffset, uvs.getX(i), options.littleEndian);
5234
+ vOffset += 4;
5235
+ output.setFloat32(vOffset, uvs.getY(i), options.littleEndian);
5236
+ vOffset += 4;
5237
+ } else {
5238
+ output.setFloat32(vOffset, 0, options.littleEndian);
5239
+ vOffset += 4;
5240
+ output.setFloat32(vOffset, 0, options.littleEndian);
5241
+ vOffset += 4;
5242
+ }
5243
+ }
5244
+ if (includeColors === true) {
5245
+ if (colors != null) {
5246
+ tempColor.fromBufferAttribute(colors, i).convertLinearToSRGB();
5247
+ output.setUint8(vOffset, Math.floor(tempColor.r * 255));
5248
+ vOffset += 1;
5249
+ output.setUint8(vOffset, Math.floor(tempColor.g * 255));
5250
+ vOffset += 1;
5251
+ output.setUint8(vOffset, Math.floor(tempColor.b * 255));
5252
+ vOffset += 1;
5253
+ } else {
5254
+ output.setUint8(vOffset, 255);
5255
+ vOffset += 1;
5256
+ output.setUint8(vOffset, 255);
5257
+ vOffset += 1;
5258
+ output.setUint8(vOffset, 255);
5259
+ vOffset += 1;
5260
+ }
5261
+ }
5262
+ }
5263
+ if (includeIndices === true) {
5264
+ if (indices !== null) {
5265
+ for (let i = 0, l = indices.count; i < l; i += 3) {
5266
+ output.setUint8(fOffset, 3);
5267
+ fOffset += 1;
5268
+ output.setUint32(fOffset, indices.getX(i + 0) + writtenVertices, options.littleEndian);
5269
+ fOffset += indexByteCount;
5270
+ output.setUint32(fOffset, indices.getX(i + 1) + writtenVertices, options.littleEndian);
5271
+ fOffset += indexByteCount;
5272
+ output.setUint32(fOffset, indices.getX(i + 2) + writtenVertices, options.littleEndian);
5273
+ fOffset += indexByteCount;
5274
+ }
5275
+ } else {
5276
+ for (let i = 0, l = vertices.count; i < l; i += 3) {
5277
+ output.setUint8(fOffset, 3);
5278
+ fOffset += 1;
5279
+ output.setUint32(fOffset, writtenVertices + i, options.littleEndian);
5280
+ fOffset += indexByteCount;
5281
+ output.setUint32(fOffset, writtenVertices + i + 1, options.littleEndian);
5282
+ fOffset += indexByteCount;
5283
+ output.setUint32(fOffset, writtenVertices + i + 2, options.littleEndian);
5284
+ fOffset += indexByteCount;
5285
+ }
5286
+ }
5287
+ }
5288
+ writtenVertices += vertices.count;
5289
+ });
5290
+ result = output.buffer;
5291
+ } else {
5292
+ let writtenVertices = 0;
5293
+ let vertexList = "";
5294
+ let faceList = "";
5295
+ traverseMeshes(function(mesh, geometry) {
5296
+ const vertices = geometry.getAttribute("position");
5297
+ const normals = geometry.getAttribute("normal");
5298
+ const uvs = geometry.getAttribute("uv");
5299
+ const colors = geometry.getAttribute("color");
5300
+ const indices = geometry.getIndex();
5301
+ normalMatrixWorld.getNormalMatrix(mesh.matrixWorld);
5302
+ for (let i = 0, l = vertices.count; i < l; i++) {
5303
+ vertex.fromBufferAttribute(vertices, i);
5304
+ vertex.applyMatrix4(mesh.matrixWorld);
5305
+ let line = vertex.x + " " + vertex.y + " " + vertex.z;
5306
+ if (includeNormals === true) {
5307
+ if (normals != null) {
5308
+ vertex.fromBufferAttribute(normals, i);
5309
+ vertex.applyMatrix3(normalMatrixWorld).normalize();
5310
+ line += " " + vertex.x + " " + vertex.y + " " + vertex.z;
5311
+ } else {
5312
+ line += " 0 0 0";
5313
+ }
5314
+ }
5315
+ if (includeUVs === true) {
5316
+ if (uvs != null) {
5317
+ line += " " + uvs.getX(i) + " " + uvs.getY(i);
5318
+ } else {
5319
+ line += " 0 0";
5320
+ }
5321
+ }
5322
+ if (includeColors === true) {
5323
+ if (colors != null) {
5324
+ tempColor.fromBufferAttribute(colors, i).convertLinearToSRGB();
5325
+ line += " " + Math.floor(tempColor.r * 255) + " " + Math.floor(tempColor.g * 255) + " " + Math.floor(tempColor.b * 255);
5326
+ } else {
5327
+ line += " 255 255 255";
5328
+ }
5329
+ }
5330
+ vertexList += line + "\n";
5331
+ }
5332
+ if (includeIndices === true) {
5333
+ if (indices !== null) {
5334
+ for (let i = 0, l = indices.count; i < l; i += 3) {
5335
+ faceList += `3 ${indices.getX(i + 0) + writtenVertices}`;
5336
+ faceList += ` ${indices.getX(i + 1) + writtenVertices}`;
5337
+ faceList += ` ${indices.getX(i + 2) + writtenVertices}
5338
+ `;
5339
+ }
5340
+ } else {
5341
+ for (let i = 0, l = vertices.count; i < l; i += 3) {
5342
+ faceList += `3 ${writtenVertices + i} ${writtenVertices + i + 1} ${writtenVertices + i + 2}
5343
+ `;
5344
+ }
5345
+ }
5346
+ faceCount += indices ? indices.count / 3 : vertices.count / 3;
5347
+ }
5348
+ writtenVertices += vertices.count;
5349
+ });
5350
+ result = `${header}${vertexList}${includeIndices ? `${faceList}
5351
+ ` : "\n"}`;
5352
+ }
5353
+ if (typeof onDone === "function") requestAnimationFrame(() => onDone(result));
5354
+ return result;
5355
+ }
5356
+ };
5357
+
5358
+ // ../../node_modules/three/examples/jsm/exporters/GLTFExporter.js
5359
+ import {
5360
+ BufferAttribute as BufferAttribute3,
5361
+ ClampToEdgeWrapping,
5362
+ Color as Color5,
5363
+ DoubleSide as DoubleSide2,
5364
+ InterpolateDiscrete,
5365
+ InterpolateLinear,
5366
+ NoColorSpace,
5367
+ LinearFilter,
5368
+ LinearMipmapLinearFilter,
5369
+ LinearMipmapNearestFilter,
5370
+ MathUtils as MathUtils2,
5371
+ Matrix4 as Matrix44,
5372
+ MirroredRepeatWrapping,
5373
+ NearestFilter as NearestFilter2,
5374
+ NearestMipmapLinearFilter,
5375
+ NearestMipmapNearestFilter,
5376
+ PropertyBinding,
5377
+ RGBAFormat as RGBAFormat2,
5378
+ RepeatWrapping,
5379
+ Scene as Scene3,
5380
+ Source,
5381
+ SRGBColorSpace as SRGBColorSpace4,
5382
+ CompressedTexture,
5383
+ Vector3 as Vector38,
5384
+ Quaternion as Quaternion4
5385
+ } from "three";
5386
+
5387
+ // ../../node_modules/three/examples/jsm/utils/TextureUtils.js
5388
+ import {
5389
+ PlaneGeometry,
5390
+ ShaderMaterial as ShaderMaterial2,
5391
+ Uniform,
5392
+ Mesh as Mesh4,
5393
+ PerspectiveCamera,
5394
+ Scene as Scene2,
5395
+ WebGLRenderer,
5396
+ Texture as Texture3,
5397
+ SRGBColorSpace as SRGBColorSpace3
5398
+ } from "three";
5399
+ var _renderer;
5400
+ var fullscreenQuadGeometry;
5401
+ var fullscreenQuadMaterial;
5402
+ var fullscreenQuad;
5403
+ function decompress(texture, maxTextureSize = Infinity, renderer = null) {
5404
+ if (!fullscreenQuadGeometry) fullscreenQuadGeometry = new PlaneGeometry(2, 2, 1, 1);
5405
+ if (!fullscreenQuadMaterial) fullscreenQuadMaterial = new ShaderMaterial2({
5406
+ uniforms: { blitTexture: new Uniform(texture) },
5407
+ vertexShader: `
5408
+ varying vec2 vUv;
5409
+ void main(){
5410
+ vUv = uv;
5411
+ gl_Position = vec4(position.xy * 1.0,0.,.999999);
5412
+ }`,
5413
+ fragmentShader: `
5414
+ uniform sampler2D blitTexture;
5415
+ varying vec2 vUv;
5416
+
5417
+ void main(){
5418
+ gl_FragColor = vec4(vUv.xy, 0, 1);
5419
+
5420
+ #ifdef IS_SRGB
5421
+ gl_FragColor = LinearTosRGB( texture2D( blitTexture, vUv) );
5422
+ #else
5423
+ gl_FragColor = texture2D( blitTexture, vUv);
5424
+ #endif
5425
+ }`
5426
+ });
5427
+ fullscreenQuadMaterial.uniforms.blitTexture.value = texture;
5428
+ fullscreenQuadMaterial.defines.IS_SRGB = texture.colorSpace == SRGBColorSpace3;
5429
+ fullscreenQuadMaterial.needsUpdate = true;
5430
+ if (!fullscreenQuad) {
5431
+ fullscreenQuad = new Mesh4(fullscreenQuadGeometry, fullscreenQuadMaterial);
5432
+ fullscreenQuad.frustrumCulled = false;
5433
+ }
5434
+ const _camera = new PerspectiveCamera();
5435
+ const _scene = new Scene2();
5436
+ _scene.add(fullscreenQuad);
5437
+ if (!renderer) {
5438
+ renderer = _renderer = new WebGLRenderer({ antialias: false });
5439
+ }
5440
+ renderer.setSize(Math.min(texture.image.width, maxTextureSize), Math.min(texture.image.height, maxTextureSize));
5441
+ renderer.clear();
5442
+ renderer.render(_scene, _camera);
5443
+ const readableTexture = new Texture3(renderer.domElement);
5444
+ readableTexture.minFilter = texture.minFilter;
5445
+ readableTexture.magFilter = texture.magFilter;
5446
+ readableTexture.wrapS = texture.wrapS;
5447
+ readableTexture.wrapT = texture.wrapT;
5448
+ readableTexture.name = texture.name;
5449
+ if (_renderer) {
5450
+ _renderer.dispose();
5451
+ _renderer = null;
5452
+ }
5453
+ return readableTexture;
5454
+ }
5455
+
5456
+ // ../../node_modules/three/examples/jsm/exporters/GLTFExporter.js
5457
+ var KHR_mesh_quantization_ExtraAttrTypes = {
5458
+ POSITION: [
5459
+ "byte",
5460
+ "byte normalized",
5461
+ "unsigned byte",
5462
+ "unsigned byte normalized",
5463
+ "short",
5464
+ "short normalized",
5465
+ "unsigned short",
5466
+ "unsigned short normalized"
5467
+ ],
5468
+ NORMAL: [
5469
+ "byte normalized",
5470
+ "short normalized"
5471
+ ],
5472
+ TANGENT: [
5473
+ "byte normalized",
5474
+ "short normalized"
5475
+ ],
5476
+ TEXCOORD: [
5477
+ "byte",
5478
+ "byte normalized",
5479
+ "unsigned byte",
5480
+ "short",
5481
+ "short normalized",
5482
+ "unsigned short"
5483
+ ]
5484
+ };
5485
+ var GLTFExporter = class {
5486
+ constructor() {
5487
+ this.pluginCallbacks = [];
5488
+ this.register(function(writer) {
5489
+ return new GLTFLightExtension(writer);
5490
+ });
5491
+ this.register(function(writer) {
5492
+ return new GLTFMaterialsUnlitExtension(writer);
5493
+ });
5494
+ this.register(function(writer) {
5495
+ return new GLTFMaterialsTransmissionExtension(writer);
5496
+ });
5497
+ this.register(function(writer) {
5498
+ return new GLTFMaterialsVolumeExtension(writer);
5499
+ });
5500
+ this.register(function(writer) {
5501
+ return new GLTFMaterialsIorExtension(writer);
5502
+ });
5503
+ this.register(function(writer) {
5504
+ return new GLTFMaterialsSpecularExtension(writer);
5505
+ });
5506
+ this.register(function(writer) {
5507
+ return new GLTFMaterialsClearcoatExtension(writer);
5508
+ });
5509
+ this.register(function(writer) {
5510
+ return new GLTFMaterialsIridescenceExtension(writer);
5511
+ });
5512
+ this.register(function(writer) {
5513
+ return new GLTFMaterialsSheenExtension(writer);
5514
+ });
5515
+ this.register(function(writer) {
5516
+ return new GLTFMaterialsAnisotropyExtension(writer);
5517
+ });
5518
+ this.register(function(writer) {
5519
+ return new GLTFMaterialsEmissiveStrengthExtension(writer);
5520
+ });
5521
+ this.register(function(writer) {
5522
+ return new GLTFMeshGpuInstancing(writer);
5523
+ });
5524
+ }
5525
+ register(callback) {
5526
+ if (this.pluginCallbacks.indexOf(callback) === -1) {
5527
+ this.pluginCallbacks.push(callback);
5528
+ }
5529
+ return this;
5530
+ }
5531
+ unregister(callback) {
5532
+ if (this.pluginCallbacks.indexOf(callback) !== -1) {
5533
+ this.pluginCallbacks.splice(this.pluginCallbacks.indexOf(callback), 1);
5534
+ }
5535
+ return this;
5536
+ }
5537
+ /**
5538
+ * Parse scenes and generate GLTF output
5539
+ * @param {Scene or [THREE.Scenes]} input Scene or Array of THREE.Scenes
5540
+ * @param {Function} onDone Callback on completed
5541
+ * @param {Function} onError Callback on errors
5542
+ * @param {Object} options options
5543
+ */
5544
+ parse(input, onDone, onError, options) {
5545
+ const writer = new GLTFWriter();
5546
+ const plugins = [];
5547
+ for (let i = 0, il = this.pluginCallbacks.length; i < il; i++) {
5548
+ plugins.push(this.pluginCallbacks[i](writer));
5549
+ }
5550
+ writer.setPlugins(plugins);
5551
+ writer.write(input, onDone, options).catch(onError);
5552
+ }
5553
+ parseAsync(input, options) {
5554
+ const scope = this;
5555
+ return new Promise(function(resolve, reject) {
5556
+ scope.parse(input, resolve, reject, options);
5557
+ });
5558
+ }
5559
+ };
5560
+ var WEBGL_CONSTANTS = {
5561
+ POINTS: 0,
5562
+ LINES: 1,
5563
+ LINE_LOOP: 2,
5564
+ LINE_STRIP: 3,
5565
+ TRIANGLES: 4,
5566
+ TRIANGLE_STRIP: 5,
5567
+ TRIANGLE_FAN: 6,
5568
+ BYTE: 5120,
5569
+ UNSIGNED_BYTE: 5121,
5570
+ SHORT: 5122,
5571
+ UNSIGNED_SHORT: 5123,
5572
+ INT: 5124,
5573
+ UNSIGNED_INT: 5125,
5574
+ FLOAT: 5126,
5575
+ ARRAY_BUFFER: 34962,
5576
+ ELEMENT_ARRAY_BUFFER: 34963,
5577
+ NEAREST: 9728,
5578
+ LINEAR: 9729,
5579
+ NEAREST_MIPMAP_NEAREST: 9984,
5580
+ LINEAR_MIPMAP_NEAREST: 9985,
5581
+ NEAREST_MIPMAP_LINEAR: 9986,
5582
+ LINEAR_MIPMAP_LINEAR: 9987,
5583
+ CLAMP_TO_EDGE: 33071,
5584
+ MIRRORED_REPEAT: 33648,
5585
+ REPEAT: 10497
5586
+ };
5587
+ var KHR_MESH_QUANTIZATION = "KHR_mesh_quantization";
5588
+ var THREE_TO_WEBGL = {};
5589
+ THREE_TO_WEBGL[NearestFilter2] = WEBGL_CONSTANTS.NEAREST;
5590
+ THREE_TO_WEBGL[NearestMipmapNearestFilter] = WEBGL_CONSTANTS.NEAREST_MIPMAP_NEAREST;
5591
+ THREE_TO_WEBGL[NearestMipmapLinearFilter] = WEBGL_CONSTANTS.NEAREST_MIPMAP_LINEAR;
5592
+ THREE_TO_WEBGL[LinearFilter] = WEBGL_CONSTANTS.LINEAR;
5593
+ THREE_TO_WEBGL[LinearMipmapNearestFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_NEAREST;
5594
+ THREE_TO_WEBGL[LinearMipmapLinearFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_LINEAR;
5595
+ THREE_TO_WEBGL[ClampToEdgeWrapping] = WEBGL_CONSTANTS.CLAMP_TO_EDGE;
5596
+ THREE_TO_WEBGL[RepeatWrapping] = WEBGL_CONSTANTS.REPEAT;
5597
+ THREE_TO_WEBGL[MirroredRepeatWrapping] = WEBGL_CONSTANTS.MIRRORED_REPEAT;
5598
+ var PATH_PROPERTIES = {
5599
+ scale: "scale",
5600
+ position: "translation",
5601
+ quaternion: "rotation",
5602
+ morphTargetInfluences: "weights"
5603
+ };
5604
+ var DEFAULT_SPECULAR_COLOR = new Color5();
5605
+ var GLB_HEADER_BYTES = 12;
5606
+ var GLB_HEADER_MAGIC = 1179937895;
5607
+ var GLB_VERSION = 2;
5608
+ var GLB_CHUNK_PREFIX_BYTES = 8;
5609
+ var GLB_CHUNK_TYPE_JSON = 1313821514;
5610
+ var GLB_CHUNK_TYPE_BIN = 5130562;
5611
+ function equalArray(array1, array2) {
5612
+ return array1.length === array2.length && array1.every(function(element, index) {
5613
+ return element === array2[index];
5614
+ });
5615
+ }
5616
+ function stringToArrayBuffer(text) {
5617
+ return new TextEncoder().encode(text).buffer;
5618
+ }
5619
+ function isIdentityMatrix(matrix) {
5620
+ return equalArray(matrix.elements, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
5621
+ }
5622
+ function getMinMax(attribute, start, count) {
5623
+ const output = {
5624
+ min: new Array(attribute.itemSize).fill(Number.POSITIVE_INFINITY),
5625
+ max: new Array(attribute.itemSize).fill(Number.NEGATIVE_INFINITY)
5626
+ };
5627
+ for (let i = start; i < start + count; i++) {
5628
+ for (let a = 0; a < attribute.itemSize; a++) {
5629
+ let value;
5630
+ if (attribute.itemSize > 4) {
5631
+ value = attribute.array[i * attribute.itemSize + a];
5632
+ } else {
5633
+ if (a === 0) value = attribute.getX(i);
5634
+ else if (a === 1) value = attribute.getY(i);
5635
+ else if (a === 2) value = attribute.getZ(i);
5636
+ else if (a === 3) value = attribute.getW(i);
5637
+ if (attribute.normalized === true) {
5638
+ value = MathUtils2.normalize(value, attribute.array);
5639
+ }
5640
+ }
5641
+ output.min[a] = Math.min(output.min[a], value);
5642
+ output.max[a] = Math.max(output.max[a], value);
5643
+ }
5644
+ }
5645
+ return output;
5646
+ }
5647
+ function getPaddedBufferSize(bufferSize) {
5648
+ return Math.ceil(bufferSize / 4) * 4;
5649
+ }
5650
+ function getPaddedArrayBuffer(arrayBuffer, paddingByte = 0) {
5651
+ const paddedLength = getPaddedBufferSize(arrayBuffer.byteLength);
5652
+ if (paddedLength !== arrayBuffer.byteLength) {
5653
+ const array = new Uint8Array(paddedLength);
5654
+ array.set(new Uint8Array(arrayBuffer));
5655
+ if (paddingByte !== 0) {
5656
+ for (let i = arrayBuffer.byteLength; i < paddedLength; i++) {
5657
+ array[i] = paddingByte;
5658
+ }
5659
+ }
5660
+ return array.buffer;
5661
+ }
5662
+ return arrayBuffer;
5663
+ }
5664
+ function getCanvas() {
5665
+ if (typeof document === "undefined" && typeof OffscreenCanvas !== "undefined") {
5666
+ return new OffscreenCanvas(1, 1);
5667
+ }
5668
+ return document.createElement("canvas");
5669
+ }
5670
+ function getToBlobPromise(canvas, mimeType) {
5671
+ if (canvas.toBlob !== void 0) {
5672
+ return new Promise((resolve) => canvas.toBlob(resolve, mimeType));
5673
+ }
5674
+ let quality;
5675
+ if (mimeType === "image/jpeg") {
5676
+ quality = 0.92;
5677
+ } else if (mimeType === "image/webp") {
5678
+ quality = 0.8;
5679
+ }
5680
+ return canvas.convertToBlob({
5681
+ type: mimeType,
5682
+ quality
5683
+ });
5684
+ }
5685
+ var GLTFWriter = class {
5686
+ constructor() {
5687
+ this.plugins = [];
5688
+ this.options = {};
5689
+ this.pending = [];
5690
+ this.buffers = [];
5691
+ this.byteOffset = 0;
5692
+ this.buffers = [];
5693
+ this.nodeMap = /* @__PURE__ */ new Map();
5694
+ this.skins = [];
5695
+ this.extensionsUsed = {};
5696
+ this.extensionsRequired = {};
5697
+ this.uids = /* @__PURE__ */ new Map();
5698
+ this.uid = 0;
5699
+ this.json = {
5700
+ asset: {
5701
+ version: "2.0",
5702
+ generator: "THREE.GLTFExporter"
5703
+ }
5704
+ };
5705
+ this.cache = {
5706
+ meshes: /* @__PURE__ */ new Map(),
5707
+ attributes: /* @__PURE__ */ new Map(),
5708
+ attributesNormalized: /* @__PURE__ */ new Map(),
5709
+ materials: /* @__PURE__ */ new Map(),
5710
+ textures: /* @__PURE__ */ new Map(),
5711
+ images: /* @__PURE__ */ new Map()
5712
+ };
5713
+ }
5714
+ setPlugins(plugins) {
5715
+ this.plugins = plugins;
5716
+ }
5717
+ /**
5718
+ * Parse scenes and generate GLTF output
5719
+ * @param {Scene or [THREE.Scenes]} input Scene or Array of THREE.Scenes
5720
+ * @param {Function} onDone Callback on completed
5721
+ * @param {Object} options options
5722
+ */
5723
+ async write(input, onDone, options = {}) {
5724
+ this.options = Object.assign({
5725
+ // default options
5726
+ binary: false,
5727
+ trs: false,
5728
+ onlyVisible: true,
5729
+ maxTextureSize: Infinity,
5730
+ animations: [],
5731
+ includeCustomExtensions: false
5732
+ }, options);
5733
+ if (this.options.animations.length > 0) {
5734
+ this.options.trs = true;
5735
+ }
5736
+ this.processInput(input);
5737
+ await Promise.all(this.pending);
5738
+ const writer = this;
5739
+ const buffers = writer.buffers;
5740
+ const json = writer.json;
5741
+ options = writer.options;
5742
+ const extensionsUsed = writer.extensionsUsed;
5743
+ const extensionsRequired = writer.extensionsRequired;
5744
+ const blob = new Blob(buffers, { type: "application/octet-stream" });
5745
+ const extensionsUsedList = Object.keys(extensionsUsed);
5746
+ const extensionsRequiredList = Object.keys(extensionsRequired);
5747
+ if (extensionsUsedList.length > 0) json.extensionsUsed = extensionsUsedList;
5748
+ if (extensionsRequiredList.length > 0) json.extensionsRequired = extensionsRequiredList;
5749
+ if (json.buffers && json.buffers.length > 0) json.buffers[0].byteLength = blob.size;
5750
+ if (options.binary === true) {
5751
+ const reader = new FileReader();
5752
+ reader.readAsArrayBuffer(blob);
5753
+ reader.onloadend = function() {
5754
+ const binaryChunk = getPaddedArrayBuffer(reader.result);
5755
+ const binaryChunkPrefix = new DataView(new ArrayBuffer(GLB_CHUNK_PREFIX_BYTES));
5756
+ binaryChunkPrefix.setUint32(0, binaryChunk.byteLength, true);
5757
+ binaryChunkPrefix.setUint32(4, GLB_CHUNK_TYPE_BIN, true);
5758
+ const jsonChunk = getPaddedArrayBuffer(stringToArrayBuffer(JSON.stringify(json)), 32);
5759
+ const jsonChunkPrefix = new DataView(new ArrayBuffer(GLB_CHUNK_PREFIX_BYTES));
5760
+ jsonChunkPrefix.setUint32(0, jsonChunk.byteLength, true);
5761
+ jsonChunkPrefix.setUint32(4, GLB_CHUNK_TYPE_JSON, true);
5762
+ const header = new ArrayBuffer(GLB_HEADER_BYTES);
5763
+ const headerView = new DataView(header);
5764
+ headerView.setUint32(0, GLB_HEADER_MAGIC, true);
5765
+ headerView.setUint32(4, GLB_VERSION, true);
5766
+ const totalByteLength = GLB_HEADER_BYTES + jsonChunkPrefix.byteLength + jsonChunk.byteLength + binaryChunkPrefix.byteLength + binaryChunk.byteLength;
5767
+ headerView.setUint32(8, totalByteLength, true);
5768
+ const glbBlob = new Blob([
5769
+ header,
5770
+ jsonChunkPrefix,
5771
+ jsonChunk,
5772
+ binaryChunkPrefix,
5773
+ binaryChunk
5774
+ ], { type: "application/octet-stream" });
5775
+ const glbReader = new FileReader();
5776
+ glbReader.readAsArrayBuffer(glbBlob);
5777
+ glbReader.onloadend = function() {
5778
+ onDone(glbReader.result);
5779
+ };
5780
+ };
5781
+ } else {
5782
+ if (json.buffers && json.buffers.length > 0) {
5783
+ const reader = new FileReader();
5784
+ reader.readAsDataURL(blob);
5785
+ reader.onloadend = function() {
5786
+ const base64data = reader.result;
5787
+ json.buffers[0].uri = base64data;
5788
+ onDone(json);
5789
+ };
5790
+ } else {
5791
+ onDone(json);
5792
+ }
5793
+ }
5794
+ }
5795
+ /**
5796
+ * Serializes a userData.
5797
+ *
5798
+ * @param {THREE.Object3D|THREE.Material} object
5799
+ * @param {Object} objectDef
5800
+ */
5801
+ serializeUserData(object, objectDef) {
5802
+ if (Object.keys(object.userData).length === 0) return;
5803
+ const options = this.options;
5804
+ const extensionsUsed = this.extensionsUsed;
5805
+ try {
5806
+ const json = JSON.parse(JSON.stringify(object.userData));
5807
+ if (options.includeCustomExtensions && json.gltfExtensions) {
5808
+ if (objectDef.extensions === void 0) objectDef.extensions = {};
5809
+ for (const extensionName in json.gltfExtensions) {
5810
+ objectDef.extensions[extensionName] = json.gltfExtensions[extensionName];
5811
+ extensionsUsed[extensionName] = true;
5812
+ }
5813
+ delete json.gltfExtensions;
5814
+ }
5815
+ if (Object.keys(json).length > 0) objectDef.extras = json;
5816
+ } catch (error) {
5817
+ console.warn("THREE.GLTFExporter: userData of '" + object.name + "' won't be serialized because of JSON.stringify error - " + error.message);
5818
+ }
5819
+ }
5820
+ /**
5821
+ * Returns ids for buffer attributes.
5822
+ * @param {Object} object
5823
+ * @return {Integer}
5824
+ */
5825
+ getUID(attribute, isRelativeCopy = false) {
5826
+ if (this.uids.has(attribute) === false) {
5827
+ const uids2 = /* @__PURE__ */ new Map();
5828
+ uids2.set(true, this.uid++);
5829
+ uids2.set(false, this.uid++);
5830
+ this.uids.set(attribute, uids2);
5831
+ }
5832
+ const uids = this.uids.get(attribute);
5833
+ return uids.get(isRelativeCopy);
5834
+ }
5835
+ /**
5836
+ * Checks if normal attribute values are normalized.
5837
+ *
5838
+ * @param {BufferAttribute} normal
5839
+ * @returns {Boolean}
5840
+ */
5841
+ isNormalizedNormalAttribute(normal) {
5842
+ const cache = this.cache;
5843
+ if (cache.attributesNormalized.has(normal)) return false;
5844
+ const v = new Vector38();
5845
+ for (let i = 0, il = normal.count; i < il; i++) {
5846
+ if (Math.abs(v.fromBufferAttribute(normal, i).length() - 1) > 5e-4) return false;
5847
+ }
5848
+ return true;
5849
+ }
5850
+ /**
5851
+ * Creates normalized normal buffer attribute.
5852
+ *
5853
+ * @param {BufferAttribute} normal
5854
+ * @returns {BufferAttribute}
5855
+ *
5856
+ */
5857
+ createNormalizedNormalAttribute(normal) {
5858
+ const cache = this.cache;
5859
+ if (cache.attributesNormalized.has(normal)) return cache.attributesNormalized.get(normal);
5860
+ const attribute = normal.clone();
5861
+ const v = new Vector38();
5862
+ for (let i = 0, il = attribute.count; i < il; i++) {
5863
+ v.fromBufferAttribute(attribute, i);
5864
+ if (v.x === 0 && v.y === 0 && v.z === 0) {
5865
+ v.setX(1);
5866
+ } else {
5867
+ v.normalize();
5868
+ }
5869
+ attribute.setXYZ(i, v.x, v.y, v.z);
5870
+ }
5871
+ cache.attributesNormalized.set(normal, attribute);
5872
+ return attribute;
5873
+ }
5874
+ /**
5875
+ * Applies a texture transform, if present, to the map definition. Requires
5876
+ * the KHR_texture_transform extension.
5877
+ *
5878
+ * @param {Object} mapDef
5879
+ * @param {THREE.Texture} texture
5880
+ */
5881
+ applyTextureTransform(mapDef, texture) {
5882
+ let didTransform = false;
5883
+ const transformDef = {};
5884
+ if (texture.offset.x !== 0 || texture.offset.y !== 0) {
5885
+ transformDef.offset = texture.offset.toArray();
5886
+ didTransform = true;
5887
+ }
5888
+ if (texture.rotation !== 0) {
5889
+ transformDef.rotation = texture.rotation;
5890
+ didTransform = true;
5891
+ }
5892
+ if (texture.repeat.x !== 1 || texture.repeat.y !== 1) {
5893
+ transformDef.scale = texture.repeat.toArray();
5894
+ didTransform = true;
5895
+ }
5896
+ if (didTransform) {
5897
+ mapDef.extensions = mapDef.extensions || {};
5898
+ mapDef.extensions["KHR_texture_transform"] = transformDef;
5899
+ this.extensionsUsed["KHR_texture_transform"] = true;
5900
+ }
5901
+ }
5902
+ buildMetalRoughTexture(metalnessMap, roughnessMap) {
5903
+ if (metalnessMap === roughnessMap) return metalnessMap;
5904
+ function getEncodingConversion(map) {
5905
+ if (map.colorSpace === SRGBColorSpace4) {
5906
+ return function SRGBToLinear(c) {
5907
+ return c < 0.04045 ? c * 0.0773993808 : Math.pow(c * 0.9478672986 + 0.0521327014, 2.4);
5908
+ };
5909
+ }
5910
+ return function LinearToLinear(c) {
5911
+ return c;
5912
+ };
5913
+ }
5914
+ console.warn("THREE.GLTFExporter: Merged metalnessMap and roughnessMap textures.");
5915
+ if (metalnessMap instanceof CompressedTexture) {
5916
+ metalnessMap = decompress(metalnessMap);
5917
+ }
5918
+ if (roughnessMap instanceof CompressedTexture) {
5919
+ roughnessMap = decompress(roughnessMap);
5920
+ }
5921
+ const metalness = metalnessMap ? metalnessMap.image : null;
5922
+ const roughness = roughnessMap ? roughnessMap.image : null;
5923
+ const width = Math.max(metalness ? metalness.width : 0, roughness ? roughness.width : 0);
5924
+ const height = Math.max(metalness ? metalness.height : 0, roughness ? roughness.height : 0);
5925
+ const canvas = getCanvas();
5926
+ canvas.width = width;
5927
+ canvas.height = height;
5928
+ const context = canvas.getContext("2d");
5929
+ context.fillStyle = "#00ffff";
5930
+ context.fillRect(0, 0, width, height);
5931
+ const composite = context.getImageData(0, 0, width, height);
5932
+ if (metalness) {
5933
+ context.drawImage(metalness, 0, 0, width, height);
5934
+ const convert = getEncodingConversion(metalnessMap);
5935
+ const data = context.getImageData(0, 0, width, height).data;
5936
+ for (let i = 2; i < data.length; i += 4) {
5937
+ composite.data[i] = convert(data[i] / 256) * 256;
5938
+ }
5939
+ }
5940
+ if (roughness) {
5941
+ context.drawImage(roughness, 0, 0, width, height);
5942
+ const convert = getEncodingConversion(roughnessMap);
5943
+ const data = context.getImageData(0, 0, width, height).data;
5944
+ for (let i = 1; i < data.length; i += 4) {
5945
+ composite.data[i] = convert(data[i] / 256) * 256;
5946
+ }
5947
+ }
5948
+ context.putImageData(composite, 0, 0);
5949
+ const reference = metalnessMap || roughnessMap;
5950
+ const texture = reference.clone();
5951
+ texture.source = new Source(canvas);
5952
+ texture.colorSpace = NoColorSpace;
5953
+ texture.channel = (metalnessMap || roughnessMap).channel;
5954
+ if (metalnessMap && roughnessMap && metalnessMap.channel !== roughnessMap.channel) {
5955
+ console.warn("THREE.GLTFExporter: UV channels for metalnessMap and roughnessMap textures must match.");
5956
+ }
5957
+ return texture;
5958
+ }
5959
+ /**
5960
+ * Process a buffer to append to the default one.
5961
+ * @param {ArrayBuffer} buffer
5962
+ * @return {Integer}
5963
+ */
5964
+ processBuffer(buffer) {
5965
+ const json = this.json;
5966
+ const buffers = this.buffers;
5967
+ if (!json.buffers) json.buffers = [{ byteLength: 0 }];
5968
+ buffers.push(buffer);
5969
+ return 0;
5970
+ }
5971
+ /**
5972
+ * Process and generate a BufferView
5973
+ * @param {BufferAttribute} attribute
5974
+ * @param {number} componentType
5975
+ * @param {number} start
5976
+ * @param {number} count
5977
+ * @param {number} target (Optional) Target usage of the BufferView
5978
+ * @return {Object}
5979
+ */
5980
+ processBufferView(attribute, componentType, start, count, target) {
5981
+ const json = this.json;
5982
+ if (!json.bufferViews) json.bufferViews = [];
5983
+ let componentSize;
5984
+ switch (componentType) {
5985
+ case WEBGL_CONSTANTS.BYTE:
5986
+ case WEBGL_CONSTANTS.UNSIGNED_BYTE:
5987
+ componentSize = 1;
5988
+ break;
5989
+ case WEBGL_CONSTANTS.SHORT:
5990
+ case WEBGL_CONSTANTS.UNSIGNED_SHORT:
5991
+ componentSize = 2;
5992
+ break;
5993
+ default:
5994
+ componentSize = 4;
5995
+ }
5996
+ const byteLength = getPaddedBufferSize(count * attribute.itemSize * componentSize);
5997
+ const dataView = new DataView(new ArrayBuffer(byteLength));
5998
+ let offset = 0;
5999
+ for (let i = start; i < start + count; i++) {
6000
+ for (let a = 0; a < attribute.itemSize; a++) {
6001
+ let value;
6002
+ if (attribute.itemSize > 4) {
6003
+ value = attribute.array[i * attribute.itemSize + a];
6004
+ } else {
6005
+ if (a === 0) value = attribute.getX(i);
6006
+ else if (a === 1) value = attribute.getY(i);
6007
+ else if (a === 2) value = attribute.getZ(i);
6008
+ else if (a === 3) value = attribute.getW(i);
6009
+ if (attribute.normalized === true) {
6010
+ value = MathUtils2.normalize(value, attribute.array);
6011
+ }
6012
+ }
6013
+ if (componentType === WEBGL_CONSTANTS.FLOAT) {
6014
+ dataView.setFloat32(offset, value, true);
6015
+ } else if (componentType === WEBGL_CONSTANTS.INT) {
6016
+ dataView.setInt32(offset, value, true);
6017
+ } else if (componentType === WEBGL_CONSTANTS.UNSIGNED_INT) {
6018
+ dataView.setUint32(offset, value, true);
6019
+ } else if (componentType === WEBGL_CONSTANTS.SHORT) {
6020
+ dataView.setInt16(offset, value, true);
6021
+ } else if (componentType === WEBGL_CONSTANTS.UNSIGNED_SHORT) {
6022
+ dataView.setUint16(offset, value, true);
6023
+ } else if (componentType === WEBGL_CONSTANTS.BYTE) {
6024
+ dataView.setInt8(offset, value);
6025
+ } else if (componentType === WEBGL_CONSTANTS.UNSIGNED_BYTE) {
6026
+ dataView.setUint8(offset, value);
6027
+ }
6028
+ offset += componentSize;
6029
+ }
6030
+ }
6031
+ const bufferViewDef = {
6032
+ buffer: this.processBuffer(dataView.buffer),
6033
+ byteOffset: this.byteOffset,
6034
+ byteLength
6035
+ };
6036
+ if (target !== void 0) bufferViewDef.target = target;
6037
+ if (target === WEBGL_CONSTANTS.ARRAY_BUFFER) {
6038
+ bufferViewDef.byteStride = attribute.itemSize * componentSize;
6039
+ }
6040
+ this.byteOffset += byteLength;
6041
+ json.bufferViews.push(bufferViewDef);
6042
+ const output = {
6043
+ id: json.bufferViews.length - 1,
6044
+ byteLength: 0
6045
+ };
6046
+ return output;
6047
+ }
6048
+ /**
6049
+ * Process and generate a BufferView from an image Blob.
6050
+ * @param {Blob} blob
6051
+ * @return {Promise<Integer>}
6052
+ */
6053
+ processBufferViewImage(blob) {
6054
+ const writer = this;
6055
+ const json = writer.json;
6056
+ if (!json.bufferViews) json.bufferViews = [];
6057
+ return new Promise(function(resolve) {
6058
+ const reader = new FileReader();
6059
+ reader.readAsArrayBuffer(blob);
6060
+ reader.onloadend = function() {
6061
+ const buffer = getPaddedArrayBuffer(reader.result);
6062
+ const bufferViewDef = {
6063
+ buffer: writer.processBuffer(buffer),
6064
+ byteOffset: writer.byteOffset,
6065
+ byteLength: buffer.byteLength
6066
+ };
6067
+ writer.byteOffset += buffer.byteLength;
6068
+ resolve(json.bufferViews.push(bufferViewDef) - 1);
6069
+ };
6070
+ });
6071
+ }
6072
+ /**
6073
+ * Process attribute to generate an accessor
6074
+ * @param {BufferAttribute} attribute Attribute to process
6075
+ * @param {THREE.BufferGeometry} geometry (Optional) Geometry used for truncated draw range
6076
+ * @param {Integer} start (Optional)
6077
+ * @param {Integer} count (Optional)
6078
+ * @return {Integer|null} Index of the processed accessor on the "accessors" array
6079
+ */
6080
+ processAccessor(attribute, geometry, start, count) {
6081
+ const json = this.json;
6082
+ const types = {
6083
+ 1: "SCALAR",
6084
+ 2: "VEC2",
6085
+ 3: "VEC3",
6086
+ 4: "VEC4",
6087
+ 9: "MAT3",
6088
+ 16: "MAT4"
6089
+ };
6090
+ let componentType;
6091
+ if (attribute.array.constructor === Float32Array) {
6092
+ componentType = WEBGL_CONSTANTS.FLOAT;
6093
+ } else if (attribute.array.constructor === Int32Array) {
6094
+ componentType = WEBGL_CONSTANTS.INT;
6095
+ } else if (attribute.array.constructor === Uint32Array) {
6096
+ componentType = WEBGL_CONSTANTS.UNSIGNED_INT;
6097
+ } else if (attribute.array.constructor === Int16Array) {
6098
+ componentType = WEBGL_CONSTANTS.SHORT;
6099
+ } else if (attribute.array.constructor === Uint16Array) {
6100
+ componentType = WEBGL_CONSTANTS.UNSIGNED_SHORT;
6101
+ } else if (attribute.array.constructor === Int8Array) {
6102
+ componentType = WEBGL_CONSTANTS.BYTE;
6103
+ } else if (attribute.array.constructor === Uint8Array) {
6104
+ componentType = WEBGL_CONSTANTS.UNSIGNED_BYTE;
6105
+ } else {
6106
+ throw new Error("THREE.GLTFExporter: Unsupported bufferAttribute component type: " + attribute.array.constructor.name);
6107
+ }
6108
+ if (start === void 0) start = 0;
6109
+ if (count === void 0 || count === Infinity) count = attribute.count;
6110
+ if (count === 0) return null;
6111
+ const minMax = getMinMax(attribute, start, count);
6112
+ let bufferViewTarget;
6113
+ if (geometry !== void 0) {
6114
+ bufferViewTarget = attribute === geometry.index ? WEBGL_CONSTANTS.ELEMENT_ARRAY_BUFFER : WEBGL_CONSTANTS.ARRAY_BUFFER;
6115
+ }
6116
+ const bufferView = this.processBufferView(attribute, componentType, start, count, bufferViewTarget);
6117
+ const accessorDef = {
6118
+ bufferView: bufferView.id,
6119
+ byteOffset: bufferView.byteOffset,
6120
+ componentType,
6121
+ count,
6122
+ max: minMax.max,
6123
+ min: minMax.min,
6124
+ type: types[attribute.itemSize]
6125
+ };
6126
+ if (attribute.normalized === true) accessorDef.normalized = true;
6127
+ if (!json.accessors) json.accessors = [];
6128
+ return json.accessors.push(accessorDef) - 1;
6129
+ }
6130
+ /**
6131
+ * Process image
6132
+ * @param {Image} image to process
6133
+ * @param {Integer} format of the image (RGBAFormat)
6134
+ * @param {Boolean} flipY before writing out the image
6135
+ * @param {String} mimeType export format
6136
+ * @return {Integer} Index of the processed texture in the "images" array
6137
+ */
6138
+ processImage(image, format, flipY, mimeType = "image/png") {
6139
+ if (image !== null) {
6140
+ const writer = this;
6141
+ const cache = writer.cache;
6142
+ const json = writer.json;
6143
+ const options = writer.options;
6144
+ const pending = writer.pending;
6145
+ if (!cache.images.has(image)) cache.images.set(image, {});
6146
+ const cachedImages = cache.images.get(image);
6147
+ const key = mimeType + ":flipY/" + flipY.toString();
6148
+ if (cachedImages[key] !== void 0) return cachedImages[key];
6149
+ if (!json.images) json.images = [];
6150
+ const imageDef = { mimeType };
6151
+ const canvas = getCanvas();
6152
+ canvas.width = Math.min(image.width, options.maxTextureSize);
6153
+ canvas.height = Math.min(image.height, options.maxTextureSize);
6154
+ const ctx = canvas.getContext("2d");
6155
+ if (flipY === true) {
6156
+ ctx.translate(0, canvas.height);
6157
+ ctx.scale(1, -1);
6158
+ }
6159
+ if (image.data !== void 0) {
6160
+ if (format !== RGBAFormat2) {
6161
+ console.error("GLTFExporter: Only RGBAFormat is supported.", format);
6162
+ }
6163
+ if (image.width > options.maxTextureSize || image.height > options.maxTextureSize) {
6164
+ console.warn("GLTFExporter: Image size is bigger than maxTextureSize", image);
6165
+ }
6166
+ const data = new Uint8ClampedArray(image.height * image.width * 4);
6167
+ for (let i = 0; i < data.length; i += 4) {
6168
+ data[i + 0] = image.data[i + 0];
6169
+ data[i + 1] = image.data[i + 1];
6170
+ data[i + 2] = image.data[i + 2];
6171
+ data[i + 3] = image.data[i + 3];
6172
+ }
6173
+ ctx.putImageData(new ImageData(data, image.width, image.height), 0, 0);
6174
+ } else {
6175
+ ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
6176
+ }
6177
+ if (options.binary === true) {
6178
+ pending.push(
6179
+ getToBlobPromise(canvas, mimeType).then((blob) => writer.processBufferViewImage(blob)).then((bufferViewIndex) => {
6180
+ imageDef.bufferView = bufferViewIndex;
6181
+ })
6182
+ );
6183
+ } else {
6184
+ if (canvas.toDataURL !== void 0) {
6185
+ imageDef.uri = canvas.toDataURL(mimeType);
6186
+ } else {
6187
+ pending.push(
6188
+ getToBlobPromise(canvas, mimeType).then((blob) => new FileReader().readAsDataURL(blob)).then((dataURL) => {
6189
+ imageDef.uri = dataURL;
6190
+ })
6191
+ );
6192
+ }
6193
+ }
6194
+ const index = json.images.push(imageDef) - 1;
6195
+ cachedImages[key] = index;
6196
+ return index;
6197
+ } else {
6198
+ throw new Error("THREE.GLTFExporter: No valid image data found. Unable to process texture.");
6199
+ }
6200
+ }
6201
+ /**
6202
+ * Process sampler
6203
+ * @param {Texture} map Texture to process
6204
+ * @return {Integer} Index of the processed texture in the "samplers" array
6205
+ */
6206
+ processSampler(map) {
6207
+ const json = this.json;
6208
+ if (!json.samplers) json.samplers = [];
6209
+ const samplerDef = {
6210
+ magFilter: THREE_TO_WEBGL[map.magFilter],
6211
+ minFilter: THREE_TO_WEBGL[map.minFilter],
6212
+ wrapS: THREE_TO_WEBGL[map.wrapS],
6213
+ wrapT: THREE_TO_WEBGL[map.wrapT]
6214
+ };
6215
+ return json.samplers.push(samplerDef) - 1;
6216
+ }
6217
+ /**
6218
+ * Process texture
6219
+ * @param {Texture} map Map to process
6220
+ * @return {Integer} Index of the processed texture in the "textures" array
6221
+ */
6222
+ processTexture(map) {
6223
+ const writer = this;
6224
+ const options = writer.options;
6225
+ const cache = this.cache;
6226
+ const json = this.json;
6227
+ if (cache.textures.has(map)) return cache.textures.get(map);
6228
+ if (!json.textures) json.textures = [];
6229
+ if (map instanceof CompressedTexture) {
6230
+ map = decompress(map, options.maxTextureSize);
6231
+ }
6232
+ let mimeType = map.userData.mimeType;
6233
+ if (mimeType === "image/webp") mimeType = "image/png";
6234
+ const textureDef = {
6235
+ sampler: this.processSampler(map),
6236
+ source: this.processImage(map.image, map.format, map.flipY, mimeType)
6237
+ };
6238
+ if (map.name) textureDef.name = map.name;
6239
+ this._invokeAll(function(ext) {
6240
+ ext.writeTexture && ext.writeTexture(map, textureDef);
6241
+ });
6242
+ const index = json.textures.push(textureDef) - 1;
6243
+ cache.textures.set(map, index);
6244
+ return index;
6245
+ }
6246
+ /**
6247
+ * Process material
6248
+ * @param {THREE.Material} material Material to process
6249
+ * @return {Integer|null} Index of the processed material in the "materials" array
6250
+ */
6251
+ processMaterial(material) {
6252
+ const cache = this.cache;
6253
+ const json = this.json;
6254
+ if (cache.materials.has(material)) return cache.materials.get(material);
6255
+ if (material.isShaderMaterial) {
6256
+ console.warn("GLTFExporter: THREE.ShaderMaterial not supported.");
6257
+ return null;
6258
+ }
6259
+ if (!json.materials) json.materials = [];
6260
+ const materialDef = { pbrMetallicRoughness: {} };
6261
+ if (material.isMeshStandardMaterial !== true && material.isMeshBasicMaterial !== true) {
6262
+ console.warn("GLTFExporter: Use MeshStandardMaterial or MeshBasicMaterial for best results.");
6263
+ }
6264
+ const color = material.color.toArray().concat([material.opacity]);
6265
+ if (!equalArray(color, [1, 1, 1, 1])) {
6266
+ materialDef.pbrMetallicRoughness.baseColorFactor = color;
6267
+ }
6268
+ if (material.isMeshStandardMaterial) {
6269
+ materialDef.pbrMetallicRoughness.metallicFactor = material.metalness;
6270
+ materialDef.pbrMetallicRoughness.roughnessFactor = material.roughness;
6271
+ } else {
6272
+ materialDef.pbrMetallicRoughness.metallicFactor = 0.5;
6273
+ materialDef.pbrMetallicRoughness.roughnessFactor = 0.5;
6274
+ }
6275
+ if (material.metalnessMap || material.roughnessMap) {
6276
+ const metalRoughTexture = this.buildMetalRoughTexture(material.metalnessMap, material.roughnessMap);
6277
+ const metalRoughMapDef = {
6278
+ index: this.processTexture(metalRoughTexture),
6279
+ channel: metalRoughTexture.channel
6280
+ };
6281
+ this.applyTextureTransform(metalRoughMapDef, metalRoughTexture);
6282
+ materialDef.pbrMetallicRoughness.metallicRoughnessTexture = metalRoughMapDef;
6283
+ }
6284
+ if (material.map) {
6285
+ const baseColorMapDef = {
6286
+ index: this.processTexture(material.map),
6287
+ texCoord: material.map.channel
6288
+ };
6289
+ this.applyTextureTransform(baseColorMapDef, material.map);
6290
+ materialDef.pbrMetallicRoughness.baseColorTexture = baseColorMapDef;
6291
+ }
6292
+ if (material.emissive) {
6293
+ const emissive = material.emissive;
6294
+ const maxEmissiveComponent = Math.max(emissive.r, emissive.g, emissive.b);
6295
+ if (maxEmissiveComponent > 0) {
6296
+ materialDef.emissiveFactor = material.emissive.toArray();
6297
+ }
6298
+ if (material.emissiveMap) {
6299
+ const emissiveMapDef = {
6300
+ index: this.processTexture(material.emissiveMap),
6301
+ texCoord: material.emissiveMap.channel
6302
+ };
6303
+ this.applyTextureTransform(emissiveMapDef, material.emissiveMap);
6304
+ materialDef.emissiveTexture = emissiveMapDef;
6305
+ }
6306
+ }
6307
+ if (material.normalMap) {
6308
+ const normalMapDef = {
6309
+ index: this.processTexture(material.normalMap),
6310
+ texCoord: material.normalMap.channel
6311
+ };
6312
+ if (material.normalScale && material.normalScale.x !== 1) {
6313
+ normalMapDef.scale = material.normalScale.x;
6314
+ }
6315
+ this.applyTextureTransform(normalMapDef, material.normalMap);
6316
+ materialDef.normalTexture = normalMapDef;
6317
+ }
6318
+ if (material.aoMap) {
6319
+ const occlusionMapDef = {
6320
+ index: this.processTexture(material.aoMap),
6321
+ texCoord: material.aoMap.channel
6322
+ };
6323
+ if (material.aoMapIntensity !== 1) {
6324
+ occlusionMapDef.strength = material.aoMapIntensity;
6325
+ }
6326
+ this.applyTextureTransform(occlusionMapDef, material.aoMap);
6327
+ materialDef.occlusionTexture = occlusionMapDef;
6328
+ }
6329
+ if (material.transparent) {
6330
+ materialDef.alphaMode = "BLEND";
6331
+ } else {
6332
+ if (material.alphaTest > 0) {
6333
+ materialDef.alphaMode = "MASK";
6334
+ materialDef.alphaCutoff = material.alphaTest;
6335
+ }
6336
+ }
6337
+ if (material.side === DoubleSide2) materialDef.doubleSided = true;
6338
+ if (material.name !== "") materialDef.name = material.name;
6339
+ this.serializeUserData(material, materialDef);
6340
+ this._invokeAll(function(ext) {
6341
+ ext.writeMaterial && ext.writeMaterial(material, materialDef);
6342
+ });
6343
+ const index = json.materials.push(materialDef) - 1;
6344
+ cache.materials.set(material, index);
6345
+ return index;
6346
+ }
6347
+ /**
6348
+ * Process mesh
6349
+ * @param {THREE.Mesh} mesh Mesh to process
6350
+ * @return {Integer|null} Index of the processed mesh in the "meshes" array
6351
+ */
6352
+ processMesh(mesh) {
6353
+ const cache = this.cache;
6354
+ const json = this.json;
6355
+ const meshCacheKeyParts = [mesh.geometry.uuid];
6356
+ if (Array.isArray(mesh.material)) {
6357
+ for (let i = 0, l = mesh.material.length; i < l; i++) {
6358
+ meshCacheKeyParts.push(mesh.material[i].uuid);
6359
+ }
6360
+ } else {
6361
+ meshCacheKeyParts.push(mesh.material.uuid);
6362
+ }
6363
+ const meshCacheKey = meshCacheKeyParts.join(":");
6364
+ if (cache.meshes.has(meshCacheKey)) return cache.meshes.get(meshCacheKey);
6365
+ const geometry = mesh.geometry;
6366
+ let mode;
6367
+ if (mesh.isLineSegments) {
6368
+ mode = WEBGL_CONSTANTS.LINES;
6369
+ } else if (mesh.isLineLoop) {
6370
+ mode = WEBGL_CONSTANTS.LINE_LOOP;
6371
+ } else if (mesh.isLine) {
6372
+ mode = WEBGL_CONSTANTS.LINE_STRIP;
6373
+ } else if (mesh.isPoints) {
6374
+ mode = WEBGL_CONSTANTS.POINTS;
6375
+ } else {
6376
+ mode = mesh.material.wireframe ? WEBGL_CONSTANTS.LINES : WEBGL_CONSTANTS.TRIANGLES;
6377
+ }
6378
+ const meshDef = {};
6379
+ const attributes = {};
6380
+ const primitives = [];
6381
+ const targets = [];
6382
+ const nameConversion = {
6383
+ uv: "TEXCOORD_0",
6384
+ uv1: "TEXCOORD_1",
6385
+ uv2: "TEXCOORD_2",
6386
+ uv3: "TEXCOORD_3",
6387
+ color: "COLOR_0",
6388
+ skinWeight: "WEIGHTS_0",
6389
+ skinIndex: "JOINTS_0"
6390
+ };
6391
+ const originalNormal = geometry.getAttribute("normal");
6392
+ if (originalNormal !== void 0 && !this.isNormalizedNormalAttribute(originalNormal)) {
6393
+ console.warn("THREE.GLTFExporter: Creating normalized normal attribute from the non-normalized one.");
6394
+ geometry.setAttribute("normal", this.createNormalizedNormalAttribute(originalNormal));
6395
+ }
6396
+ let modifiedAttribute = null;
6397
+ for (let attributeName in geometry.attributes) {
6398
+ if (attributeName.slice(0, 5) === "morph") continue;
6399
+ const attribute = geometry.attributes[attributeName];
6400
+ attributeName = nameConversion[attributeName] || attributeName.toUpperCase();
6401
+ const validVertexAttributes = /^(POSITION|NORMAL|TANGENT|TEXCOORD_\d+|COLOR_\d+|JOINTS_\d+|WEIGHTS_\d+)$/;
6402
+ if (!validVertexAttributes.test(attributeName)) attributeName = "_" + attributeName;
6403
+ if (cache.attributes.has(this.getUID(attribute))) {
6404
+ attributes[attributeName] = cache.attributes.get(this.getUID(attribute));
6405
+ continue;
6406
+ }
6407
+ modifiedAttribute = null;
6408
+ const array = attribute.array;
6409
+ if (attributeName === "JOINTS_0" && !(array instanceof Uint16Array) && !(array instanceof Uint8Array)) {
6410
+ console.warn('GLTFExporter: Attribute "skinIndex" converted to type UNSIGNED_SHORT.');
6411
+ modifiedAttribute = new BufferAttribute3(new Uint16Array(array), attribute.itemSize, attribute.normalized);
6412
+ }
6413
+ const accessor = this.processAccessor(modifiedAttribute || attribute, geometry);
6414
+ if (accessor !== null) {
6415
+ if (!attributeName.startsWith("_")) {
6416
+ this.detectMeshQuantization(attributeName, attribute);
6417
+ }
6418
+ attributes[attributeName] = accessor;
6419
+ cache.attributes.set(this.getUID(attribute), accessor);
6420
+ }
6421
+ }
6422
+ if (originalNormal !== void 0) geometry.setAttribute("normal", originalNormal);
6423
+ if (Object.keys(attributes).length === 0) return null;
6424
+ if (mesh.morphTargetInfluences !== void 0 && mesh.morphTargetInfluences.length > 0) {
6425
+ const weights = [];
6426
+ const targetNames = [];
6427
+ const reverseDictionary = {};
6428
+ if (mesh.morphTargetDictionary !== void 0) {
6429
+ for (const key in mesh.morphTargetDictionary) {
6430
+ reverseDictionary[mesh.morphTargetDictionary[key]] = key;
6431
+ }
6432
+ }
6433
+ for (let i = 0; i < mesh.morphTargetInfluences.length; ++i) {
6434
+ const target = {};
6435
+ let warned = false;
6436
+ for (const attributeName in geometry.morphAttributes) {
6437
+ if (attributeName !== "position" && attributeName !== "normal") {
6438
+ if (!warned) {
6439
+ console.warn("GLTFExporter: Only POSITION and NORMAL morph are supported.");
6440
+ warned = true;
6441
+ }
6442
+ continue;
6443
+ }
6444
+ const attribute = geometry.morphAttributes[attributeName][i];
6445
+ const gltfAttributeName = attributeName.toUpperCase();
6446
+ const baseAttribute = geometry.attributes[attributeName];
6447
+ if (cache.attributes.has(this.getUID(attribute, true))) {
6448
+ target[gltfAttributeName] = cache.attributes.get(this.getUID(attribute, true));
6449
+ continue;
6450
+ }
6451
+ const relativeAttribute = attribute.clone();
6452
+ if (!geometry.morphTargetsRelative) {
6453
+ for (let j = 0, jl = attribute.count; j < jl; j++) {
6454
+ for (let a = 0; a < attribute.itemSize; a++) {
6455
+ if (a === 0) relativeAttribute.setX(j, attribute.getX(j) - baseAttribute.getX(j));
6456
+ if (a === 1) relativeAttribute.setY(j, attribute.getY(j) - baseAttribute.getY(j));
6457
+ if (a === 2) relativeAttribute.setZ(j, attribute.getZ(j) - baseAttribute.getZ(j));
6458
+ if (a === 3) relativeAttribute.setW(j, attribute.getW(j) - baseAttribute.getW(j));
6459
+ }
6460
+ }
6461
+ }
6462
+ target[gltfAttributeName] = this.processAccessor(relativeAttribute, geometry);
6463
+ cache.attributes.set(this.getUID(baseAttribute, true), target[gltfAttributeName]);
6464
+ }
6465
+ targets.push(target);
6466
+ weights.push(mesh.morphTargetInfluences[i]);
6467
+ if (mesh.morphTargetDictionary !== void 0) targetNames.push(reverseDictionary[i]);
6468
+ }
6469
+ meshDef.weights = weights;
6470
+ if (targetNames.length > 0) {
6471
+ meshDef.extras = {};
6472
+ meshDef.extras.targetNames = targetNames;
6473
+ }
6474
+ }
6475
+ const isMultiMaterial = Array.isArray(mesh.material);
6476
+ if (isMultiMaterial && geometry.groups.length === 0) return null;
6477
+ const materials = isMultiMaterial ? mesh.material : [mesh.material];
6478
+ const groups = isMultiMaterial ? geometry.groups : [{ materialIndex: 0, start: void 0, count: void 0 }];
6479
+ for (let i = 0, il = groups.length; i < il; i++) {
6480
+ const primitive = {
6481
+ mode,
6482
+ attributes
6483
+ };
6484
+ this.serializeUserData(geometry, primitive);
6485
+ if (targets.length > 0) primitive.targets = targets;
6486
+ if (geometry.index !== null) {
6487
+ let cacheKey = this.getUID(geometry.index);
6488
+ if (groups[i].start !== void 0 || groups[i].count !== void 0) {
6489
+ cacheKey += ":" + groups[i].start + ":" + groups[i].count;
6490
+ }
6491
+ if (cache.attributes.has(cacheKey)) {
6492
+ primitive.indices = cache.attributes.get(cacheKey);
6493
+ } else {
6494
+ primitive.indices = this.processAccessor(geometry.index, geometry, groups[i].start, groups[i].count);
6495
+ cache.attributes.set(cacheKey, primitive.indices);
6496
+ }
6497
+ if (primitive.indices === null) delete primitive.indices;
6498
+ }
6499
+ const material = this.processMaterial(materials[groups[i].materialIndex]);
6500
+ if (material !== null) primitive.material = material;
6501
+ primitives.push(primitive);
6502
+ }
6503
+ meshDef.primitives = primitives;
6504
+ if (!json.meshes) json.meshes = [];
6505
+ this._invokeAll(function(ext) {
6506
+ ext.writeMesh && ext.writeMesh(mesh, meshDef);
6507
+ });
6508
+ const index = json.meshes.push(meshDef) - 1;
6509
+ cache.meshes.set(meshCacheKey, index);
6510
+ return index;
6511
+ }
6512
+ /**
6513
+ * If a vertex attribute with a
6514
+ * [non-standard data type](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#meshes-overview)
6515
+ * is used, it is checked whether it is a valid data type according to the
6516
+ * [KHR_mesh_quantization](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_mesh_quantization/README.md)
6517
+ * extension.
6518
+ * In this case the extension is automatically added to the list of used extensions.
6519
+ *
6520
+ * @param {string} attributeName
6521
+ * @param {THREE.BufferAttribute} attribute
6522
+ */
6523
+ detectMeshQuantization(attributeName, attribute) {
6524
+ if (this.extensionsUsed[KHR_MESH_QUANTIZATION]) return;
6525
+ let attrType = void 0;
6526
+ switch (attribute.array.constructor) {
6527
+ case Int8Array:
6528
+ attrType = "byte";
6529
+ break;
6530
+ case Uint8Array:
6531
+ attrType = "unsigned byte";
6532
+ break;
6533
+ case Int16Array:
6534
+ attrType = "short";
6535
+ break;
6536
+ case Uint16Array:
6537
+ attrType = "unsigned short";
6538
+ break;
6539
+ default:
6540
+ return;
6541
+ }
6542
+ if (attribute.normalized) attrType += " normalized";
6543
+ const attrNamePrefix = attributeName.split("_", 1)[0];
6544
+ if (KHR_mesh_quantization_ExtraAttrTypes[attrNamePrefix] && KHR_mesh_quantization_ExtraAttrTypes[attrNamePrefix].includes(attrType)) {
6545
+ this.extensionsUsed[KHR_MESH_QUANTIZATION] = true;
6546
+ this.extensionsRequired[KHR_MESH_QUANTIZATION] = true;
6547
+ }
6548
+ }
6549
+ /**
6550
+ * Process camera
6551
+ * @param {THREE.Camera} camera Camera to process
6552
+ * @return {Integer} Index of the processed mesh in the "camera" array
6553
+ */
6554
+ processCamera(camera) {
6555
+ const json = this.json;
6556
+ if (!json.cameras) json.cameras = [];
6557
+ const isOrtho = camera.isOrthographicCamera;
6558
+ const cameraDef = {
6559
+ type: isOrtho ? "orthographic" : "perspective"
6560
+ };
6561
+ if (isOrtho) {
6562
+ cameraDef.orthographic = {
6563
+ xmag: camera.right * 2,
6564
+ ymag: camera.top * 2,
6565
+ zfar: camera.far <= 0 ? 1e-3 : camera.far,
6566
+ znear: camera.near < 0 ? 0 : camera.near
6567
+ };
6568
+ } else {
6569
+ cameraDef.perspective = {
6570
+ aspectRatio: camera.aspect,
6571
+ yfov: MathUtils2.degToRad(camera.fov),
6572
+ zfar: camera.far <= 0 ? 1e-3 : camera.far,
6573
+ znear: camera.near < 0 ? 0 : camera.near
6574
+ };
6575
+ }
6576
+ if (camera.name !== "") cameraDef.name = camera.type;
6577
+ return json.cameras.push(cameraDef) - 1;
6578
+ }
6579
+ /**
6580
+ * Creates glTF animation entry from AnimationClip object.
6581
+ *
6582
+ * Status:
6583
+ * - Only properties listed in PATH_PROPERTIES may be animated.
6584
+ *
6585
+ * @param {THREE.AnimationClip} clip
6586
+ * @param {THREE.Object3D} root
6587
+ * @return {number|null}
6588
+ */
6589
+ processAnimation(clip, root) {
6590
+ const json = this.json;
6591
+ const nodeMap = this.nodeMap;
6592
+ if (!json.animations) json.animations = [];
6593
+ clip = GLTFExporter.Utils.mergeMorphTargetTracks(clip.clone(), root);
6594
+ const tracks = clip.tracks;
6595
+ const channels = [];
6596
+ const samplers = [];
6597
+ for (let i = 0; i < tracks.length; ++i) {
6598
+ const track = tracks[i];
6599
+ const trackBinding = PropertyBinding.parseTrackName(track.name);
6600
+ let trackNode = PropertyBinding.findNode(root, trackBinding.nodeName);
6601
+ const trackProperty = PATH_PROPERTIES[trackBinding.propertyName];
6602
+ if (trackBinding.objectName === "bones") {
6603
+ if (trackNode.isSkinnedMesh === true) {
6604
+ trackNode = trackNode.skeleton.getBoneByName(trackBinding.objectIndex);
6605
+ } else {
6606
+ trackNode = void 0;
6607
+ }
6608
+ }
6609
+ if (!trackNode || !trackProperty) {
6610
+ console.warn('THREE.GLTFExporter: Could not export animation track "%s".', track.name);
6611
+ return null;
6612
+ }
6613
+ const inputItemSize = 1;
6614
+ let outputItemSize = track.values.length / track.times.length;
6615
+ if (trackProperty === PATH_PROPERTIES.morphTargetInfluences) {
6616
+ outputItemSize /= trackNode.morphTargetInfluences.length;
6617
+ }
6618
+ let interpolation;
6619
+ if (track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline === true) {
6620
+ interpolation = "CUBICSPLINE";
6621
+ outputItemSize /= 3;
6622
+ } else if (track.getInterpolation() === InterpolateDiscrete) {
6623
+ interpolation = "STEP";
6624
+ } else {
6625
+ interpolation = "LINEAR";
6626
+ }
6627
+ samplers.push({
6628
+ input: this.processAccessor(new BufferAttribute3(track.times, inputItemSize)),
6629
+ output: this.processAccessor(new BufferAttribute3(track.values, outputItemSize)),
6630
+ interpolation
6631
+ });
6632
+ channels.push({
6633
+ sampler: samplers.length - 1,
6634
+ target: {
6635
+ node: nodeMap.get(trackNode),
6636
+ path: trackProperty
6637
+ }
6638
+ });
6639
+ }
6640
+ json.animations.push({
6641
+ name: clip.name || "clip_" + json.animations.length,
6642
+ samplers,
6643
+ channels
6644
+ });
6645
+ return json.animations.length - 1;
6646
+ }
6647
+ /**
6648
+ * @param {THREE.Object3D} object
6649
+ * @return {number|null}
6650
+ */
6651
+ processSkin(object) {
6652
+ const json = this.json;
6653
+ const nodeMap = this.nodeMap;
6654
+ const node = json.nodes[nodeMap.get(object)];
6655
+ const skeleton = object.skeleton;
6656
+ if (skeleton === void 0) return null;
6657
+ const rootJoint = object.skeleton.bones[0];
6658
+ if (rootJoint === void 0) return null;
6659
+ const joints = [];
6660
+ const inverseBindMatrices = new Float32Array(skeleton.bones.length * 16);
6661
+ const temporaryBoneInverse = new Matrix44();
6662
+ for (let i = 0; i < skeleton.bones.length; ++i) {
6663
+ joints.push(nodeMap.get(skeleton.bones[i]));
6664
+ temporaryBoneInverse.copy(skeleton.boneInverses[i]);
6665
+ temporaryBoneInverse.multiply(object.bindMatrix).toArray(inverseBindMatrices, i * 16);
6666
+ }
6667
+ if (json.skins === void 0) json.skins = [];
6668
+ json.skins.push({
6669
+ inverseBindMatrices: this.processAccessor(new BufferAttribute3(inverseBindMatrices, 16)),
6670
+ joints,
6671
+ skeleton: nodeMap.get(rootJoint)
6672
+ });
6673
+ const skinIndex = node.skin = json.skins.length - 1;
6674
+ return skinIndex;
6675
+ }
6676
+ /**
6677
+ * Process Object3D node
6678
+ * @param {THREE.Object3D} node Object3D to processNode
6679
+ * @return {Integer} Index of the node in the nodes list
6680
+ */
6681
+ processNode(object) {
6682
+ const json = this.json;
6683
+ const options = this.options;
6684
+ const nodeMap = this.nodeMap;
6685
+ if (!json.nodes) json.nodes = [];
6686
+ const nodeDef = {};
6687
+ if (options.trs) {
6688
+ const rotation = object.quaternion.toArray();
6689
+ const position = object.position.toArray();
6690
+ const scale = object.scale.toArray();
6691
+ if (!equalArray(rotation, [0, 0, 0, 1])) {
6692
+ nodeDef.rotation = rotation;
6693
+ }
6694
+ if (!equalArray(position, [0, 0, 0])) {
6695
+ nodeDef.translation = position;
6696
+ }
6697
+ if (!equalArray(scale, [1, 1, 1])) {
6698
+ nodeDef.scale = scale;
6699
+ }
6700
+ } else {
6701
+ if (object.matrixAutoUpdate) {
6702
+ object.updateMatrix();
6703
+ }
6704
+ if (isIdentityMatrix(object.matrix) === false) {
6705
+ nodeDef.matrix = object.matrix.elements;
6706
+ }
6707
+ }
6708
+ if (object.name !== "") nodeDef.name = String(object.name);
6709
+ this.serializeUserData(object, nodeDef);
6710
+ if (object.isMesh || object.isLine || object.isPoints) {
6711
+ const meshIndex = this.processMesh(object);
6712
+ if (meshIndex !== null) nodeDef.mesh = meshIndex;
6713
+ } else if (object.isCamera) {
6714
+ nodeDef.camera = this.processCamera(object);
6715
+ }
6716
+ if (object.isSkinnedMesh) this.skins.push(object);
6717
+ if (object.children.length > 0) {
6718
+ const children = [];
6719
+ for (let i = 0, l = object.children.length; i < l; i++) {
6720
+ const child = object.children[i];
6721
+ if (child.visible || options.onlyVisible === false) {
6722
+ const nodeIndex2 = this.processNode(child);
6723
+ if (nodeIndex2 !== null) children.push(nodeIndex2);
6724
+ }
6725
+ }
6726
+ if (children.length > 0) nodeDef.children = children;
6727
+ }
6728
+ this._invokeAll(function(ext) {
6729
+ ext.writeNode && ext.writeNode(object, nodeDef);
6730
+ });
6731
+ const nodeIndex = json.nodes.push(nodeDef) - 1;
6732
+ nodeMap.set(object, nodeIndex);
6733
+ return nodeIndex;
6734
+ }
6735
+ /**
6736
+ * Process Scene
6737
+ * @param {Scene} node Scene to process
6738
+ */
6739
+ processScene(scene) {
6740
+ const json = this.json;
6741
+ const options = this.options;
6742
+ if (!json.scenes) {
6743
+ json.scenes = [];
6744
+ json.scene = 0;
6745
+ }
6746
+ const sceneDef = {};
6747
+ if (scene.name !== "") sceneDef.name = scene.name;
6748
+ json.scenes.push(sceneDef);
6749
+ const nodes = [];
6750
+ for (let i = 0, l = scene.children.length; i < l; i++) {
6751
+ const child = scene.children[i];
6752
+ if (child.visible || options.onlyVisible === false) {
6753
+ const nodeIndex = this.processNode(child);
6754
+ if (nodeIndex !== null) nodes.push(nodeIndex);
6755
+ }
6756
+ }
6757
+ if (nodes.length > 0) sceneDef.nodes = nodes;
6758
+ this.serializeUserData(scene, sceneDef);
6759
+ }
6760
+ /**
6761
+ * Creates a Scene to hold a list of objects and parse it
6762
+ * @param {Array} objects List of objects to process
6763
+ */
6764
+ processObjects(objects) {
6765
+ const scene = new Scene3();
6766
+ scene.name = "AuxScene";
6767
+ for (let i = 0; i < objects.length; i++) {
6768
+ scene.children.push(objects[i]);
6769
+ }
6770
+ this.processScene(scene);
6771
+ }
6772
+ /**
6773
+ * @param {THREE.Object3D|Array<THREE.Object3D>} input
6774
+ */
6775
+ processInput(input) {
6776
+ const options = this.options;
6777
+ input = input instanceof Array ? input : [input];
6778
+ this._invokeAll(function(ext) {
6779
+ ext.beforeParse && ext.beforeParse(input);
6780
+ });
6781
+ const objectsWithoutScene = [];
6782
+ for (let i = 0; i < input.length; i++) {
6783
+ if (input[i] instanceof Scene3) {
6784
+ this.processScene(input[i]);
6785
+ } else {
6786
+ objectsWithoutScene.push(input[i]);
6787
+ }
6788
+ }
6789
+ if (objectsWithoutScene.length > 0) this.processObjects(objectsWithoutScene);
6790
+ for (let i = 0; i < this.skins.length; ++i) {
6791
+ this.processSkin(this.skins[i]);
6792
+ }
6793
+ for (let i = 0; i < options.animations.length; ++i) {
6794
+ this.processAnimation(options.animations[i], input[0]);
6795
+ }
6796
+ this._invokeAll(function(ext) {
6797
+ ext.afterParse && ext.afterParse(input);
6798
+ });
6799
+ }
6800
+ _invokeAll(func) {
6801
+ for (let i = 0, il = this.plugins.length; i < il; i++) {
6802
+ func(this.plugins[i]);
6803
+ }
6804
+ }
6805
+ };
6806
+ var GLTFLightExtension = class {
6807
+ constructor(writer) {
6808
+ this.writer = writer;
6809
+ this.name = "KHR_lights_punctual";
6810
+ }
6811
+ writeNode(light, nodeDef) {
6812
+ if (!light.isLight) return;
6813
+ if (!light.isDirectionalLight && !light.isPointLight && !light.isSpotLight) {
6814
+ console.warn("THREE.GLTFExporter: Only directional, point, and spot lights are supported.", light);
6815
+ return;
6816
+ }
6817
+ const writer = this.writer;
6818
+ const json = writer.json;
6819
+ const extensionsUsed = writer.extensionsUsed;
6820
+ const lightDef = {};
6821
+ if (light.name) lightDef.name = light.name;
6822
+ lightDef.color = light.color.toArray();
6823
+ lightDef.intensity = light.intensity;
6824
+ if (light.isDirectionalLight) {
6825
+ lightDef.type = "directional";
6826
+ } else if (light.isPointLight) {
6827
+ lightDef.type = "point";
6828
+ if (light.distance > 0) lightDef.range = light.distance;
6829
+ } else if (light.isSpotLight) {
6830
+ lightDef.type = "spot";
6831
+ if (light.distance > 0) lightDef.range = light.distance;
6832
+ lightDef.spot = {};
6833
+ lightDef.spot.innerConeAngle = (1 - light.penumbra) * light.angle;
6834
+ lightDef.spot.outerConeAngle = light.angle;
6835
+ }
6836
+ if (light.decay !== void 0 && light.decay !== 2) {
6837
+ console.warn("THREE.GLTFExporter: Light decay may be lost. glTF is physically-based, and expects light.decay=2.");
6838
+ }
6839
+ if (light.target && (light.target.parent !== light || light.target.position.x !== 0 || light.target.position.y !== 0 || light.target.position.z !== -1)) {
6840
+ 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.");
6841
+ }
6842
+ if (!extensionsUsed[this.name]) {
6843
+ json.extensions = json.extensions || {};
6844
+ json.extensions[this.name] = { lights: [] };
6845
+ extensionsUsed[this.name] = true;
6846
+ }
6847
+ const lights = json.extensions[this.name].lights;
6848
+ lights.push(lightDef);
6849
+ nodeDef.extensions = nodeDef.extensions || {};
6850
+ nodeDef.extensions[this.name] = { light: lights.length - 1 };
6851
+ }
6852
+ };
6853
+ var GLTFMaterialsUnlitExtension = class {
6854
+ constructor(writer) {
6855
+ this.writer = writer;
6856
+ this.name = "KHR_materials_unlit";
6857
+ }
6858
+ writeMaterial(material, materialDef) {
6859
+ if (!material.isMeshBasicMaterial) return;
6860
+ const writer = this.writer;
6861
+ const extensionsUsed = writer.extensionsUsed;
6862
+ materialDef.extensions = materialDef.extensions || {};
6863
+ materialDef.extensions[this.name] = {};
6864
+ extensionsUsed[this.name] = true;
6865
+ materialDef.pbrMetallicRoughness.metallicFactor = 0;
6866
+ materialDef.pbrMetallicRoughness.roughnessFactor = 0.9;
6867
+ }
6868
+ };
6869
+ var GLTFMaterialsClearcoatExtension = class {
6870
+ constructor(writer) {
6871
+ this.writer = writer;
6872
+ this.name = "KHR_materials_clearcoat";
6873
+ }
6874
+ writeMaterial(material, materialDef) {
6875
+ if (!material.isMeshPhysicalMaterial || material.clearcoat === 0) return;
6876
+ const writer = this.writer;
6877
+ const extensionsUsed = writer.extensionsUsed;
6878
+ const extensionDef = {};
6879
+ extensionDef.clearcoatFactor = material.clearcoat;
6880
+ if (material.clearcoatMap) {
6881
+ const clearcoatMapDef = {
6882
+ index: writer.processTexture(material.clearcoatMap),
6883
+ texCoord: material.clearcoatMap.channel
6884
+ };
6885
+ writer.applyTextureTransform(clearcoatMapDef, material.clearcoatMap);
6886
+ extensionDef.clearcoatTexture = clearcoatMapDef;
6887
+ }
6888
+ extensionDef.clearcoatRoughnessFactor = material.clearcoatRoughness;
6889
+ if (material.clearcoatRoughnessMap) {
6890
+ const clearcoatRoughnessMapDef = {
6891
+ index: writer.processTexture(material.clearcoatRoughnessMap),
6892
+ texCoord: material.clearcoatRoughnessMap.channel
6893
+ };
6894
+ writer.applyTextureTransform(clearcoatRoughnessMapDef, material.clearcoatRoughnessMap);
6895
+ extensionDef.clearcoatRoughnessTexture = clearcoatRoughnessMapDef;
6896
+ }
6897
+ if (material.clearcoatNormalMap) {
6898
+ const clearcoatNormalMapDef = {
6899
+ index: writer.processTexture(material.clearcoatNormalMap),
6900
+ texCoord: material.clearcoatNormalMap.channel
6901
+ };
6902
+ writer.applyTextureTransform(clearcoatNormalMapDef, material.clearcoatNormalMap);
6903
+ extensionDef.clearcoatNormalTexture = clearcoatNormalMapDef;
6904
+ }
6905
+ materialDef.extensions = materialDef.extensions || {};
6906
+ materialDef.extensions[this.name] = extensionDef;
6907
+ extensionsUsed[this.name] = true;
6908
+ }
6909
+ };
6910
+ var GLTFMaterialsIridescenceExtension = class {
6911
+ constructor(writer) {
6912
+ this.writer = writer;
6913
+ this.name = "KHR_materials_iridescence";
6914
+ }
6915
+ writeMaterial(material, materialDef) {
6916
+ if (!material.isMeshPhysicalMaterial || material.iridescence === 0) return;
6917
+ const writer = this.writer;
6918
+ const extensionsUsed = writer.extensionsUsed;
6919
+ const extensionDef = {};
6920
+ extensionDef.iridescenceFactor = material.iridescence;
6921
+ if (material.iridescenceMap) {
6922
+ const iridescenceMapDef = {
6923
+ index: writer.processTexture(material.iridescenceMap),
6924
+ texCoord: material.iridescenceMap.channel
6925
+ };
6926
+ writer.applyTextureTransform(iridescenceMapDef, material.iridescenceMap);
6927
+ extensionDef.iridescenceTexture = iridescenceMapDef;
6928
+ }
6929
+ extensionDef.iridescenceIor = material.iridescenceIOR;
6930
+ extensionDef.iridescenceThicknessMinimum = material.iridescenceThicknessRange[0];
6931
+ extensionDef.iridescenceThicknessMaximum = material.iridescenceThicknessRange[1];
6932
+ if (material.iridescenceThicknessMap) {
6933
+ const iridescenceThicknessMapDef = {
6934
+ index: writer.processTexture(material.iridescenceThicknessMap),
6935
+ texCoord: material.iridescenceThicknessMap.channel
6936
+ };
6937
+ writer.applyTextureTransform(iridescenceThicknessMapDef, material.iridescenceThicknessMap);
6938
+ extensionDef.iridescenceThicknessTexture = iridescenceThicknessMapDef;
6939
+ }
6940
+ materialDef.extensions = materialDef.extensions || {};
6941
+ materialDef.extensions[this.name] = extensionDef;
6942
+ extensionsUsed[this.name] = true;
6943
+ }
6944
+ };
6945
+ var GLTFMaterialsTransmissionExtension = class {
6946
+ constructor(writer) {
6947
+ this.writer = writer;
6948
+ this.name = "KHR_materials_transmission";
6949
+ }
6950
+ writeMaterial(material, materialDef) {
6951
+ if (!material.isMeshPhysicalMaterial || material.transmission === 0) return;
6952
+ const writer = this.writer;
6953
+ const extensionsUsed = writer.extensionsUsed;
6954
+ const extensionDef = {};
6955
+ extensionDef.transmissionFactor = material.transmission;
6956
+ if (material.transmissionMap) {
6957
+ const transmissionMapDef = {
6958
+ index: writer.processTexture(material.transmissionMap),
6959
+ texCoord: material.transmissionMap.channel
6960
+ };
6961
+ writer.applyTextureTransform(transmissionMapDef, material.transmissionMap);
6962
+ extensionDef.transmissionTexture = transmissionMapDef;
6963
+ }
6964
+ materialDef.extensions = materialDef.extensions || {};
6965
+ materialDef.extensions[this.name] = extensionDef;
6966
+ extensionsUsed[this.name] = true;
6967
+ }
6968
+ };
6969
+ var GLTFMaterialsVolumeExtension = class {
6970
+ constructor(writer) {
6971
+ this.writer = writer;
6972
+ this.name = "KHR_materials_volume";
6973
+ }
6974
+ writeMaterial(material, materialDef) {
6975
+ if (!material.isMeshPhysicalMaterial || material.transmission === 0) return;
6976
+ const writer = this.writer;
6977
+ const extensionsUsed = writer.extensionsUsed;
6978
+ const extensionDef = {};
6979
+ extensionDef.thicknessFactor = material.thickness;
6980
+ if (material.thicknessMap) {
6981
+ const thicknessMapDef = {
6982
+ index: writer.processTexture(material.thicknessMap),
6983
+ texCoord: material.thicknessMap.channel
6984
+ };
6985
+ writer.applyTextureTransform(thicknessMapDef, material.thicknessMap);
6986
+ extensionDef.thicknessTexture = thicknessMapDef;
6987
+ }
6988
+ extensionDef.attenuationDistance = material.attenuationDistance;
6989
+ extensionDef.attenuationColor = material.attenuationColor.toArray();
6990
+ materialDef.extensions = materialDef.extensions || {};
6991
+ materialDef.extensions[this.name] = extensionDef;
6992
+ extensionsUsed[this.name] = true;
6993
+ }
6994
+ };
6995
+ var GLTFMaterialsIorExtension = class {
6996
+ constructor(writer) {
6997
+ this.writer = writer;
6998
+ this.name = "KHR_materials_ior";
6999
+ }
7000
+ writeMaterial(material, materialDef) {
7001
+ if (!material.isMeshPhysicalMaterial || material.ior === 1.5) return;
7002
+ const writer = this.writer;
7003
+ const extensionsUsed = writer.extensionsUsed;
7004
+ const extensionDef = {};
7005
+ extensionDef.ior = material.ior;
7006
+ materialDef.extensions = materialDef.extensions || {};
7007
+ materialDef.extensions[this.name] = extensionDef;
7008
+ extensionsUsed[this.name] = true;
7009
+ }
7010
+ };
7011
+ var GLTFMaterialsSpecularExtension = class {
7012
+ constructor(writer) {
7013
+ this.writer = writer;
7014
+ this.name = "KHR_materials_specular";
7015
+ }
7016
+ writeMaterial(material, materialDef) {
7017
+ if (!material.isMeshPhysicalMaterial || material.specularIntensity === 1 && material.specularColor.equals(DEFAULT_SPECULAR_COLOR) && !material.specularIntensityMap && !material.specularColorTexture) return;
7018
+ const writer = this.writer;
7019
+ const extensionsUsed = writer.extensionsUsed;
7020
+ const extensionDef = {};
7021
+ if (material.specularIntensityMap) {
7022
+ const specularIntensityMapDef = {
7023
+ index: writer.processTexture(material.specularIntensityMap),
7024
+ texCoord: material.specularIntensityMap.channel
7025
+ };
7026
+ writer.applyTextureTransform(specularIntensityMapDef, material.specularIntensityMap);
7027
+ extensionDef.specularTexture = specularIntensityMapDef;
7028
+ }
7029
+ if (material.specularColorMap) {
7030
+ const specularColorMapDef = {
7031
+ index: writer.processTexture(material.specularColorMap),
7032
+ texCoord: material.specularColorMap.channel
7033
+ };
7034
+ writer.applyTextureTransform(specularColorMapDef, material.specularColorMap);
7035
+ extensionDef.specularColorTexture = specularColorMapDef;
7036
+ }
7037
+ extensionDef.specularFactor = material.specularIntensity;
7038
+ extensionDef.specularColorFactor = material.specularColor.toArray();
7039
+ materialDef.extensions = materialDef.extensions || {};
7040
+ materialDef.extensions[this.name] = extensionDef;
7041
+ extensionsUsed[this.name] = true;
7042
+ }
7043
+ };
7044
+ var GLTFMaterialsSheenExtension = class {
7045
+ constructor(writer) {
7046
+ this.writer = writer;
7047
+ this.name = "KHR_materials_sheen";
7048
+ }
7049
+ writeMaterial(material, materialDef) {
7050
+ if (!material.isMeshPhysicalMaterial || material.sheen == 0) return;
7051
+ const writer = this.writer;
7052
+ const extensionsUsed = writer.extensionsUsed;
7053
+ const extensionDef = {};
7054
+ if (material.sheenRoughnessMap) {
7055
+ const sheenRoughnessMapDef = {
7056
+ index: writer.processTexture(material.sheenRoughnessMap),
7057
+ texCoord: material.sheenRoughnessMap.channel
7058
+ };
7059
+ writer.applyTextureTransform(sheenRoughnessMapDef, material.sheenRoughnessMap);
7060
+ extensionDef.sheenRoughnessTexture = sheenRoughnessMapDef;
7061
+ }
7062
+ if (material.sheenColorMap) {
7063
+ const sheenColorMapDef = {
7064
+ index: writer.processTexture(material.sheenColorMap),
7065
+ texCoord: material.sheenColorMap.channel
7066
+ };
7067
+ writer.applyTextureTransform(sheenColorMapDef, material.sheenColorMap);
7068
+ extensionDef.sheenColorTexture = sheenColorMapDef;
7069
+ }
7070
+ extensionDef.sheenRoughnessFactor = material.sheenRoughness;
7071
+ extensionDef.sheenColorFactor = material.sheenColor.toArray();
7072
+ materialDef.extensions = materialDef.extensions || {};
7073
+ materialDef.extensions[this.name] = extensionDef;
7074
+ extensionsUsed[this.name] = true;
7075
+ }
7076
+ };
7077
+ var GLTFMaterialsAnisotropyExtension = class {
7078
+ constructor(writer) {
7079
+ this.writer = writer;
7080
+ this.name = "KHR_materials_anisotropy";
7081
+ }
7082
+ writeMaterial(material, materialDef) {
7083
+ if (!material.isMeshPhysicalMaterial || material.anisotropy == 0) return;
7084
+ const writer = this.writer;
7085
+ const extensionsUsed = writer.extensionsUsed;
7086
+ const extensionDef = {};
7087
+ if (material.anisotropyMap) {
7088
+ const anisotropyMapDef = { index: writer.processTexture(material.anisotropyMap) };
7089
+ writer.applyTextureTransform(anisotropyMapDef, material.anisotropyMap);
7090
+ extensionDef.anisotropyTexture = anisotropyMapDef;
7091
+ }
7092
+ extensionDef.anisotropyStrength = material.anisotropy;
7093
+ extensionDef.anisotropyRotation = material.anisotropyRotation;
7094
+ materialDef.extensions = materialDef.extensions || {};
7095
+ materialDef.extensions[this.name] = extensionDef;
7096
+ extensionsUsed[this.name] = true;
7097
+ }
7098
+ };
7099
+ var GLTFMaterialsEmissiveStrengthExtension = class {
7100
+ constructor(writer) {
7101
+ this.writer = writer;
7102
+ this.name = "KHR_materials_emissive_strength";
7103
+ }
7104
+ writeMaterial(material, materialDef) {
7105
+ if (!material.isMeshStandardMaterial || material.emissiveIntensity === 1) return;
7106
+ const writer = this.writer;
7107
+ const extensionsUsed = writer.extensionsUsed;
7108
+ const extensionDef = {};
7109
+ extensionDef.emissiveStrength = material.emissiveIntensity;
7110
+ materialDef.extensions = materialDef.extensions || {};
7111
+ materialDef.extensions[this.name] = extensionDef;
7112
+ extensionsUsed[this.name] = true;
7113
+ }
7114
+ };
7115
+ var GLTFMeshGpuInstancing = class {
7116
+ constructor(writer) {
7117
+ this.writer = writer;
7118
+ this.name = "EXT_mesh_gpu_instancing";
7119
+ }
7120
+ writeNode(object, nodeDef) {
7121
+ if (!object.isInstancedMesh) return;
7122
+ const writer = this.writer;
7123
+ const mesh = object;
7124
+ const translationAttr = new Float32Array(mesh.count * 3);
7125
+ const rotationAttr = new Float32Array(mesh.count * 4);
7126
+ const scaleAttr = new Float32Array(mesh.count * 3);
7127
+ const matrix = new Matrix44();
7128
+ const position = new Vector38();
7129
+ const quaternion = new Quaternion4();
7130
+ const scale = new Vector38();
7131
+ for (let i = 0; i < mesh.count; i++) {
7132
+ mesh.getMatrixAt(i, matrix);
7133
+ matrix.decompose(position, quaternion, scale);
7134
+ position.toArray(translationAttr, i * 3);
7135
+ quaternion.toArray(rotationAttr, i * 4);
7136
+ scale.toArray(scaleAttr, i * 3);
7137
+ }
7138
+ const attributes = {
7139
+ TRANSLATION: writer.processAccessor(new BufferAttribute3(translationAttr, 3)),
7140
+ ROTATION: writer.processAccessor(new BufferAttribute3(rotationAttr, 4)),
7141
+ SCALE: writer.processAccessor(new BufferAttribute3(scaleAttr, 3))
7142
+ };
7143
+ if (mesh.instanceColor)
7144
+ attributes._COLOR_0 = writer.processAccessor(mesh.instanceColor);
7145
+ nodeDef.extensions = nodeDef.extensions || {};
7146
+ nodeDef.extensions[this.name] = { attributes };
7147
+ writer.extensionsUsed[this.name] = true;
7148
+ writer.extensionsRequired[this.name] = true;
7149
+ }
7150
+ };
7151
+ GLTFExporter.Utils = {
7152
+ insertKeyframe: function(track, time) {
7153
+ const tolerance = 1e-3;
7154
+ const valueSize = track.getValueSize();
7155
+ const times = new track.TimeBufferType(track.times.length + 1);
7156
+ const values = new track.ValueBufferType(track.values.length + valueSize);
7157
+ const interpolant = track.createInterpolant(new track.ValueBufferType(valueSize));
7158
+ let index;
7159
+ if (track.times.length === 0) {
7160
+ times[0] = time;
7161
+ for (let i = 0; i < valueSize; i++) {
7162
+ values[i] = 0;
7163
+ }
7164
+ index = 0;
7165
+ } else if (time < track.times[0]) {
7166
+ if (Math.abs(track.times[0] - time) < tolerance) return 0;
7167
+ times[0] = time;
7168
+ times.set(track.times, 1);
7169
+ values.set(interpolant.evaluate(time), 0);
7170
+ values.set(track.values, valueSize);
7171
+ index = 0;
7172
+ } else if (time > track.times[track.times.length - 1]) {
7173
+ if (Math.abs(track.times[track.times.length - 1] - time) < tolerance) {
7174
+ return track.times.length - 1;
7175
+ }
7176
+ times[times.length - 1] = time;
7177
+ times.set(track.times, 0);
7178
+ values.set(track.values, 0);
7179
+ values.set(interpolant.evaluate(time), track.values.length);
7180
+ index = times.length - 1;
7181
+ } else {
7182
+ for (let i = 0; i < track.times.length; i++) {
7183
+ if (Math.abs(track.times[i] - time) < tolerance) return i;
7184
+ if (track.times[i] < time && track.times[i + 1] > time) {
7185
+ times.set(track.times.slice(0, i + 1), 0);
7186
+ times[i + 1] = time;
7187
+ times.set(track.times.slice(i + 1), i + 2);
7188
+ values.set(track.values.slice(0, (i + 1) * valueSize), 0);
7189
+ values.set(interpolant.evaluate(time), (i + 1) * valueSize);
7190
+ values.set(track.values.slice((i + 1) * valueSize), (i + 2) * valueSize);
7191
+ index = i + 1;
7192
+ break;
7193
+ }
7194
+ }
7195
+ }
7196
+ track.times = times;
7197
+ track.values = values;
7198
+ return index;
7199
+ },
7200
+ mergeMorphTargetTracks: function(clip, root) {
7201
+ const tracks = [];
7202
+ const mergedTracks = {};
7203
+ const sourceTracks = clip.tracks;
7204
+ for (let i = 0; i < sourceTracks.length; ++i) {
7205
+ let sourceTrack = sourceTracks[i];
7206
+ const sourceTrackBinding = PropertyBinding.parseTrackName(sourceTrack.name);
7207
+ const sourceTrackNode = PropertyBinding.findNode(root, sourceTrackBinding.nodeName);
7208
+ if (sourceTrackBinding.propertyName !== "morphTargetInfluences" || sourceTrackBinding.propertyIndex === void 0) {
7209
+ tracks.push(sourceTrack);
7210
+ continue;
7211
+ }
7212
+ if (sourceTrack.createInterpolant !== sourceTrack.InterpolantFactoryMethodDiscrete && sourceTrack.createInterpolant !== sourceTrack.InterpolantFactoryMethodLinear) {
7213
+ if (sourceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline) {
7214
+ throw new Error("THREE.GLTFExporter: Cannot merge tracks with glTF CUBICSPLINE interpolation.");
7215
+ }
7216
+ console.warn("THREE.GLTFExporter: Morph target interpolation mode not yet supported. Using LINEAR instead.");
7217
+ sourceTrack = sourceTrack.clone();
7218
+ sourceTrack.setInterpolation(InterpolateLinear);
7219
+ }
7220
+ const targetCount = sourceTrackNode.morphTargetInfluences.length;
7221
+ const targetIndex = sourceTrackNode.morphTargetDictionary[sourceTrackBinding.propertyIndex];
7222
+ if (targetIndex === void 0) {
7223
+ throw new Error("THREE.GLTFExporter: Morph target name not found: " + sourceTrackBinding.propertyIndex);
7224
+ }
7225
+ let mergedTrack;
7226
+ if (mergedTracks[sourceTrackNode.uuid] === void 0) {
7227
+ mergedTrack = sourceTrack.clone();
7228
+ const values = new mergedTrack.ValueBufferType(targetCount * mergedTrack.times.length);
7229
+ for (let j = 0; j < mergedTrack.times.length; j++) {
7230
+ values[j * targetCount + targetIndex] = mergedTrack.values[j];
7231
+ }
7232
+ mergedTrack.name = (sourceTrackBinding.nodeName || "") + ".morphTargetInfluences";
7233
+ mergedTrack.values = values;
7234
+ mergedTracks[sourceTrackNode.uuid] = mergedTrack;
7235
+ tracks.push(mergedTrack);
7236
+ continue;
7237
+ }
7238
+ const sourceInterpolant = sourceTrack.createInterpolant(new sourceTrack.ValueBufferType(1));
7239
+ mergedTrack = mergedTracks[sourceTrackNode.uuid];
7240
+ for (let j = 0; j < mergedTrack.times.length; j++) {
7241
+ mergedTrack.values[j * targetCount + targetIndex] = sourceInterpolant.evaluate(mergedTrack.times[j]);
7242
+ }
7243
+ for (let j = 0; j < sourceTrack.times.length; j++) {
7244
+ const keyframeIndex = this.insertKeyframe(mergedTrack, sourceTrack.times[j]);
7245
+ mergedTrack.values[keyframeIndex * targetCount + targetIndex] = sourceTrack.values[j];
7246
+ }
7247
+ }
7248
+ clip.tracks = tracks;
7249
+ return clip;
7250
+ }
7251
+ };
7252
+
7253
+ // src/export/SceneExporter.ts
7254
+ init_MineRenderError();
7255
+ init_DisplayTransforms();
7256
+ init_CanvasCompat();
7257
+ var SceneExporter = class {
7258
+ /** Returns OBJ geometry with normals and UVs; material files and textures are not included. */
7259
+ static toObj(root) {
7260
+ const snapshot = createSnapshot(root, false);
7261
+ try {
7262
+ return new OBJExporter().parse(snapshot.scene);
7263
+ } finally {
7264
+ snapshot.dispose();
7265
+ }
7266
+ }
7267
+ /** Returns PLY geometry with vertex colors and UVs; texture images are not included. */
7268
+ static toPLY(root, options) {
7269
+ const snapshot = createSnapshot(root, false, true);
7270
+ try {
7271
+ const result = new PLYExporter().parse(snapshot.scene, void 0, options);
7272
+ if (result === null) throw new MineRenderError("The scene could not be exported as PLY");
7273
+ return result;
7274
+ } finally {
7275
+ snapshot.dispose();
7276
+ }
7277
+ }
7278
+ /**
7279
+ * Exports a static glTF/GLB snapshot in a browser. Atlas textures and vertex tints are retained;
7280
+ * MineRender's custom directional lighting is not baked into the exported materials.
7281
+ */
7282
+ static async toGLTF(root, options = {}) {
7283
+ if (typeof document === "undefined" || typeof FileReader === "undefined") {
7284
+ throw new MineRenderError("glTF export requires a browser with canvas and FileReader support");
7285
+ }
7286
+ if (options.maxTextureSize !== void 0 && !(options.maxTextureSize >= 1)) {
7287
+ throw new MineRenderError("maxTextureSize must be at least 1 pixel");
7288
+ }
7289
+ const snapshot = createSnapshot(root, true);
7290
+ try {
7291
+ return await new GLTFExporter().parseAsync(snapshot.scene, {
7292
+ binary: options.binary ?? false,
7293
+ maxTextureSize: options.maxTextureSize ?? Infinity
7294
+ });
7295
+ } finally {
7296
+ snapshot.dispose();
7297
+ }
7298
+ }
7299
+ };
7300
+ function localMatrix(object) {
7301
+ return object.matrixAutoUpdate ? new Matrix45().compose(object.position, object.quaternion, object.scale) : object.matrix.clone();
7302
+ }
7303
+ function createSnapshot(root, gltf, bakeColors = false) {
7304
+ const scene = new Scene4();
7305
+ const geometries = [];
7306
+ const materials = [];
7307
+ const textures = [];
7308
+ const textureCopies = /* @__PURE__ */ new Map();
7309
+ const dispose = () => {
7310
+ for (const geometry of geometries) geometry.dispose();
7311
+ for (const material of materials) material.dispose();
7312
+ for (const texture of textures) texture.dispose();
7313
+ };
7314
+ const copyMaterial = (source, geometry) => {
7315
+ let material;
7316
+ const shader = source;
7317
+ if (shader.isShaderMaterial && gltf) {
7318
+ const uniforms = shader.uniforms;
7319
+ if (!uniforms.map?.value?.isTexture || !uniforms.SHADE || !uniforms.BRIGHTNESS || !uniforms.EMISSIVE) {
7320
+ throw new MineRenderError("glTF export does not support this custom ShaderMaterial");
7321
+ }
7322
+ material = new MeshBasicMaterial2({
7323
+ map: uniforms.map.value,
7324
+ vertexColors: source.vertexColors,
7325
+ transparent: source.transparent,
7326
+ side: source.side,
7327
+ alphaTest: 0.01,
7328
+ depthWrite: source.depthWrite
7329
+ });
7330
+ material.name = source.name;
7331
+ } else if (shader.isShaderMaterial) {
7332
+ material = new MeshBasicMaterial2({ vertexColors: source.vertexColors });
7333
+ material.name = source.name;
7334
+ } else {
7335
+ const copySource = Object.create(source);
7336
+ copySource.userData = {};
7337
+ material = source.clone.call(copySource);
7338
+ }
7339
+ materials.push(material);
7340
+ if (gltf) {
7341
+ selectAlphaMode(material, geometry);
7342
+ for (const [key, value] of Object.entries(material)) {
7343
+ if (value?.isDataTexture) {
7344
+ let texture = textureCopies.get(value);
7345
+ if (!texture) {
7346
+ texture = copyDataTexture(value);
7347
+ textureCopies.set(value, texture);
7348
+ textures.push(texture);
7349
+ }
7350
+ material[key] = texture;
7351
+ }
7352
+ }
7353
+ }
7354
+ return material;
7355
+ };
7356
+ const addMesh = (mesh, world, instanceColor) => {
7357
+ if (world.determinant() === 0 || !mesh.geometry.getAttribute("position")) return;
7358
+ const source = mesh.geometry;
7359
+ const count = source.index?.count ?? source.getAttribute("position").count;
7360
+ const groups = Array.isArray(mesh.material) ? source.groups : [{ start: 0, count, materialIndex: 0 }];
7361
+ for (const group of groups) {
7362
+ const sourceMaterial = Array.isArray(mesh.material) ? mesh.material[group.materialIndex ?? 0] : mesh.material;
7363
+ if (!sourceMaterial?.visible) continue;
7364
+ const start = Math.max(group.start, source.drawRange.start);
7365
+ const end = Math.min(count, group.start + group.count, source.drawRange.start + source.drawRange.count);
7366
+ const indices = [];
7367
+ for (let i = start; i + 2 < end; i += 3) {
7368
+ for (let corner = 0; corner < 3; corner++) indices.push(source.index?.getX(i + corner) ?? i + corner);
7369
+ }
7370
+ if (!indices.length) continue;
7371
+ let geometry = source.clone();
7372
+ geometry.setIndex(indices);
7373
+ if (new Set(indices).size < geometry.getAttribute("position").count) {
7374
+ const compact = geometry.toNonIndexed();
7375
+ geometry.dispose();
7376
+ geometry = compact;
7377
+ }
7378
+ geometries.push(geometry);
7379
+ geometry.userData = {};
7380
+ geometry.clearGroups();
7381
+ geometry.setDrawRange(0, Infinity);
7382
+ DisplayTransforms.apply(geometry, world);
7383
+ const material = copyMaterial(sourceMaterial, geometry);
7384
+ if (!sourceMaterial.vertexColors) geometry.deleteAttribute("color");
7385
+ if (bakeColors || instanceColor) {
7386
+ const tint = (material.color ?? new Color6()).clone();
7387
+ if (instanceColor) tint.multiply(instanceColor);
7388
+ if (bakeColors) {
7389
+ const original = geometry.getAttribute("color");
7390
+ const colors = new Float32BufferAttribute3(new Float32Array(geometry.getAttribute("position").count * 3), 3);
7391
+ for (let i = 0; i < colors.count; i++) {
7392
+ colors.setXYZ(i, (original?.getX(i) ?? 1) * tint.r, (original?.getY(i) ?? 1) * tint.g, (original?.getZ(i) ?? 1) * tint.b);
7393
+ }
7394
+ geometry.setAttribute("color", colors);
7395
+ } else if (material.color) {
7396
+ material.color.copy(tint);
7397
+ }
7398
+ }
7399
+ const copy = new Mesh5(geometry, material);
7400
+ copy.name = mesh.name;
7401
+ copy.renderOrder = mesh.renderOrder;
7402
+ scene.add(copy);
7403
+ }
7404
+ };
7405
+ const visit = (object, parentWorld) => {
7406
+ if (!object.visible) return;
7407
+ const world = parentWorld.clone().multiply(localMatrix(object));
7408
+ const mesh = object;
7409
+ if (mesh.isMesh) {
7410
+ const instanced = mesh;
7411
+ if (instanced.isInstancedMesh) {
7412
+ for (let i = 0; i < instanced.count; i++) {
7413
+ const matrix = new Matrix45();
7414
+ instanced.getMatrixAt(i, matrix);
7415
+ const color = instanced.instanceColor ? new Color6().fromBufferAttribute(instanced.instanceColor, i) : void 0;
7416
+ addMesh(mesh, world.clone().multiply(matrix), color);
7417
+ }
7418
+ } else {
7419
+ addMesh(mesh, world);
7420
+ }
7421
+ }
7422
+ for (const child of object.children) visit(child, world);
7423
+ };
7424
+ try {
7425
+ const ancestors = [];
7426
+ for (let parent = root.parent; parent; parent = parent.parent) ancestors.unshift(parent);
7427
+ const world = new Matrix45();
7428
+ for (const ancestor of ancestors) {
7429
+ if (!ancestor.visible) return { scene, dispose };
7430
+ world.multiply(localMatrix(ancestor));
7431
+ }
7432
+ visit(root, world);
7433
+ return { scene, dispose };
7434
+ } catch (error) {
7435
+ dispose();
7436
+ throw error;
7437
+ }
7438
+ }
7439
+ function selectAlphaMode(material, geometry) {
7440
+ const texture = material.map;
7441
+ 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;
7442
+ const uv = geometry.getAttribute(texture.channel === 0 ? "uv" : `uv${texture.channel}`);
7443
+ const colors = geometry.getAttribute("color");
7444
+ if (!uv || material.vertexColors && colors?.itemSize === 4) return;
7445
+ const { data, width, height } = texture.image;
7446
+ if (!data || width < 1 || height < 1 || data.length < width * height * 4) return;
7447
+ const count = geometry.index?.count ?? uv.count;
7448
+ let holes = false;
7449
+ for (let i = 0; i + 2 < count; i += 3) {
7450
+ let minU = Infinity, maxU = -Infinity, minV = Infinity, maxV = -Infinity;
7451
+ for (let corner = 0; corner < 3; corner++) {
7452
+ const index = geometry.index?.getX(i + corner) ?? i + corner;
7453
+ const u = uv.getX(index), v = texture.flipY ? 1 - uv.getY(index) : uv.getY(index);
7454
+ if (!Number.isFinite(u) || !Number.isFinite(v)) return;
7455
+ minU = Math.min(minU, u);
7456
+ maxU = Math.max(maxU, u);
7457
+ minV = Math.min(minV, v);
7458
+ maxV = Math.max(maxV, v);
7459
+ }
7460
+ const minX = Math.max(0, Math.min(width - 1, Math.floor(minU * width)));
7461
+ const maxX = Math.max(minX, Math.min(width - 1, Math.ceil(maxU * width) - 1));
7462
+ const minY = Math.max(0, Math.min(height - 1, Math.floor(minV * height)));
7463
+ const maxY = Math.max(minY, Math.min(height - 1, Math.ceil(maxV * height) - 1));
7464
+ for (let y = minY; y <= maxY; y++) {
7465
+ for (let x = minX; x <= maxX; x++) {
7466
+ const alpha = data[(y * width + x) * 4 + 3];
7467
+ if (alpha === 255) continue;
7468
+ if (alpha !== 0 && alpha / 255 >= material.alphaTest) return;
7469
+ holes = true;
7470
+ }
7471
+ }
7472
+ }
7473
+ material.transparent = false;
7474
+ if (holes && material.alphaTest === 0) material.alphaTest = 1 / 255;
7475
+ }
7476
+ function copyDataTexture(source) {
7477
+ const image = source.image;
7478
+ if (source.format !== RGBAFormat3 || source.type !== UnsignedByteType) {
7479
+ throw new MineRenderError("glTF export requires RGBA unsigned-byte data textures");
7480
+ }
7481
+ const canvas = createCanvas(image.width, image.height);
7482
+ const context = canvas.getContext("2d");
7483
+ if (!context) throw new MineRenderError("glTF export could not create a 2D canvas context");
7484
+ const pixels = context.createImageData(image.width, image.height);
7485
+ pixels.data.set(image.data);
7486
+ context.putImageData(pixels, 0, 0);
7487
+ const copySource = Object.create(source);
7488
+ copySource.userData = {};
7489
+ copySource.source = new Source2(canvas);
7490
+ return new Texture4().copy(copySource);
7491
+ }
7492
+
4913
7493
  // src/gui/GuiHelper.ts
4914
7494
  var GuiHelper = class {
4915
7495
  static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
@@ -4924,7 +7504,7 @@ init_ModelTextures();
4924
7504
  init_Caching();
4925
7505
  init_SceneObject();
4926
7506
  init_Materials();
4927
- import { Box2, Mesh as Mesh4, PlaneGeometry, Vector2 as Vector22 } from "three";
7507
+ import { Box2, Mesh as Mesh6, PlaneGeometry as PlaneGeometry2, Vector2 as Vector23 } from "three";
4928
7508
  var GuiObject = class extends SceneObject {
4929
7509
  constructor(textureLayers, options) {
4930
7510
  super({ ...options, instanceMeshes: false, mergeMeshes: false });
@@ -4946,7 +7526,7 @@ var GuiObject = class extends SceneObject {
4946
7526
  const [cropX, cropY, cropWidth, cropHeight] = layer.crop ?? [0, 0, image.width, image.height];
4947
7527
  const [width, height] = layer.size ?? [cropWidth, cropHeight];
4948
7528
  const [x, y] = layer.position ?? [0, 0];
4949
- const geometry = new PlaneGeometry(width, height);
7529
+ const geometry = new PlaneGeometry2(width, height);
4950
7530
  this.geometries.add(geometry);
4951
7531
  const uv = geometry.getAttribute("uv");
4952
7532
  for (let i = 0; i < uv.count; i++) {
@@ -4956,13 +7536,13 @@ var GuiObject = class extends SceneObject {
4956
7536
  1 - (cropY + (1 - uv.getY(i)) * cropHeight) / image.height
4957
7537
  );
4958
7538
  }
4959
- const mesh = new Mesh4(geometry, material);
7539
+ const mesh = new Mesh6(geometry, material);
4960
7540
  mesh.name = `mesh:${layer.name ?? index}`;
4961
7541
  mesh.position.set(x + width / 2, -y - height / 2, 0);
4962
7542
  mesh.renderOrder = index;
4963
7543
  this.add(mesh);
4964
- this.bounds.expandByPoint(new Vector22(x, y));
4965
- this.bounds.expandByPoint(new Vector22(x + width, y + height));
7544
+ this.bounds.expandByPoint(new Vector23(x, y));
7545
+ this.bounds.expandByPoint(new Vector23(x + width, y + height));
4966
7546
  }
4967
7547
  this.initialized = true;
4968
7548
  this.notifyDirty();
@@ -5011,7 +7591,7 @@ init_image();
5011
7591
  // src/inspector/SceneInspector.ts
5012
7592
  init_SceneObject();
5013
7593
  init_util();
5014
- import { Raycaster, Vector2 as Vector23 } from "three";
7594
+ import { Raycaster, Vector2 as Vector24 } from "three";
5015
7595
  init_log();
5016
7596
  init_three();
5017
7597
  var p7 = prefix("SceneInspector");
@@ -5019,7 +7599,7 @@ var help = "<span>Ctrl/Cmd+Click to Select<br/></span><br/>";
5019
7599
  var SceneInspector = class {
5020
7600
  constructor(renderer) {
5021
7601
  this.renderer = renderer;
5022
- this.mouse = new Vector23();
7602
+ this.mouse = new Vector24();
5023
7603
  this.listeners = new AbortController();
5024
7604
  this.objectInfoContainer = document.createElement("div");
5025
7605
  this.objectControlsContainer = document.createElement("div");
@@ -5627,7 +8207,7 @@ var import_ts_deepmerge6 = __toESM(require_dist());
5627
8207
  init_MineRenderError();
5628
8208
  init_InstanceReference();
5629
8209
  init_AssetKey();
5630
- import { Euler as Euler7, Matrix4 as Matrix45, Quaternion as Quaternion4, Vector3 as Vector38 } from "three";
8210
+ import { Euler as Euler7, Matrix4 as Matrix47, Quaternion as Quaternion5, Vector3 as Vector311 } from "three";
5631
8211
  init_ModelCulling();
5632
8212
  init_FluidGeometry();
5633
8213
  var _BlockObject = class _BlockObject extends SceneObject {
@@ -5688,11 +8268,11 @@ var _BlockObject = class _BlockObject extends SceneObject {
5688
8268
  getModelCullMask(model, worldMask) {
5689
8269
  const object = isInstanceReference(model) ? model.instanceable : model;
5690
8270
  if (object.options.displayPosition) return 0;
5691
- const position = new Vector38();
5692
- const rotation = new Quaternion4();
5693
- const scale = new Vector38();
8271
+ const position = new Vector311();
8272
+ const rotation = new Quaternion5();
8273
+ const scale = new Vector311();
5694
8274
  this.getModelMatrix(model).decompose(position, rotation, scale);
5695
- if (position.distanceToSquared(this.position) > 1e-10 || scale.distanceToSquared(new Vector38(1, 1, 1)) > 1e-10) return 0;
8275
+ if (position.distanceToSquared(this.position) > 1e-10 || scale.distanceToSquared(new Vector311(1, 1, 1)) > 1e-10) return 0;
5696
8276
  return ModelCulling.toLocalMask(worldMask, new Euler7().setFromQuaternion(rotation));
5697
8277
  }
5698
8278
  async setCullMask(worldMask) {
@@ -5755,7 +8335,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
5755
8335
  () => new FluidModelObject2(kind, surface.sample, this.blockState.key, this.options)
5756
8336
  );
5757
8337
  const previous = this._fluidModel;
5758
- const matrix = previous ? this.getModelMatrix(previous) : new Matrix45().makeTranslation(...this.position.toArray());
8338
+ const matrix = previous ? this.getModelMatrix(previous) : new Matrix47().makeTranslation(...this.position.toArray());
5759
8339
  if (isInstanceReference(replacement)) replacement.setMatrix(matrix);
5760
8340
  else matrix.decompose(replacement.position, replacement.quaternion, replacement.scale);
5761
8341
  this._models = this._models.filter((model) => model !== previous);
@@ -5886,7 +8466,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
5886
8466
  setPositionRotationScaleAt(index, position, rotation, scale) {
5887
8467
  super.setPositionRotationScaleAt(index, position, rotation, scale);
5888
8468
  }
5889
- getMatrixAt(index, matrix = new Matrix45()) {
8469
+ getMatrixAt(index, matrix = new Matrix47()) {
5890
8470
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
5891
8471
  const child = this._models[0];
5892
8472
  if (child && isModelObject(child)) {
@@ -7759,7 +10339,7 @@ init_nbt();
7759
10339
  init_SceneObject();
7760
10340
  var import_ts_deepmerge8 = __toESM(require_dist());
7761
10341
  init_ModelObject();
7762
- import { Scene as Scene2 } from "three";
10342
+ import { Scene as Scene5 } from "three";
7763
10343
 
7764
10344
  // src/skin/scene/SkinObject.ts
7765
10345
  init_SceneObject();
@@ -8492,7 +11072,7 @@ init_util();
8492
11072
  init_Caching();
8493
11073
  init_CacheKey();
8494
11074
  init_MineRenderError();
8495
- import { DataTexture, DoubleSide as DoubleSide3, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial4, SRGBColorSpace as SRGBColorSpace3 } from "three";
11075
+ import { DataTexture as DataTexture2, DoubleSide as DoubleSide4, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial5, SRGBColorSpace as SRGBColorSpace5 } from "three";
8496
11076
 
8497
11077
  // src/skin/SkinImage.ts
8498
11078
  init_Caching();
@@ -8573,11 +11153,11 @@ var SkinTextures = class {
8573
11153
  });
8574
11154
  }
8575
11155
  static createMaterial(pixels, width, height, transparent = true) {
8576
- const texture = Textures.initTextureProps(new DataTexture(pixels, width, height));
8577
- texture.colorSpace = SRGBColorSpace3;
11156
+ const texture = Textures.initTextureProps(new DataTexture2(pixels, width, height));
11157
+ texture.colorSpace = SRGBColorSpace5;
8578
11158
  texture.flipY = true;
8579
11159
  texture.needsUpdate = true;
8580
- return new MeshBasicMaterial4({ map: texture, transparent, side: transparent ? DoubleSide3 : FrontSide2, alphaTest: transparent ? 0.1 : 0 });
11160
+ return new MeshBasicMaterial5({ map: texture, transparent, side: transparent ? DoubleSide4 : FrontSide2, alphaTest: transparent ? 0.1 : 0 });
8581
11161
  }
8582
11162
  static isSlim(image, scale) {
8583
11163
  for (const [x, y] of [[46, 52], [54, 20]]) {
@@ -8804,7 +11384,7 @@ var SkinObject = class extends SceneObject {
8804
11384
  };
8805
11385
 
8806
11386
  // src/renderer/MineRenderScene.ts
8807
- var _MineRenderScene = class _MineRenderScene extends Scene2 {
11387
+ var _MineRenderScene = class _MineRenderScene extends Scene5 {
8808
11388
  constructor(options) {
8809
11389
  super();
8810
11390
  this.isMineRenderScene = true;
@@ -8936,7 +11516,7 @@ function isMineRenderScene(obj) {
8936
11516
  }
8937
11517
 
8938
11518
  // src/renderer/Renderer.ts
8939
- import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace4, Vector3 as Vector310, WebGLRenderer } from "three";
11519
+ import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera as PerspectiveCamera2, SRGBColorSpace as SRGBColorSpace6, Vector3 as Vector313, WebGLRenderer as WebGLRenderer2 } from "three";
8940
11520
  var import_ts_deepmerge9 = __toESM(require_dist());
8941
11521
  init_util();
8942
11522
  import Stats from "stats.js";
@@ -8947,11 +11527,11 @@ init_three();
8947
11527
  import {
8948
11528
  EventDispatcher,
8949
11529
  MOUSE,
8950
- Quaternion as Quaternion5,
11530
+ Quaternion as Quaternion6,
8951
11531
  Spherical,
8952
11532
  TOUCH,
8953
- Vector2 as Vector24,
8954
- Vector3 as Vector39
11533
+ Vector2 as Vector25,
11534
+ Vector3 as Vector312
8955
11535
  } from "three";
8956
11536
  var _changeEvent = { type: "change" };
8957
11537
  var _startEvent = { type: "start" };
@@ -8965,7 +11545,7 @@ var OrbitControls = class extends EventDispatcher {
8965
11545
  this.domElement = domElement;
8966
11546
  this.domElement.style.touchAction = "none";
8967
11547
  this.enabled = true;
8968
- this.target = new Vector39();
11548
+ this.target = new Vector312();
8969
11549
  this.minDistance = 0;
8970
11550
  this.maxDistance = Infinity;
8971
11551
  this.minZoom = 0;
@@ -9017,11 +11597,11 @@ var OrbitControls = class extends EventDispatcher {
9017
11597
  state = STATE.NONE;
9018
11598
  };
9019
11599
  this.update = function() {
9020
- const offset = new Vector39();
9021
- const quat = new Quaternion5().setFromUnitVectors(object.up, new Vector39(0, 1, 0));
11600
+ const offset = new Vector312();
11601
+ const quat = new Quaternion6().setFromUnitVectors(object.up, new Vector312(0, 1, 0));
9022
11602
  const quatInverse = quat.clone().invert();
9023
- const lastPosition = new Vector39();
9024
- const lastQuaternion = new Quaternion5();
11603
+ const lastPosition = new Vector312();
11604
+ const lastQuaternion = new Quaternion6();
9025
11605
  const twoPI = 2 * Math.PI;
9026
11606
  return function update() {
9027
11607
  const position = scope.object.position;
@@ -9110,17 +11690,17 @@ var OrbitControls = class extends EventDispatcher {
9110
11690
  const spherical = new Spherical();
9111
11691
  const sphericalDelta = new Spherical();
9112
11692
  let scale = 1;
9113
- const panOffset = new Vector39();
11693
+ const panOffset = new Vector312();
9114
11694
  let zoomChanged = false;
9115
- const rotateStart = new Vector24();
9116
- const rotateEnd = new Vector24();
9117
- const rotateDelta = new Vector24();
9118
- const panStart = new Vector24();
9119
- const panEnd = new Vector24();
9120
- const panDelta = new Vector24();
9121
- const dollyStart = new Vector24();
9122
- const dollyEnd = new Vector24();
9123
- const dollyDelta = new Vector24();
11695
+ const rotateStart = new Vector25();
11696
+ const rotateEnd = new Vector25();
11697
+ const rotateDelta = new Vector25();
11698
+ const panStart = new Vector25();
11699
+ const panEnd = new Vector25();
11700
+ const panDelta = new Vector25();
11701
+ const dollyStart = new Vector25();
11702
+ const dollyEnd = new Vector25();
11703
+ const dollyDelta = new Vector25();
9124
11704
  const pointers = [];
9125
11705
  const pointerPositions = {};
9126
11706
  function getAutoRotationAngle() {
@@ -9136,7 +11716,7 @@ var OrbitControls = class extends EventDispatcher {
9136
11716
  sphericalDelta.phi -= angle;
9137
11717
  }
9138
11718
  const panLeft = function() {
9139
- const v = new Vector39();
11719
+ const v = new Vector312();
9140
11720
  return function panLeft2(distance, objectMatrix) {
9141
11721
  v.setFromMatrixColumn(objectMatrix, 0);
9142
11722
  v.multiplyScalar(-distance);
@@ -9144,7 +11724,7 @@ var OrbitControls = class extends EventDispatcher {
9144
11724
  };
9145
11725
  }();
9146
11726
  const panUp = function() {
9147
- const v = new Vector39();
11727
+ const v = new Vector312();
9148
11728
  return function panUp2(distance, objectMatrix) {
9149
11729
  if (scope.screenSpacePanning === true) {
9150
11730
  v.setFromMatrixColumn(objectMatrix, 1);
@@ -9157,7 +11737,7 @@ var OrbitControls = class extends EventDispatcher {
9157
11737
  };
9158
11738
  }();
9159
11739
  const pan = function() {
9160
- const offset = new Vector39();
11740
+ const offset = new Vector312();
9161
11741
  return function pan2(deltaX, deltaY) {
9162
11742
  const element = scope.domElement;
9163
11743
  if (scope.object.isPerspectiveCamera) {
@@ -9566,7 +12146,7 @@ var OrbitControls = class extends EventDispatcher {
9566
12146
  function trackPointer(event) {
9567
12147
  let position = pointerPositions[event.pointerId];
9568
12148
  if (position === void 0) {
9569
- position = new Vector24();
12149
+ position = new Vector25();
9570
12150
  pointerPositions[event.pointerId] = position;
9571
12151
  }
9572
12152
  position.set(event.pageX, event.pageY);
@@ -9630,7 +12210,7 @@ var _Renderer = class _Renderer {
9630
12210
  switch (this.options.camera.type) {
9631
12211
  case "perspective":
9632
12212
  default:
9633
- return new PerspectiveCamera(
12213
+ return new PerspectiveCamera2(
9634
12214
  this.options.camera.perspective.fov,
9635
12215
  this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
9636
12216
  this.options.camera.near,
@@ -9648,7 +12228,7 @@ var _Renderer = class _Renderer {
9648
12228
  }
9649
12229
  }
9650
12230
  createRenderer() {
9651
- const renderer = new WebGLRenderer({
12231
+ const renderer = new WebGLRenderer2({
9652
12232
  antialias: this.options.render.antialias,
9653
12233
  alpha: true,
9654
12234
  powerPreference: "high-performance",
@@ -9657,7 +12237,7 @@ var _Renderer = class _Renderer {
9657
12237
  renderer.setClearColor(0, 0);
9658
12238
  renderer.shadowMap.enabled = true;
9659
12239
  renderer.shadowMap.type = PCFSoftShadowMap;
9660
- renderer.outputColorSpace = SRGBColorSpace4;
12240
+ renderer.outputColorSpace = SRGBColorSpace6;
9661
12241
  renderer.setPixelRatio(this.options.render.pixelRatio ?? 1);
9662
12242
  renderer.setSize(this.viewWidth, this.viewHeight);
9663
12243
  return renderer;
@@ -9849,6 +12429,9 @@ var _Renderer = class _Renderer {
9849
12429
  if (next !== void 0 && t + 0.1 < next) return;
9850
12430
  this._nextFrameTime = next !== void 0 && t - next < interval ? next + interval : t + interval;
9851
12431
  }
12432
+ this.drawFrame();
12433
+ }
12434
+ drawFrame() {
9852
12435
  if (this._stats) {
9853
12436
  this._stats.begin();
9854
12437
  }
@@ -9863,8 +12446,28 @@ var _Renderer = class _Renderer {
9863
12446
  }
9864
12447
  }
9865
12448
  //</editor-fold>
9866
- toImage() {
9867
- return this.renderer.domElement.toDataURL();
12449
+ /**
12450
+ * Renders a fresh frame and returns an image data URL, including while the animation loop is stopped.
12451
+ * Trimming removes transparent borders; an empty image becomes one transparent pixel.
12452
+ * MIME type support and lossy quality (0–1) follow the canvas encoder.
12453
+ */
12454
+ toImage(trim = false, mime = "image/png", quality) {
12455
+ if (this._disposed) throw new Error("Cannot export an image from a disposed renderer");
12456
+ if (this._controls?.enabled) {
12457
+ this._controls.update();
12458
+ }
12459
+ this.drawFrame();
12460
+ const canvas = trim ? trimCanvas(this.renderer.domElement) : this.renderer.domElement;
12461
+ return canvas.toDataURL(mime, quality);
12462
+ }
12463
+ toObj() {
12464
+ return SceneExporter.toObj(this.scene);
12465
+ }
12466
+ toPLY(options) {
12467
+ return SceneExporter.toPLY(this.scene, options);
12468
+ }
12469
+ toGLTF(options) {
12470
+ return SceneExporter.toGLTF(this.scene, options);
9868
12471
  }
9869
12472
  ///
9870
12473
  get attachedToBody() {
@@ -9909,8 +12512,8 @@ _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
9909
12512
  top: void 0,
9910
12513
  bottom: void 0
9911
12514
  },
9912
- position: new Vector310(50, 50, 50),
9913
- lookingAt: new Vector310(0, 0, 0)
12515
+ position: new Vector313(50, 50, 50),
12516
+ lookingAt: new Vector313(0, 0, 0)
9914
12517
  },
9915
12518
  render: {
9916
12519
  fpsLimit: 60,
@@ -10374,12 +12977,12 @@ var AnvilParser = class {
10374
12977
  };
10375
12978
 
10376
12979
  // src/world/Chunk.ts
10377
- import { Vector3 as Vector313 } from "three";
12980
+ import { Vector3 as Vector316 } from "three";
10378
12981
  init_BlockStates();
10379
12982
  init_AssetKey();
10380
12983
 
10381
12984
  // src/world/MineRenderWorld.ts
10382
- import { Vector3 as Vector312 } from "three";
12985
+ import { Vector3 as Vector315 } from "three";
10383
12986
  init_BatchedExecutor();
10384
12987
  init_AssetKey();
10385
12988
  init_BlockStates();
@@ -10389,7 +12992,7 @@ init_CubeFace();
10389
12992
  init_AssetKey();
10390
12993
  init_Models();
10391
12994
  init_CubeFace();
10392
- import { Matrix4 as Matrix46, Vector3 as Vector311 } from "three";
12995
+ import { Matrix4 as Matrix48, Vector3 as Vector314 } from "three";
10393
12996
  init_ModelCulling();
10394
12997
  init_ModelObject();
10395
12998
  init_UVMapper();
@@ -10452,12 +13055,12 @@ var SectionModels = class {
10452
13055
  });
10453
13056
  await object.init();
10454
13057
  const geometry = object.children[0].geometry;
10455
- geometry.applyMatrix4(new Matrix46().makeRotationFromEuler(rotation));
13058
+ geometry.applyMatrix4(new Matrix48().makeRotationFromEuler(rotation));
10456
13059
  object.clear();
10457
13060
  const cullFaces = CUBE_FACES.map((face) => {
10458
13061
  const local = CUBE_FACES.findIndex((name) => name === atlas.model.elements[0].faces[face]?.cullface);
10459
13062
  if (local < 0) return 0;
10460
- const normal = new Vector311(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
13063
+ const normal = new Vector314(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
10461
13064
  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);
10462
13065
  return 1 << world;
10463
13066
  });
@@ -10487,20 +13090,20 @@ var MineRenderWorld = class {
10487
13090
  }
10488
13091
  getBlockAt(posOrX, y, z) {
10489
13092
  if (typeof posOrX == "number") {
10490
- return this.getBlockAt(new Vector312(posOrX, y, z));
13093
+ return this.getBlockAt(new Vector315(posOrX, y, z));
10491
13094
  }
10492
13095
  if (isTripleArray(posOrX)) {
10493
- return this.getBlockAt(new Vector312(posOrX[0], posOrX[1], posOrX[2]));
13096
+ return this.getBlockAt(new Vector315(posOrX[0], posOrX[1], posOrX[2]));
10494
13097
  }
10495
13098
  this.validatePosBounds(posOrX);
10496
13099
  return this.getChunkAt(posOrX)?.getBlockAt(posOrX);
10497
13100
  }
10498
13101
  async setBlockAt(posOrX, yOrBlock, z, block) {
10499
13102
  if (typeof posOrX == "number") {
10500
- return this.setBlockAt(new Vector312(posOrX, yOrBlock, z), block);
13103
+ return this.setBlockAt(new Vector315(posOrX, yOrBlock, z), block);
10501
13104
  }
10502
13105
  if (isTripleArray(posOrX)) {
10503
- return this.setBlockAt(new Vector312(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
13106
+ return this.setBlockAt(new Vector315(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
10504
13107
  }
10505
13108
  return this.placeBlock(posOrX, yOrBlock);
10506
13109
  }
@@ -10521,7 +13124,7 @@ var MineRenderWorld = class {
10521
13124
  const collect = async (positions2) => {
10522
13125
  for (const pos of positions2) changes.set(pos.toArray().join(","), pos);
10523
13126
  };
10524
- const place = (block) => this.placeBlock(new Vector312(...block.position), block, collect);
13127
+ const place = (block) => this.placeBlock(new Vector315(...block.position), block, collect);
10525
13128
  const keys = /* @__PURE__ */ new Map();
10526
13129
  for (const block of multiblock.blocks) {
10527
13130
  if (Chunk.isAir(block)) continue;
@@ -10599,13 +13202,13 @@ var MineRenderWorld = class {
10599
13202
  for (const pos of positions) {
10600
13203
  this.pendingCulling.set(pos.toArray().join(","), pos.clone());
10601
13204
  for (const offset of CUBE_FACE_OFFSETS) {
10602
- const neighbor = pos.clone().add(new Vector312(...offset));
13205
+ const neighbor = pos.clone().add(new Vector315(...offset));
10603
13206
  this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
10604
13207
  }
10605
13208
  for (let y = -1; y <= 1; y++) {
10606
13209
  for (let z = -1; z <= 1; z++) {
10607
13210
  for (let x = -1; x <= 1; x++) {
10608
- const neighbor = pos.clone().add(new Vector312(x, y, z));
13211
+ const neighbor = pos.clone().add(new Vector315(x, y, z));
10609
13212
  if (this.getBlockAt(neighbor)?.object?.fluidKind) {
10610
13213
  this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
10611
13214
  }
@@ -10627,7 +13230,7 @@ var MineRenderWorld = class {
10627
13230
  if (!block) continue;
10628
13231
  if (block.object?.fluidKind) {
10629
13232
  await block.object.updateFluid((x, y, z) => {
10630
- const neighbor = pos.clone().add(new Vector312(x, y, z));
13233
+ const neighbor = pos.clone().add(new Vector315(x, y, z));
10631
13234
  const section = this.getChunkAt(neighbor);
10632
13235
  const object = section?.getBlockAt(neighbor)?.object;
10633
13236
  return {
@@ -10639,7 +13242,7 @@ var MineRenderWorld = class {
10639
13242
  }
10640
13243
  let mask = 0;
10641
13244
  for (const [face, offset] of CUBE_FACE_OFFSETS.entries()) {
10642
- const neighbor = pos.clone().add(new Vector312(...offset));
13245
+ const neighbor = pos.clone().add(new Vector315(...offset));
10643
13246
  if (this.getChunkAt(neighbor)?.isOccludingAt(neighbor)) {
10644
13247
  mask |= 1 << face;
10645
13248
  }
@@ -10673,14 +13276,14 @@ var MineRenderWorld = class {
10673
13276
  return this._chunks.get(this.worldPosToChunkKey(pos));
10674
13277
  }
10675
13278
  static worldToScenePosition(pos) {
10676
- return new Vector312(
13279
+ return new Vector315(
10677
13280
  pos.x * 16,
10678
13281
  pos.y * 16,
10679
13282
  pos.z * 16
10680
13283
  );
10681
13284
  }
10682
13285
  static sceneToWorldPosition(pos) {
10683
- return new Vector312(
13286
+ return new Vector315(
10684
13287
  pos.x / 16,
10685
13288
  pos.y / 16,
10686
13289
  pos.z / 16
@@ -10702,7 +13305,7 @@ var MineRenderWorld = class {
10702
13305
  // src/world/SectionMesh.ts
10703
13306
  init_CanvasCompat();
10704
13307
  init_Materials();
10705
- import { BufferGeometry as BufferGeometry4, Float32BufferAttribute as Float32BufferAttribute5, Group, Mesh as Mesh8 } from "three";
13308
+ import { BufferGeometry as BufferGeometry5, Float32BufferAttribute as Float32BufferAttribute6, Group, Mesh as Mesh10 } from "three";
10706
13309
  var SectionMesh = class _SectionMesh extends Group {
10707
13310
  constructor() {
10708
13311
  super(...arguments);
@@ -10776,18 +13379,18 @@ var SectionMesh = class _SectionMesh extends Group {
10776
13379
  for (let corner = 0; corner < 6; corner++) indices.push(start + sourceIndices.getX(face * 6 + corner) - face * 4);
10777
13380
  }
10778
13381
  }
10779
- const geometry = new BufferGeometry4();
10780
- geometry.setAttribute("position", new Float32BufferAttribute5(positions, 3));
10781
- geometry.setAttribute("normal", new Float32BufferAttribute5(normals, 3));
10782
- geometry.setAttribute("uv", new Float32BufferAttribute5(uvs, 2));
10783
- geometry.setAttribute("color", new Float32BufferAttribute5(colors, 3));
13382
+ const geometry = new BufferGeometry5();
13383
+ geometry.setAttribute("position", new Float32BufferAttribute6(positions, 3));
13384
+ geometry.setAttribute("normal", new Float32BufferAttribute6(normals, 3));
13385
+ geometry.setAttribute("uv", new Float32BufferAttribute6(uvs, 2));
13386
+ geometry.setAttribute("color", new Float32BufferAttribute6(colors, 3));
10784
13387
  geometry.setIndex(indices);
10785
13388
  geometry.computeBoundingBox();
10786
13389
  geometry.computeBoundingSphere();
10787
13390
  const material = Materials.createShadedCanvasMaterial(canvas, false);
10788
13391
  material.vertexColors = true;
10789
13392
  const texture = material.uniforms?.map?.value ?? material.map;
10790
- const mesh = new Mesh8(geometry, material);
13393
+ const mesh = new Mesh10(geometry, material);
10791
13394
  section.add(mesh);
10792
13395
  section.ownedMeshes.push({ mesh, texture });
10793
13396
  }
@@ -10821,10 +13424,10 @@ var Chunk = class _Chunk {
10821
13424
  }
10822
13425
  getBlockAt(posOrX, y, z) {
10823
13426
  if (typeof posOrX == "number") {
10824
- return this.getBlockAt(new Vector313(posOrX, y, z));
13427
+ return this.getBlockAt(new Vector316(posOrX, y, z));
10825
13428
  }
10826
13429
  if (isTripleArray(posOrX)) {
10827
- return this.getBlockAt(new Vector313(posOrX[0], posOrX[1], posOrX[2]));
13430
+ return this.getBlockAt(new Vector316(posOrX[0], posOrX[1], posOrX[2]));
10828
13431
  }
10829
13432
  const pos = this.worldPosToChunkPos(posOrX);
10830
13433
  const index = _Chunk.chunkPosToBlockIndex(pos);
@@ -10832,10 +13435,10 @@ var Chunk = class _Chunk {
10832
13435
  }
10833
13436
  async setBlockAt(posOrX, yOrBlock, z, block) {
10834
13437
  if (typeof posOrX == "number") {
10835
- return this.setBlockAt(new Vector313(posOrX, yOrBlock, z), block);
13438
+ return this.setBlockAt(new Vector316(posOrX, yOrBlock, z), block);
10836
13439
  }
10837
13440
  if (isTripleArray(posOrX)) {
10838
- return this.setBlockAt(new Vector313(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
13441
+ return this.setBlockAt(new Vector316(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
10839
13442
  }
10840
13443
  const worldPos = posOrX;
10841
13444
  const pos = this.worldPosToChunkPos(worldPos);
@@ -10920,7 +13523,7 @@ var Chunk = class _Chunk {
10920
13523
  }
10921
13524
  async clear(onBlocksChanged = this.onBlocksChanged) {
10922
13525
  const positions = [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
10923
- new Vector313(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
13526
+ new Vector316(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
10924
13527
  ));
10925
13528
  for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
10926
13529
  this.sectionBlocks.clear();
@@ -10944,14 +13547,14 @@ var Chunk = class _Chunk {
10944
13547
  return pos.y * 16 * 16 + pos.z * 16 + pos.x;
10945
13548
  }
10946
13549
  worldPosToChunkPos(pos) {
10947
- return new Vector313(
13550
+ return new Vector316(
10948
13551
  pos.x - this.x * 16,
10949
13552
  pos.y - this.y * 16,
10950
13553
  pos.z - this.z * 16
10951
13554
  );
10952
13555
  }
10953
13556
  chunkPosToWorldPos(pos) {
10954
- return new Vector313(
13557
+ return new Vector316(
10955
13558
  this.x * 16 + pos.x,
10956
13559
  this.y * 16 + pos.y,
10957
13560
  this.z * 16 + pos.z
@@ -11030,6 +13633,7 @@ export {
11030
13633
  RequestError,
11031
13634
  Requests,
11032
13635
  SKIN_PARTS,
13636
+ SceneExporter,
11033
13637
  SceneInspector,
11034
13638
  SceneObject,
11035
13639
  SceneStats,
@@ -11119,6 +13723,7 @@ export {
11119
13723
  timingStart,
11120
13724
  toDegrees,
11121
13725
  toRadians,
11122
- toTrianglesDrawMode
13726
+ toTrianglesDrawMode,
13727
+ trimCanvas
11123
13728
  };
11124
13729
  //# sourceMappingURL=index.mjs.map