minerender 2.1.0-alpha.66 → 2.1.0-alpha.68

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.
@@ -3512,7 +3512,7 @@ var init_InstanceReference = __esm({
3512
3512
  });
3513
3513
 
3514
3514
  // src/renderer/SceneObject.ts
3515
- import { Color as Color2, Euler as Euler4, InstancedBufferAttribute, InstancedMesh, MathUtils, Matrix4 as Matrix44, Mesh as Mesh3, Object3D as Object3D2, Quaternion as Quaternion3, Vector3 as Vector36 } from "three";
3515
+ import { Color as Color2, Euler as Euler4, InstancedBufferAttribute, InstancedMesh, Matrix4 as Matrix44, Mesh as Mesh3, Object3D as Object3D2, Quaternion as Quaternion3, Vector3 as Vector36 } from "three";
3516
3516
  function isSceneObject(obj) {
3517
3517
  return obj.isSceneObject;
3518
3518
  }
@@ -3940,6 +3940,7 @@ var init_SceneObject = __esm({
3940
3940
  dispose() {
3941
3941
  this.disposeAndRemoveAllChildren();
3942
3942
  this.notifyDirty();
3943
+ super.dispose();
3943
3944
  }
3944
3945
  disposeAndRemoveAllChildren() {
3945
3946
  if (this.instanceMesh) {
@@ -4157,6 +4158,7 @@ var init_EntityObject = __esm({
4157
4158
  else matrix.makeRotationFromEuler(new Euler5(...op.rotate, "ZYX"));
4158
4159
  modelRoot.matrix.multiply(matrix);
4159
4160
  }
4161
+ modelRoot.matrixWorldNeedsUpdate = true;
4160
4162
  modelRoot.matrixAutoUpdate = false;
4161
4163
  } else if (this.options.flip ?? true) {
4162
4164
  modelRoot.scale.set(-1, -1, 1);
@@ -4245,8 +4247,8 @@ var init_EntityObject = __esm({
4245
4247
  // src/three/BufferGeometryUtils.js
4246
4248
  import {
4247
4249
  BufferAttribute as BufferAttribute4,
4248
- BufferGeometry as BufferGeometry2,
4249
- Float32BufferAttribute as Float32BufferAttribute4,
4250
+ BufferGeometry as BufferGeometry3,
4251
+ Float32BufferAttribute as Float32BufferAttribute5,
4250
4252
  InterleavedBuffer,
4251
4253
  InterleavedBufferAttribute,
4252
4254
  TriangleFanDrawMode,
@@ -4265,7 +4267,7 @@ function mergeBufferGeometries(geometries, useGroups = false) {
4265
4267
  const attributes = {};
4266
4268
  const morphAttributes = {};
4267
4269
  const morphTargetsRelative = geometries[0].morphTargetsRelative;
4268
- const mergedGeometry = new BufferGeometry2();
4270
+ const mergedGeometry = new BufferGeometry3();
4269
4271
  let offset = 0;
4270
4272
  for (let i = 0; i < geometries.length; ++i) {
4271
4273
  const geometry = geometries[i];
@@ -4774,8 +4776,8 @@ function computeMorphedAttributes(object) {
4774
4776
  }
4775
4777
  }
4776
4778
  }
4777
- const morphedPositionAttribute = new Float32BufferAttribute4(modifiedPosition, 3);
4778
- const morphedNormalAttribute = new Float32BufferAttribute4(modifiedNormal, 3);
4779
+ const morphedPositionAttribute = new Float32BufferAttribute5(modifiedPosition, 3);
4780
+ const morphedNormalAttribute = new Float32BufferAttribute5(modifiedNormal, 3);
4779
4781
  return {
4780
4782
  positionAttribute,
4781
4783
  normalAttribute,
@@ -5072,6 +5074,7 @@ var init_ModelObject = __esm({
5072
5074
  for (const part of parts) {
5073
5075
  const object = new EntityObject(part.model, { flip: false, wireframe: this.options.wireframe });
5074
5076
  object.matrix.copy(transform).multiply(part.transform);
5077
+ object.matrixWorldNeedsUpdate = true;
5075
5078
  object.matrixAutoUpdate = false;
5076
5079
  this.add(object);
5077
5080
  await object.init();
@@ -5267,7 +5270,7 @@ var init_fluidBlocks = __esm({
5267
5270
  });
5268
5271
 
5269
5272
  // src/model/fluid/FluidGeometry.ts
5270
- import { BufferGeometry as BufferGeometry4, Float32BufferAttribute as Float32BufferAttribute5 } from "three";
5273
+ import { BufferGeometry as BufferGeometry5, Float32BufferAttribute as Float32BufferAttribute6 } from "three";
5271
5274
  function getBlockFluidState(key, state) {
5272
5275
  const rule = key && fluidRules[key.toNamespacedString()];
5273
5276
  if (rule) return {
@@ -5285,7 +5288,7 @@ function ownHeight(sample) {
5285
5288
  return (level === 0 || level >= 8 ? 8 : 8 - level) / 9;
5286
5289
  }
5287
5290
  function createFluidGeometry(kind, sample) {
5288
- const geometry = new BufferGeometry4();
5291
+ const geometry = new BufferGeometry5();
5289
5292
  const positions = [], normals = [], uvs = [], indices = [];
5290
5293
  const self = sample(0, 0, 0);
5291
5294
  const height = (x, z) => {
@@ -5384,9 +5387,9 @@ function createFluidGeometry(kind, sample) {
5384
5387
  1
5385
5388
  );
5386
5389
  }
5387
- geometry.setAttribute("position", new Float32BufferAttribute5(positions, 3));
5388
- geometry.setAttribute("normal", new Float32BufferAttribute5(normals, 3));
5389
- geometry.setAttribute("uv", new Float32BufferAttribute5(uvs, 2));
5390
+ geometry.setAttribute("position", new Float32BufferAttribute6(positions, 3));
5391
+ geometry.setAttribute("normal", new Float32BufferAttribute6(normals, 3));
5392
+ geometry.setAttribute("uv", new Float32BufferAttribute6(uvs, 2));
5390
5393
  geometry.setIndex(indices);
5391
5394
  return geometry;
5392
5395
  }
@@ -5783,16 +5786,26 @@ init_EntityObject();
5783
5786
  init_MineRenderError();
5784
5787
 
5785
5788
  // src/export/SceneExporter.ts
5786
- import { ClampToEdgeWrapping as ClampToEdgeWrapping2, Color as Color7, Float32BufferAttribute as Float32BufferAttribute3, Matrix4 as Matrix47, Mesh as Mesh5, MeshBasicMaterial as MeshBasicMaterial2, NearestFilter as NearestFilter3, RGBAFormat as RGBAFormat3, Scene as Scene4, Source as Source2, Texture as Texture4, UnsignedByteType } from "three";
5789
+ import { ClampToEdgeWrapping as ClampToEdgeWrapping2, Color as Color7, Float32BufferAttribute as Float32BufferAttribute3, Matrix4 as Matrix47, Mesh as Mesh4, MeshBasicMaterial as MeshBasicMaterial2, NearestFilter as NearestFilter3, RGBAFormat as RGBAFormat3, Scene as Scene3, TextureSource as TextureSource2, Texture as Texture3, UnsignedByteType } from "three";
5787
5790
 
5788
5791
  // ../../node_modules/three/examples/jsm/exporters/OBJExporter.js
5789
5792
  import {
5790
5793
  Color as Color4,
5794
+ ColorManagement,
5791
5795
  Matrix3,
5796
+ SRGBColorSpace as SRGBColorSpace3,
5792
5797
  Vector2 as Vector22,
5793
5798
  Vector3 as Vector37
5794
5799
  } from "three";
5795
5800
  var OBJExporter = class {
5801
+ /**
5802
+ * Parses the given 3D object and generates the OBJ output.
5803
+ *
5804
+ * If the 3D object is composed of multiple children and geometry, they are merged into a single mesh in the file.
5805
+ *
5806
+ * @param {Object3D} object - The 3D object to export.
5807
+ * @return {string} The exported OBJ.
5808
+ */
5796
5809
  parse(object) {
5797
5810
  let output = "";
5798
5811
  let indexVertex = 0;
@@ -5898,7 +5911,8 @@ var OBJExporter = class {
5898
5911
  vertex.applyMatrix4(points.matrixWorld);
5899
5912
  output += "v " + vertex.x + " " + vertex.y + " " + vertex.z;
5900
5913
  if (colors !== void 0) {
5901
- color.fromBufferAttribute(colors, i).convertLinearToSRGB();
5914
+ color.fromBufferAttribute(colors, i);
5915
+ ColorManagement.workingToColorSpace(color, SRGBColorSpace3);
5902
5916
  output += " " + color.r + " " + color.g + " " + color.b;
5903
5917
  }
5904
5918
  output += "\n";
@@ -5930,9 +5944,21 @@ var OBJExporter = class {
5930
5944
  import {
5931
5945
  Matrix3 as Matrix32,
5932
5946
  Vector3 as Vector38,
5933
- Color as Color5
5947
+ Color as Color5,
5948
+ ColorManagement as ColorManagement2,
5949
+ SRGBColorSpace as SRGBColorSpace4
5934
5950
  } from "three";
5935
5951
  var PLYExporter = class {
5952
+ /**
5953
+ * Parses the given 3D object and generates the PLY output.
5954
+ *
5955
+ * If the 3D object is composed of multiple children and geometry, they are merged into a single mesh in the file.
5956
+ *
5957
+ * @param {Object3D} object - The 3D object to export.
5958
+ * @param {PLYExporter~OnDone} onDone - A callback function that is executed when the export has finished.
5959
+ * @param {PLYExporter~Options} options - The export options.
5960
+ * @return {?(string|ArrayBuffer)} The exported PLY.
5961
+ */
5936
5962
  parse(object, onDone, options = {}) {
5937
5963
  function traverseMeshes(cb) {
5938
5964
  object.traverse(function(child) {
@@ -5949,14 +5975,23 @@ var PLYExporter = class {
5949
5975
  binary: false,
5950
5976
  excludeAttributes: [],
5951
5977
  // normal, uv, color, index
5952
- littleEndian: false
5978
+ littleEndian: false,
5979
+ customPropertyMapping: {}
5953
5980
  };
5954
5981
  options = Object.assign(defaultOptions, options);
5955
5982
  const excludeAttributes = options.excludeAttributes;
5983
+ const customPropertyMapping = options.customPropertyMapping;
5984
+ const customAttributeNames = Object.keys(customPropertyMapping);
5956
5985
  let includeIndices = true;
5957
5986
  let includeNormals = false;
5958
5987
  let includeColors = false;
5959
5988
  let includeUVs = false;
5989
+ let positionType = "float";
5990
+ let normalType = "float";
5991
+ let uvType = "float";
5992
+ let colorType = "uchar";
5993
+ const customTypes = {};
5994
+ for (const name of customAttributeNames) customTypes[name] = "float";
5960
5995
  let vertexCount = 0;
5961
5996
  let faceCount = 0;
5962
5997
  object.traverse(function(child) {
@@ -5973,9 +6008,23 @@ var PLYExporter = class {
5973
6008
  }
5974
6009
  vertexCount += vertices.count;
5975
6010
  faceCount += indices ? indices.count / 3 : vertices.count / 3;
5976
- if (normals !== void 0) includeNormals = true;
5977
- if (uvs !== void 0) includeUVs = true;
5978
- if (colors !== void 0) includeColors = true;
6011
+ positionType = getPlyType(vertices.array);
6012
+ if (normals !== void 0) {
6013
+ includeNormals = true;
6014
+ normalType = getPlyType(normals.array);
6015
+ }
6016
+ if (uvs !== void 0) {
6017
+ includeUVs = true;
6018
+ uvType = getPlyType(uvs.array);
6019
+ }
6020
+ if (colors !== void 0) {
6021
+ includeColors = true;
6022
+ colorType = getPlyType(colors.array);
6023
+ }
6024
+ for (const name of customAttributeNames) {
6025
+ const attr = geometry.getAttribute(name);
6026
+ if (attr !== void 0) customTypes[name] = getPlyType(attr.array);
6027
+ }
5979
6028
  } else if (child.isPoints) {
5980
6029
  const mesh = child;
5981
6030
  const geometry = mesh.geometry;
@@ -5983,8 +6032,19 @@ var PLYExporter = class {
5983
6032
  const normals = geometry.getAttribute("normal");
5984
6033
  const colors = geometry.getAttribute("color");
5985
6034
  vertexCount += vertices.count;
5986
- if (normals !== void 0) includeNormals = true;
5987
- if (colors !== void 0) includeColors = true;
6035
+ positionType = getPlyType(vertices.array);
6036
+ if (normals !== void 0) {
6037
+ includeNormals = true;
6038
+ normalType = getPlyType(normals.array);
6039
+ }
6040
+ if (colors !== void 0) {
6041
+ includeColors = true;
6042
+ colorType = getPlyType(colors.array);
6043
+ }
6044
+ for (const name of customAttributeNames) {
6045
+ const attr = geometry.getAttribute(name);
6046
+ if (attr !== void 0) customTypes[name] = getPlyType(attr.array);
6047
+ }
5988
6048
  includeIndices = false;
5989
6049
  }
5990
6050
  });
@@ -6003,18 +6063,33 @@ var PLYExporter = class {
6003
6063
  let header = `ply
6004
6064
  format ${options.binary ? options.littleEndian ? "binary_little_endian" : "binary_big_endian" : "ascii"} 1.0
6005
6065
  element vertex ${vertexCount}
6006
- property float x
6007
- property float y
6008
- property float z
6066
+ property ${positionType} x
6067
+ property ${positionType} y
6068
+ property ${positionType} z
6009
6069
  `;
6010
6070
  if (includeNormals === true) {
6011
- header += "property float nx\nproperty float ny\nproperty float nz\n";
6071
+ header += `property ${normalType} nx
6072
+ property ${normalType} ny
6073
+ property ${normalType} nz
6074
+ `;
6012
6075
  }
6013
6076
  if (includeUVs === true) {
6014
- header += "property float s\nproperty float t\n";
6077
+ header += `property ${uvType} s
6078
+ property ${uvType} t
6079
+ `;
6015
6080
  }
6016
6081
  if (includeColors === true) {
6017
- header += "property uchar red\nproperty uchar green\nproperty uchar blue\n";
6082
+ header += `property ${colorType} red
6083
+ property ${colorType} green
6084
+ property ${colorType} blue
6085
+ `;
6086
+ }
6087
+ for (const name of customAttributeNames) {
6088
+ const type = customTypes[name];
6089
+ for (const propName of customPropertyMapping[name]) {
6090
+ header += `property ${type} ${propName}
6091
+ `;
6092
+ }
6018
6093
  }
6019
6094
  if (includeIndices === true) {
6020
6095
  header += `element face ${faceCount}
@@ -6027,7 +6102,23 @@ property list uchar int vertex_index
6027
6102
  let result = null;
6028
6103
  if (options.binary === true) {
6029
6104
  const headerBin = new TextEncoder().encode(header);
6030
- const vertexListLength = vertexCount * (4 * 3 + (includeNormals ? 4 * 3 : 0) + (includeColors ? 3 : 0) + (includeUVs ? 4 * 2 : 0));
6105
+ const posWriter = getBinaryWriter(positionType);
6106
+ const normalWriter = includeNormals ? getBinaryWriter(normalType) : null;
6107
+ const uvWriter = includeUVs ? getBinaryWriter(uvType) : null;
6108
+ const colorWriter = includeColors ? getBinaryWriter(colorType) : null;
6109
+ const colorIsFloat = isFloatType(colorType);
6110
+ const colorScale = getColorScale(colorType);
6111
+ const customWriters = {};
6112
+ const customIsFloat = {};
6113
+ let customStride = 0;
6114
+ for (const name of customAttributeNames) {
6115
+ const type = customTypes[name];
6116
+ const writer = getBinaryWriter(type);
6117
+ customWriters[name] = writer;
6118
+ customIsFloat[name] = isFloatType(type);
6119
+ customStride += customPropertyMapping[name].length * writer.size;
6120
+ }
6121
+ const vertexListLength = vertexCount * (3 * posWriter.size + (includeNormals ? 3 * normalWriter.size : 0) + (includeUVs ? 2 * uvWriter.size : 0) + (includeColors ? 3 * colorWriter.size : 0) + customStride);
6031
6122
  const faceListLength = includeIndices ? faceCount * (indexByteCount * 3 + 1) : 0;
6032
6123
  const output = new DataView(new ArrayBuffer(headerBin.length + vertexListLength + faceListLength));
6033
6124
  new Uint8Array(output.buffer).set(headerBin, 0);
@@ -6044,60 +6135,76 @@ property list uchar int vertex_index
6044
6135
  for (let i = 0, l = vertices.count; i < l; i++) {
6045
6136
  vertex.fromBufferAttribute(vertices, i);
6046
6137
  vertex.applyMatrix4(mesh.matrixWorld);
6047
- output.setFloat32(vOffset, vertex.x, options.littleEndian);
6048
- vOffset += 4;
6049
- output.setFloat32(vOffset, vertex.y, options.littleEndian);
6050
- vOffset += 4;
6051
- output.setFloat32(vOffset, vertex.z, options.littleEndian);
6052
- vOffset += 4;
6138
+ posWriter.write(output, vOffset, vertex.x, options.littleEndian);
6139
+ vOffset += posWriter.size;
6140
+ posWriter.write(output, vOffset, vertex.y, options.littleEndian);
6141
+ vOffset += posWriter.size;
6142
+ posWriter.write(output, vOffset, vertex.z, options.littleEndian);
6143
+ vOffset += posWriter.size;
6053
6144
  if (includeNormals === true) {
6054
6145
  if (normals != null) {
6055
6146
  vertex.fromBufferAttribute(normals, i);
6056
6147
  vertex.applyMatrix3(normalMatrixWorld).normalize();
6057
- output.setFloat32(vOffset, vertex.x, options.littleEndian);
6058
- vOffset += 4;
6059
- output.setFloat32(vOffset, vertex.y, options.littleEndian);
6060
- vOffset += 4;
6061
- output.setFloat32(vOffset, vertex.z, options.littleEndian);
6062
- vOffset += 4;
6148
+ normalWriter.write(output, vOffset, vertex.x, options.littleEndian);
6149
+ vOffset += normalWriter.size;
6150
+ normalWriter.write(output, vOffset, vertex.y, options.littleEndian);
6151
+ vOffset += normalWriter.size;
6152
+ normalWriter.write(output, vOffset, vertex.z, options.littleEndian);
6153
+ vOffset += normalWriter.size;
6063
6154
  } else {
6064
- output.setFloat32(vOffset, 0, options.littleEndian);
6065
- vOffset += 4;
6066
- output.setFloat32(vOffset, 0, options.littleEndian);
6067
- vOffset += 4;
6068
- output.setFloat32(vOffset, 0, options.littleEndian);
6069
- vOffset += 4;
6155
+ normalWriter.write(output, vOffset, 0, options.littleEndian);
6156
+ vOffset += normalWriter.size;
6157
+ normalWriter.write(output, vOffset, 0, options.littleEndian);
6158
+ vOffset += normalWriter.size;
6159
+ normalWriter.write(output, vOffset, 0, options.littleEndian);
6160
+ vOffset += normalWriter.size;
6070
6161
  }
6071
6162
  }
6072
6163
  if (includeUVs === true) {
6073
6164
  if (uvs != null) {
6074
- output.setFloat32(vOffset, uvs.getX(i), options.littleEndian);
6075
- vOffset += 4;
6076
- output.setFloat32(vOffset, uvs.getY(i), options.littleEndian);
6077
- vOffset += 4;
6165
+ uvWriter.write(output, vOffset, uvs.getX(i), options.littleEndian);
6166
+ vOffset += uvWriter.size;
6167
+ uvWriter.write(output, vOffset, uvs.getY(i), options.littleEndian);
6168
+ vOffset += uvWriter.size;
6078
6169
  } else {
6079
- output.setFloat32(vOffset, 0, options.littleEndian);
6080
- vOffset += 4;
6081
- output.setFloat32(vOffset, 0, options.littleEndian);
6082
- vOffset += 4;
6170
+ uvWriter.write(output, vOffset, 0, options.littleEndian);
6171
+ vOffset += uvWriter.size;
6172
+ uvWriter.write(output, vOffset, 0, options.littleEndian);
6173
+ vOffset += uvWriter.size;
6083
6174
  }
6084
6175
  }
6085
6176
  if (includeColors === true) {
6086
6177
  if (colors != null) {
6087
- tempColor.fromBufferAttribute(colors, i).convertLinearToSRGB();
6088
- output.setUint8(vOffset, Math.floor(tempColor.r * 255));
6089
- vOffset += 1;
6090
- output.setUint8(vOffset, Math.floor(tempColor.g * 255));
6091
- vOffset += 1;
6092
- output.setUint8(vOffset, Math.floor(tempColor.b * 255));
6093
- vOffset += 1;
6178
+ tempColor.fromBufferAttribute(colors, i);
6179
+ ColorManagement2.workingToColorSpace(tempColor, SRGBColorSpace4);
6180
+ const r = colorIsFloat ? tempColor.r : Math.round(tempColor.r * colorScale);
6181
+ const g = colorIsFloat ? tempColor.g : Math.round(tempColor.g * colorScale);
6182
+ const b = colorIsFloat ? tempColor.b : Math.round(tempColor.b * colorScale);
6183
+ colorWriter.write(output, vOffset, r, options.littleEndian);
6184
+ vOffset += colorWriter.size;
6185
+ colorWriter.write(output, vOffset, g, options.littleEndian);
6186
+ vOffset += colorWriter.size;
6187
+ colorWriter.write(output, vOffset, b, options.littleEndian);
6188
+ vOffset += colorWriter.size;
6094
6189
  } else {
6095
- output.setUint8(vOffset, 255);
6096
- vOffset += 1;
6097
- output.setUint8(vOffset, 255);
6098
- vOffset += 1;
6099
- output.setUint8(vOffset, 255);
6100
- vOffset += 1;
6190
+ const white = colorIsFloat ? 1 : colorScale;
6191
+ colorWriter.write(output, vOffset, white, options.littleEndian);
6192
+ vOffset += colorWriter.size;
6193
+ colorWriter.write(output, vOffset, white, options.littleEndian);
6194
+ vOffset += colorWriter.size;
6195
+ colorWriter.write(output, vOffset, white, options.littleEndian);
6196
+ vOffset += colorWriter.size;
6197
+ }
6198
+ }
6199
+ for (const name of customAttributeNames) {
6200
+ const writer = customWriters[name];
6201
+ const propCount = customPropertyMapping[name].length;
6202
+ const attr = geometry.getAttribute(name);
6203
+ const isFloat = customIsFloat[name];
6204
+ for (let c = 0; c < propCount; c++) {
6205
+ const raw = attr != null ? getAttributeComponent(attr, i, c) : 0;
6206
+ writer.write(output, vOffset, isFloat ? raw : Math.round(raw), options.littleEndian);
6207
+ vOffset += writer.size;
6101
6208
  }
6102
6209
  }
6103
6210
  }
@@ -6133,6 +6240,14 @@ property list uchar int vertex_index
6133
6240
  let writtenVertices = 0;
6134
6241
  let vertexList = "";
6135
6242
  let faceList = "";
6243
+ const positionIsFloat = isFloatType(positionType);
6244
+ const normalIsFloat = isFloatType(normalType);
6245
+ const uvIsFloat = isFloatType(uvType);
6246
+ const colorIsFloat = isFloatType(colorType);
6247
+ const colorScale = getColorScale(colorType);
6248
+ const customIsFloat = {};
6249
+ for (const name of customAttributeNames) customIsFloat[name] = isFloatType(customTypes[name]);
6250
+ const encode = (v, isFloat) => isFloat ? v : Math.round(v);
6136
6251
  traverseMeshes(function(mesh, geometry) {
6137
6252
  const vertices = geometry.getAttribute("position");
6138
6253
  const normals = geometry.getAttribute("normal");
@@ -6143,29 +6258,43 @@ property list uchar int vertex_index
6143
6258
  for (let i = 0, l = vertices.count; i < l; i++) {
6144
6259
  vertex.fromBufferAttribute(vertices, i);
6145
6260
  vertex.applyMatrix4(mesh.matrixWorld);
6146
- let line = vertex.x + " " + vertex.y + " " + vertex.z;
6261
+ let line = encode(vertex.x, positionIsFloat) + " " + encode(vertex.y, positionIsFloat) + " " + encode(vertex.z, positionIsFloat);
6147
6262
  if (includeNormals === true) {
6148
6263
  if (normals != null) {
6149
6264
  vertex.fromBufferAttribute(normals, i);
6150
6265
  vertex.applyMatrix3(normalMatrixWorld).normalize();
6151
- line += " " + vertex.x + " " + vertex.y + " " + vertex.z;
6266
+ line += " " + encode(vertex.x, normalIsFloat) + " " + encode(vertex.y, normalIsFloat) + " " + encode(vertex.z, normalIsFloat);
6152
6267
  } else {
6153
6268
  line += " 0 0 0";
6154
6269
  }
6155
6270
  }
6156
6271
  if (includeUVs === true) {
6157
6272
  if (uvs != null) {
6158
- line += " " + uvs.getX(i) + " " + uvs.getY(i);
6273
+ line += " " + encode(uvs.getX(i), uvIsFloat) + " " + encode(uvs.getY(i), uvIsFloat);
6159
6274
  } else {
6160
6275
  line += " 0 0";
6161
6276
  }
6162
6277
  }
6163
6278
  if (includeColors === true) {
6164
6279
  if (colors != null) {
6165
- tempColor.fromBufferAttribute(colors, i).convertLinearToSRGB();
6166
- line += " " + Math.floor(tempColor.r * 255) + " " + Math.floor(tempColor.g * 255) + " " + Math.floor(tempColor.b * 255);
6280
+ tempColor.fromBufferAttribute(colors, i);
6281
+ ColorManagement2.workingToColorSpace(tempColor, SRGBColorSpace4);
6282
+ const r = colorIsFloat ? tempColor.r : Math.round(tempColor.r * colorScale);
6283
+ const g = colorIsFloat ? tempColor.g : Math.round(tempColor.g * colorScale);
6284
+ const b = colorIsFloat ? tempColor.b : Math.round(tempColor.b * colorScale);
6285
+ line += ` ${r} ${g} ${b}`;
6167
6286
  } else {
6168
- line += " 255 255 255";
6287
+ const white = colorIsFloat ? 1 : colorScale;
6288
+ line += ` ${white} ${white} ${white}`;
6289
+ }
6290
+ }
6291
+ for (const name of customAttributeNames) {
6292
+ const propCount = customPropertyMapping[name].length;
6293
+ const attr = geometry.getAttribute(name);
6294
+ const isFloat = customIsFloat[name];
6295
+ for (let c = 0; c < propCount; c++) {
6296
+ const raw = attr != null ? getAttributeComponent(attr, i, c) : 0;
6297
+ line += " " + encode(raw, isFloat);
6169
6298
  }
6170
6299
  }
6171
6300
  vertexList += line + "\n";
@@ -6195,6 +6324,62 @@ property list uchar int vertex_index
6195
6324
  return result;
6196
6325
  }
6197
6326
  };
6327
+ function getPlyType(array) {
6328
+ if (array instanceof Int8Array) return "char";
6329
+ if (array instanceof Uint8Array || array instanceof Uint8ClampedArray) return "uchar";
6330
+ if (array instanceof Int16Array) return "short";
6331
+ if (array instanceof Uint16Array) return "ushort";
6332
+ if (array instanceof Int32Array) return "int";
6333
+ if (array instanceof Uint32Array) return "uint";
6334
+ if (array instanceof Float32Array) return "float";
6335
+ if (array instanceof Float64Array) return "double";
6336
+ return "float";
6337
+ }
6338
+ function getBinaryWriter(type) {
6339
+ switch (type) {
6340
+ case "char":
6341
+ return { write: (dv, at, v) => dv.setInt8(at, v), size: 1 };
6342
+ case "uchar":
6343
+ return { write: (dv, at, v) => dv.setUint8(at, v), size: 1 };
6344
+ case "short":
6345
+ return { write: (dv, at, v, le) => dv.setInt16(at, v, le), size: 2 };
6346
+ case "ushort":
6347
+ return { write: (dv, at, v, le) => dv.setUint16(at, v, le), size: 2 };
6348
+ case "int":
6349
+ return { write: (dv, at, v, le) => dv.setInt32(at, v, le), size: 4 };
6350
+ case "uint":
6351
+ return { write: (dv, at, v, le) => dv.setUint32(at, v, le), size: 4 };
6352
+ case "float":
6353
+ return { write: (dv, at, v, le) => dv.setFloat32(at, v, le), size: 4 };
6354
+ case "double":
6355
+ return { write: (dv, at, v, le) => dv.setFloat64(at, v, le), size: 8 };
6356
+ }
6357
+ }
6358
+ function isFloatType(type) {
6359
+ return type === "float" || type === "double";
6360
+ }
6361
+ function getAttributeComponent(attr, i, c) {
6362
+ switch (c) {
6363
+ case 0:
6364
+ return attr.getX(i);
6365
+ case 1:
6366
+ return attr.getY(i);
6367
+ case 2:
6368
+ return attr.getZ(i);
6369
+ case 3:
6370
+ return attr.getW(i);
6371
+ }
6372
+ }
6373
+ function getColorScale(type) {
6374
+ switch (type) {
6375
+ case "uchar":
6376
+ return 255;
6377
+ case "ushort":
6378
+ return 65535;
6379
+ default:
6380
+ return 1;
6381
+ }
6382
+ }
6198
6383
 
6199
6384
  // ../../node_modules/three/examples/jsm/exporters/GLTFExporter.js
6200
6385
  import {
@@ -6208,7 +6393,7 @@ import {
6208
6393
  LinearFilter,
6209
6394
  LinearMipmapLinearFilter,
6210
6395
  LinearMipmapNearestFilter,
6211
- MathUtils as MathUtils2,
6396
+ MathUtils,
6212
6397
  Matrix4 as Matrix46,
6213
6398
  MirroredRepeatWrapping,
6214
6399
  NearestFilter as NearestFilter2,
@@ -6217,84 +6402,15 @@ import {
6217
6402
  PropertyBinding,
6218
6403
  RGBAFormat as RGBAFormat2,
6219
6404
  RepeatWrapping as RepeatWrapping2,
6220
- Scene as Scene3,
6221
- Source,
6222
- SRGBColorSpace as SRGBColorSpace4,
6405
+ Scene as Scene2,
6406
+ SRGBColorSpace as SRGBColorSpace5,
6407
+ TextureSource,
6223
6408
  CompressedTexture,
6224
6409
  Vector3 as Vector39,
6225
- Quaternion as Quaternion4
6226
- } from "three";
6227
-
6228
- // ../../node_modules/three/examples/jsm/utils/TextureUtils.js
6229
- import {
6230
- PlaneGeometry,
6231
- ShaderMaterial as ShaderMaterial2,
6232
- Uniform,
6233
- Mesh as Mesh4,
6234
- PerspectiveCamera,
6235
- Scene as Scene2,
6236
- WebGLRenderer,
6237
- Texture as Texture3,
6238
- SRGBColorSpace as SRGBColorSpace3
6410
+ Quaternion as Quaternion4,
6411
+ REVISION,
6412
+ ImageUtils
6239
6413
  } from "three";
6240
- var _renderer;
6241
- var fullscreenQuadGeometry;
6242
- var fullscreenQuadMaterial;
6243
- var fullscreenQuad;
6244
- function decompress(texture, maxTextureSize = Infinity, renderer = null) {
6245
- if (!fullscreenQuadGeometry) fullscreenQuadGeometry = new PlaneGeometry(2, 2, 1, 1);
6246
- if (!fullscreenQuadMaterial) fullscreenQuadMaterial = new ShaderMaterial2({
6247
- uniforms: { blitTexture: new Uniform(texture) },
6248
- vertexShader: `
6249
- varying vec2 vUv;
6250
- void main(){
6251
- vUv = uv;
6252
- gl_Position = vec4(position.xy * 1.0,0.,.999999);
6253
- }`,
6254
- fragmentShader: `
6255
- uniform sampler2D blitTexture;
6256
- varying vec2 vUv;
6257
-
6258
- void main(){
6259
- gl_FragColor = vec4(vUv.xy, 0, 1);
6260
-
6261
- #ifdef IS_SRGB
6262
- gl_FragColor = LinearTosRGB( texture2D( blitTexture, vUv) );
6263
- #else
6264
- gl_FragColor = texture2D( blitTexture, vUv);
6265
- #endif
6266
- }`
6267
- });
6268
- fullscreenQuadMaterial.uniforms.blitTexture.value = texture;
6269
- fullscreenQuadMaterial.defines.IS_SRGB = texture.colorSpace == SRGBColorSpace3;
6270
- fullscreenQuadMaterial.needsUpdate = true;
6271
- if (!fullscreenQuad) {
6272
- fullscreenQuad = new Mesh4(fullscreenQuadGeometry, fullscreenQuadMaterial);
6273
- fullscreenQuad.frustrumCulled = false;
6274
- }
6275
- const _camera = new PerspectiveCamera();
6276
- const _scene = new Scene2();
6277
- _scene.add(fullscreenQuad);
6278
- if (!renderer) {
6279
- renderer = _renderer = new WebGLRenderer({ antialias: false });
6280
- }
6281
- renderer.setSize(Math.min(texture.image.width, maxTextureSize), Math.min(texture.image.height, maxTextureSize));
6282
- renderer.clear();
6283
- renderer.render(_scene, _camera);
6284
- const readableTexture = new Texture3(renderer.domElement);
6285
- readableTexture.minFilter = texture.minFilter;
6286
- readableTexture.magFilter = texture.magFilter;
6287
- readableTexture.wrapS = texture.wrapS;
6288
- readableTexture.wrapT = texture.wrapT;
6289
- readableTexture.name = texture.name;
6290
- if (_renderer) {
6291
- _renderer.dispose();
6292
- _renderer = null;
6293
- }
6294
- return readableTexture;
6295
- }
6296
-
6297
- // ../../node_modules/three/examples/jsm/exporters/GLTFExporter.js
6298
6414
  var KHR_mesh_quantization_ExtraAttrTypes = {
6299
6415
  POSITION: [
6300
6416
  "byte",
@@ -6324,7 +6440,11 @@ var KHR_mesh_quantization_ExtraAttrTypes = {
6324
6440
  ]
6325
6441
  };
6326
6442
  var GLTFExporter = class {
6443
+ /**
6444
+ * Constructs a new glTF exporter.
6445
+ */
6327
6446
  constructor() {
6447
+ this.textureUtils = null;
6328
6448
  this.pluginCallbacks = [];
6329
6449
  this.register(function(writer) {
6330
6450
  return new GLTFLightExtension(writer);
@@ -6347,6 +6467,9 @@ var GLTFExporter = class {
6347
6467
  this.register(function(writer) {
6348
6468
  return new GLTFMaterialsClearcoatExtension(writer);
6349
6469
  });
6470
+ this.register(function(writer) {
6471
+ return new GLTFMaterialsDispersionExtension(writer);
6472
+ });
6350
6473
  this.register(function(writer) {
6351
6474
  return new GLTFMaterialsIridescenceExtension(writer);
6352
6475
  });
@@ -6359,16 +6482,33 @@ var GLTFExporter = class {
6359
6482
  this.register(function(writer) {
6360
6483
  return new GLTFMaterialsEmissiveStrengthExtension(writer);
6361
6484
  });
6485
+ this.register(function(writer) {
6486
+ return new GLTFMaterialsBumpExtension(writer);
6487
+ });
6362
6488
  this.register(function(writer) {
6363
6489
  return new GLTFMeshGpuInstancing(writer);
6364
6490
  });
6365
6491
  }
6492
+ /**
6493
+ * Registers a plugin callback. This API is internally used to implement the various
6494
+ * glTF extensions but can also used by third-party code to add additional logic
6495
+ * to the exporter.
6496
+ *
6497
+ * @param {function(writer:GLTFWriter)} callback - The callback function to register.
6498
+ * @return {GLTFExporter} A reference to this exporter.
6499
+ */
6366
6500
  register(callback) {
6367
6501
  if (this.pluginCallbacks.indexOf(callback) === -1) {
6368
6502
  this.pluginCallbacks.push(callback);
6369
6503
  }
6370
6504
  return this;
6371
6505
  }
6506
+ /**
6507
+ * Unregisters a plugin callback.
6508
+ *
6509
+ * @param {Function} callback - The callback function to unregister.
6510
+ * @return {GLTFExporter} A reference to this exporter.
6511
+ */
6372
6512
  unregister(callback) {
6373
6513
  if (this.pluginCallbacks.indexOf(callback) !== -1) {
6374
6514
  this.pluginCallbacks.splice(this.pluginCallbacks.indexOf(callback), 1);
@@ -6376,11 +6516,25 @@ var GLTFExporter = class {
6376
6516
  return this;
6377
6517
  }
6378
6518
  /**
6379
- * Parse scenes and generate GLTF output
6380
- * @param {Scene or [THREE.Scenes]} input Scene or Array of THREE.Scenes
6381
- * @param {Function} onDone Callback on completed
6382
- * @param {Function} onError Callback on errors
6383
- * @param {Object} options options
6519
+ * Sets the texture utils for this exporter. Only relevant when compressed textures have to be exported.
6520
+ *
6521
+ * Depending on whether you use {@link WebGLRenderer} or {@link WebGPURenderer}, you must inject the
6522
+ * corresponding texture utils {@link module:WebGLTextureUtils} or {@link module:WebGPUTextureUtils}.
6523
+ *
6524
+ * @param {WebGLTextureUtils|WebGPUTextureUtils} utils - The texture utils.
6525
+ * @return {GLTFExporter} A reference to this exporter.
6526
+ */
6527
+ setTextureUtils(utils) {
6528
+ this.textureUtils = utils;
6529
+ return this;
6530
+ }
6531
+ /**
6532
+ * Parses the given scenes and generates the glTF output.
6533
+ *
6534
+ * @param {Scene|Array<Scene>} input - A scene or an array of scenes.
6535
+ * @param {GLTFExporter~OnDone} onDone - A callback function that is executed when the export has finished.
6536
+ * @param {GLTFExporter~OnError} onError - A callback function that is executed when an error happens.
6537
+ * @param {GLTFExporter~Options} options - options
6384
6538
  */
6385
6539
  parse(input, onDone, onError, options) {
6386
6540
  const writer = new GLTFWriter();
@@ -6389,8 +6543,16 @@ var GLTFExporter = class {
6389
6543
  plugins.push(this.pluginCallbacks[i](writer));
6390
6544
  }
6391
6545
  writer.setPlugins(plugins);
6392
- writer.write(input, onDone, options).catch(onError);
6546
+ writer.setTextureUtils(this.textureUtils);
6547
+ writer.writeAsync(input, onDone, options).catch(onError);
6393
6548
  }
6549
+ /**
6550
+ * Async version of {@link GLTFExporter#parse}.
6551
+ *
6552
+ * @param {Scene|Array<Scene>} input - A scene or an array of scenes.
6553
+ * @param {GLTFExporter~Options} options - options.
6554
+ * @return {Promise<ArrayBuffer|string>} A Promise that resolved with the exported glTF data.
6555
+ */
6394
6556
  parseAsync(input, options) {
6395
6557
  const scope = this;
6396
6558
  return new Promise(function(resolve, reject) {
@@ -6476,7 +6638,7 @@ function getMinMax(attribute, start, count) {
6476
6638
  else if (a === 2) value = attribute.getZ(i);
6477
6639
  else if (a === 3) value = attribute.getW(i);
6478
6640
  if (attribute.normalized === true) {
6479
- value = MathUtils2.normalize(value, attribute.array);
6641
+ value = MathUtils.normalize(value, attribute.array);
6480
6642
  }
6481
6643
  }
6482
6644
  output.min[a] = Math.min(output.min[a], value);
@@ -6509,19 +6671,20 @@ function getCanvas() {
6509
6671
  return document.createElement("canvas");
6510
6672
  }
6511
6673
  function getToBlobPromise(canvas, mimeType) {
6512
- if (canvas.toBlob !== void 0) {
6674
+ if (typeof OffscreenCanvas !== "undefined" && canvas instanceof OffscreenCanvas) {
6675
+ let quality;
6676
+ if (mimeType === "image/jpeg") {
6677
+ quality = 0.92;
6678
+ } else if (mimeType === "image/webp") {
6679
+ quality = 0.8;
6680
+ }
6681
+ return canvas.convertToBlob({
6682
+ type: mimeType,
6683
+ quality
6684
+ });
6685
+ } else {
6513
6686
  return new Promise((resolve) => canvas.toBlob(resolve, mimeType));
6514
6687
  }
6515
- let quality;
6516
- if (mimeType === "image/jpeg") {
6517
- quality = 0.92;
6518
- } else if (mimeType === "image/webp") {
6519
- quality = 0.8;
6520
- }
6521
- return canvas.convertToBlob({
6522
- type: mimeType,
6523
- quality
6524
- });
6525
6688
  }
6526
6689
  var GLTFWriter = class {
6527
6690
  constructor() {
@@ -6540,7 +6703,7 @@ var GLTFWriter = class {
6540
6703
  this.json = {
6541
6704
  asset: {
6542
6705
  version: "2.0",
6543
- generator: "THREE.GLTFExporter"
6706
+ generator: "THREE.GLTFExporter r" + REVISION
6544
6707
  }
6545
6708
  };
6546
6709
  this.cache = {
@@ -6549,19 +6712,25 @@ var GLTFWriter = class {
6549
6712
  attributesNormalized: /* @__PURE__ */ new Map(),
6550
6713
  materials: /* @__PURE__ */ new Map(),
6551
6714
  textures: /* @__PURE__ */ new Map(),
6552
- images: /* @__PURE__ */ new Map()
6715
+ images: /* @__PURE__ */ new Map(),
6716
+ normalMaps: /* @__PURE__ */ new Map()
6553
6717
  };
6718
+ this.textureUtils = null;
6554
6719
  }
6555
6720
  setPlugins(plugins) {
6556
6721
  this.plugins = plugins;
6557
6722
  }
6723
+ setTextureUtils(utils) {
6724
+ this.textureUtils = utils;
6725
+ }
6558
6726
  /**
6559
6727
  * Parse scenes and generate GLTF output
6560
- * @param {Scene or [THREE.Scenes]} input Scene or Array of THREE.Scenes
6561
- * @param {Function} onDone Callback on completed
6562
- * @param {Object} options options
6728
+ *
6729
+ * @param {Scene|Array<Scene>} input Scene or Array of THREE.Scenes
6730
+ * @param {Function} onDone Callback on completed
6731
+ * @param {Object} options options
6563
6732
  */
6564
- async write(input, onDone, options = {}) {
6733
+ async writeAsync(input, onDone, options = {}) {
6565
6734
  this.options = Object.assign({
6566
6735
  // default options
6567
6736
  binary: false,
@@ -6569,12 +6738,13 @@ var GLTFWriter = class {
6569
6738
  onlyVisible: true,
6570
6739
  maxTextureSize: Infinity,
6571
6740
  animations: [],
6572
- includeCustomExtensions: false
6741
+ includeCustomExtensions: false,
6742
+ copyright: null
6573
6743
  }, options);
6574
6744
  if (this.options.animations.length > 0) {
6575
6745
  this.options.trs = true;
6576
6746
  }
6577
- this.processInput(input);
6747
+ await this.processInputAsync(input);
6578
6748
  await Promise.all(this.pending);
6579
6749
  const writer = this;
6580
6750
  const buffers = writer.buffers;
@@ -6588,6 +6758,7 @@ var GLTFWriter = class {
6588
6758
  if (extensionsUsedList.length > 0) json.extensionsUsed = extensionsUsedList;
6589
6759
  if (extensionsRequiredList.length > 0) json.extensionsRequired = extensionsRequiredList;
6590
6760
  if (json.buffers && json.buffers.length > 0) json.buffers[0].byteLength = blob.size;
6761
+ if (options.copyright) json.asset.copyright = options.copyright;
6591
6762
  if (options.binary === true) {
6592
6763
  const reader = new FileReader();
6593
6764
  reader.readAsArrayBuffer(blob);
@@ -6636,7 +6807,7 @@ var GLTFWriter = class {
6636
6807
  /**
6637
6808
  * Serializes a userData.
6638
6809
  *
6639
- * @param {THREE.Object3D|THREE.Material} object
6810
+ * @param {THREE.Object3D|THREE.Material|THREE.BufferGeometry|THREE.AnimationClip} object
6640
6811
  * @param {Object} objectDef
6641
6812
  */
6642
6813
  serializeUserData(object, objectDef) {
@@ -6660,8 +6831,10 @@ var GLTFWriter = class {
6660
6831
  }
6661
6832
  /**
6662
6833
  * Returns ids for buffer attributes.
6663
- * @param {Object} object
6664
- * @return {Integer}
6834
+ *
6835
+ * @param {Object} attribute
6836
+ * @param {boolean} [isRelativeCopy=false]
6837
+ * @return {number} An integer
6665
6838
  */
6666
6839
  getUID(attribute, isRelativeCopy = false) {
6667
6840
  if (this.uids.has(attribute) === false) {
@@ -6677,7 +6850,7 @@ var GLTFWriter = class {
6677
6850
  * Checks if normal attribute values are normalized.
6678
6851
  *
6679
6852
  * @param {BufferAttribute} normal
6680
- * @returns {Boolean}
6853
+ * @returns {boolean}
6681
6854
  */
6682
6855
  isNormalizedNormalAttribute(normal) {
6683
6856
  const cache = this.cache;
@@ -6740,10 +6913,10 @@ var GLTFWriter = class {
6740
6913
  this.extensionsUsed["KHR_texture_transform"] = true;
6741
6914
  }
6742
6915
  }
6743
- buildMetalRoughTexture(metalnessMap, roughnessMap) {
6916
+ async buildMetalRoughTextureAsync(metalnessMap, roughnessMap) {
6744
6917
  if (metalnessMap === roughnessMap) return metalnessMap;
6745
6918
  function getEncodingConversion(map) {
6746
- if (map.colorSpace === SRGBColorSpace4) {
6919
+ if (map.colorSpace === SRGBColorSpace5) {
6747
6920
  return function SRGBToLinear(c) {
6748
6921
  return c < 0.04045 ? c * 0.0773993808 : Math.pow(c * 0.9478672986 + 0.0521327014, 2.4);
6749
6922
  };
@@ -6752,12 +6925,11 @@ var GLTFWriter = class {
6752
6925
  return c;
6753
6926
  };
6754
6927
  }
6755
- console.warn("THREE.GLTFExporter: Merged metalnessMap and roughnessMap textures.");
6756
6928
  if (metalnessMap instanceof CompressedTexture) {
6757
- metalnessMap = decompress(metalnessMap);
6929
+ metalnessMap = await this.decompressTextureAsync(metalnessMap);
6758
6930
  }
6759
6931
  if (roughnessMap instanceof CompressedTexture) {
6760
- roughnessMap = decompress(roughnessMap);
6932
+ roughnessMap = await this.decompressTextureAsync(roughnessMap);
6761
6933
  }
6762
6934
  const metalness = metalnessMap ? metalnessMap.image : null;
6763
6935
  const roughness = roughnessMap ? roughnessMap.image : null;
@@ -6766,7 +6938,9 @@ var GLTFWriter = class {
6766
6938
  const canvas = getCanvas();
6767
6939
  canvas.width = width;
6768
6940
  canvas.height = height;
6769
- const context = canvas.getContext("2d");
6941
+ const context = canvas.getContext("2d", {
6942
+ willReadFrequently: true
6943
+ });
6770
6944
  context.fillStyle = "#00ffff";
6771
6945
  context.fillRect(0, 0, width, height);
6772
6946
  const composite = context.getImageData(0, 0, width, height);
@@ -6789,18 +6963,60 @@ var GLTFWriter = class {
6789
6963
  context.putImageData(composite, 0, 0);
6790
6964
  const reference = metalnessMap || roughnessMap;
6791
6965
  const texture = reference.clone();
6792
- texture.source = new Source(canvas);
6966
+ texture.source = new TextureSource(canvas);
6793
6967
  texture.colorSpace = NoColorSpace;
6794
6968
  texture.channel = (metalnessMap || roughnessMap).channel;
6795
6969
  if (metalnessMap && roughnessMap && metalnessMap.channel !== roughnessMap.channel) {
6796
6970
  console.warn("THREE.GLTFExporter: UV channels for metalnessMap and roughnessMap textures must match.");
6797
6971
  }
6972
+ console.warn("THREE.GLTFExporter: Merged metalnessMap and roughnessMap textures.");
6973
+ return texture;
6974
+ }
6975
+ /**
6976
+ * Builds a copy of the given normal map with the red and/or green channels
6977
+ * inverted (`color = 255 - color`). This is used to bake the sign of
6978
+ * `material.normalScale` and the tangent-space convention into the texture,
6979
+ * since glTF only supports OpenGL-style normal maps with a univariate,
6980
+ * positive scale.
6981
+ *
6982
+ * @param {THREE.Texture} normalMap The source normal map.
6983
+ * @param {boolean} flipX Whether to invert the red channel (normal X).
6984
+ * @param {boolean} flipY Whether to invert the green channel (normal Y).
6985
+ * @return {Promise<THREE.Texture>} The derived normal map texture.
6986
+ */
6987
+ async buildNormalMapTextureAsync(normalMap, flipX, flipY) {
6988
+ if (normalMap instanceof CompressedTexture) {
6989
+ normalMap = await this.decompressTextureAsync(normalMap);
6990
+ }
6991
+ const image = normalMap.image;
6992
+ const canvas = getCanvas();
6993
+ canvas.width = image.width;
6994
+ canvas.height = image.height;
6995
+ const context = canvas.getContext("2d", {
6996
+ willReadFrequently: true
6997
+ });
6998
+ context.drawImage(image, 0, 0, canvas.width, canvas.height);
6999
+ const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
7000
+ const data = imageData.data;
7001
+ for (let i = 0; i < data.length; i += 4) {
7002
+ if (flipX) data[i + 0] = 255 - data[i + 0];
7003
+ if (flipY) data[i + 1] = 255 - data[i + 1];
7004
+ }
7005
+ context.putImageData(imageData, 0, 0);
7006
+ const texture = normalMap.clone();
7007
+ texture.source = new TextureSource(canvas);
6798
7008
  return texture;
6799
7009
  }
7010
+ async decompressTextureAsync(texture, maxTextureSize = Infinity) {
7011
+ if (this.textureUtils === null) {
7012
+ throw new Error("THREE.GLTFExporter: setTextureUtils() must be called to process compressed textures.");
7013
+ }
7014
+ return await this.textureUtils.decompress(texture, maxTextureSize);
7015
+ }
6800
7016
  /**
6801
7017
  * Process a buffer to append to the default one.
6802
- * @param {ArrayBuffer} buffer
6803
- * @return {Integer}
7018
+ * @param {ArrayBuffer} buffer
7019
+ * @return {0}
6804
7020
  */
6805
7021
  processBuffer(buffer) {
6806
7022
  const json = this.json;
@@ -6811,11 +7027,11 @@ var GLTFWriter = class {
6811
7027
  }
6812
7028
  /**
6813
7029
  * Process and generate a BufferView
6814
- * @param {BufferAttribute} attribute
6815
- * @param {number} componentType
6816
- * @param {number} start
6817
- * @param {number} count
6818
- * @param {number} target (Optional) Target usage of the BufferView
7030
+ * @param {BufferAttribute} attribute
7031
+ * @param {number} componentType
7032
+ * @param {number} start
7033
+ * @param {number} count
7034
+ * @param {number} [target] Target usage of the BufferView
6819
7035
  * @return {Object}
6820
7036
  */
6821
7037
  processBufferView(attribute, componentType, start, count, target) {
@@ -6834,7 +7050,11 @@ var GLTFWriter = class {
6834
7050
  default:
6835
7051
  componentSize = 4;
6836
7052
  }
6837
- const byteLength = getPaddedBufferSize(count * attribute.itemSize * componentSize);
7053
+ let byteStride = attribute.itemSize * componentSize;
7054
+ if (target === WEBGL_CONSTANTS.ARRAY_BUFFER) {
7055
+ byteStride = Math.ceil(byteStride / 4) * 4;
7056
+ }
7057
+ const byteLength = getPaddedBufferSize(count * byteStride);
6838
7058
  const dataView = new DataView(new ArrayBuffer(byteLength));
6839
7059
  let offset = 0;
6840
7060
  for (let i = start; i < start + count; i++) {
@@ -6848,7 +7068,7 @@ var GLTFWriter = class {
6848
7068
  else if (a === 2) value = attribute.getZ(i);
6849
7069
  else if (a === 3) value = attribute.getW(i);
6850
7070
  if (attribute.normalized === true) {
6851
- value = MathUtils2.normalize(value, attribute.array);
7071
+ value = MathUtils.normalize(value, attribute.array);
6852
7072
  }
6853
7073
  }
6854
7074
  if (componentType === WEBGL_CONSTANTS.FLOAT) {
@@ -6868,6 +7088,9 @@ var GLTFWriter = class {
6868
7088
  }
6869
7089
  offset += componentSize;
6870
7090
  }
7091
+ if (offset % byteStride !== 0) {
7092
+ offset += byteStride - offset % byteStride;
7093
+ }
6871
7094
  }
6872
7095
  const bufferViewDef = {
6873
7096
  buffer: this.processBuffer(dataView.buffer),
@@ -6876,7 +7099,7 @@ var GLTFWriter = class {
6876
7099
  };
6877
7100
  if (target !== void 0) bufferViewDef.target = target;
6878
7101
  if (target === WEBGL_CONSTANTS.ARRAY_BUFFER) {
6879
- bufferViewDef.byteStride = attribute.itemSize * componentSize;
7102
+ bufferViewDef.byteStride = byteStride;
6880
7103
  }
6881
7104
  this.byteOffset += byteLength;
6882
7105
  json.bufferViews.push(bufferViewDef);
@@ -6889,7 +7112,7 @@ var GLTFWriter = class {
6889
7112
  /**
6890
7113
  * Process and generate a BufferView from an image Blob.
6891
7114
  * @param {Blob} blob
6892
- * @return {Promise<Integer>}
7115
+ * @return {Promise<number>} An integer
6893
7116
  */
6894
7117
  processBufferViewImage(blob) {
6895
7118
  const writer = this;
@@ -6912,11 +7135,11 @@ var GLTFWriter = class {
6912
7135
  }
6913
7136
  /**
6914
7137
  * Process attribute to generate an accessor
6915
- * @param {BufferAttribute} attribute Attribute to process
6916
- * @param {THREE.BufferGeometry} geometry (Optional) Geometry used for truncated draw range
6917
- * @param {Integer} start (Optional)
6918
- * @param {Integer} count (Optional)
6919
- * @return {Integer|null} Index of the processed accessor on the "accessors" array
7138
+ * @param {BufferAttribute} attribute Attribute to process
7139
+ * @param {?BufferGeometry} [geometry] Geometry used for truncated draw range
7140
+ * @param {number} [start=0]
7141
+ * @param {number} [count=Infinity]
7142
+ * @return {?number} Index of the processed accessor on the "accessors" array
6920
7143
  */
6921
7144
  processAccessor(attribute, geometry, start, count) {
6922
7145
  const json = this.json;
@@ -6970,11 +7193,11 @@ var GLTFWriter = class {
6970
7193
  }
6971
7194
  /**
6972
7195
  * Process image
6973
- * @param {Image} image to process
6974
- * @param {Integer} format of the image (RGBAFormat)
6975
- * @param {Boolean} flipY before writing out the image
6976
- * @param {String} mimeType export format
6977
- * @return {Integer} Index of the processed texture in the "images" array
7196
+ * @param {Image} image to process
7197
+ * @param {number} format Identifier of the format (RGBAFormat)
7198
+ * @param {boolean} flipY before writing out the image
7199
+ * @param {string} mimeType export format
7200
+ * @return {number} Index of the processed texture in the "images" array
6978
7201
  */
6979
7202
  processImage(image, format, flipY, mimeType = "image/png") {
6980
7203
  if (image !== null) {
@@ -6992,7 +7215,9 @@ var GLTFWriter = class {
6992
7215
  const canvas = getCanvas();
6993
7216
  canvas.width = Math.min(image.width, options.maxTextureSize);
6994
7217
  canvas.height = Math.min(image.height, options.maxTextureSize);
6995
- const ctx = canvas.getContext("2d");
7218
+ const ctx = canvas.getContext("2d", {
7219
+ willReadFrequently: true
7220
+ });
6996
7221
  if (flipY === true) {
6997
7222
  ctx.translate(0, canvas.height);
6998
7223
  ctx.scale(1, -1);
@@ -7013,7 +7238,11 @@ var GLTFWriter = class {
7013
7238
  }
7014
7239
  ctx.putImageData(new ImageData(data, image.width, image.height), 0, 0);
7015
7240
  } else {
7016
- ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
7241
+ if (typeof HTMLImageElement !== "undefined" && image instanceof HTMLImageElement || typeof HTMLCanvasElement !== "undefined" && image instanceof HTMLCanvasElement || typeof ImageBitmap !== "undefined" && image instanceof ImageBitmap || typeof OffscreenCanvas !== "undefined" && image instanceof OffscreenCanvas) {
7242
+ ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
7243
+ } else {
7244
+ throw new Error("THREE.GLTFExporter: Invalid image type. Use HTMLImageElement, HTMLCanvasElement, ImageBitmap or OffscreenCanvas.");
7245
+ }
7017
7246
  }
7018
7247
  if (options.binary === true) {
7019
7248
  pending.push(
@@ -7022,15 +7251,7 @@ var GLTFWriter = class {
7022
7251
  })
7023
7252
  );
7024
7253
  } else {
7025
- if (canvas.toDataURL !== void 0) {
7026
- imageDef.uri = canvas.toDataURL(mimeType);
7027
- } else {
7028
- pending.push(
7029
- getToBlobPromise(canvas, mimeType).then((blob) => new FileReader().readAsDataURL(blob)).then((dataURL) => {
7030
- imageDef.uri = dataURL;
7031
- })
7032
- );
7033
- }
7254
+ imageDef.uri = ImageUtils.getDataURL(canvas, mimeType);
7034
7255
  }
7035
7256
  const index = json.images.push(imageDef) - 1;
7036
7257
  cachedImages[key] = index;
@@ -7041,8 +7262,8 @@ var GLTFWriter = class {
7041
7262
  }
7042
7263
  /**
7043
7264
  * Process sampler
7044
- * @param {Texture} map Texture to process
7045
- * @return {Integer} Index of the processed texture in the "samplers" array
7265
+ * @param {Texture} map Texture to process
7266
+ * @return {number} Index of the processed texture in the "samplers" array
7046
7267
  */
7047
7268
  processSampler(map) {
7048
7269
  const json = this.json;
@@ -7057,10 +7278,10 @@ var GLTFWriter = class {
7057
7278
  }
7058
7279
  /**
7059
7280
  * Process texture
7060
- * @param {Texture} map Map to process
7061
- * @return {Integer} Index of the processed texture in the "textures" array
7281
+ * @param {Texture} map Map to process
7282
+ * @return {Promise<number>} Index of the processed texture in the "textures" array
7062
7283
  */
7063
- processTexture(map) {
7284
+ async processTextureAsync(map) {
7064
7285
  const writer = this;
7065
7286
  const options = writer.options;
7066
7287
  const cache = this.cache;
@@ -7068,17 +7289,26 @@ var GLTFWriter = class {
7068
7289
  if (cache.textures.has(map)) return cache.textures.get(map);
7069
7290
  if (!json.textures) json.textures = [];
7070
7291
  if (map instanceof CompressedTexture) {
7071
- map = decompress(map, options.maxTextureSize);
7292
+ map = await this.decompressTextureAsync(map, options.maxTextureSize);
7072
7293
  }
7073
- let mimeType = map.userData.mimeType;
7074
- if (mimeType === "image/webp") mimeType = "image/png";
7294
+ const mimeType = map.userData.mimeType;
7295
+ const imageIndex = this.processImage(map.image, map.format, map.flipY, mimeType);
7075
7296
  const textureDef = {
7076
- sampler: this.processSampler(map),
7077
- source: this.processImage(map.image, map.format, map.flipY, mimeType)
7297
+ sampler: this.processSampler(map)
7078
7298
  };
7299
+ if (mimeType === "image/webp") {
7300
+ textureDef.extensions = textureDef.extensions || {};
7301
+ textureDef.extensions["EXT_texture_webp"] = {
7302
+ source: imageIndex
7303
+ };
7304
+ this.extensionsUsed["EXT_texture_webp"] = true;
7305
+ this.extensionsRequired["EXT_texture_webp"] = true;
7306
+ } else {
7307
+ textureDef.source = imageIndex;
7308
+ }
7079
7309
  if (map.name) textureDef.name = map.name;
7080
- this._invokeAll(function(ext) {
7081
- ext.writeTexture && ext.writeTexture(map, textureDef);
7310
+ await this._invokeAllAsync(async function(ext) {
7311
+ ext.writeTexture && await ext.writeTexture(map, textureDef);
7082
7312
  });
7083
7313
  const index = json.textures.push(textureDef) - 1;
7084
7314
  cache.textures.set(map, index);
@@ -7086,13 +7316,16 @@ var GLTFWriter = class {
7086
7316
  }
7087
7317
  /**
7088
7318
  * Process material
7089
- * @param {THREE.Material} material Material to process
7090
- * @return {Integer|null} Index of the processed material in the "materials" array
7319
+ * @param {THREE.Material} material Material to process
7320
+ * @param {THREE.BufferGeometry} [geometry] Geometry the material is used with.
7321
+ * @return {Promise<?number>} Index of the processed material in the "materials" array
7091
7322
  */
7092
- processMaterial(material) {
7323
+ async processMaterialAsync(material, geometry) {
7093
7324
  const cache = this.cache;
7094
7325
  const json = this.json;
7095
- if (cache.materials.has(material)) return cache.materials.get(material);
7326
+ const hasTangent = geometry !== void 0 && geometry.hasAttribute("tangent");
7327
+ const cacheKey = material.normalMap ? material.uuid + ":" + hasTangent : material.uuid;
7328
+ if (cache.materials.has(cacheKey)) return cache.materials.get(cacheKey);
7096
7329
  if (material.isShaderMaterial) {
7097
7330
  console.warn("GLTFExporter: THREE.ShaderMaterial not supported.");
7098
7331
  return null;
@@ -7110,21 +7343,21 @@ var GLTFWriter = class {
7110
7343
  materialDef.pbrMetallicRoughness.metallicFactor = material.metalness;
7111
7344
  materialDef.pbrMetallicRoughness.roughnessFactor = material.roughness;
7112
7345
  } else {
7113
- materialDef.pbrMetallicRoughness.metallicFactor = 0.5;
7114
- materialDef.pbrMetallicRoughness.roughnessFactor = 0.5;
7346
+ materialDef.pbrMetallicRoughness.metallicFactor = 0;
7347
+ materialDef.pbrMetallicRoughness.roughnessFactor = 1;
7115
7348
  }
7116
7349
  if (material.metalnessMap || material.roughnessMap) {
7117
- const metalRoughTexture = this.buildMetalRoughTexture(material.metalnessMap, material.roughnessMap);
7350
+ const metalRoughTexture = await this.buildMetalRoughTextureAsync(material.metalnessMap, material.roughnessMap);
7118
7351
  const metalRoughMapDef = {
7119
- index: this.processTexture(metalRoughTexture),
7120
- channel: metalRoughTexture.channel
7352
+ index: await this.processTextureAsync(metalRoughTexture),
7353
+ texCoord: metalRoughTexture.channel
7121
7354
  };
7122
7355
  this.applyTextureTransform(metalRoughMapDef, metalRoughTexture);
7123
7356
  materialDef.pbrMetallicRoughness.metallicRoughnessTexture = metalRoughMapDef;
7124
7357
  }
7125
7358
  if (material.map) {
7126
7359
  const baseColorMapDef = {
7127
- index: this.processTexture(material.map),
7360
+ index: await this.processTextureAsync(material.map),
7128
7361
  texCoord: material.map.channel
7129
7362
  };
7130
7363
  this.applyTextureTransform(baseColorMapDef, material.map);
@@ -7138,7 +7371,7 @@ var GLTFWriter = class {
7138
7371
  }
7139
7372
  if (material.emissiveMap) {
7140
7373
  const emissiveMapDef = {
7141
- index: this.processTexture(material.emissiveMap),
7374
+ index: await this.processTextureAsync(material.emissiveMap),
7142
7375
  texCoord: material.emissiveMap.channel
7143
7376
  };
7144
7377
  this.applyTextureTransform(emissiveMapDef, material.emissiveMap);
@@ -7146,19 +7379,32 @@ var GLTFWriter = class {
7146
7379
  }
7147
7380
  }
7148
7381
  if (material.normalMap) {
7382
+ const normalScale = material.normalScale;
7383
+ const flipX = normalScale.x < 0;
7384
+ const flipY = hasTangent ? normalScale.y < 0 : normalScale.y > 0;
7385
+ let normalMap = material.normalMap;
7386
+ if (flipX || flipY) {
7387
+ if (cache.normalMaps.has(material.normalMap) === false) cache.normalMaps.set(material.normalMap, {});
7388
+ const cachedVariants = cache.normalMaps.get(material.normalMap);
7389
+ const cacheKey2 = `${flipX}:${flipY}`;
7390
+ if (cachedVariants[cacheKey2] === void 0) {
7391
+ cachedVariants[cacheKey2] = await this.buildNormalMapTextureAsync(material.normalMap, flipX, flipY);
7392
+ }
7393
+ normalMap = cachedVariants[cacheKey2];
7394
+ }
7149
7395
  const normalMapDef = {
7150
- index: this.processTexture(material.normalMap),
7396
+ index: await this.processTextureAsync(normalMap),
7151
7397
  texCoord: material.normalMap.channel
7152
7398
  };
7153
- if (material.normalScale && material.normalScale.x !== 1) {
7154
- normalMapDef.scale = material.normalScale.x;
7399
+ if (Math.abs(normalScale.x) !== 1) {
7400
+ normalMapDef.scale = Math.abs(normalScale.x);
7155
7401
  }
7156
7402
  this.applyTextureTransform(normalMapDef, material.normalMap);
7157
7403
  materialDef.normalTexture = normalMapDef;
7158
7404
  }
7159
7405
  if (material.aoMap) {
7160
7406
  const occlusionMapDef = {
7161
- index: this.processTexture(material.aoMap),
7407
+ index: await this.processTextureAsync(material.aoMap),
7162
7408
  texCoord: material.aoMap.channel
7163
7409
  };
7164
7410
  if (material.aoMapIntensity !== 1) {
@@ -7178,19 +7424,19 @@ var GLTFWriter = class {
7178
7424
  if (material.side === DoubleSide2) materialDef.doubleSided = true;
7179
7425
  if (material.name !== "") materialDef.name = material.name;
7180
7426
  this.serializeUserData(material, materialDef);
7181
- this._invokeAll(function(ext) {
7182
- ext.writeMaterial && ext.writeMaterial(material, materialDef);
7427
+ await this._invokeAllAsync(async function(ext) {
7428
+ ext.writeMaterialAsync && await ext.writeMaterialAsync(material, materialDef);
7183
7429
  });
7184
7430
  const index = json.materials.push(materialDef) - 1;
7185
- cache.materials.set(material, index);
7431
+ cache.materials.set(cacheKey, index);
7186
7432
  return index;
7187
7433
  }
7188
7434
  /**
7189
7435
  * Process mesh
7190
- * @param {THREE.Mesh} mesh Mesh to process
7191
- * @return {Integer|null} Index of the processed mesh in the "meshes" array
7436
+ * @param {THREE.Mesh} mesh Mesh to process
7437
+ * @return {Promise<?number>} Index of the processed mesh in the "meshes" array
7192
7438
  */
7193
- processMesh(mesh) {
7439
+ async processMeshAsync(mesh) {
7194
7440
  const cache = this.cache;
7195
7441
  const json = this.json;
7196
7442
  const meshCacheKeyParts = [mesh.geometry.uuid];
@@ -7240,7 +7486,7 @@ var GLTFWriter = class {
7240
7486
  const attribute = geometry.attributes[attributeName];
7241
7487
  attributeName = nameConversion[attributeName] || attributeName.toUpperCase();
7242
7488
  const validVertexAttributes = /^(POSITION|NORMAL|TANGENT|TEXCOORD_\d+|COLOR_\d+|JOINTS_\d+|WEIGHTS_\d+)$/;
7243
- if (!validVertexAttributes.test(attributeName)) attributeName = "_" + attributeName;
7489
+ if (!validVertexAttributes.test(attributeName) && !attributeName.startsWith("_")) attributeName = "_" + attributeName;
7244
7490
  if (cache.attributes.has(this.getUID(attribute))) {
7245
7491
  attributes[attributeName] = cache.attributes.get(this.getUID(attribute));
7246
7492
  continue;
@@ -7249,7 +7495,10 @@ var GLTFWriter = class {
7249
7495
  const array = attribute.array;
7250
7496
  if (attributeName === "JOINTS_0" && !(array instanceof Uint16Array) && !(array instanceof Uint8Array)) {
7251
7497
  console.warn('GLTFExporter: Attribute "skinIndex" converted to type UNSIGNED_SHORT.');
7252
- modifiedAttribute = new BufferAttribute3(new Uint16Array(array), attribute.itemSize, attribute.normalized);
7498
+ modifiedAttribute = GLTFExporter.Utils.toTypedBufferAttribute(attribute, Uint16Array);
7499
+ } else if ((array instanceof Uint32Array || array instanceof Int32Array) && !attributeName.startsWith("_")) {
7500
+ console.warn(`GLTFExporter: Attribute "${attributeName}" converted to type FLOAT.`);
7501
+ modifiedAttribute = GLTFExporter.Utils.toTypedBufferAttribute(attribute, Float32Array);
7253
7502
  }
7254
7503
  const accessor = this.processAccessor(modifiedAttribute || attribute, geometry);
7255
7504
  if (accessor !== null) {
@@ -7315,6 +7564,15 @@ var GLTFWriter = class {
7315
7564
  }
7316
7565
  const isMultiMaterial = Array.isArray(mesh.material);
7317
7566
  if (isMultiMaterial && geometry.groups.length === 0) return null;
7567
+ let didForceIndices = false;
7568
+ if (isMultiMaterial && geometry.index === null) {
7569
+ const indices = [];
7570
+ for (let i = 0, il = geometry.attributes.position.count; i < il; i++) {
7571
+ indices[i] = i;
7572
+ }
7573
+ geometry.setIndex(indices);
7574
+ didForceIndices = true;
7575
+ }
7318
7576
  const materials = isMultiMaterial ? mesh.material : [mesh.material];
7319
7577
  const groups = isMultiMaterial ? geometry.groups : [{ materialIndex: 0, start: void 0, count: void 0 }];
7320
7578
  for (let i = 0, il = groups.length; i < il; i++) {
@@ -7337,13 +7595,16 @@ var GLTFWriter = class {
7337
7595
  }
7338
7596
  if (primitive.indices === null) delete primitive.indices;
7339
7597
  }
7340
- const material = this.processMaterial(materials[groups[i].materialIndex]);
7598
+ const material = await this.processMaterialAsync(materials[groups[i].materialIndex], geometry);
7341
7599
  if (material !== null) primitive.material = material;
7342
7600
  primitives.push(primitive);
7343
7601
  }
7602
+ if (didForceIndices === true) {
7603
+ geometry.setIndex(null);
7604
+ }
7344
7605
  meshDef.primitives = primitives;
7345
7606
  if (!json.meshes) json.meshes = [];
7346
- this._invokeAll(function(ext) {
7607
+ await this._invokeAllAsync(function(ext) {
7347
7608
  ext.writeMesh && ext.writeMesh(mesh, meshDef);
7348
7609
  });
7349
7610
  const index = json.meshes.push(meshDef) - 1;
@@ -7389,8 +7650,8 @@ var GLTFWriter = class {
7389
7650
  }
7390
7651
  /**
7391
7652
  * Process camera
7392
- * @param {THREE.Camera} camera Camera to process
7393
- * @return {Integer} Index of the processed mesh in the "camera" array
7653
+ * @param {THREE.Camera} camera Camera to process
7654
+ * @return {number} Index of the processed mesh in the "camera" array
7394
7655
  */
7395
7656
  processCamera(camera) {
7396
7657
  const json = this.json;
@@ -7409,7 +7670,7 @@ var GLTFWriter = class {
7409
7670
  } else {
7410
7671
  cameraDef.perspective = {
7411
7672
  aspectRatio: camera.aspect,
7412
- yfov: MathUtils2.degToRad(camera.fov),
7673
+ yfov: MathUtils.degToRad(camera.fov),
7413
7674
  zfar: camera.far <= 0 ? 1e-3 : camera.far,
7414
7675
  znear: camera.near < 0 ? 0 : camera.near
7415
7676
  };
@@ -7425,7 +7686,7 @@ var GLTFWriter = class {
7425
7686
  *
7426
7687
  * @param {THREE.AnimationClip} clip
7427
7688
  * @param {THREE.Object3D} root
7428
- * @return {number|null}
7689
+ * @return {?number}
7429
7690
  */
7430
7691
  processAnimation(clip, root) {
7431
7692
  const json = this.json;
@@ -7449,7 +7710,7 @@ var GLTFWriter = class {
7449
7710
  }
7450
7711
  if (!trackNode || !trackProperty) {
7451
7712
  console.warn('THREE.GLTFExporter: Could not export animation track "%s".', track.name);
7452
- return null;
7713
+ continue;
7453
7714
  }
7454
7715
  const inputItemSize = 1;
7455
7716
  let outputItemSize = track.values.length / track.times.length;
@@ -7478,16 +7739,18 @@ var GLTFWriter = class {
7478
7739
  }
7479
7740
  });
7480
7741
  }
7481
- json.animations.push({
7742
+ const animationDef = {
7482
7743
  name: clip.name || "clip_" + json.animations.length,
7483
7744
  samplers,
7484
7745
  channels
7485
- });
7746
+ };
7747
+ this.serializeUserData(clip, animationDef);
7748
+ json.animations.push(animationDef);
7486
7749
  return json.animations.length - 1;
7487
7750
  }
7488
7751
  /**
7489
7752
  * @param {THREE.Object3D} object
7490
- * @return {number|null}
7753
+ * @return {?number}
7491
7754
  */
7492
7755
  processSkin(object) {
7493
7756
  const json = this.json;
@@ -7516,14 +7779,17 @@ var GLTFWriter = class {
7516
7779
  }
7517
7780
  /**
7518
7781
  * Process Object3D node
7519
- * @param {THREE.Object3D} node Object3D to processNode
7520
- * @return {Integer} Index of the node in the nodes list
7782
+ * @param {THREE.Object3D} object Object3D to processNodeAsync
7783
+ * @return {Promise<number>} Index of the node in the nodes list
7521
7784
  */
7522
- processNode(object) {
7785
+ async processNodeAsync(object) {
7523
7786
  const json = this.json;
7524
7787
  const options = this.options;
7525
7788
  const nodeMap = this.nodeMap;
7526
7789
  if (!json.nodes) json.nodes = [];
7790
+ if (object.pivot !== null) {
7791
+ return await this._processNodeWithPivotAsync(object);
7792
+ }
7527
7793
  const nodeDef = {};
7528
7794
  if (options.trs) {
7529
7795
  const rotation = object.quaternion.toArray();
@@ -7549,35 +7815,98 @@ var GLTFWriter = class {
7549
7815
  if (object.name !== "") nodeDef.name = String(object.name);
7550
7816
  this.serializeUserData(object, nodeDef);
7551
7817
  if (object.isMesh || object.isLine || object.isPoints) {
7552
- const meshIndex = this.processMesh(object);
7818
+ const meshIndex = await this.processMeshAsync(object);
7553
7819
  if (meshIndex !== null) nodeDef.mesh = meshIndex;
7554
7820
  } else if (object.isCamera) {
7555
7821
  nodeDef.camera = this.processCamera(object);
7556
7822
  }
7557
7823
  if (object.isSkinnedMesh) this.skins.push(object);
7824
+ const nodeIndex = json.nodes.push(nodeDef) - 1;
7825
+ nodeMap.set(object, nodeIndex);
7558
7826
  if (object.children.length > 0) {
7559
7827
  const children = [];
7560
7828
  for (let i = 0, l = object.children.length; i < l; i++) {
7561
7829
  const child = object.children[i];
7562
7830
  if (child.visible || options.onlyVisible === false) {
7563
- const nodeIndex2 = this.processNode(child);
7564
- if (nodeIndex2 !== null) children.push(nodeIndex2);
7831
+ const childNodeIndex = await this.processNodeAsync(child);
7832
+ if (childNodeIndex !== null) children.push(childNodeIndex);
7565
7833
  }
7566
7834
  }
7567
7835
  if (children.length > 0) nodeDef.children = children;
7568
7836
  }
7569
- this._invokeAll(function(ext) {
7837
+ await this._invokeAllAsync(function(ext) {
7570
7838
  ext.writeNode && ext.writeNode(object, nodeDef);
7571
7839
  });
7572
- const nodeIndex = json.nodes.push(nodeDef) - 1;
7573
- nodeMap.set(object, nodeIndex);
7574
7840
  return nodeIndex;
7575
7841
  }
7842
+ /**
7843
+ * Process Object3D node with pivot using container approach
7844
+ * @param {THREE.Object3D} object Object3D with pivot
7845
+ * @return {Promise<number>} Index of the container node
7846
+ */
7847
+ async _processNodeWithPivotAsync(object) {
7848
+ const json = this.json;
7849
+ const options = this.options;
7850
+ const nodeMap = this.nodeMap;
7851
+ const pivot = object.pivot;
7852
+ const containerDef = {};
7853
+ const rotation = object.quaternion.toArray();
7854
+ const position = [
7855
+ object.position.x + pivot.x,
7856
+ object.position.y + pivot.y,
7857
+ object.position.z + pivot.z
7858
+ ];
7859
+ const scale = object.scale.toArray();
7860
+ if (!equalArray(rotation, [0, 0, 0, 1])) {
7861
+ containerDef.rotation = rotation;
7862
+ }
7863
+ if (!equalArray(position, [0, 0, 0])) {
7864
+ containerDef.translation = position;
7865
+ }
7866
+ if (!equalArray(scale, [1, 1, 1])) {
7867
+ containerDef.scale = scale;
7868
+ }
7869
+ containerDef.extras = { pivot: pivot.toArray() };
7870
+ if (object.name !== "") containerDef.name = String(object.name);
7871
+ this.serializeUserData(object, containerDef);
7872
+ const containerIndex = json.nodes.push(containerDef) - 1;
7873
+ nodeMap.set(object, containerIndex);
7874
+ const childDef = {};
7875
+ const childPosition = [-pivot.x, -pivot.y, -pivot.z];
7876
+ if (!equalArray(childPosition, [0, 0, 0])) {
7877
+ childDef.translation = childPosition;
7878
+ }
7879
+ if (object.isMesh || object.isLine || object.isPoints) {
7880
+ const meshIndex = await this.processMeshAsync(object);
7881
+ if (meshIndex !== null) childDef.mesh = meshIndex;
7882
+ } else if (object.isCamera) {
7883
+ childDef.camera = this.processCamera(object);
7884
+ }
7885
+ if (object.isSkinnedMesh) this.skins.push(object);
7886
+ const childIndex = json.nodes.push(childDef) - 1;
7887
+ const containerChildren = [childIndex];
7888
+ if (object.children.length > 0) {
7889
+ const grandchildren = [];
7890
+ for (let i = 0, l = object.children.length; i < l; i++) {
7891
+ const child = object.children[i];
7892
+ if (child.visible || options.onlyVisible === false) {
7893
+ const childNodeIndex = await this.processNodeAsync(child);
7894
+ if (childNodeIndex !== null) grandchildren.push(childNodeIndex);
7895
+ }
7896
+ }
7897
+ if (grandchildren.length > 0) childDef.children = grandchildren;
7898
+ }
7899
+ containerDef.children = containerChildren;
7900
+ await this._invokeAllAsync(function(ext) {
7901
+ ext.writeNode && ext.writeNode(object, containerDef);
7902
+ });
7903
+ return containerIndex;
7904
+ }
7576
7905
  /**
7577
7906
  * Process Scene
7578
- * @param {Scene} node Scene to process
7907
+ * @param {Scene} scene Scene to process
7579
7908
  */
7580
- processScene(scene) {
7909
+ async processSceneAsync(scene) {
7581
7910
  const json = this.json;
7582
7911
  const options = this.options;
7583
7912
  if (!json.scenes) {
@@ -7591,7 +7920,7 @@ var GLTFWriter = class {
7591
7920
  for (let i = 0, l = scene.children.length; i < l; i++) {
7592
7921
  const child = scene.children[i];
7593
7922
  if (child.visible || options.onlyVisible === false) {
7594
- const nodeIndex = this.processNode(child);
7923
+ const nodeIndex = await this.processNodeAsync(child);
7595
7924
  if (nodeIndex !== null) nodes.push(nodeIndex);
7596
7925
  }
7597
7926
  }
@@ -7600,47 +7929,58 @@ var GLTFWriter = class {
7600
7929
  }
7601
7930
  /**
7602
7931
  * Creates a Scene to hold a list of objects and parse it
7603
- * @param {Array} objects List of objects to process
7932
+ * @param {Array<THREE.Object3D>} objects List of objects to process
7604
7933
  */
7605
- processObjects(objects) {
7606
- const scene = new Scene3();
7934
+ async processObjectsAsync(objects) {
7935
+ const scene = new Scene2();
7607
7936
  scene.name = "AuxScene";
7608
7937
  for (let i = 0; i < objects.length; i++) {
7609
7938
  scene.children.push(objects[i]);
7610
7939
  }
7611
- this.processScene(scene);
7940
+ await this.processSceneAsync(scene);
7612
7941
  }
7613
7942
  /**
7614
7943
  * @param {THREE.Object3D|Array<THREE.Object3D>} input
7615
7944
  */
7616
- processInput(input) {
7945
+ async processInputAsync(input) {
7617
7946
  const options = this.options;
7618
7947
  input = input instanceof Array ? input : [input];
7619
- this._invokeAll(function(ext) {
7948
+ await this._invokeAllAsync(function(ext) {
7620
7949
  ext.beforeParse && ext.beforeParse(input);
7621
7950
  });
7622
7951
  const objectsWithoutScene = [];
7623
7952
  for (let i = 0; i < input.length; i++) {
7624
- if (input[i] instanceof Scene3) {
7625
- this.processScene(input[i]);
7953
+ if (input[i] instanceof Scene2) {
7954
+ await this.processSceneAsync(input[i]);
7626
7955
  } else {
7627
7956
  objectsWithoutScene.push(input[i]);
7628
7957
  }
7629
7958
  }
7630
- if (objectsWithoutScene.length > 0) this.processObjects(objectsWithoutScene);
7959
+ if (objectsWithoutScene.length > 0) {
7960
+ await this.processObjectsAsync(objectsWithoutScene);
7961
+ }
7631
7962
  for (let i = 0; i < this.skins.length; ++i) {
7632
7963
  this.processSkin(this.skins[i]);
7633
7964
  }
7634
- for (let i = 0; i < options.animations.length; ++i) {
7635
- this.processAnimation(options.animations[i], input[0]);
7965
+ if (input.length === 1) {
7966
+ for (let i = 0; i < options.animations.length; ++i) {
7967
+ this.processAnimation(options.animations[i], input[0]);
7968
+ }
7969
+ } else {
7970
+ for (let i = 0; i < input.length; i++) {
7971
+ const animations = options.animations[i] || [];
7972
+ for (let j = 0; j < animations.length; ++j) {
7973
+ this.processAnimation(animations[j], input[i]);
7974
+ }
7975
+ }
7636
7976
  }
7637
- this._invokeAll(function(ext) {
7977
+ await this._invokeAllAsync(function(ext) {
7638
7978
  ext.afterParse && ext.afterParse(input);
7639
7979
  });
7640
7980
  }
7641
- _invokeAll(func) {
7981
+ async _invokeAllAsync(func) {
7642
7982
  for (let i = 0, il = this.plugins.length; i < il; i++) {
7643
- func(this.plugins[i]);
7983
+ await func(this.plugins[i]);
7644
7984
  }
7645
7985
  }
7646
7986
  };
@@ -7696,7 +8036,7 @@ var GLTFMaterialsUnlitExtension = class {
7696
8036
  this.writer = writer;
7697
8037
  this.name = "KHR_materials_unlit";
7698
8038
  }
7699
- writeMaterial(material, materialDef) {
8039
+ async writeMaterialAsync(material, materialDef) {
7700
8040
  if (!material.isMeshBasicMaterial) return;
7701
8041
  const writer = this.writer;
7702
8042
  const extensionsUsed = writer.extensionsUsed;
@@ -7712,7 +8052,7 @@ var GLTFMaterialsClearcoatExtension = class {
7712
8052
  this.writer = writer;
7713
8053
  this.name = "KHR_materials_clearcoat";
7714
8054
  }
7715
- writeMaterial(material, materialDef) {
8055
+ async writeMaterialAsync(material, materialDef) {
7716
8056
  if (!material.isMeshPhysicalMaterial || material.clearcoat === 0) return;
7717
8057
  const writer = this.writer;
7718
8058
  const extensionsUsed = writer.extensionsUsed;
@@ -7720,7 +8060,7 @@ var GLTFMaterialsClearcoatExtension = class {
7720
8060
  extensionDef.clearcoatFactor = material.clearcoat;
7721
8061
  if (material.clearcoatMap) {
7722
8062
  const clearcoatMapDef = {
7723
- index: writer.processTexture(material.clearcoatMap),
8063
+ index: await writer.processTextureAsync(material.clearcoatMap),
7724
8064
  texCoord: material.clearcoatMap.channel
7725
8065
  };
7726
8066
  writer.applyTextureTransform(clearcoatMapDef, material.clearcoatMap);
@@ -7729,7 +8069,7 @@ var GLTFMaterialsClearcoatExtension = class {
7729
8069
  extensionDef.clearcoatRoughnessFactor = material.clearcoatRoughness;
7730
8070
  if (material.clearcoatRoughnessMap) {
7731
8071
  const clearcoatRoughnessMapDef = {
7732
- index: writer.processTexture(material.clearcoatRoughnessMap),
8072
+ index: await writer.processTextureAsync(material.clearcoatRoughnessMap),
7733
8073
  texCoord: material.clearcoatRoughnessMap.channel
7734
8074
  };
7735
8075
  writer.applyTextureTransform(clearcoatRoughnessMapDef, material.clearcoatRoughnessMap);
@@ -7737,9 +8077,10 @@ var GLTFMaterialsClearcoatExtension = class {
7737
8077
  }
7738
8078
  if (material.clearcoatNormalMap) {
7739
8079
  const clearcoatNormalMapDef = {
7740
- index: writer.processTexture(material.clearcoatNormalMap),
8080
+ index: await writer.processTextureAsync(material.clearcoatNormalMap),
7741
8081
  texCoord: material.clearcoatNormalMap.channel
7742
8082
  };
8083
+ if (material.clearcoatNormalScale.x !== 1) clearcoatNormalMapDef.scale = material.clearcoatNormalScale.x;
7743
8084
  writer.applyTextureTransform(clearcoatNormalMapDef, material.clearcoatNormalMap);
7744
8085
  extensionDef.clearcoatNormalTexture = clearcoatNormalMapDef;
7745
8086
  }
@@ -7748,12 +8089,28 @@ var GLTFMaterialsClearcoatExtension = class {
7748
8089
  extensionsUsed[this.name] = true;
7749
8090
  }
7750
8091
  };
8092
+ var GLTFMaterialsDispersionExtension = class {
8093
+ constructor(writer) {
8094
+ this.writer = writer;
8095
+ this.name = "KHR_materials_dispersion";
8096
+ }
8097
+ async writeMaterialAsync(material, materialDef) {
8098
+ if (!material.isMeshPhysicalMaterial || material.dispersion === 0) return;
8099
+ const writer = this.writer;
8100
+ const extensionsUsed = writer.extensionsUsed;
8101
+ const extensionDef = {};
8102
+ extensionDef.dispersion = material.dispersion;
8103
+ materialDef.extensions = materialDef.extensions || {};
8104
+ materialDef.extensions[this.name] = extensionDef;
8105
+ extensionsUsed[this.name] = true;
8106
+ }
8107
+ };
7751
8108
  var GLTFMaterialsIridescenceExtension = class {
7752
8109
  constructor(writer) {
7753
8110
  this.writer = writer;
7754
8111
  this.name = "KHR_materials_iridescence";
7755
8112
  }
7756
- writeMaterial(material, materialDef) {
8113
+ async writeMaterialAsync(material, materialDef) {
7757
8114
  if (!material.isMeshPhysicalMaterial || material.iridescence === 0) return;
7758
8115
  const writer = this.writer;
7759
8116
  const extensionsUsed = writer.extensionsUsed;
@@ -7761,7 +8118,7 @@ var GLTFMaterialsIridescenceExtension = class {
7761
8118
  extensionDef.iridescenceFactor = material.iridescence;
7762
8119
  if (material.iridescenceMap) {
7763
8120
  const iridescenceMapDef = {
7764
- index: writer.processTexture(material.iridescenceMap),
8121
+ index: await writer.processTextureAsync(material.iridescenceMap),
7765
8122
  texCoord: material.iridescenceMap.channel
7766
8123
  };
7767
8124
  writer.applyTextureTransform(iridescenceMapDef, material.iridescenceMap);
@@ -7772,7 +8129,7 @@ var GLTFMaterialsIridescenceExtension = class {
7772
8129
  extensionDef.iridescenceThicknessMaximum = material.iridescenceThicknessRange[1];
7773
8130
  if (material.iridescenceThicknessMap) {
7774
8131
  const iridescenceThicknessMapDef = {
7775
- index: writer.processTexture(material.iridescenceThicknessMap),
8132
+ index: await writer.processTextureAsync(material.iridescenceThicknessMap),
7776
8133
  texCoord: material.iridescenceThicknessMap.channel
7777
8134
  };
7778
8135
  writer.applyTextureTransform(iridescenceThicknessMapDef, material.iridescenceThicknessMap);
@@ -7788,7 +8145,7 @@ var GLTFMaterialsTransmissionExtension = class {
7788
8145
  this.writer = writer;
7789
8146
  this.name = "KHR_materials_transmission";
7790
8147
  }
7791
- writeMaterial(material, materialDef) {
8148
+ async writeMaterialAsync(material, materialDef) {
7792
8149
  if (!material.isMeshPhysicalMaterial || material.transmission === 0) return;
7793
8150
  const writer = this.writer;
7794
8151
  const extensionsUsed = writer.extensionsUsed;
@@ -7796,7 +8153,7 @@ var GLTFMaterialsTransmissionExtension = class {
7796
8153
  extensionDef.transmissionFactor = material.transmission;
7797
8154
  if (material.transmissionMap) {
7798
8155
  const transmissionMapDef = {
7799
- index: writer.processTexture(material.transmissionMap),
8156
+ index: await writer.processTextureAsync(material.transmissionMap),
7800
8157
  texCoord: material.transmissionMap.channel
7801
8158
  };
7802
8159
  writer.applyTextureTransform(transmissionMapDef, material.transmissionMap);
@@ -7812,7 +8169,7 @@ var GLTFMaterialsVolumeExtension = class {
7812
8169
  this.writer = writer;
7813
8170
  this.name = "KHR_materials_volume";
7814
8171
  }
7815
- writeMaterial(material, materialDef) {
8172
+ async writeMaterialAsync(material, materialDef) {
7816
8173
  if (!material.isMeshPhysicalMaterial || material.transmission === 0) return;
7817
8174
  const writer = this.writer;
7818
8175
  const extensionsUsed = writer.extensionsUsed;
@@ -7820,13 +8177,15 @@ var GLTFMaterialsVolumeExtension = class {
7820
8177
  extensionDef.thicknessFactor = material.thickness;
7821
8178
  if (material.thicknessMap) {
7822
8179
  const thicknessMapDef = {
7823
- index: writer.processTexture(material.thicknessMap),
8180
+ index: await writer.processTextureAsync(material.thicknessMap),
7824
8181
  texCoord: material.thicknessMap.channel
7825
8182
  };
7826
8183
  writer.applyTextureTransform(thicknessMapDef, material.thicknessMap);
7827
8184
  extensionDef.thicknessTexture = thicknessMapDef;
7828
8185
  }
7829
- extensionDef.attenuationDistance = material.attenuationDistance;
8186
+ if (material.attenuationDistance !== Infinity) {
8187
+ extensionDef.attenuationDistance = material.attenuationDistance;
8188
+ }
7830
8189
  extensionDef.attenuationColor = material.attenuationColor.toArray();
7831
8190
  materialDef.extensions = materialDef.extensions || {};
7832
8191
  materialDef.extensions[this.name] = extensionDef;
@@ -7838,7 +8197,7 @@ var GLTFMaterialsIorExtension = class {
7838
8197
  this.writer = writer;
7839
8198
  this.name = "KHR_materials_ior";
7840
8199
  }
7841
- writeMaterial(material, materialDef) {
8200
+ async writeMaterialAsync(material, materialDef) {
7842
8201
  if (!material.isMeshPhysicalMaterial || material.ior === 1.5) return;
7843
8202
  const writer = this.writer;
7844
8203
  const extensionsUsed = writer.extensionsUsed;
@@ -7854,14 +8213,14 @@ var GLTFMaterialsSpecularExtension = class {
7854
8213
  this.writer = writer;
7855
8214
  this.name = "KHR_materials_specular";
7856
8215
  }
7857
- writeMaterial(material, materialDef) {
7858
- if (!material.isMeshPhysicalMaterial || material.specularIntensity === 1 && material.specularColor.equals(DEFAULT_SPECULAR_COLOR) && !material.specularIntensityMap && !material.specularColorTexture) return;
8216
+ async writeMaterialAsync(material, materialDef) {
8217
+ if (!material.isMeshPhysicalMaterial || material.specularIntensity === 1 && material.specularColor.equals(DEFAULT_SPECULAR_COLOR) && !material.specularIntensityMap && !material.specularColorMap) return;
7859
8218
  const writer = this.writer;
7860
8219
  const extensionsUsed = writer.extensionsUsed;
7861
8220
  const extensionDef = {};
7862
8221
  if (material.specularIntensityMap) {
7863
8222
  const specularIntensityMapDef = {
7864
- index: writer.processTexture(material.specularIntensityMap),
8223
+ index: await writer.processTextureAsync(material.specularIntensityMap),
7865
8224
  texCoord: material.specularIntensityMap.channel
7866
8225
  };
7867
8226
  writer.applyTextureTransform(specularIntensityMapDef, material.specularIntensityMap);
@@ -7869,7 +8228,7 @@ var GLTFMaterialsSpecularExtension = class {
7869
8228
  }
7870
8229
  if (material.specularColorMap) {
7871
8230
  const specularColorMapDef = {
7872
- index: writer.processTexture(material.specularColorMap),
8231
+ index: await writer.processTextureAsync(material.specularColorMap),
7873
8232
  texCoord: material.specularColorMap.channel
7874
8233
  };
7875
8234
  writer.applyTextureTransform(specularColorMapDef, material.specularColorMap);
@@ -7887,14 +8246,14 @@ var GLTFMaterialsSheenExtension = class {
7887
8246
  this.writer = writer;
7888
8247
  this.name = "KHR_materials_sheen";
7889
8248
  }
7890
- writeMaterial(material, materialDef) {
8249
+ async writeMaterialAsync(material, materialDef) {
7891
8250
  if (!material.isMeshPhysicalMaterial || material.sheen == 0) return;
7892
8251
  const writer = this.writer;
7893
8252
  const extensionsUsed = writer.extensionsUsed;
7894
8253
  const extensionDef = {};
7895
8254
  if (material.sheenRoughnessMap) {
7896
8255
  const sheenRoughnessMapDef = {
7897
- index: writer.processTexture(material.sheenRoughnessMap),
8256
+ index: await writer.processTextureAsync(material.sheenRoughnessMap),
7898
8257
  texCoord: material.sheenRoughnessMap.channel
7899
8258
  };
7900
8259
  writer.applyTextureTransform(sheenRoughnessMapDef, material.sheenRoughnessMap);
@@ -7902,7 +8261,7 @@ var GLTFMaterialsSheenExtension = class {
7902
8261
  }
7903
8262
  if (material.sheenColorMap) {
7904
8263
  const sheenColorMapDef = {
7905
- index: writer.processTexture(material.sheenColorMap),
8264
+ index: await writer.processTextureAsync(material.sheenColorMap),
7906
8265
  texCoord: material.sheenColorMap.channel
7907
8266
  };
7908
8267
  writer.applyTextureTransform(sheenColorMapDef, material.sheenColorMap);
@@ -7920,13 +8279,13 @@ var GLTFMaterialsAnisotropyExtension = class {
7920
8279
  this.writer = writer;
7921
8280
  this.name = "KHR_materials_anisotropy";
7922
8281
  }
7923
- writeMaterial(material, materialDef) {
8282
+ async writeMaterialAsync(material, materialDef) {
7924
8283
  if (!material.isMeshPhysicalMaterial || material.anisotropy == 0) return;
7925
8284
  const writer = this.writer;
7926
8285
  const extensionsUsed = writer.extensionsUsed;
7927
8286
  const extensionDef = {};
7928
8287
  if (material.anisotropyMap) {
7929
- const anisotropyMapDef = { index: writer.processTexture(material.anisotropyMap) };
8288
+ const anisotropyMapDef = { index: await writer.processTextureAsync(material.anisotropyMap) };
7930
8289
  writer.applyTextureTransform(anisotropyMapDef, material.anisotropyMap);
7931
8290
  extensionDef.anisotropyTexture = anisotropyMapDef;
7932
8291
  }
@@ -7942,7 +8301,7 @@ var GLTFMaterialsEmissiveStrengthExtension = class {
7942
8301
  this.writer = writer;
7943
8302
  this.name = "KHR_materials_emissive_strength";
7944
8303
  }
7945
- writeMaterial(material, materialDef) {
8304
+ async writeMaterialAsync(material, materialDef) {
7946
8305
  if (!material.isMeshStandardMaterial || material.emissiveIntensity === 1) return;
7947
8306
  const writer = this.writer;
7948
8307
  const extensionsUsed = writer.extensionsUsed;
@@ -7953,6 +8312,30 @@ var GLTFMaterialsEmissiveStrengthExtension = class {
7953
8312
  extensionsUsed[this.name] = true;
7954
8313
  }
7955
8314
  };
8315
+ var GLTFMaterialsBumpExtension = class {
8316
+ constructor(writer) {
8317
+ this.writer = writer;
8318
+ this.name = "EXT_materials_bump";
8319
+ }
8320
+ async writeMaterialAsync(material, materialDef) {
8321
+ if (!material.isMeshStandardMaterial || material.bumpScale === 1 && !material.bumpMap) return;
8322
+ const writer = this.writer;
8323
+ const extensionsUsed = writer.extensionsUsed;
8324
+ const extensionDef = {};
8325
+ if (material.bumpMap) {
8326
+ const bumpMapDef = {
8327
+ index: await writer.processTextureAsync(material.bumpMap),
8328
+ texCoord: material.bumpMap.channel
8329
+ };
8330
+ writer.applyTextureTransform(bumpMapDef, material.bumpMap);
8331
+ extensionDef.bumpTexture = bumpMapDef;
8332
+ }
8333
+ extensionDef.bumpFactor = material.bumpScale;
8334
+ materialDef.extensions = materialDef.extensions || {};
8335
+ materialDef.extensions[this.name] = extensionDef;
8336
+ extensionsUsed[this.name] = true;
8337
+ }
8338
+ };
7956
8339
  var GLTFMeshGpuInstancing = class {
7957
8340
  constructor(writer) {
7958
8341
  this.writer = writer;
@@ -8088,6 +8471,19 @@ GLTFExporter.Utils = {
8088
8471
  }
8089
8472
  clip.tracks = tracks;
8090
8473
  return clip;
8474
+ },
8475
+ toTypedBufferAttribute: function(srcAttribute, TypedArray) {
8476
+ const dstAttribute = new BufferAttribute3(new TypedArray(srcAttribute.count * srcAttribute.itemSize), srcAttribute.itemSize, false);
8477
+ if (!srcAttribute.normalized && !srcAttribute.isInterleavedBufferAttribute) {
8478
+ dstAttribute.array.set(srcAttribute.array);
8479
+ return dstAttribute;
8480
+ }
8481
+ for (let i = 0, il = srcAttribute.count; i < il; i++) {
8482
+ for (let j = 0; j < srcAttribute.itemSize; j++) {
8483
+ dstAttribute.setComponent(i, j, srcAttribute.getComponent(i, j));
8484
+ }
8485
+ }
8486
+ return dstAttribute;
8091
8487
  }
8092
8488
  };
8093
8489
 
@@ -8142,7 +8538,7 @@ function localMatrix(object) {
8142
8538
  return object.matrixAutoUpdate ? new Matrix47().compose(object.position, object.quaternion, object.scale) : object.matrix.clone();
8143
8539
  }
8144
8540
  function createSnapshot(root, gltf, bakeColors = false) {
8145
- const scene = new Scene4();
8541
+ const scene = new Scene3();
8146
8542
  const geometries = [];
8147
8543
  const materials = [];
8148
8544
  const textures = [];
@@ -8237,7 +8633,7 @@ function createSnapshot(root, gltf, bakeColors = false) {
8237
8633
  material.color.copy(tint);
8238
8634
  }
8239
8635
  }
8240
- const copy = new Mesh5(geometry, material);
8636
+ const copy = new Mesh4(geometry, material);
8241
8637
  copy.name = mesh.name;
8242
8638
  copy.renderOrder = mesh.renderOrder;
8243
8639
  scene.add(copy);
@@ -8316,7 +8712,7 @@ function selectAlphaMode(material, geometry) {
8316
8712
  }
8317
8713
  function copyDataTexture(source) {
8318
8714
  const image = source.image;
8319
- if (source.format !== RGBAFormat3 || source.type !== UnsignedByteType) {
8715
+ if (!image.data || source.format !== RGBAFormat3 || source.type !== UnsignedByteType) {
8320
8716
  throw new MineRenderError("glTF export requires RGBA unsigned-byte data textures");
8321
8717
  }
8322
8718
  const canvas = createCanvas(image.width, image.height);
@@ -8327,8 +8723,8 @@ function copyDataTexture(source) {
8327
8723
  context.putImageData(pixels, 0, 0);
8328
8724
  const copySource = Object.create(source);
8329
8725
  copySource.userData = {};
8330
- copySource.source = new Source2(canvas);
8331
- return new Texture4().copy(copySource);
8726
+ copySource.source = new TextureSource2(canvas);
8727
+ return new Texture3().copy(copySource);
8332
8728
  }
8333
8729
 
8334
8730
  // src/gui/GuiHelper.ts
@@ -8397,6 +8793,85 @@ var GuiHelper = class {
8397
8793
  }
8398
8794
  };
8399
8795
 
8796
+ // src/gui/GuiTextureGeometry.ts
8797
+ import { BufferGeometry as BufferGeometry2, Float32BufferAttribute as Float32BufferAttribute4, PlaneGeometry } from "three";
8798
+ function createGuiTextureGeometry(width, height, imageWidth, imageHeight, crop, scaling) {
8799
+ if (crop || !scaling || scaling.type === "stretch") {
8800
+ const [x, y, w, h] = crop ?? [0, 0, imageWidth, imageHeight];
8801
+ const geometry = new PlaneGeometry(width, height);
8802
+ const uv = geometry.getAttribute("uv");
8803
+ for (let i = 0; i < uv.count; i++) {
8804
+ uv.setXY(
8805
+ i,
8806
+ (x + uv.getX(i) * w) / imageWidth,
8807
+ 1 - (y + (1 - uv.getY(i)) * h) / imageHeight
8808
+ );
8809
+ }
8810
+ return geometry;
8811
+ }
8812
+ const sw = scaling.width, sh = scaling.height;
8813
+ if (![sw, sh].every((value) => Number.isInteger(value) && value > 0)) {
8814
+ throw new Error("GUI sprite dimensions must be positive integers");
8815
+ }
8816
+ if (![width, height].every((value) => Number.isFinite(value) && value >= 0)) {
8817
+ throw new Error("GUI output dimensions must be finite and nonnegative");
8818
+ }
8819
+ const positions = [], uvs = [], normals = [], indices = [];
8820
+ function quad(x, y, w, h, u, v, uw, vh) {
8821
+ if (w <= 0 || h <= 0) return;
8822
+ const index = positions.length / 3;
8823
+ const left = x - width / 2, top = height / 2 - y;
8824
+ positions.push(left, top, 0, left + w, top, 0, left, top - h, 0, left + w, top - h, 0);
8825
+ uvs.push(
8826
+ u / sw,
8827
+ 1 - v / sh,
8828
+ (u + uw) / sw,
8829
+ 1 - v / sh,
8830
+ u / sw,
8831
+ 1 - (v + vh) / sh,
8832
+ (u + uw) / sw,
8833
+ 1 - (v + vh) / sh
8834
+ );
8835
+ normals.push(0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1);
8836
+ indices.push(index, index + 2, index + 1, index + 2, index + 3, index + 1);
8837
+ }
8838
+ function tile(x, y, w, h, u, v, tw, th) {
8839
+ for (let dy = 0; dy < h; dy += th) {
8840
+ for (let dx = 0; dx < w; dx += tw) {
8841
+ const cw = Math.min(tw, w - dx), ch = Math.min(th, h - dy);
8842
+ quad(x + dx, y + dy, cw, ch, u, v, cw, ch);
8843
+ }
8844
+ }
8845
+ }
8846
+ if (scaling.type === "tile") {
8847
+ tile(0, 0, width, height, 0, 0, sw, sh);
8848
+ } else {
8849
+ let segments = function(size, sourceSize, start, end) {
8850
+ if (size === sourceSize) return [[0, size, 0, sourceSize]];
8851
+ start = Math.min(start, Math.floor(size / 2));
8852
+ end = Math.min(end, Math.floor(size / 2));
8853
+ return [
8854
+ [0, start, 0, start],
8855
+ [start, size - start - end, start, sourceSize - start - end],
8856
+ [size - end, end, sourceSize - end, end]
8857
+ ];
8858
+ };
8859
+ const border = typeof scaling.border === "number" ? { left: scaling.border, top: scaling.border, right: scaling.border, bottom: scaling.border } : scaling.border;
8860
+ if (!border || typeof scaling.border === "number" && scaling.border <= 0 || ![border.left, border.top, border.right, border.bottom].every((value) => Number.isInteger(value) && value >= 0) || border.left + border.right >= sw || border.top + border.bottom >= sh) {
8861
+ throw new Error("GUI nine-slice borders must be nonnegative integers with a nonempty center");
8862
+ }
8863
+ const columns = segments(width, sw, border.left, border.right);
8864
+ const rows = segments(height, sh, border.top, border.bottom);
8865
+ for (const [y, h, v, vh] of rows) {
8866
+ for (const [x, w, u, uw] of columns) {
8867
+ if (w <= 0 || h <= 0) continue;
8868
+ (scaling.stretch_inner ? quad : tile)(x, y, w, h, u, v, uw, vh);
8869
+ }
8870
+ }
8871
+ }
8872
+ return new BufferGeometry2().setAttribute("position", new Float32BufferAttribute4(positions, 3)).setAttribute("normal", new Float32BufferAttribute4(normals, 3)).setAttribute("uv", new Float32BufferAttribute4(uvs, 2)).setIndex(indices);
8873
+ }
8874
+
8400
8875
  // src/gui/scene/GuiObject.ts
8401
8876
  init_AssetKey();
8402
8877
  init_ModelTextures();
@@ -8407,7 +8882,7 @@ init_Materials();
8407
8882
  init_ModelObject();
8408
8883
  init_DisplayPosition();
8409
8884
  init_GuiLight();
8410
- import { Box2, Box3 as Box32, Matrix4 as Matrix410, Mesh as Mesh7, PlaneGeometry as PlaneGeometry2, Vector2 as Vector23 } from "three";
8885
+ import { Box2, Box3 as Box32, Matrix4 as Matrix410, Mesh as Mesh6, Vector2 as Vector23 } from "three";
8411
8886
  var GuiObject = class extends SceneObject {
8412
8887
  constructor(textureLayers, options) {
8413
8888
  super({ ...options, instanceMeshes: false, mergeMeshes: false });
@@ -8448,19 +8923,11 @@ var GuiObject = class extends SceneObject {
8448
8923
  const key = typeof layer.texture === "string" ? AssetKey.parse("textures", layer.texture) : layer.texture;
8449
8924
  const material = await this.loadMaterial(key);
8450
8925
  const image = material.map.image;
8451
- const [cropX, cropY, cropWidth, cropHeight] = layer.crop ?? [0, 0, image.width, image.height];
8452
- const [width, height] = layer.size ?? [cropWidth, cropHeight];
8453
- const geometry = new PlaneGeometry2(width, height);
8926
+ const scaling = layer.crop ? void 0 : (await ModelTextures.getMeta(key))?.gui?.scaling;
8927
+ const [width, height] = layer.size ?? (layer.crop ? layer.crop.slice(2) : scaling && scaling.type !== "stretch" ? [scaling.width, scaling.height] : [image.width, image.height]);
8928
+ const geometry = createGuiTextureGeometry(width, height, image.width, image.height, layer.crop, scaling);
8454
8929
  this.geometries.add(geometry);
8455
- const uv = geometry.getAttribute("uv");
8456
- for (let i = 0; i < uv.count; i++) {
8457
- uv.setXY(
8458
- i,
8459
- (cropX + uv.getX(i) * cropWidth) / image.width,
8460
- 1 - (cropY + (1 - uv.getY(i)) * cropHeight) / image.height
8461
- );
8462
- }
8463
- const mesh = new Mesh7(geometry, material);
8930
+ const mesh = new Mesh6(geometry, material);
8464
8931
  mesh.name = `mesh:${layer.name ?? index}`;
8465
8932
  mesh.position.set(x + width / 2, -y - height / 2, depth);
8466
8933
  mesh.renderOrder = index;
@@ -9297,6 +9764,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
9297
9764
  replacement.setMatrix(matrix);
9298
9765
  } else {
9299
9766
  replacement.matrix.copy(matrix);
9767
+ replacement.matrixWorldNeedsUpdate = true;
9300
9768
  matrix.decompose(replacement.position, replacement.quaternion, replacement.scale);
9301
9769
  replacement.matrixAutoUpdate = object.matrixAutoUpdate;
9302
9770
  replacement.visible = object.visible;
@@ -11359,7 +11827,7 @@ init_nbt();
11359
11827
  init_SceneObject();
11360
11828
  var import_ts_deepmerge8 = __toESM(require_dist());
11361
11829
  init_ModelObject();
11362
- import { Scene as Scene5 } from "three";
11830
+ import { Scene as Scene4 } from "three";
11363
11831
 
11364
11832
  // src/skin/scene/SkinObject.ts
11365
11833
  init_SceneObject();
@@ -12092,7 +12560,7 @@ init_util();
12092
12560
  init_Caching();
12093
12561
  init_CacheKey();
12094
12562
  init_MineRenderError();
12095
- import { DataTexture as DataTexture2, DoubleSide as DoubleSide4, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial6, SRGBColorSpace as SRGBColorSpace5 } from "three";
12563
+ import { DataTexture as DataTexture2, DoubleSide as DoubleSide4, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial6, SRGBColorSpace as SRGBColorSpace6 } from "three";
12096
12564
 
12097
12565
  // src/skin/SkinImage.ts
12098
12566
  init_Caching();
@@ -12174,7 +12642,7 @@ var SkinTextures = class {
12174
12642
  }
12175
12643
  static createMaterial(pixels, width, height, transparent = true) {
12176
12644
  const texture = Textures.initTextureProps(new DataTexture2(pixels, width, height));
12177
- texture.colorSpace = SRGBColorSpace5;
12645
+ texture.colorSpace = SRGBColorSpace6;
12178
12646
  texture.flipY = true;
12179
12647
  texture.needsUpdate = true;
12180
12648
  return new MeshBasicMaterial6({ map: texture, transparent, side: transparent ? DoubleSide4 : FrontSide2, alphaTest: transparent ? 0.1 : 0 });
@@ -12407,7 +12875,7 @@ var SkinObject = class extends SceneObject {
12407
12875
  // src/renderer/MineRenderScene.ts
12408
12876
  init_EntityObject();
12409
12877
  init_ItemTints();
12410
- var _MineRenderScene = class _MineRenderScene extends Scene5 {
12878
+ var _MineRenderScene = class _MineRenderScene extends Scene4 {
12411
12879
  constructor(options) {
12412
12880
  super();
12413
12881
  this.isMineRenderScene = true;
@@ -12450,12 +12918,13 @@ var _MineRenderScene = class _MineRenderScene extends Scene5 {
12450
12918
  }
12451
12919
  updateObjectRegistration(object, attached) {
12452
12920
  if (this.observedObjects.has(object) === attached) return;
12921
+ const observable = object;
12453
12922
  if (attached) {
12454
12923
  this.observedObjects.add(object);
12455
- object.addEventListener("change", this.onObjectChange);
12924
+ observable.addEventListener("change", this.onObjectChange);
12456
12925
  } else {
12457
12926
  this.observedObjects.delete(object);
12458
- object.removeEventListener("change", this.onObjectChange);
12927
+ observable.removeEventListener("change", this.onObjectChange);
12459
12928
  }
12460
12929
  const change = attached ? 1 : -1;
12461
12930
  this.stats.objectCount += change;
@@ -12535,7 +13004,7 @@ function isMineRenderScene(obj) {
12535
13004
  }
12536
13005
 
12537
13006
  // src/renderer/Renderer.ts
12538
- import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera as PerspectiveCamera2, SRGBColorSpace as SRGBColorSpace6, Vector3 as Vector314, WebGLRenderer as WebGLRenderer2 } from "three";
13007
+ import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace7, Vector3 as Vector314, WebGLRenderer } from "three";
12539
13008
  var import_ts_deepmerge9 = __toESM(require_dist());
12540
13009
  init_util();
12541
13010
  init_Model();
@@ -13240,7 +13709,7 @@ var _Renderer = class _Renderer {
13240
13709
  switch (this.options.camera.type) {
13241
13710
  case "perspective":
13242
13711
  default:
13243
- return new PerspectiveCamera2(
13712
+ return new PerspectiveCamera(
13244
13713
  this.options.camera.perspective.fov,
13245
13714
  this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
13246
13715
  this.options.camera.near,
@@ -13258,7 +13727,7 @@ var _Renderer = class _Renderer {
13258
13727
  }
13259
13728
  }
13260
13729
  createRenderer() {
13261
- const renderer = new WebGLRenderer2({
13730
+ const renderer = new WebGLRenderer({
13262
13731
  antialias: this.options.render.antialias,
13263
13732
  alpha: true,
13264
13733
  powerPreference: "high-performance",
@@ -13266,8 +13735,8 @@ var _Renderer = class _Renderer {
13266
13735
  });
13267
13736
  renderer.setClearColor(0, 0);
13268
13737
  renderer.shadowMap.enabled = true;
13269
- renderer.shadowMap.type = PCFSoftShadowMap;
13270
- renderer.outputColorSpace = SRGBColorSpace6;
13738
+ renderer.shadowMap.type = PCFShadowMap;
13739
+ renderer.outputColorSpace = SRGBColorSpace7;
13271
13740
  renderer.setPixelRatio(this.options.render.pixelRatio ?? 1);
13272
13741
  renderer.setSize(this.viewWidth, this.viewHeight);
13273
13742
  return renderer;
@@ -14384,7 +14853,7 @@ init_Model();
14384
14853
  // src/world/SectionMesh.ts
14385
14854
  init_CanvasCompat();
14386
14855
  init_Materials();
14387
- import { BufferGeometry as BufferGeometry6, Float32BufferAttribute as Float32BufferAttribute6, Group, Mesh as Mesh10 } from "three";
14856
+ import { BufferGeometry as BufferGeometry7, Float32BufferAttribute as Float32BufferAttribute7, Group, Mesh as Mesh9 } from "three";
14388
14857
  var SectionMesh = class _SectionMesh extends Group {
14389
14858
  constructor() {
14390
14859
  super(...arguments);
@@ -14458,18 +14927,18 @@ var SectionMesh = class _SectionMesh extends Group {
14458
14927
  for (let corner = 0; corner < 6; corner++) indices.push(start + sourceIndices.getX(face * 6 + corner) - face * 4);
14459
14928
  }
14460
14929
  }
14461
- const geometry = new BufferGeometry6();
14462
- geometry.setAttribute("position", new Float32BufferAttribute6(positions, 3));
14463
- geometry.setAttribute("normal", new Float32BufferAttribute6(normals, 3));
14464
- geometry.setAttribute("uv", new Float32BufferAttribute6(uvs, 2));
14465
- geometry.setAttribute("color", new Float32BufferAttribute6(colors, 3));
14930
+ const geometry = new BufferGeometry7();
14931
+ geometry.setAttribute("position", new Float32BufferAttribute7(positions, 3));
14932
+ geometry.setAttribute("normal", new Float32BufferAttribute7(normals, 3));
14933
+ geometry.setAttribute("uv", new Float32BufferAttribute7(uvs, 2));
14934
+ geometry.setAttribute("color", new Float32BufferAttribute7(colors, 3));
14466
14935
  geometry.setIndex(indices);
14467
14936
  geometry.computeBoundingBox();
14468
14937
  geometry.computeBoundingSphere();
14469
14938
  const material = Materials.createShadedCanvasMaterial(canvas, false);
14470
14939
  material.vertexColors = true;
14471
14940
  const texture = material.uniforms?.map?.value ?? material.map;
14472
- const mesh = new Mesh10(geometry, material);
14941
+ const mesh = new Mesh9(geometry, material);
14473
14942
  section.add(mesh);
14474
14943
  section.ownedMeshes.push({ mesh, texture });
14475
14944
  }
@@ -14483,6 +14952,7 @@ var SectionMesh = class _SectionMesh extends Group {
14483
14952
  texture?.dispose();
14484
14953
  }
14485
14954
  this.removeFromParent();
14955
+ super.dispose();
14486
14956
  }
14487
14957
  };
14488
14958
 
@@ -14786,6 +15256,7 @@ export {
14786
15256
  computeTangents,
14787
15257
  createCanvas,
14788
15258
  createFluidGeometry,
15259
+ createGuiTextureGeometry,
14789
15260
  createImage,
14790
15261
  entityAnimationTime,
14791
15262
  estimateBytesUsed,