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.
@@ -3598,7 +3598,7 @@ var init_InstanceReference = __esm({
3598
3598
  });
3599
3599
 
3600
3600
  // src/renderer/SceneObject.ts
3601
- 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";
3601
+ 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";
3602
3602
  function isSceneObject(obj) {
3603
3603
  return obj.isSceneObject;
3604
3604
  }
@@ -4034,6 +4034,7 @@ var init_SceneObject = __esm({
4034
4034
  dispose() {
4035
4035
  this.disposeAndRemoveAllChildren();
4036
4036
  this.notifyDirty();
4037
+ super.dispose();
4037
4038
  }
4038
4039
  disposeAndRemoveAllChildren() {
4039
4040
  if (this.instanceMesh) {
@@ -4247,6 +4248,7 @@ var init_EntityObject = __esm({
4247
4248
  else matrix.makeRotationFromEuler(new Euler5(...op.rotate, "ZYX"));
4248
4249
  modelRoot.matrix.multiply(matrix);
4249
4250
  }
4251
+ modelRoot.matrixWorldNeedsUpdate = true;
4250
4252
  modelRoot.matrixAutoUpdate = false;
4251
4253
  } else if (this.options.flip ?? true) {
4252
4254
  modelRoot.scale.set(-1, -1, 1);
@@ -4333,8 +4335,8 @@ var init_EntityObject = __esm({
4333
4335
  // src/three/BufferGeometryUtils.js
4334
4336
  import {
4335
4337
  BufferAttribute as BufferAttribute4,
4336
- BufferGeometry as BufferGeometry2,
4337
- Float32BufferAttribute as Float32BufferAttribute4,
4338
+ BufferGeometry as BufferGeometry3,
4339
+ Float32BufferAttribute as Float32BufferAttribute5,
4338
4340
  InterleavedBuffer,
4339
4341
  InterleavedBufferAttribute,
4340
4342
  TriangleFanDrawMode,
@@ -4353,7 +4355,7 @@ function mergeBufferGeometries(geometries, useGroups = false) {
4353
4355
  const attributes = {};
4354
4356
  const morphAttributes = {};
4355
4357
  const morphTargetsRelative = geometries[0].morphTargetsRelative;
4356
- const mergedGeometry = new BufferGeometry2();
4358
+ const mergedGeometry = new BufferGeometry3();
4357
4359
  let offset = 0;
4358
4360
  for (let i = 0; i < geometries.length; ++i) {
4359
4361
  const geometry = geometries[i];
@@ -4862,8 +4864,8 @@ function computeMorphedAttributes(object) {
4862
4864
  }
4863
4865
  }
4864
4866
  }
4865
- const morphedPositionAttribute = new Float32BufferAttribute4(modifiedPosition, 3);
4866
- const morphedNormalAttribute = new Float32BufferAttribute4(modifiedNormal, 3);
4867
+ const morphedPositionAttribute = new Float32BufferAttribute5(modifiedPosition, 3);
4868
+ const morphedNormalAttribute = new Float32BufferAttribute5(modifiedNormal, 3);
4867
4869
  return {
4868
4870
  positionAttribute,
4869
4871
  normalAttribute,
@@ -5163,6 +5165,7 @@ var init_ModelObject = __esm({
5163
5165
  for (const part of parts) {
5164
5166
  const object = new EntityObject(part.model, { flip: false, wireframe: this.options.wireframe });
5165
5167
  object.matrix.copy(transform).multiply(part.transform);
5168
+ object.matrixWorldNeedsUpdate = true;
5166
5169
  object.matrixAutoUpdate = false;
5167
5170
  this.add(object);
5168
5171
  await object.init();
@@ -5356,7 +5359,7 @@ var init_fluidBlocks = __esm({
5356
5359
  });
5357
5360
 
5358
5361
  // src/model/fluid/FluidGeometry.ts
5359
- import { BufferGeometry as BufferGeometry4, Float32BufferAttribute as Float32BufferAttribute5 } from "three";
5362
+ import { BufferGeometry as BufferGeometry5, Float32BufferAttribute as Float32BufferAttribute6 } from "three";
5360
5363
  function getBlockFluidState(key, state) {
5361
5364
  const rule = key && fluidRules[key.toNamespacedString()];
5362
5365
  if (rule) return {
@@ -5374,7 +5377,7 @@ function ownHeight(sample) {
5374
5377
  return (level === 0 || level >= 8 ? 8 : 8 - level) / 9;
5375
5378
  }
5376
5379
  function createFluidGeometry(kind, sample) {
5377
- const geometry = new BufferGeometry4();
5380
+ const geometry = new BufferGeometry5();
5378
5381
  const positions = [], normals = [], uvs = [], indices = [];
5379
5382
  const self = sample(0, 0, 0);
5380
5383
  const height = (x, z) => {
@@ -5473,9 +5476,9 @@ function createFluidGeometry(kind, sample) {
5473
5476
  1
5474
5477
  );
5475
5478
  }
5476
- geometry.setAttribute("position", new Float32BufferAttribute5(positions, 3));
5477
- geometry.setAttribute("normal", new Float32BufferAttribute5(normals, 3));
5478
- geometry.setAttribute("uv", new Float32BufferAttribute5(uvs, 2));
5479
+ geometry.setAttribute("position", new Float32BufferAttribute6(positions, 3));
5480
+ geometry.setAttribute("normal", new Float32BufferAttribute6(normals, 3));
5481
+ geometry.setAttribute("uv", new Float32BufferAttribute6(uvs, 2));
5479
5482
  geometry.setIndex(indices);
5480
5483
  return geometry;
5481
5484
  }
@@ -5834,16 +5837,26 @@ init_EntityObject();
5834
5837
  init_MineRenderError();
5835
5838
 
5836
5839
  // src/export/SceneExporter.ts
5837
- 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";
5840
+ 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";
5838
5841
 
5839
5842
  // ../../node_modules/three/examples/jsm/exporters/OBJExporter.js
5840
5843
  import {
5841
5844
  Color as Color4,
5845
+ ColorManagement,
5842
5846
  Matrix3,
5847
+ SRGBColorSpace as SRGBColorSpace3,
5843
5848
  Vector2 as Vector22,
5844
5849
  Vector3 as Vector37
5845
5850
  } from "three";
5846
5851
  var OBJExporter = class {
5852
+ /**
5853
+ * Parses the given 3D object and generates the OBJ output.
5854
+ *
5855
+ * If the 3D object is composed of multiple children and geometry, they are merged into a single mesh in the file.
5856
+ *
5857
+ * @param {Object3D} object - The 3D object to export.
5858
+ * @return {string} The exported OBJ.
5859
+ */
5847
5860
  parse(object) {
5848
5861
  let output = "";
5849
5862
  let indexVertex = 0;
@@ -5949,7 +5962,8 @@ var OBJExporter = class {
5949
5962
  vertex.applyMatrix4(points.matrixWorld);
5950
5963
  output += "v " + vertex.x + " " + vertex.y + " " + vertex.z;
5951
5964
  if (colors !== void 0) {
5952
- color.fromBufferAttribute(colors, i).convertLinearToSRGB();
5965
+ color.fromBufferAttribute(colors, i);
5966
+ ColorManagement.workingToColorSpace(color, SRGBColorSpace3);
5953
5967
  output += " " + color.r + " " + color.g + " " + color.b;
5954
5968
  }
5955
5969
  output += "\n";
@@ -5981,9 +5995,21 @@ var OBJExporter = class {
5981
5995
  import {
5982
5996
  Matrix3 as Matrix32,
5983
5997
  Vector3 as Vector38,
5984
- Color as Color5
5998
+ Color as Color5,
5999
+ ColorManagement as ColorManagement2,
6000
+ SRGBColorSpace as SRGBColorSpace4
5985
6001
  } from "three";
5986
6002
  var PLYExporter = class {
6003
+ /**
6004
+ * Parses the given 3D object and generates the PLY output.
6005
+ *
6006
+ * If the 3D object is composed of multiple children and geometry, they are merged into a single mesh in the file.
6007
+ *
6008
+ * @param {Object3D} object - The 3D object to export.
6009
+ * @param {PLYExporter~OnDone} onDone - A callback function that is executed when the export has finished.
6010
+ * @param {PLYExporter~Options} options - The export options.
6011
+ * @return {?(string|ArrayBuffer)} The exported PLY.
6012
+ */
5987
6013
  parse(object, onDone, options = {}) {
5988
6014
  function traverseMeshes(cb) {
5989
6015
  object.traverse(function(child) {
@@ -6000,14 +6026,23 @@ var PLYExporter = class {
6000
6026
  binary: false,
6001
6027
  excludeAttributes: [],
6002
6028
  // normal, uv, color, index
6003
- littleEndian: false
6029
+ littleEndian: false,
6030
+ customPropertyMapping: {}
6004
6031
  };
6005
6032
  options = Object.assign(defaultOptions, options);
6006
6033
  const excludeAttributes = options.excludeAttributes;
6034
+ const customPropertyMapping = options.customPropertyMapping;
6035
+ const customAttributeNames = Object.keys(customPropertyMapping);
6007
6036
  let includeIndices = true;
6008
6037
  let includeNormals = false;
6009
6038
  let includeColors = false;
6010
6039
  let includeUVs = false;
6040
+ let positionType = "float";
6041
+ let normalType = "float";
6042
+ let uvType = "float";
6043
+ let colorType = "uchar";
6044
+ const customTypes = {};
6045
+ for (const name of customAttributeNames) customTypes[name] = "float";
6011
6046
  let vertexCount = 0;
6012
6047
  let faceCount = 0;
6013
6048
  object.traverse(function(child) {
@@ -6024,9 +6059,23 @@ var PLYExporter = class {
6024
6059
  }
6025
6060
  vertexCount += vertices.count;
6026
6061
  faceCount += indices ? indices.count / 3 : vertices.count / 3;
6027
- if (normals !== void 0) includeNormals = true;
6028
- if (uvs !== void 0) includeUVs = true;
6029
- if (colors !== void 0) includeColors = true;
6062
+ positionType = getPlyType(vertices.array);
6063
+ if (normals !== void 0) {
6064
+ includeNormals = true;
6065
+ normalType = getPlyType(normals.array);
6066
+ }
6067
+ if (uvs !== void 0) {
6068
+ includeUVs = true;
6069
+ uvType = getPlyType(uvs.array);
6070
+ }
6071
+ if (colors !== void 0) {
6072
+ includeColors = true;
6073
+ colorType = getPlyType(colors.array);
6074
+ }
6075
+ for (const name of customAttributeNames) {
6076
+ const attr = geometry.getAttribute(name);
6077
+ if (attr !== void 0) customTypes[name] = getPlyType(attr.array);
6078
+ }
6030
6079
  } else if (child.isPoints) {
6031
6080
  const mesh = child;
6032
6081
  const geometry = mesh.geometry;
@@ -6034,8 +6083,19 @@ var PLYExporter = class {
6034
6083
  const normals = geometry.getAttribute("normal");
6035
6084
  const colors = geometry.getAttribute("color");
6036
6085
  vertexCount += vertices.count;
6037
- if (normals !== void 0) includeNormals = true;
6038
- if (colors !== void 0) includeColors = true;
6086
+ positionType = getPlyType(vertices.array);
6087
+ if (normals !== void 0) {
6088
+ includeNormals = true;
6089
+ normalType = getPlyType(normals.array);
6090
+ }
6091
+ if (colors !== void 0) {
6092
+ includeColors = true;
6093
+ colorType = getPlyType(colors.array);
6094
+ }
6095
+ for (const name of customAttributeNames) {
6096
+ const attr = geometry.getAttribute(name);
6097
+ if (attr !== void 0) customTypes[name] = getPlyType(attr.array);
6098
+ }
6039
6099
  includeIndices = false;
6040
6100
  }
6041
6101
  });
@@ -6054,18 +6114,33 @@ var PLYExporter = class {
6054
6114
  let header = `ply
6055
6115
  format ${options.binary ? options.littleEndian ? "binary_little_endian" : "binary_big_endian" : "ascii"} 1.0
6056
6116
  element vertex ${vertexCount}
6057
- property float x
6058
- property float y
6059
- property float z
6117
+ property ${positionType} x
6118
+ property ${positionType} y
6119
+ property ${positionType} z
6060
6120
  `;
6061
6121
  if (includeNormals === true) {
6062
- header += "property float nx\nproperty float ny\nproperty float nz\n";
6122
+ header += `property ${normalType} nx
6123
+ property ${normalType} ny
6124
+ property ${normalType} nz
6125
+ `;
6063
6126
  }
6064
6127
  if (includeUVs === true) {
6065
- header += "property float s\nproperty float t\n";
6128
+ header += `property ${uvType} s
6129
+ property ${uvType} t
6130
+ `;
6066
6131
  }
6067
6132
  if (includeColors === true) {
6068
- header += "property uchar red\nproperty uchar green\nproperty uchar blue\n";
6133
+ header += `property ${colorType} red
6134
+ property ${colorType} green
6135
+ property ${colorType} blue
6136
+ `;
6137
+ }
6138
+ for (const name of customAttributeNames) {
6139
+ const type = customTypes[name];
6140
+ for (const propName of customPropertyMapping[name]) {
6141
+ header += `property ${type} ${propName}
6142
+ `;
6143
+ }
6069
6144
  }
6070
6145
  if (includeIndices === true) {
6071
6146
  header += `element face ${faceCount}
@@ -6078,7 +6153,23 @@ property list uchar int vertex_index
6078
6153
  let result = null;
6079
6154
  if (options.binary === true) {
6080
6155
  const headerBin = new TextEncoder().encode(header);
6081
- const vertexListLength = vertexCount * (4 * 3 + (includeNormals ? 4 * 3 : 0) + (includeColors ? 3 : 0) + (includeUVs ? 4 * 2 : 0));
6156
+ const posWriter = getBinaryWriter(positionType);
6157
+ const normalWriter = includeNormals ? getBinaryWriter(normalType) : null;
6158
+ const uvWriter = includeUVs ? getBinaryWriter(uvType) : null;
6159
+ const colorWriter = includeColors ? getBinaryWriter(colorType) : null;
6160
+ const colorIsFloat = isFloatType(colorType);
6161
+ const colorScale = getColorScale(colorType);
6162
+ const customWriters = {};
6163
+ const customIsFloat = {};
6164
+ let customStride = 0;
6165
+ for (const name of customAttributeNames) {
6166
+ const type = customTypes[name];
6167
+ const writer = getBinaryWriter(type);
6168
+ customWriters[name] = writer;
6169
+ customIsFloat[name] = isFloatType(type);
6170
+ customStride += customPropertyMapping[name].length * writer.size;
6171
+ }
6172
+ const vertexListLength = vertexCount * (3 * posWriter.size + (includeNormals ? 3 * normalWriter.size : 0) + (includeUVs ? 2 * uvWriter.size : 0) + (includeColors ? 3 * colorWriter.size : 0) + customStride);
6082
6173
  const faceListLength = includeIndices ? faceCount * (indexByteCount * 3 + 1) : 0;
6083
6174
  const output = new DataView(new ArrayBuffer(headerBin.length + vertexListLength + faceListLength));
6084
6175
  new Uint8Array(output.buffer).set(headerBin, 0);
@@ -6095,60 +6186,76 @@ property list uchar int vertex_index
6095
6186
  for (let i = 0, l = vertices.count; i < l; i++) {
6096
6187
  vertex.fromBufferAttribute(vertices, i);
6097
6188
  vertex.applyMatrix4(mesh.matrixWorld);
6098
- output.setFloat32(vOffset, vertex.x, options.littleEndian);
6099
- vOffset += 4;
6100
- output.setFloat32(vOffset, vertex.y, options.littleEndian);
6101
- vOffset += 4;
6102
- output.setFloat32(vOffset, vertex.z, options.littleEndian);
6103
- vOffset += 4;
6189
+ posWriter.write(output, vOffset, vertex.x, options.littleEndian);
6190
+ vOffset += posWriter.size;
6191
+ posWriter.write(output, vOffset, vertex.y, options.littleEndian);
6192
+ vOffset += posWriter.size;
6193
+ posWriter.write(output, vOffset, vertex.z, options.littleEndian);
6194
+ vOffset += posWriter.size;
6104
6195
  if (includeNormals === true) {
6105
6196
  if (normals != null) {
6106
6197
  vertex.fromBufferAttribute(normals, i);
6107
6198
  vertex.applyMatrix3(normalMatrixWorld).normalize();
6108
- output.setFloat32(vOffset, vertex.x, options.littleEndian);
6109
- vOffset += 4;
6110
- output.setFloat32(vOffset, vertex.y, options.littleEndian);
6111
- vOffset += 4;
6112
- output.setFloat32(vOffset, vertex.z, options.littleEndian);
6113
- vOffset += 4;
6199
+ normalWriter.write(output, vOffset, vertex.x, options.littleEndian);
6200
+ vOffset += normalWriter.size;
6201
+ normalWriter.write(output, vOffset, vertex.y, options.littleEndian);
6202
+ vOffset += normalWriter.size;
6203
+ normalWriter.write(output, vOffset, vertex.z, options.littleEndian);
6204
+ vOffset += normalWriter.size;
6114
6205
  } else {
6115
- output.setFloat32(vOffset, 0, options.littleEndian);
6116
- vOffset += 4;
6117
- output.setFloat32(vOffset, 0, options.littleEndian);
6118
- vOffset += 4;
6119
- output.setFloat32(vOffset, 0, options.littleEndian);
6120
- vOffset += 4;
6206
+ normalWriter.write(output, vOffset, 0, options.littleEndian);
6207
+ vOffset += normalWriter.size;
6208
+ normalWriter.write(output, vOffset, 0, options.littleEndian);
6209
+ vOffset += normalWriter.size;
6210
+ normalWriter.write(output, vOffset, 0, options.littleEndian);
6211
+ vOffset += normalWriter.size;
6121
6212
  }
6122
6213
  }
6123
6214
  if (includeUVs === true) {
6124
6215
  if (uvs != null) {
6125
- output.setFloat32(vOffset, uvs.getX(i), options.littleEndian);
6126
- vOffset += 4;
6127
- output.setFloat32(vOffset, uvs.getY(i), options.littleEndian);
6128
- vOffset += 4;
6216
+ uvWriter.write(output, vOffset, uvs.getX(i), options.littleEndian);
6217
+ vOffset += uvWriter.size;
6218
+ uvWriter.write(output, vOffset, uvs.getY(i), options.littleEndian);
6219
+ vOffset += uvWriter.size;
6129
6220
  } else {
6130
- output.setFloat32(vOffset, 0, options.littleEndian);
6131
- vOffset += 4;
6132
- output.setFloat32(vOffset, 0, options.littleEndian);
6133
- vOffset += 4;
6221
+ uvWriter.write(output, vOffset, 0, options.littleEndian);
6222
+ vOffset += uvWriter.size;
6223
+ uvWriter.write(output, vOffset, 0, options.littleEndian);
6224
+ vOffset += uvWriter.size;
6134
6225
  }
6135
6226
  }
6136
6227
  if (includeColors === true) {
6137
6228
  if (colors != null) {
6138
- tempColor.fromBufferAttribute(colors, i).convertLinearToSRGB();
6139
- output.setUint8(vOffset, Math.floor(tempColor.r * 255));
6140
- vOffset += 1;
6141
- output.setUint8(vOffset, Math.floor(tempColor.g * 255));
6142
- vOffset += 1;
6143
- output.setUint8(vOffset, Math.floor(tempColor.b * 255));
6144
- vOffset += 1;
6229
+ tempColor.fromBufferAttribute(colors, i);
6230
+ ColorManagement2.workingToColorSpace(tempColor, SRGBColorSpace4);
6231
+ const r = colorIsFloat ? tempColor.r : Math.round(tempColor.r * colorScale);
6232
+ const g = colorIsFloat ? tempColor.g : Math.round(tempColor.g * colorScale);
6233
+ const b = colorIsFloat ? tempColor.b : Math.round(tempColor.b * colorScale);
6234
+ colorWriter.write(output, vOffset, r, options.littleEndian);
6235
+ vOffset += colorWriter.size;
6236
+ colorWriter.write(output, vOffset, g, options.littleEndian);
6237
+ vOffset += colorWriter.size;
6238
+ colorWriter.write(output, vOffset, b, options.littleEndian);
6239
+ vOffset += colorWriter.size;
6145
6240
  } else {
6146
- output.setUint8(vOffset, 255);
6147
- vOffset += 1;
6148
- output.setUint8(vOffset, 255);
6149
- vOffset += 1;
6150
- output.setUint8(vOffset, 255);
6151
- vOffset += 1;
6241
+ const white = colorIsFloat ? 1 : colorScale;
6242
+ colorWriter.write(output, vOffset, white, options.littleEndian);
6243
+ vOffset += colorWriter.size;
6244
+ colorWriter.write(output, vOffset, white, options.littleEndian);
6245
+ vOffset += colorWriter.size;
6246
+ colorWriter.write(output, vOffset, white, options.littleEndian);
6247
+ vOffset += colorWriter.size;
6248
+ }
6249
+ }
6250
+ for (const name of customAttributeNames) {
6251
+ const writer = customWriters[name];
6252
+ const propCount = customPropertyMapping[name].length;
6253
+ const attr = geometry.getAttribute(name);
6254
+ const isFloat = customIsFloat[name];
6255
+ for (let c = 0; c < propCount; c++) {
6256
+ const raw = attr != null ? getAttributeComponent(attr, i, c) : 0;
6257
+ writer.write(output, vOffset, isFloat ? raw : Math.round(raw), options.littleEndian);
6258
+ vOffset += writer.size;
6152
6259
  }
6153
6260
  }
6154
6261
  }
@@ -6184,6 +6291,14 @@ property list uchar int vertex_index
6184
6291
  let writtenVertices = 0;
6185
6292
  let vertexList = "";
6186
6293
  let faceList = "";
6294
+ const positionIsFloat = isFloatType(positionType);
6295
+ const normalIsFloat = isFloatType(normalType);
6296
+ const uvIsFloat = isFloatType(uvType);
6297
+ const colorIsFloat = isFloatType(colorType);
6298
+ const colorScale = getColorScale(colorType);
6299
+ const customIsFloat = {};
6300
+ for (const name of customAttributeNames) customIsFloat[name] = isFloatType(customTypes[name]);
6301
+ const encode = (v, isFloat) => isFloat ? v : Math.round(v);
6187
6302
  traverseMeshes(function(mesh, geometry) {
6188
6303
  const vertices = geometry.getAttribute("position");
6189
6304
  const normals = geometry.getAttribute("normal");
@@ -6194,29 +6309,43 @@ property list uchar int vertex_index
6194
6309
  for (let i = 0, l = vertices.count; i < l; i++) {
6195
6310
  vertex.fromBufferAttribute(vertices, i);
6196
6311
  vertex.applyMatrix4(mesh.matrixWorld);
6197
- let line = vertex.x + " " + vertex.y + " " + vertex.z;
6312
+ let line = encode(vertex.x, positionIsFloat) + " " + encode(vertex.y, positionIsFloat) + " " + encode(vertex.z, positionIsFloat);
6198
6313
  if (includeNormals === true) {
6199
6314
  if (normals != null) {
6200
6315
  vertex.fromBufferAttribute(normals, i);
6201
6316
  vertex.applyMatrix3(normalMatrixWorld).normalize();
6202
- line += " " + vertex.x + " " + vertex.y + " " + vertex.z;
6317
+ line += " " + encode(vertex.x, normalIsFloat) + " " + encode(vertex.y, normalIsFloat) + " " + encode(vertex.z, normalIsFloat);
6203
6318
  } else {
6204
6319
  line += " 0 0 0";
6205
6320
  }
6206
6321
  }
6207
6322
  if (includeUVs === true) {
6208
6323
  if (uvs != null) {
6209
- line += " " + uvs.getX(i) + " " + uvs.getY(i);
6324
+ line += " " + encode(uvs.getX(i), uvIsFloat) + " " + encode(uvs.getY(i), uvIsFloat);
6210
6325
  } else {
6211
6326
  line += " 0 0";
6212
6327
  }
6213
6328
  }
6214
6329
  if (includeColors === true) {
6215
6330
  if (colors != null) {
6216
- tempColor.fromBufferAttribute(colors, i).convertLinearToSRGB();
6217
- line += " " + Math.floor(tempColor.r * 255) + " " + Math.floor(tempColor.g * 255) + " " + Math.floor(tempColor.b * 255);
6331
+ tempColor.fromBufferAttribute(colors, i);
6332
+ ColorManagement2.workingToColorSpace(tempColor, SRGBColorSpace4);
6333
+ const r = colorIsFloat ? tempColor.r : Math.round(tempColor.r * colorScale);
6334
+ const g = colorIsFloat ? tempColor.g : Math.round(tempColor.g * colorScale);
6335
+ const b = colorIsFloat ? tempColor.b : Math.round(tempColor.b * colorScale);
6336
+ line += ` ${r} ${g} ${b}`;
6218
6337
  } else {
6219
- line += " 255 255 255";
6338
+ const white = colorIsFloat ? 1 : colorScale;
6339
+ line += ` ${white} ${white} ${white}`;
6340
+ }
6341
+ }
6342
+ for (const name of customAttributeNames) {
6343
+ const propCount = customPropertyMapping[name].length;
6344
+ const attr = geometry.getAttribute(name);
6345
+ const isFloat = customIsFloat[name];
6346
+ for (let c = 0; c < propCount; c++) {
6347
+ const raw = attr != null ? getAttributeComponent(attr, i, c) : 0;
6348
+ line += " " + encode(raw, isFloat);
6220
6349
  }
6221
6350
  }
6222
6351
  vertexList += line + "\n";
@@ -6246,6 +6375,62 @@ property list uchar int vertex_index
6246
6375
  return result;
6247
6376
  }
6248
6377
  };
6378
+ function getPlyType(array) {
6379
+ if (array instanceof Int8Array) return "char";
6380
+ if (array instanceof Uint8Array || array instanceof Uint8ClampedArray) return "uchar";
6381
+ if (array instanceof Int16Array) return "short";
6382
+ if (array instanceof Uint16Array) return "ushort";
6383
+ if (array instanceof Int32Array) return "int";
6384
+ if (array instanceof Uint32Array) return "uint";
6385
+ if (array instanceof Float32Array) return "float";
6386
+ if (array instanceof Float64Array) return "double";
6387
+ return "float";
6388
+ }
6389
+ function getBinaryWriter(type) {
6390
+ switch (type) {
6391
+ case "char":
6392
+ return { write: (dv, at, v) => dv.setInt8(at, v), size: 1 };
6393
+ case "uchar":
6394
+ return { write: (dv, at, v) => dv.setUint8(at, v), size: 1 };
6395
+ case "short":
6396
+ return { write: (dv, at, v, le) => dv.setInt16(at, v, le), size: 2 };
6397
+ case "ushort":
6398
+ return { write: (dv, at, v, le) => dv.setUint16(at, v, le), size: 2 };
6399
+ case "int":
6400
+ return { write: (dv, at, v, le) => dv.setInt32(at, v, le), size: 4 };
6401
+ case "uint":
6402
+ return { write: (dv, at, v, le) => dv.setUint32(at, v, le), size: 4 };
6403
+ case "float":
6404
+ return { write: (dv, at, v, le) => dv.setFloat32(at, v, le), size: 4 };
6405
+ case "double":
6406
+ return { write: (dv, at, v, le) => dv.setFloat64(at, v, le), size: 8 };
6407
+ }
6408
+ }
6409
+ function isFloatType(type) {
6410
+ return type === "float" || type === "double";
6411
+ }
6412
+ function getAttributeComponent(attr, i, c) {
6413
+ switch (c) {
6414
+ case 0:
6415
+ return attr.getX(i);
6416
+ case 1:
6417
+ return attr.getY(i);
6418
+ case 2:
6419
+ return attr.getZ(i);
6420
+ case 3:
6421
+ return attr.getW(i);
6422
+ }
6423
+ }
6424
+ function getColorScale(type) {
6425
+ switch (type) {
6426
+ case "uchar":
6427
+ return 255;
6428
+ case "ushort":
6429
+ return 65535;
6430
+ default:
6431
+ return 1;
6432
+ }
6433
+ }
6249
6434
 
6250
6435
  // ../../node_modules/three/examples/jsm/exporters/GLTFExporter.js
6251
6436
  import {
@@ -6259,7 +6444,7 @@ import {
6259
6444
  LinearFilter,
6260
6445
  LinearMipmapLinearFilter,
6261
6446
  LinearMipmapNearestFilter,
6262
- MathUtils as MathUtils2,
6447
+ MathUtils,
6263
6448
  Matrix4 as Matrix46,
6264
6449
  MirroredRepeatWrapping,
6265
6450
  NearestFilter as NearestFilter2,
@@ -6268,84 +6453,15 @@ import {
6268
6453
  PropertyBinding,
6269
6454
  RGBAFormat as RGBAFormat2,
6270
6455
  RepeatWrapping as RepeatWrapping2,
6271
- Scene as Scene3,
6272
- Source,
6273
- SRGBColorSpace as SRGBColorSpace4,
6456
+ Scene as Scene2,
6457
+ SRGBColorSpace as SRGBColorSpace5,
6458
+ TextureSource,
6274
6459
  CompressedTexture,
6275
6460
  Vector3 as Vector39,
6276
- Quaternion as Quaternion4
6277
- } from "three";
6278
-
6279
- // ../../node_modules/three/examples/jsm/utils/TextureUtils.js
6280
- import {
6281
- PlaneGeometry,
6282
- ShaderMaterial as ShaderMaterial2,
6283
- Uniform,
6284
- Mesh as Mesh4,
6285
- PerspectiveCamera,
6286
- Scene as Scene2,
6287
- WebGLRenderer,
6288
- Texture as Texture3,
6289
- SRGBColorSpace as SRGBColorSpace3
6461
+ Quaternion as Quaternion4,
6462
+ REVISION,
6463
+ ImageUtils
6290
6464
  } from "three";
6291
- var _renderer;
6292
- var fullscreenQuadGeometry;
6293
- var fullscreenQuadMaterial;
6294
- var fullscreenQuad;
6295
- function decompress(texture, maxTextureSize = Infinity, renderer = null) {
6296
- if (!fullscreenQuadGeometry) fullscreenQuadGeometry = new PlaneGeometry(2, 2, 1, 1);
6297
- if (!fullscreenQuadMaterial) fullscreenQuadMaterial = new ShaderMaterial2({
6298
- uniforms: { blitTexture: new Uniform(texture) },
6299
- vertexShader: `
6300
- varying vec2 vUv;
6301
- void main(){
6302
- vUv = uv;
6303
- gl_Position = vec4(position.xy * 1.0,0.,.999999);
6304
- }`,
6305
- fragmentShader: `
6306
- uniform sampler2D blitTexture;
6307
- varying vec2 vUv;
6308
-
6309
- void main(){
6310
- gl_FragColor = vec4(vUv.xy, 0, 1);
6311
-
6312
- #ifdef IS_SRGB
6313
- gl_FragColor = LinearTosRGB( texture2D( blitTexture, vUv) );
6314
- #else
6315
- gl_FragColor = texture2D( blitTexture, vUv);
6316
- #endif
6317
- }`
6318
- });
6319
- fullscreenQuadMaterial.uniforms.blitTexture.value = texture;
6320
- fullscreenQuadMaterial.defines.IS_SRGB = texture.colorSpace == SRGBColorSpace3;
6321
- fullscreenQuadMaterial.needsUpdate = true;
6322
- if (!fullscreenQuad) {
6323
- fullscreenQuad = new Mesh4(fullscreenQuadGeometry, fullscreenQuadMaterial);
6324
- fullscreenQuad.frustrumCulled = false;
6325
- }
6326
- const _camera = new PerspectiveCamera();
6327
- const _scene = new Scene2();
6328
- _scene.add(fullscreenQuad);
6329
- if (!renderer) {
6330
- renderer = _renderer = new WebGLRenderer({ antialias: false });
6331
- }
6332
- renderer.setSize(Math.min(texture.image.width, maxTextureSize), Math.min(texture.image.height, maxTextureSize));
6333
- renderer.clear();
6334
- renderer.render(_scene, _camera);
6335
- const readableTexture = new Texture3(renderer.domElement);
6336
- readableTexture.minFilter = texture.minFilter;
6337
- readableTexture.magFilter = texture.magFilter;
6338
- readableTexture.wrapS = texture.wrapS;
6339
- readableTexture.wrapT = texture.wrapT;
6340
- readableTexture.name = texture.name;
6341
- if (_renderer) {
6342
- _renderer.dispose();
6343
- _renderer = null;
6344
- }
6345
- return readableTexture;
6346
- }
6347
-
6348
- // ../../node_modules/three/examples/jsm/exporters/GLTFExporter.js
6349
6465
  var KHR_mesh_quantization_ExtraAttrTypes = {
6350
6466
  POSITION: [
6351
6467
  "byte",
@@ -6375,7 +6491,11 @@ var KHR_mesh_quantization_ExtraAttrTypes = {
6375
6491
  ]
6376
6492
  };
6377
6493
  var GLTFExporter = class {
6494
+ /**
6495
+ * Constructs a new glTF exporter.
6496
+ */
6378
6497
  constructor() {
6498
+ this.textureUtils = null;
6379
6499
  this.pluginCallbacks = [];
6380
6500
  this.register(function(writer) {
6381
6501
  return new GLTFLightExtension(writer);
@@ -6398,6 +6518,9 @@ var GLTFExporter = class {
6398
6518
  this.register(function(writer) {
6399
6519
  return new GLTFMaterialsClearcoatExtension(writer);
6400
6520
  });
6521
+ this.register(function(writer) {
6522
+ return new GLTFMaterialsDispersionExtension(writer);
6523
+ });
6401
6524
  this.register(function(writer) {
6402
6525
  return new GLTFMaterialsIridescenceExtension(writer);
6403
6526
  });
@@ -6410,16 +6533,33 @@ var GLTFExporter = class {
6410
6533
  this.register(function(writer) {
6411
6534
  return new GLTFMaterialsEmissiveStrengthExtension(writer);
6412
6535
  });
6536
+ this.register(function(writer) {
6537
+ return new GLTFMaterialsBumpExtension(writer);
6538
+ });
6413
6539
  this.register(function(writer) {
6414
6540
  return new GLTFMeshGpuInstancing(writer);
6415
6541
  });
6416
6542
  }
6543
+ /**
6544
+ * Registers a plugin callback. This API is internally used to implement the various
6545
+ * glTF extensions but can also used by third-party code to add additional logic
6546
+ * to the exporter.
6547
+ *
6548
+ * @param {function(writer:GLTFWriter)} callback - The callback function to register.
6549
+ * @return {GLTFExporter} A reference to this exporter.
6550
+ */
6417
6551
  register(callback) {
6418
6552
  if (this.pluginCallbacks.indexOf(callback) === -1) {
6419
6553
  this.pluginCallbacks.push(callback);
6420
6554
  }
6421
6555
  return this;
6422
6556
  }
6557
+ /**
6558
+ * Unregisters a plugin callback.
6559
+ *
6560
+ * @param {Function} callback - The callback function to unregister.
6561
+ * @return {GLTFExporter} A reference to this exporter.
6562
+ */
6423
6563
  unregister(callback) {
6424
6564
  if (this.pluginCallbacks.indexOf(callback) !== -1) {
6425
6565
  this.pluginCallbacks.splice(this.pluginCallbacks.indexOf(callback), 1);
@@ -6427,11 +6567,25 @@ var GLTFExporter = class {
6427
6567
  return this;
6428
6568
  }
6429
6569
  /**
6430
- * Parse scenes and generate GLTF output
6431
- * @param {Scene or [THREE.Scenes]} input Scene or Array of THREE.Scenes
6432
- * @param {Function} onDone Callback on completed
6433
- * @param {Function} onError Callback on errors
6434
- * @param {Object} options options
6570
+ * Sets the texture utils for this exporter. Only relevant when compressed textures have to be exported.
6571
+ *
6572
+ * Depending on whether you use {@link WebGLRenderer} or {@link WebGPURenderer}, you must inject the
6573
+ * corresponding texture utils {@link module:WebGLTextureUtils} or {@link module:WebGPUTextureUtils}.
6574
+ *
6575
+ * @param {WebGLTextureUtils|WebGPUTextureUtils} utils - The texture utils.
6576
+ * @return {GLTFExporter} A reference to this exporter.
6577
+ */
6578
+ setTextureUtils(utils) {
6579
+ this.textureUtils = utils;
6580
+ return this;
6581
+ }
6582
+ /**
6583
+ * Parses the given scenes and generates the glTF output.
6584
+ *
6585
+ * @param {Scene|Array<Scene>} input - A scene or an array of scenes.
6586
+ * @param {GLTFExporter~OnDone} onDone - A callback function that is executed when the export has finished.
6587
+ * @param {GLTFExporter~OnError} onError - A callback function that is executed when an error happens.
6588
+ * @param {GLTFExporter~Options} options - options
6435
6589
  */
6436
6590
  parse(input, onDone, onError, options) {
6437
6591
  const writer = new GLTFWriter();
@@ -6440,8 +6594,16 @@ var GLTFExporter = class {
6440
6594
  plugins.push(this.pluginCallbacks[i](writer));
6441
6595
  }
6442
6596
  writer.setPlugins(plugins);
6443
- writer.write(input, onDone, options).catch(onError);
6597
+ writer.setTextureUtils(this.textureUtils);
6598
+ writer.writeAsync(input, onDone, options).catch(onError);
6444
6599
  }
6600
+ /**
6601
+ * Async version of {@link GLTFExporter#parse}.
6602
+ *
6603
+ * @param {Scene|Array<Scene>} input - A scene or an array of scenes.
6604
+ * @param {GLTFExporter~Options} options - options.
6605
+ * @return {Promise<ArrayBuffer|string>} A Promise that resolved with the exported glTF data.
6606
+ */
6445
6607
  parseAsync(input, options) {
6446
6608
  const scope = this;
6447
6609
  return new Promise(function(resolve, reject) {
@@ -6527,7 +6689,7 @@ function getMinMax(attribute, start, count) {
6527
6689
  else if (a === 2) value = attribute.getZ(i);
6528
6690
  else if (a === 3) value = attribute.getW(i);
6529
6691
  if (attribute.normalized === true) {
6530
- value = MathUtils2.normalize(value, attribute.array);
6692
+ value = MathUtils.normalize(value, attribute.array);
6531
6693
  }
6532
6694
  }
6533
6695
  output.min[a] = Math.min(output.min[a], value);
@@ -6560,19 +6722,20 @@ function getCanvas() {
6560
6722
  return document.createElement("canvas");
6561
6723
  }
6562
6724
  function getToBlobPromise(canvas, mimeType) {
6563
- if (canvas.toBlob !== void 0) {
6725
+ if (typeof OffscreenCanvas !== "undefined" && canvas instanceof OffscreenCanvas) {
6726
+ let quality;
6727
+ if (mimeType === "image/jpeg") {
6728
+ quality = 0.92;
6729
+ } else if (mimeType === "image/webp") {
6730
+ quality = 0.8;
6731
+ }
6732
+ return canvas.convertToBlob({
6733
+ type: mimeType,
6734
+ quality
6735
+ });
6736
+ } else {
6564
6737
  return new Promise((resolve) => canvas.toBlob(resolve, mimeType));
6565
6738
  }
6566
- let quality;
6567
- if (mimeType === "image/jpeg") {
6568
- quality = 0.92;
6569
- } else if (mimeType === "image/webp") {
6570
- quality = 0.8;
6571
- }
6572
- return canvas.convertToBlob({
6573
- type: mimeType,
6574
- quality
6575
- });
6576
6739
  }
6577
6740
  var GLTFWriter = class {
6578
6741
  constructor() {
@@ -6591,7 +6754,7 @@ var GLTFWriter = class {
6591
6754
  this.json = {
6592
6755
  asset: {
6593
6756
  version: "2.0",
6594
- generator: "THREE.GLTFExporter"
6757
+ generator: "THREE.GLTFExporter r" + REVISION
6595
6758
  }
6596
6759
  };
6597
6760
  this.cache = {
@@ -6600,19 +6763,25 @@ var GLTFWriter = class {
6600
6763
  attributesNormalized: /* @__PURE__ */ new Map(),
6601
6764
  materials: /* @__PURE__ */ new Map(),
6602
6765
  textures: /* @__PURE__ */ new Map(),
6603
- images: /* @__PURE__ */ new Map()
6766
+ images: /* @__PURE__ */ new Map(),
6767
+ normalMaps: /* @__PURE__ */ new Map()
6604
6768
  };
6769
+ this.textureUtils = null;
6605
6770
  }
6606
6771
  setPlugins(plugins) {
6607
6772
  this.plugins = plugins;
6608
6773
  }
6774
+ setTextureUtils(utils) {
6775
+ this.textureUtils = utils;
6776
+ }
6609
6777
  /**
6610
6778
  * Parse scenes and generate GLTF output
6611
- * @param {Scene or [THREE.Scenes]} input Scene or Array of THREE.Scenes
6612
- * @param {Function} onDone Callback on completed
6613
- * @param {Object} options options
6779
+ *
6780
+ * @param {Scene|Array<Scene>} input Scene or Array of THREE.Scenes
6781
+ * @param {Function} onDone Callback on completed
6782
+ * @param {Object} options options
6614
6783
  */
6615
- async write(input, onDone, options = {}) {
6784
+ async writeAsync(input, onDone, options = {}) {
6616
6785
  this.options = Object.assign({
6617
6786
  // default options
6618
6787
  binary: false,
@@ -6620,12 +6789,13 @@ var GLTFWriter = class {
6620
6789
  onlyVisible: true,
6621
6790
  maxTextureSize: Infinity,
6622
6791
  animations: [],
6623
- includeCustomExtensions: false
6792
+ includeCustomExtensions: false,
6793
+ copyright: null
6624
6794
  }, options);
6625
6795
  if (this.options.animations.length > 0) {
6626
6796
  this.options.trs = true;
6627
6797
  }
6628
- this.processInput(input);
6798
+ await this.processInputAsync(input);
6629
6799
  await Promise.all(this.pending);
6630
6800
  const writer = this;
6631
6801
  const buffers = writer.buffers;
@@ -6639,6 +6809,7 @@ var GLTFWriter = class {
6639
6809
  if (extensionsUsedList.length > 0) json.extensionsUsed = extensionsUsedList;
6640
6810
  if (extensionsRequiredList.length > 0) json.extensionsRequired = extensionsRequiredList;
6641
6811
  if (json.buffers && json.buffers.length > 0) json.buffers[0].byteLength = blob.size;
6812
+ if (options.copyright) json.asset.copyright = options.copyright;
6642
6813
  if (options.binary === true) {
6643
6814
  const reader = new FileReader();
6644
6815
  reader.readAsArrayBuffer(blob);
@@ -6687,7 +6858,7 @@ var GLTFWriter = class {
6687
6858
  /**
6688
6859
  * Serializes a userData.
6689
6860
  *
6690
- * @param {THREE.Object3D|THREE.Material} object
6861
+ * @param {THREE.Object3D|THREE.Material|THREE.BufferGeometry|THREE.AnimationClip} object
6691
6862
  * @param {Object} objectDef
6692
6863
  */
6693
6864
  serializeUserData(object, objectDef) {
@@ -6711,8 +6882,10 @@ var GLTFWriter = class {
6711
6882
  }
6712
6883
  /**
6713
6884
  * Returns ids for buffer attributes.
6714
- * @param {Object} object
6715
- * @return {Integer}
6885
+ *
6886
+ * @param {Object} attribute
6887
+ * @param {boolean} [isRelativeCopy=false]
6888
+ * @return {number} An integer
6716
6889
  */
6717
6890
  getUID(attribute, isRelativeCopy = false) {
6718
6891
  if (this.uids.has(attribute) === false) {
@@ -6728,7 +6901,7 @@ var GLTFWriter = class {
6728
6901
  * Checks if normal attribute values are normalized.
6729
6902
  *
6730
6903
  * @param {BufferAttribute} normal
6731
- * @returns {Boolean}
6904
+ * @returns {boolean}
6732
6905
  */
6733
6906
  isNormalizedNormalAttribute(normal) {
6734
6907
  const cache = this.cache;
@@ -6791,10 +6964,10 @@ var GLTFWriter = class {
6791
6964
  this.extensionsUsed["KHR_texture_transform"] = true;
6792
6965
  }
6793
6966
  }
6794
- buildMetalRoughTexture(metalnessMap, roughnessMap) {
6967
+ async buildMetalRoughTextureAsync(metalnessMap, roughnessMap) {
6795
6968
  if (metalnessMap === roughnessMap) return metalnessMap;
6796
6969
  function getEncodingConversion(map) {
6797
- if (map.colorSpace === SRGBColorSpace4) {
6970
+ if (map.colorSpace === SRGBColorSpace5) {
6798
6971
  return function SRGBToLinear(c) {
6799
6972
  return c < 0.04045 ? c * 0.0773993808 : Math.pow(c * 0.9478672986 + 0.0521327014, 2.4);
6800
6973
  };
@@ -6803,12 +6976,11 @@ var GLTFWriter = class {
6803
6976
  return c;
6804
6977
  };
6805
6978
  }
6806
- console.warn("THREE.GLTFExporter: Merged metalnessMap and roughnessMap textures.");
6807
6979
  if (metalnessMap instanceof CompressedTexture) {
6808
- metalnessMap = decompress(metalnessMap);
6980
+ metalnessMap = await this.decompressTextureAsync(metalnessMap);
6809
6981
  }
6810
6982
  if (roughnessMap instanceof CompressedTexture) {
6811
- roughnessMap = decompress(roughnessMap);
6983
+ roughnessMap = await this.decompressTextureAsync(roughnessMap);
6812
6984
  }
6813
6985
  const metalness = metalnessMap ? metalnessMap.image : null;
6814
6986
  const roughness = roughnessMap ? roughnessMap.image : null;
@@ -6817,7 +6989,9 @@ var GLTFWriter = class {
6817
6989
  const canvas = getCanvas();
6818
6990
  canvas.width = width;
6819
6991
  canvas.height = height;
6820
- const context = canvas.getContext("2d");
6992
+ const context = canvas.getContext("2d", {
6993
+ willReadFrequently: true
6994
+ });
6821
6995
  context.fillStyle = "#00ffff";
6822
6996
  context.fillRect(0, 0, width, height);
6823
6997
  const composite = context.getImageData(0, 0, width, height);
@@ -6840,18 +7014,60 @@ var GLTFWriter = class {
6840
7014
  context.putImageData(composite, 0, 0);
6841
7015
  const reference = metalnessMap || roughnessMap;
6842
7016
  const texture = reference.clone();
6843
- texture.source = new Source(canvas);
7017
+ texture.source = new TextureSource(canvas);
6844
7018
  texture.colorSpace = NoColorSpace;
6845
7019
  texture.channel = (metalnessMap || roughnessMap).channel;
6846
7020
  if (metalnessMap && roughnessMap && metalnessMap.channel !== roughnessMap.channel) {
6847
7021
  console.warn("THREE.GLTFExporter: UV channels for metalnessMap and roughnessMap textures must match.");
6848
7022
  }
7023
+ console.warn("THREE.GLTFExporter: Merged metalnessMap and roughnessMap textures.");
7024
+ return texture;
7025
+ }
7026
+ /**
7027
+ * Builds a copy of the given normal map with the red and/or green channels
7028
+ * inverted (`color = 255 - color`). This is used to bake the sign of
7029
+ * `material.normalScale` and the tangent-space convention into the texture,
7030
+ * since glTF only supports OpenGL-style normal maps with a univariate,
7031
+ * positive scale.
7032
+ *
7033
+ * @param {THREE.Texture} normalMap The source normal map.
7034
+ * @param {boolean} flipX Whether to invert the red channel (normal X).
7035
+ * @param {boolean} flipY Whether to invert the green channel (normal Y).
7036
+ * @return {Promise<THREE.Texture>} The derived normal map texture.
7037
+ */
7038
+ async buildNormalMapTextureAsync(normalMap, flipX, flipY) {
7039
+ if (normalMap instanceof CompressedTexture) {
7040
+ normalMap = await this.decompressTextureAsync(normalMap);
7041
+ }
7042
+ const image = normalMap.image;
7043
+ const canvas = getCanvas();
7044
+ canvas.width = image.width;
7045
+ canvas.height = image.height;
7046
+ const context = canvas.getContext("2d", {
7047
+ willReadFrequently: true
7048
+ });
7049
+ context.drawImage(image, 0, 0, canvas.width, canvas.height);
7050
+ const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
7051
+ const data = imageData.data;
7052
+ for (let i = 0; i < data.length; i += 4) {
7053
+ if (flipX) data[i + 0] = 255 - data[i + 0];
7054
+ if (flipY) data[i + 1] = 255 - data[i + 1];
7055
+ }
7056
+ context.putImageData(imageData, 0, 0);
7057
+ const texture = normalMap.clone();
7058
+ texture.source = new TextureSource(canvas);
6849
7059
  return texture;
6850
7060
  }
7061
+ async decompressTextureAsync(texture, maxTextureSize = Infinity) {
7062
+ if (this.textureUtils === null) {
7063
+ throw new Error("THREE.GLTFExporter: setTextureUtils() must be called to process compressed textures.");
7064
+ }
7065
+ return await this.textureUtils.decompress(texture, maxTextureSize);
7066
+ }
6851
7067
  /**
6852
7068
  * Process a buffer to append to the default one.
6853
- * @param {ArrayBuffer} buffer
6854
- * @return {Integer}
7069
+ * @param {ArrayBuffer} buffer
7070
+ * @return {0}
6855
7071
  */
6856
7072
  processBuffer(buffer) {
6857
7073
  const json = this.json;
@@ -6862,11 +7078,11 @@ var GLTFWriter = class {
6862
7078
  }
6863
7079
  /**
6864
7080
  * Process and generate a BufferView
6865
- * @param {BufferAttribute} attribute
6866
- * @param {number} componentType
6867
- * @param {number} start
6868
- * @param {number} count
6869
- * @param {number} target (Optional) Target usage of the BufferView
7081
+ * @param {BufferAttribute} attribute
7082
+ * @param {number} componentType
7083
+ * @param {number} start
7084
+ * @param {number} count
7085
+ * @param {number} [target] Target usage of the BufferView
6870
7086
  * @return {Object}
6871
7087
  */
6872
7088
  processBufferView(attribute, componentType, start, count, target) {
@@ -6885,7 +7101,11 @@ var GLTFWriter = class {
6885
7101
  default:
6886
7102
  componentSize = 4;
6887
7103
  }
6888
- const byteLength = getPaddedBufferSize(count * attribute.itemSize * componentSize);
7104
+ let byteStride = attribute.itemSize * componentSize;
7105
+ if (target === WEBGL_CONSTANTS.ARRAY_BUFFER) {
7106
+ byteStride = Math.ceil(byteStride / 4) * 4;
7107
+ }
7108
+ const byteLength = getPaddedBufferSize(count * byteStride);
6889
7109
  const dataView = new DataView(new ArrayBuffer(byteLength));
6890
7110
  let offset = 0;
6891
7111
  for (let i = start; i < start + count; i++) {
@@ -6899,7 +7119,7 @@ var GLTFWriter = class {
6899
7119
  else if (a === 2) value = attribute.getZ(i);
6900
7120
  else if (a === 3) value = attribute.getW(i);
6901
7121
  if (attribute.normalized === true) {
6902
- value = MathUtils2.normalize(value, attribute.array);
7122
+ value = MathUtils.normalize(value, attribute.array);
6903
7123
  }
6904
7124
  }
6905
7125
  if (componentType === WEBGL_CONSTANTS.FLOAT) {
@@ -6919,6 +7139,9 @@ var GLTFWriter = class {
6919
7139
  }
6920
7140
  offset += componentSize;
6921
7141
  }
7142
+ if (offset % byteStride !== 0) {
7143
+ offset += byteStride - offset % byteStride;
7144
+ }
6922
7145
  }
6923
7146
  const bufferViewDef = {
6924
7147
  buffer: this.processBuffer(dataView.buffer),
@@ -6927,7 +7150,7 @@ var GLTFWriter = class {
6927
7150
  };
6928
7151
  if (target !== void 0) bufferViewDef.target = target;
6929
7152
  if (target === WEBGL_CONSTANTS.ARRAY_BUFFER) {
6930
- bufferViewDef.byteStride = attribute.itemSize * componentSize;
7153
+ bufferViewDef.byteStride = byteStride;
6931
7154
  }
6932
7155
  this.byteOffset += byteLength;
6933
7156
  json.bufferViews.push(bufferViewDef);
@@ -6940,7 +7163,7 @@ var GLTFWriter = class {
6940
7163
  /**
6941
7164
  * Process and generate a BufferView from an image Blob.
6942
7165
  * @param {Blob} blob
6943
- * @return {Promise<Integer>}
7166
+ * @return {Promise<number>} An integer
6944
7167
  */
6945
7168
  processBufferViewImage(blob) {
6946
7169
  const writer = this;
@@ -6963,11 +7186,11 @@ var GLTFWriter = class {
6963
7186
  }
6964
7187
  /**
6965
7188
  * Process attribute to generate an accessor
6966
- * @param {BufferAttribute} attribute Attribute to process
6967
- * @param {THREE.BufferGeometry} geometry (Optional) Geometry used for truncated draw range
6968
- * @param {Integer} start (Optional)
6969
- * @param {Integer} count (Optional)
6970
- * @return {Integer|null} Index of the processed accessor on the "accessors" array
7189
+ * @param {BufferAttribute} attribute Attribute to process
7190
+ * @param {?BufferGeometry} [geometry] Geometry used for truncated draw range
7191
+ * @param {number} [start=0]
7192
+ * @param {number} [count=Infinity]
7193
+ * @return {?number} Index of the processed accessor on the "accessors" array
6971
7194
  */
6972
7195
  processAccessor(attribute, geometry, start, count) {
6973
7196
  const json = this.json;
@@ -7021,11 +7244,11 @@ var GLTFWriter = class {
7021
7244
  }
7022
7245
  /**
7023
7246
  * Process image
7024
- * @param {Image} image to process
7025
- * @param {Integer} format of the image (RGBAFormat)
7026
- * @param {Boolean} flipY before writing out the image
7027
- * @param {String} mimeType export format
7028
- * @return {Integer} Index of the processed texture in the "images" array
7247
+ * @param {Image} image to process
7248
+ * @param {number} format Identifier of the format (RGBAFormat)
7249
+ * @param {boolean} flipY before writing out the image
7250
+ * @param {string} mimeType export format
7251
+ * @return {number} Index of the processed texture in the "images" array
7029
7252
  */
7030
7253
  processImage(image, format, flipY, mimeType = "image/png") {
7031
7254
  if (image !== null) {
@@ -7043,7 +7266,9 @@ var GLTFWriter = class {
7043
7266
  const canvas = getCanvas();
7044
7267
  canvas.width = Math.min(image.width, options.maxTextureSize);
7045
7268
  canvas.height = Math.min(image.height, options.maxTextureSize);
7046
- const ctx = canvas.getContext("2d");
7269
+ const ctx = canvas.getContext("2d", {
7270
+ willReadFrequently: true
7271
+ });
7047
7272
  if (flipY === true) {
7048
7273
  ctx.translate(0, canvas.height);
7049
7274
  ctx.scale(1, -1);
@@ -7064,7 +7289,11 @@ var GLTFWriter = class {
7064
7289
  }
7065
7290
  ctx.putImageData(new ImageData(data, image.width, image.height), 0, 0);
7066
7291
  } else {
7067
- ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
7292
+ 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) {
7293
+ ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
7294
+ } else {
7295
+ throw new Error("THREE.GLTFExporter: Invalid image type. Use HTMLImageElement, HTMLCanvasElement, ImageBitmap or OffscreenCanvas.");
7296
+ }
7068
7297
  }
7069
7298
  if (options.binary === true) {
7070
7299
  pending.push(
@@ -7073,15 +7302,7 @@ var GLTFWriter = class {
7073
7302
  })
7074
7303
  );
7075
7304
  } else {
7076
- if (canvas.toDataURL !== void 0) {
7077
- imageDef.uri = canvas.toDataURL(mimeType);
7078
- } else {
7079
- pending.push(
7080
- getToBlobPromise(canvas, mimeType).then((blob) => new FileReader().readAsDataURL(blob)).then((dataURL) => {
7081
- imageDef.uri = dataURL;
7082
- })
7083
- );
7084
- }
7305
+ imageDef.uri = ImageUtils.getDataURL(canvas, mimeType);
7085
7306
  }
7086
7307
  const index = json.images.push(imageDef) - 1;
7087
7308
  cachedImages[key] = index;
@@ -7092,8 +7313,8 @@ var GLTFWriter = class {
7092
7313
  }
7093
7314
  /**
7094
7315
  * Process sampler
7095
- * @param {Texture} map Texture to process
7096
- * @return {Integer} Index of the processed texture in the "samplers" array
7316
+ * @param {Texture} map Texture to process
7317
+ * @return {number} Index of the processed texture in the "samplers" array
7097
7318
  */
7098
7319
  processSampler(map) {
7099
7320
  const json = this.json;
@@ -7108,10 +7329,10 @@ var GLTFWriter = class {
7108
7329
  }
7109
7330
  /**
7110
7331
  * Process texture
7111
- * @param {Texture} map Map to process
7112
- * @return {Integer} Index of the processed texture in the "textures" array
7332
+ * @param {Texture} map Map to process
7333
+ * @return {Promise<number>} Index of the processed texture in the "textures" array
7113
7334
  */
7114
- processTexture(map) {
7335
+ async processTextureAsync(map) {
7115
7336
  const writer = this;
7116
7337
  const options = writer.options;
7117
7338
  const cache = this.cache;
@@ -7119,17 +7340,26 @@ var GLTFWriter = class {
7119
7340
  if (cache.textures.has(map)) return cache.textures.get(map);
7120
7341
  if (!json.textures) json.textures = [];
7121
7342
  if (map instanceof CompressedTexture) {
7122
- map = decompress(map, options.maxTextureSize);
7343
+ map = await this.decompressTextureAsync(map, options.maxTextureSize);
7123
7344
  }
7124
- let mimeType = map.userData.mimeType;
7125
- if (mimeType === "image/webp") mimeType = "image/png";
7345
+ const mimeType = map.userData.mimeType;
7346
+ const imageIndex = this.processImage(map.image, map.format, map.flipY, mimeType);
7126
7347
  const textureDef = {
7127
- sampler: this.processSampler(map),
7128
- source: this.processImage(map.image, map.format, map.flipY, mimeType)
7348
+ sampler: this.processSampler(map)
7129
7349
  };
7350
+ if (mimeType === "image/webp") {
7351
+ textureDef.extensions = textureDef.extensions || {};
7352
+ textureDef.extensions["EXT_texture_webp"] = {
7353
+ source: imageIndex
7354
+ };
7355
+ this.extensionsUsed["EXT_texture_webp"] = true;
7356
+ this.extensionsRequired["EXT_texture_webp"] = true;
7357
+ } else {
7358
+ textureDef.source = imageIndex;
7359
+ }
7130
7360
  if (map.name) textureDef.name = map.name;
7131
- this._invokeAll(function(ext) {
7132
- ext.writeTexture && ext.writeTexture(map, textureDef);
7361
+ await this._invokeAllAsync(async function(ext) {
7362
+ ext.writeTexture && await ext.writeTexture(map, textureDef);
7133
7363
  });
7134
7364
  const index = json.textures.push(textureDef) - 1;
7135
7365
  cache.textures.set(map, index);
@@ -7137,13 +7367,16 @@ var GLTFWriter = class {
7137
7367
  }
7138
7368
  /**
7139
7369
  * Process material
7140
- * @param {THREE.Material} material Material to process
7141
- * @return {Integer|null} Index of the processed material in the "materials" array
7370
+ * @param {THREE.Material} material Material to process
7371
+ * @param {THREE.BufferGeometry} [geometry] Geometry the material is used with.
7372
+ * @return {Promise<?number>} Index of the processed material in the "materials" array
7142
7373
  */
7143
- processMaterial(material) {
7374
+ async processMaterialAsync(material, geometry) {
7144
7375
  const cache = this.cache;
7145
7376
  const json = this.json;
7146
- if (cache.materials.has(material)) return cache.materials.get(material);
7377
+ const hasTangent = geometry !== void 0 && geometry.hasAttribute("tangent");
7378
+ const cacheKey = material.normalMap ? material.uuid + ":" + hasTangent : material.uuid;
7379
+ if (cache.materials.has(cacheKey)) return cache.materials.get(cacheKey);
7147
7380
  if (material.isShaderMaterial) {
7148
7381
  console.warn("GLTFExporter: THREE.ShaderMaterial not supported.");
7149
7382
  return null;
@@ -7161,21 +7394,21 @@ var GLTFWriter = class {
7161
7394
  materialDef.pbrMetallicRoughness.metallicFactor = material.metalness;
7162
7395
  materialDef.pbrMetallicRoughness.roughnessFactor = material.roughness;
7163
7396
  } else {
7164
- materialDef.pbrMetallicRoughness.metallicFactor = 0.5;
7165
- materialDef.pbrMetallicRoughness.roughnessFactor = 0.5;
7397
+ materialDef.pbrMetallicRoughness.metallicFactor = 0;
7398
+ materialDef.pbrMetallicRoughness.roughnessFactor = 1;
7166
7399
  }
7167
7400
  if (material.metalnessMap || material.roughnessMap) {
7168
- const metalRoughTexture = this.buildMetalRoughTexture(material.metalnessMap, material.roughnessMap);
7401
+ const metalRoughTexture = await this.buildMetalRoughTextureAsync(material.metalnessMap, material.roughnessMap);
7169
7402
  const metalRoughMapDef = {
7170
- index: this.processTexture(metalRoughTexture),
7171
- channel: metalRoughTexture.channel
7403
+ index: await this.processTextureAsync(metalRoughTexture),
7404
+ texCoord: metalRoughTexture.channel
7172
7405
  };
7173
7406
  this.applyTextureTransform(metalRoughMapDef, metalRoughTexture);
7174
7407
  materialDef.pbrMetallicRoughness.metallicRoughnessTexture = metalRoughMapDef;
7175
7408
  }
7176
7409
  if (material.map) {
7177
7410
  const baseColorMapDef = {
7178
- index: this.processTexture(material.map),
7411
+ index: await this.processTextureAsync(material.map),
7179
7412
  texCoord: material.map.channel
7180
7413
  };
7181
7414
  this.applyTextureTransform(baseColorMapDef, material.map);
@@ -7189,7 +7422,7 @@ var GLTFWriter = class {
7189
7422
  }
7190
7423
  if (material.emissiveMap) {
7191
7424
  const emissiveMapDef = {
7192
- index: this.processTexture(material.emissiveMap),
7425
+ index: await this.processTextureAsync(material.emissiveMap),
7193
7426
  texCoord: material.emissiveMap.channel
7194
7427
  };
7195
7428
  this.applyTextureTransform(emissiveMapDef, material.emissiveMap);
@@ -7197,19 +7430,32 @@ var GLTFWriter = class {
7197
7430
  }
7198
7431
  }
7199
7432
  if (material.normalMap) {
7433
+ const normalScale = material.normalScale;
7434
+ const flipX = normalScale.x < 0;
7435
+ const flipY = hasTangent ? normalScale.y < 0 : normalScale.y > 0;
7436
+ let normalMap = material.normalMap;
7437
+ if (flipX || flipY) {
7438
+ if (cache.normalMaps.has(material.normalMap) === false) cache.normalMaps.set(material.normalMap, {});
7439
+ const cachedVariants = cache.normalMaps.get(material.normalMap);
7440
+ const cacheKey2 = `${flipX}:${flipY}`;
7441
+ if (cachedVariants[cacheKey2] === void 0) {
7442
+ cachedVariants[cacheKey2] = await this.buildNormalMapTextureAsync(material.normalMap, flipX, flipY);
7443
+ }
7444
+ normalMap = cachedVariants[cacheKey2];
7445
+ }
7200
7446
  const normalMapDef = {
7201
- index: this.processTexture(material.normalMap),
7447
+ index: await this.processTextureAsync(normalMap),
7202
7448
  texCoord: material.normalMap.channel
7203
7449
  };
7204
- if (material.normalScale && material.normalScale.x !== 1) {
7205
- normalMapDef.scale = material.normalScale.x;
7450
+ if (Math.abs(normalScale.x) !== 1) {
7451
+ normalMapDef.scale = Math.abs(normalScale.x);
7206
7452
  }
7207
7453
  this.applyTextureTransform(normalMapDef, material.normalMap);
7208
7454
  materialDef.normalTexture = normalMapDef;
7209
7455
  }
7210
7456
  if (material.aoMap) {
7211
7457
  const occlusionMapDef = {
7212
- index: this.processTexture(material.aoMap),
7458
+ index: await this.processTextureAsync(material.aoMap),
7213
7459
  texCoord: material.aoMap.channel
7214
7460
  };
7215
7461
  if (material.aoMapIntensity !== 1) {
@@ -7229,19 +7475,19 @@ var GLTFWriter = class {
7229
7475
  if (material.side === DoubleSide2) materialDef.doubleSided = true;
7230
7476
  if (material.name !== "") materialDef.name = material.name;
7231
7477
  this.serializeUserData(material, materialDef);
7232
- this._invokeAll(function(ext) {
7233
- ext.writeMaterial && ext.writeMaterial(material, materialDef);
7478
+ await this._invokeAllAsync(async function(ext) {
7479
+ ext.writeMaterialAsync && await ext.writeMaterialAsync(material, materialDef);
7234
7480
  });
7235
7481
  const index = json.materials.push(materialDef) - 1;
7236
- cache.materials.set(material, index);
7482
+ cache.materials.set(cacheKey, index);
7237
7483
  return index;
7238
7484
  }
7239
7485
  /**
7240
7486
  * Process mesh
7241
- * @param {THREE.Mesh} mesh Mesh to process
7242
- * @return {Integer|null} Index of the processed mesh in the "meshes" array
7487
+ * @param {THREE.Mesh} mesh Mesh to process
7488
+ * @return {Promise<?number>} Index of the processed mesh in the "meshes" array
7243
7489
  */
7244
- processMesh(mesh) {
7490
+ async processMeshAsync(mesh) {
7245
7491
  const cache = this.cache;
7246
7492
  const json = this.json;
7247
7493
  const meshCacheKeyParts = [mesh.geometry.uuid];
@@ -7291,7 +7537,7 @@ var GLTFWriter = class {
7291
7537
  const attribute = geometry.attributes[attributeName];
7292
7538
  attributeName = nameConversion[attributeName] || attributeName.toUpperCase();
7293
7539
  const validVertexAttributes = /^(POSITION|NORMAL|TANGENT|TEXCOORD_\d+|COLOR_\d+|JOINTS_\d+|WEIGHTS_\d+)$/;
7294
- if (!validVertexAttributes.test(attributeName)) attributeName = "_" + attributeName;
7540
+ if (!validVertexAttributes.test(attributeName) && !attributeName.startsWith("_")) attributeName = "_" + attributeName;
7295
7541
  if (cache.attributes.has(this.getUID(attribute))) {
7296
7542
  attributes[attributeName] = cache.attributes.get(this.getUID(attribute));
7297
7543
  continue;
@@ -7300,7 +7546,10 @@ var GLTFWriter = class {
7300
7546
  const array = attribute.array;
7301
7547
  if (attributeName === "JOINTS_0" && !(array instanceof Uint16Array) && !(array instanceof Uint8Array)) {
7302
7548
  console.warn('GLTFExporter: Attribute "skinIndex" converted to type UNSIGNED_SHORT.');
7303
- modifiedAttribute = new BufferAttribute3(new Uint16Array(array), attribute.itemSize, attribute.normalized);
7549
+ modifiedAttribute = GLTFExporter.Utils.toTypedBufferAttribute(attribute, Uint16Array);
7550
+ } else if ((array instanceof Uint32Array || array instanceof Int32Array) && !attributeName.startsWith("_")) {
7551
+ console.warn(`GLTFExporter: Attribute "${attributeName}" converted to type FLOAT.`);
7552
+ modifiedAttribute = GLTFExporter.Utils.toTypedBufferAttribute(attribute, Float32Array);
7304
7553
  }
7305
7554
  const accessor = this.processAccessor(modifiedAttribute || attribute, geometry);
7306
7555
  if (accessor !== null) {
@@ -7366,6 +7615,15 @@ var GLTFWriter = class {
7366
7615
  }
7367
7616
  const isMultiMaterial = Array.isArray(mesh.material);
7368
7617
  if (isMultiMaterial && geometry.groups.length === 0) return null;
7618
+ let didForceIndices = false;
7619
+ if (isMultiMaterial && geometry.index === null) {
7620
+ const indices = [];
7621
+ for (let i = 0, il = geometry.attributes.position.count; i < il; i++) {
7622
+ indices[i] = i;
7623
+ }
7624
+ geometry.setIndex(indices);
7625
+ didForceIndices = true;
7626
+ }
7369
7627
  const materials = isMultiMaterial ? mesh.material : [mesh.material];
7370
7628
  const groups = isMultiMaterial ? geometry.groups : [{ materialIndex: 0, start: void 0, count: void 0 }];
7371
7629
  for (let i = 0, il = groups.length; i < il; i++) {
@@ -7388,13 +7646,16 @@ var GLTFWriter = class {
7388
7646
  }
7389
7647
  if (primitive.indices === null) delete primitive.indices;
7390
7648
  }
7391
- const material = this.processMaterial(materials[groups[i].materialIndex]);
7649
+ const material = await this.processMaterialAsync(materials[groups[i].materialIndex], geometry);
7392
7650
  if (material !== null) primitive.material = material;
7393
7651
  primitives.push(primitive);
7394
7652
  }
7653
+ if (didForceIndices === true) {
7654
+ geometry.setIndex(null);
7655
+ }
7395
7656
  meshDef.primitives = primitives;
7396
7657
  if (!json.meshes) json.meshes = [];
7397
- this._invokeAll(function(ext) {
7658
+ await this._invokeAllAsync(function(ext) {
7398
7659
  ext.writeMesh && ext.writeMesh(mesh, meshDef);
7399
7660
  });
7400
7661
  const index = json.meshes.push(meshDef) - 1;
@@ -7440,8 +7701,8 @@ var GLTFWriter = class {
7440
7701
  }
7441
7702
  /**
7442
7703
  * Process camera
7443
- * @param {THREE.Camera} camera Camera to process
7444
- * @return {Integer} Index of the processed mesh in the "camera" array
7704
+ * @param {THREE.Camera} camera Camera to process
7705
+ * @return {number} Index of the processed mesh in the "camera" array
7445
7706
  */
7446
7707
  processCamera(camera) {
7447
7708
  const json = this.json;
@@ -7460,7 +7721,7 @@ var GLTFWriter = class {
7460
7721
  } else {
7461
7722
  cameraDef.perspective = {
7462
7723
  aspectRatio: camera.aspect,
7463
- yfov: MathUtils2.degToRad(camera.fov),
7724
+ yfov: MathUtils.degToRad(camera.fov),
7464
7725
  zfar: camera.far <= 0 ? 1e-3 : camera.far,
7465
7726
  znear: camera.near < 0 ? 0 : camera.near
7466
7727
  };
@@ -7476,7 +7737,7 @@ var GLTFWriter = class {
7476
7737
  *
7477
7738
  * @param {THREE.AnimationClip} clip
7478
7739
  * @param {THREE.Object3D} root
7479
- * @return {number|null}
7740
+ * @return {?number}
7480
7741
  */
7481
7742
  processAnimation(clip, root) {
7482
7743
  const json = this.json;
@@ -7500,7 +7761,7 @@ var GLTFWriter = class {
7500
7761
  }
7501
7762
  if (!trackNode || !trackProperty) {
7502
7763
  console.warn('THREE.GLTFExporter: Could not export animation track "%s".', track.name);
7503
- return null;
7764
+ continue;
7504
7765
  }
7505
7766
  const inputItemSize = 1;
7506
7767
  let outputItemSize = track.values.length / track.times.length;
@@ -7529,16 +7790,18 @@ var GLTFWriter = class {
7529
7790
  }
7530
7791
  });
7531
7792
  }
7532
- json.animations.push({
7793
+ const animationDef = {
7533
7794
  name: clip.name || "clip_" + json.animations.length,
7534
7795
  samplers,
7535
7796
  channels
7536
- });
7797
+ };
7798
+ this.serializeUserData(clip, animationDef);
7799
+ json.animations.push(animationDef);
7537
7800
  return json.animations.length - 1;
7538
7801
  }
7539
7802
  /**
7540
7803
  * @param {THREE.Object3D} object
7541
- * @return {number|null}
7804
+ * @return {?number}
7542
7805
  */
7543
7806
  processSkin(object) {
7544
7807
  const json = this.json;
@@ -7567,14 +7830,17 @@ var GLTFWriter = class {
7567
7830
  }
7568
7831
  /**
7569
7832
  * Process Object3D node
7570
- * @param {THREE.Object3D} node Object3D to processNode
7571
- * @return {Integer} Index of the node in the nodes list
7833
+ * @param {THREE.Object3D} object Object3D to processNodeAsync
7834
+ * @return {Promise<number>} Index of the node in the nodes list
7572
7835
  */
7573
- processNode(object) {
7836
+ async processNodeAsync(object) {
7574
7837
  const json = this.json;
7575
7838
  const options = this.options;
7576
7839
  const nodeMap = this.nodeMap;
7577
7840
  if (!json.nodes) json.nodes = [];
7841
+ if (object.pivot !== null) {
7842
+ return await this._processNodeWithPivotAsync(object);
7843
+ }
7578
7844
  const nodeDef = {};
7579
7845
  if (options.trs) {
7580
7846
  const rotation = object.quaternion.toArray();
@@ -7600,35 +7866,98 @@ var GLTFWriter = class {
7600
7866
  if (object.name !== "") nodeDef.name = String(object.name);
7601
7867
  this.serializeUserData(object, nodeDef);
7602
7868
  if (object.isMesh || object.isLine || object.isPoints) {
7603
- const meshIndex = this.processMesh(object);
7869
+ const meshIndex = await this.processMeshAsync(object);
7604
7870
  if (meshIndex !== null) nodeDef.mesh = meshIndex;
7605
7871
  } else if (object.isCamera) {
7606
7872
  nodeDef.camera = this.processCamera(object);
7607
7873
  }
7608
7874
  if (object.isSkinnedMesh) this.skins.push(object);
7875
+ const nodeIndex = json.nodes.push(nodeDef) - 1;
7876
+ nodeMap.set(object, nodeIndex);
7609
7877
  if (object.children.length > 0) {
7610
7878
  const children = [];
7611
7879
  for (let i = 0, l = object.children.length; i < l; i++) {
7612
7880
  const child = object.children[i];
7613
7881
  if (child.visible || options.onlyVisible === false) {
7614
- const nodeIndex2 = this.processNode(child);
7615
- if (nodeIndex2 !== null) children.push(nodeIndex2);
7882
+ const childNodeIndex = await this.processNodeAsync(child);
7883
+ if (childNodeIndex !== null) children.push(childNodeIndex);
7616
7884
  }
7617
7885
  }
7618
7886
  if (children.length > 0) nodeDef.children = children;
7619
7887
  }
7620
- this._invokeAll(function(ext) {
7888
+ await this._invokeAllAsync(function(ext) {
7621
7889
  ext.writeNode && ext.writeNode(object, nodeDef);
7622
7890
  });
7623
- const nodeIndex = json.nodes.push(nodeDef) - 1;
7624
- nodeMap.set(object, nodeIndex);
7625
7891
  return nodeIndex;
7626
7892
  }
7893
+ /**
7894
+ * Process Object3D node with pivot using container approach
7895
+ * @param {THREE.Object3D} object Object3D with pivot
7896
+ * @return {Promise<number>} Index of the container node
7897
+ */
7898
+ async _processNodeWithPivotAsync(object) {
7899
+ const json = this.json;
7900
+ const options = this.options;
7901
+ const nodeMap = this.nodeMap;
7902
+ const pivot = object.pivot;
7903
+ const containerDef = {};
7904
+ const rotation = object.quaternion.toArray();
7905
+ const position = [
7906
+ object.position.x + pivot.x,
7907
+ object.position.y + pivot.y,
7908
+ object.position.z + pivot.z
7909
+ ];
7910
+ const scale = object.scale.toArray();
7911
+ if (!equalArray(rotation, [0, 0, 0, 1])) {
7912
+ containerDef.rotation = rotation;
7913
+ }
7914
+ if (!equalArray(position, [0, 0, 0])) {
7915
+ containerDef.translation = position;
7916
+ }
7917
+ if (!equalArray(scale, [1, 1, 1])) {
7918
+ containerDef.scale = scale;
7919
+ }
7920
+ containerDef.extras = { pivot: pivot.toArray() };
7921
+ if (object.name !== "") containerDef.name = String(object.name);
7922
+ this.serializeUserData(object, containerDef);
7923
+ const containerIndex = json.nodes.push(containerDef) - 1;
7924
+ nodeMap.set(object, containerIndex);
7925
+ const childDef = {};
7926
+ const childPosition = [-pivot.x, -pivot.y, -pivot.z];
7927
+ if (!equalArray(childPosition, [0, 0, 0])) {
7928
+ childDef.translation = childPosition;
7929
+ }
7930
+ if (object.isMesh || object.isLine || object.isPoints) {
7931
+ const meshIndex = await this.processMeshAsync(object);
7932
+ if (meshIndex !== null) childDef.mesh = meshIndex;
7933
+ } else if (object.isCamera) {
7934
+ childDef.camera = this.processCamera(object);
7935
+ }
7936
+ if (object.isSkinnedMesh) this.skins.push(object);
7937
+ const childIndex = json.nodes.push(childDef) - 1;
7938
+ const containerChildren = [childIndex];
7939
+ if (object.children.length > 0) {
7940
+ const grandchildren = [];
7941
+ for (let i = 0, l = object.children.length; i < l; i++) {
7942
+ const child = object.children[i];
7943
+ if (child.visible || options.onlyVisible === false) {
7944
+ const childNodeIndex = await this.processNodeAsync(child);
7945
+ if (childNodeIndex !== null) grandchildren.push(childNodeIndex);
7946
+ }
7947
+ }
7948
+ if (grandchildren.length > 0) childDef.children = grandchildren;
7949
+ }
7950
+ containerDef.children = containerChildren;
7951
+ await this._invokeAllAsync(function(ext) {
7952
+ ext.writeNode && ext.writeNode(object, containerDef);
7953
+ });
7954
+ return containerIndex;
7955
+ }
7627
7956
  /**
7628
7957
  * Process Scene
7629
- * @param {Scene} node Scene to process
7958
+ * @param {Scene} scene Scene to process
7630
7959
  */
7631
- processScene(scene) {
7960
+ async processSceneAsync(scene) {
7632
7961
  const json = this.json;
7633
7962
  const options = this.options;
7634
7963
  if (!json.scenes) {
@@ -7642,7 +7971,7 @@ var GLTFWriter = class {
7642
7971
  for (let i = 0, l = scene.children.length; i < l; i++) {
7643
7972
  const child = scene.children[i];
7644
7973
  if (child.visible || options.onlyVisible === false) {
7645
- const nodeIndex = this.processNode(child);
7974
+ const nodeIndex = await this.processNodeAsync(child);
7646
7975
  if (nodeIndex !== null) nodes.push(nodeIndex);
7647
7976
  }
7648
7977
  }
@@ -7651,47 +7980,58 @@ var GLTFWriter = class {
7651
7980
  }
7652
7981
  /**
7653
7982
  * Creates a Scene to hold a list of objects and parse it
7654
- * @param {Array} objects List of objects to process
7983
+ * @param {Array<THREE.Object3D>} objects List of objects to process
7655
7984
  */
7656
- processObjects(objects) {
7657
- const scene = new Scene3();
7985
+ async processObjectsAsync(objects) {
7986
+ const scene = new Scene2();
7658
7987
  scene.name = "AuxScene";
7659
7988
  for (let i = 0; i < objects.length; i++) {
7660
7989
  scene.children.push(objects[i]);
7661
7990
  }
7662
- this.processScene(scene);
7991
+ await this.processSceneAsync(scene);
7663
7992
  }
7664
7993
  /**
7665
7994
  * @param {THREE.Object3D|Array<THREE.Object3D>} input
7666
7995
  */
7667
- processInput(input) {
7996
+ async processInputAsync(input) {
7668
7997
  const options = this.options;
7669
7998
  input = input instanceof Array ? input : [input];
7670
- this._invokeAll(function(ext) {
7999
+ await this._invokeAllAsync(function(ext) {
7671
8000
  ext.beforeParse && ext.beforeParse(input);
7672
8001
  });
7673
8002
  const objectsWithoutScene = [];
7674
8003
  for (let i = 0; i < input.length; i++) {
7675
- if (input[i] instanceof Scene3) {
7676
- this.processScene(input[i]);
8004
+ if (input[i] instanceof Scene2) {
8005
+ await this.processSceneAsync(input[i]);
7677
8006
  } else {
7678
8007
  objectsWithoutScene.push(input[i]);
7679
8008
  }
7680
8009
  }
7681
- if (objectsWithoutScene.length > 0) this.processObjects(objectsWithoutScene);
8010
+ if (objectsWithoutScene.length > 0) {
8011
+ await this.processObjectsAsync(objectsWithoutScene);
8012
+ }
7682
8013
  for (let i = 0; i < this.skins.length; ++i) {
7683
8014
  this.processSkin(this.skins[i]);
7684
8015
  }
7685
- for (let i = 0; i < options.animations.length; ++i) {
7686
- this.processAnimation(options.animations[i], input[0]);
8016
+ if (input.length === 1) {
8017
+ for (let i = 0; i < options.animations.length; ++i) {
8018
+ this.processAnimation(options.animations[i], input[0]);
8019
+ }
8020
+ } else {
8021
+ for (let i = 0; i < input.length; i++) {
8022
+ const animations = options.animations[i] || [];
8023
+ for (let j = 0; j < animations.length; ++j) {
8024
+ this.processAnimation(animations[j], input[i]);
8025
+ }
8026
+ }
7687
8027
  }
7688
- this._invokeAll(function(ext) {
8028
+ await this._invokeAllAsync(function(ext) {
7689
8029
  ext.afterParse && ext.afterParse(input);
7690
8030
  });
7691
8031
  }
7692
- _invokeAll(func) {
8032
+ async _invokeAllAsync(func) {
7693
8033
  for (let i = 0, il = this.plugins.length; i < il; i++) {
7694
- func(this.plugins[i]);
8034
+ await func(this.plugins[i]);
7695
8035
  }
7696
8036
  }
7697
8037
  };
@@ -7747,7 +8087,7 @@ var GLTFMaterialsUnlitExtension = class {
7747
8087
  this.writer = writer;
7748
8088
  this.name = "KHR_materials_unlit";
7749
8089
  }
7750
- writeMaterial(material, materialDef) {
8090
+ async writeMaterialAsync(material, materialDef) {
7751
8091
  if (!material.isMeshBasicMaterial) return;
7752
8092
  const writer = this.writer;
7753
8093
  const extensionsUsed = writer.extensionsUsed;
@@ -7763,7 +8103,7 @@ var GLTFMaterialsClearcoatExtension = class {
7763
8103
  this.writer = writer;
7764
8104
  this.name = "KHR_materials_clearcoat";
7765
8105
  }
7766
- writeMaterial(material, materialDef) {
8106
+ async writeMaterialAsync(material, materialDef) {
7767
8107
  if (!material.isMeshPhysicalMaterial || material.clearcoat === 0) return;
7768
8108
  const writer = this.writer;
7769
8109
  const extensionsUsed = writer.extensionsUsed;
@@ -7771,7 +8111,7 @@ var GLTFMaterialsClearcoatExtension = class {
7771
8111
  extensionDef.clearcoatFactor = material.clearcoat;
7772
8112
  if (material.clearcoatMap) {
7773
8113
  const clearcoatMapDef = {
7774
- index: writer.processTexture(material.clearcoatMap),
8114
+ index: await writer.processTextureAsync(material.clearcoatMap),
7775
8115
  texCoord: material.clearcoatMap.channel
7776
8116
  };
7777
8117
  writer.applyTextureTransform(clearcoatMapDef, material.clearcoatMap);
@@ -7780,7 +8120,7 @@ var GLTFMaterialsClearcoatExtension = class {
7780
8120
  extensionDef.clearcoatRoughnessFactor = material.clearcoatRoughness;
7781
8121
  if (material.clearcoatRoughnessMap) {
7782
8122
  const clearcoatRoughnessMapDef = {
7783
- index: writer.processTexture(material.clearcoatRoughnessMap),
8123
+ index: await writer.processTextureAsync(material.clearcoatRoughnessMap),
7784
8124
  texCoord: material.clearcoatRoughnessMap.channel
7785
8125
  };
7786
8126
  writer.applyTextureTransform(clearcoatRoughnessMapDef, material.clearcoatRoughnessMap);
@@ -7788,9 +8128,10 @@ var GLTFMaterialsClearcoatExtension = class {
7788
8128
  }
7789
8129
  if (material.clearcoatNormalMap) {
7790
8130
  const clearcoatNormalMapDef = {
7791
- index: writer.processTexture(material.clearcoatNormalMap),
8131
+ index: await writer.processTextureAsync(material.clearcoatNormalMap),
7792
8132
  texCoord: material.clearcoatNormalMap.channel
7793
8133
  };
8134
+ if (material.clearcoatNormalScale.x !== 1) clearcoatNormalMapDef.scale = material.clearcoatNormalScale.x;
7794
8135
  writer.applyTextureTransform(clearcoatNormalMapDef, material.clearcoatNormalMap);
7795
8136
  extensionDef.clearcoatNormalTexture = clearcoatNormalMapDef;
7796
8137
  }
@@ -7799,12 +8140,28 @@ var GLTFMaterialsClearcoatExtension = class {
7799
8140
  extensionsUsed[this.name] = true;
7800
8141
  }
7801
8142
  };
8143
+ var GLTFMaterialsDispersionExtension = class {
8144
+ constructor(writer) {
8145
+ this.writer = writer;
8146
+ this.name = "KHR_materials_dispersion";
8147
+ }
8148
+ async writeMaterialAsync(material, materialDef) {
8149
+ if (!material.isMeshPhysicalMaterial || material.dispersion === 0) return;
8150
+ const writer = this.writer;
8151
+ const extensionsUsed = writer.extensionsUsed;
8152
+ const extensionDef = {};
8153
+ extensionDef.dispersion = material.dispersion;
8154
+ materialDef.extensions = materialDef.extensions || {};
8155
+ materialDef.extensions[this.name] = extensionDef;
8156
+ extensionsUsed[this.name] = true;
8157
+ }
8158
+ };
7802
8159
  var GLTFMaterialsIridescenceExtension = class {
7803
8160
  constructor(writer) {
7804
8161
  this.writer = writer;
7805
8162
  this.name = "KHR_materials_iridescence";
7806
8163
  }
7807
- writeMaterial(material, materialDef) {
8164
+ async writeMaterialAsync(material, materialDef) {
7808
8165
  if (!material.isMeshPhysicalMaterial || material.iridescence === 0) return;
7809
8166
  const writer = this.writer;
7810
8167
  const extensionsUsed = writer.extensionsUsed;
@@ -7812,7 +8169,7 @@ var GLTFMaterialsIridescenceExtension = class {
7812
8169
  extensionDef.iridescenceFactor = material.iridescence;
7813
8170
  if (material.iridescenceMap) {
7814
8171
  const iridescenceMapDef = {
7815
- index: writer.processTexture(material.iridescenceMap),
8172
+ index: await writer.processTextureAsync(material.iridescenceMap),
7816
8173
  texCoord: material.iridescenceMap.channel
7817
8174
  };
7818
8175
  writer.applyTextureTransform(iridescenceMapDef, material.iridescenceMap);
@@ -7823,7 +8180,7 @@ var GLTFMaterialsIridescenceExtension = class {
7823
8180
  extensionDef.iridescenceThicknessMaximum = material.iridescenceThicknessRange[1];
7824
8181
  if (material.iridescenceThicknessMap) {
7825
8182
  const iridescenceThicknessMapDef = {
7826
- index: writer.processTexture(material.iridescenceThicknessMap),
8183
+ index: await writer.processTextureAsync(material.iridescenceThicknessMap),
7827
8184
  texCoord: material.iridescenceThicknessMap.channel
7828
8185
  };
7829
8186
  writer.applyTextureTransform(iridescenceThicknessMapDef, material.iridescenceThicknessMap);
@@ -7839,7 +8196,7 @@ var GLTFMaterialsTransmissionExtension = class {
7839
8196
  this.writer = writer;
7840
8197
  this.name = "KHR_materials_transmission";
7841
8198
  }
7842
- writeMaterial(material, materialDef) {
8199
+ async writeMaterialAsync(material, materialDef) {
7843
8200
  if (!material.isMeshPhysicalMaterial || material.transmission === 0) return;
7844
8201
  const writer = this.writer;
7845
8202
  const extensionsUsed = writer.extensionsUsed;
@@ -7847,7 +8204,7 @@ var GLTFMaterialsTransmissionExtension = class {
7847
8204
  extensionDef.transmissionFactor = material.transmission;
7848
8205
  if (material.transmissionMap) {
7849
8206
  const transmissionMapDef = {
7850
- index: writer.processTexture(material.transmissionMap),
8207
+ index: await writer.processTextureAsync(material.transmissionMap),
7851
8208
  texCoord: material.transmissionMap.channel
7852
8209
  };
7853
8210
  writer.applyTextureTransform(transmissionMapDef, material.transmissionMap);
@@ -7863,7 +8220,7 @@ var GLTFMaterialsVolumeExtension = class {
7863
8220
  this.writer = writer;
7864
8221
  this.name = "KHR_materials_volume";
7865
8222
  }
7866
- writeMaterial(material, materialDef) {
8223
+ async writeMaterialAsync(material, materialDef) {
7867
8224
  if (!material.isMeshPhysicalMaterial || material.transmission === 0) return;
7868
8225
  const writer = this.writer;
7869
8226
  const extensionsUsed = writer.extensionsUsed;
@@ -7871,13 +8228,15 @@ var GLTFMaterialsVolumeExtension = class {
7871
8228
  extensionDef.thicknessFactor = material.thickness;
7872
8229
  if (material.thicknessMap) {
7873
8230
  const thicknessMapDef = {
7874
- index: writer.processTexture(material.thicknessMap),
8231
+ index: await writer.processTextureAsync(material.thicknessMap),
7875
8232
  texCoord: material.thicknessMap.channel
7876
8233
  };
7877
8234
  writer.applyTextureTransform(thicknessMapDef, material.thicknessMap);
7878
8235
  extensionDef.thicknessTexture = thicknessMapDef;
7879
8236
  }
7880
- extensionDef.attenuationDistance = material.attenuationDistance;
8237
+ if (material.attenuationDistance !== Infinity) {
8238
+ extensionDef.attenuationDistance = material.attenuationDistance;
8239
+ }
7881
8240
  extensionDef.attenuationColor = material.attenuationColor.toArray();
7882
8241
  materialDef.extensions = materialDef.extensions || {};
7883
8242
  materialDef.extensions[this.name] = extensionDef;
@@ -7889,7 +8248,7 @@ var GLTFMaterialsIorExtension = class {
7889
8248
  this.writer = writer;
7890
8249
  this.name = "KHR_materials_ior";
7891
8250
  }
7892
- writeMaterial(material, materialDef) {
8251
+ async writeMaterialAsync(material, materialDef) {
7893
8252
  if (!material.isMeshPhysicalMaterial || material.ior === 1.5) return;
7894
8253
  const writer = this.writer;
7895
8254
  const extensionsUsed = writer.extensionsUsed;
@@ -7905,14 +8264,14 @@ var GLTFMaterialsSpecularExtension = class {
7905
8264
  this.writer = writer;
7906
8265
  this.name = "KHR_materials_specular";
7907
8266
  }
7908
- writeMaterial(material, materialDef) {
7909
- if (!material.isMeshPhysicalMaterial || material.specularIntensity === 1 && material.specularColor.equals(DEFAULT_SPECULAR_COLOR) && !material.specularIntensityMap && !material.specularColorTexture) return;
8267
+ async writeMaterialAsync(material, materialDef) {
8268
+ if (!material.isMeshPhysicalMaterial || material.specularIntensity === 1 && material.specularColor.equals(DEFAULT_SPECULAR_COLOR) && !material.specularIntensityMap && !material.specularColorMap) return;
7910
8269
  const writer = this.writer;
7911
8270
  const extensionsUsed = writer.extensionsUsed;
7912
8271
  const extensionDef = {};
7913
8272
  if (material.specularIntensityMap) {
7914
8273
  const specularIntensityMapDef = {
7915
- index: writer.processTexture(material.specularIntensityMap),
8274
+ index: await writer.processTextureAsync(material.specularIntensityMap),
7916
8275
  texCoord: material.specularIntensityMap.channel
7917
8276
  };
7918
8277
  writer.applyTextureTransform(specularIntensityMapDef, material.specularIntensityMap);
@@ -7920,7 +8279,7 @@ var GLTFMaterialsSpecularExtension = class {
7920
8279
  }
7921
8280
  if (material.specularColorMap) {
7922
8281
  const specularColorMapDef = {
7923
- index: writer.processTexture(material.specularColorMap),
8282
+ index: await writer.processTextureAsync(material.specularColorMap),
7924
8283
  texCoord: material.specularColorMap.channel
7925
8284
  };
7926
8285
  writer.applyTextureTransform(specularColorMapDef, material.specularColorMap);
@@ -7938,14 +8297,14 @@ var GLTFMaterialsSheenExtension = class {
7938
8297
  this.writer = writer;
7939
8298
  this.name = "KHR_materials_sheen";
7940
8299
  }
7941
- writeMaterial(material, materialDef) {
8300
+ async writeMaterialAsync(material, materialDef) {
7942
8301
  if (!material.isMeshPhysicalMaterial || material.sheen == 0) return;
7943
8302
  const writer = this.writer;
7944
8303
  const extensionsUsed = writer.extensionsUsed;
7945
8304
  const extensionDef = {};
7946
8305
  if (material.sheenRoughnessMap) {
7947
8306
  const sheenRoughnessMapDef = {
7948
- index: writer.processTexture(material.sheenRoughnessMap),
8307
+ index: await writer.processTextureAsync(material.sheenRoughnessMap),
7949
8308
  texCoord: material.sheenRoughnessMap.channel
7950
8309
  };
7951
8310
  writer.applyTextureTransform(sheenRoughnessMapDef, material.sheenRoughnessMap);
@@ -7953,7 +8312,7 @@ var GLTFMaterialsSheenExtension = class {
7953
8312
  }
7954
8313
  if (material.sheenColorMap) {
7955
8314
  const sheenColorMapDef = {
7956
- index: writer.processTexture(material.sheenColorMap),
8315
+ index: await writer.processTextureAsync(material.sheenColorMap),
7957
8316
  texCoord: material.sheenColorMap.channel
7958
8317
  };
7959
8318
  writer.applyTextureTransform(sheenColorMapDef, material.sheenColorMap);
@@ -7971,13 +8330,13 @@ var GLTFMaterialsAnisotropyExtension = class {
7971
8330
  this.writer = writer;
7972
8331
  this.name = "KHR_materials_anisotropy";
7973
8332
  }
7974
- writeMaterial(material, materialDef) {
8333
+ async writeMaterialAsync(material, materialDef) {
7975
8334
  if (!material.isMeshPhysicalMaterial || material.anisotropy == 0) return;
7976
8335
  const writer = this.writer;
7977
8336
  const extensionsUsed = writer.extensionsUsed;
7978
8337
  const extensionDef = {};
7979
8338
  if (material.anisotropyMap) {
7980
- const anisotropyMapDef = { index: writer.processTexture(material.anisotropyMap) };
8339
+ const anisotropyMapDef = { index: await writer.processTextureAsync(material.anisotropyMap) };
7981
8340
  writer.applyTextureTransform(anisotropyMapDef, material.anisotropyMap);
7982
8341
  extensionDef.anisotropyTexture = anisotropyMapDef;
7983
8342
  }
@@ -7993,7 +8352,7 @@ var GLTFMaterialsEmissiveStrengthExtension = class {
7993
8352
  this.writer = writer;
7994
8353
  this.name = "KHR_materials_emissive_strength";
7995
8354
  }
7996
- writeMaterial(material, materialDef) {
8355
+ async writeMaterialAsync(material, materialDef) {
7997
8356
  if (!material.isMeshStandardMaterial || material.emissiveIntensity === 1) return;
7998
8357
  const writer = this.writer;
7999
8358
  const extensionsUsed = writer.extensionsUsed;
@@ -8004,6 +8363,30 @@ var GLTFMaterialsEmissiveStrengthExtension = class {
8004
8363
  extensionsUsed[this.name] = true;
8005
8364
  }
8006
8365
  };
8366
+ var GLTFMaterialsBumpExtension = class {
8367
+ constructor(writer) {
8368
+ this.writer = writer;
8369
+ this.name = "EXT_materials_bump";
8370
+ }
8371
+ async writeMaterialAsync(material, materialDef) {
8372
+ if (!material.isMeshStandardMaterial || material.bumpScale === 1 && !material.bumpMap) return;
8373
+ const writer = this.writer;
8374
+ const extensionsUsed = writer.extensionsUsed;
8375
+ const extensionDef = {};
8376
+ if (material.bumpMap) {
8377
+ const bumpMapDef = {
8378
+ index: await writer.processTextureAsync(material.bumpMap),
8379
+ texCoord: material.bumpMap.channel
8380
+ };
8381
+ writer.applyTextureTransform(bumpMapDef, material.bumpMap);
8382
+ extensionDef.bumpTexture = bumpMapDef;
8383
+ }
8384
+ extensionDef.bumpFactor = material.bumpScale;
8385
+ materialDef.extensions = materialDef.extensions || {};
8386
+ materialDef.extensions[this.name] = extensionDef;
8387
+ extensionsUsed[this.name] = true;
8388
+ }
8389
+ };
8007
8390
  var GLTFMeshGpuInstancing = class {
8008
8391
  constructor(writer) {
8009
8392
  this.writer = writer;
@@ -8139,6 +8522,19 @@ GLTFExporter.Utils = {
8139
8522
  }
8140
8523
  clip.tracks = tracks;
8141
8524
  return clip;
8525
+ },
8526
+ toTypedBufferAttribute: function(srcAttribute, TypedArray) {
8527
+ const dstAttribute = new BufferAttribute3(new TypedArray(srcAttribute.count * srcAttribute.itemSize), srcAttribute.itemSize, false);
8528
+ if (!srcAttribute.normalized && !srcAttribute.isInterleavedBufferAttribute) {
8529
+ dstAttribute.array.set(srcAttribute.array);
8530
+ return dstAttribute;
8531
+ }
8532
+ for (let i = 0, il = srcAttribute.count; i < il; i++) {
8533
+ for (let j = 0; j < srcAttribute.itemSize; j++) {
8534
+ dstAttribute.setComponent(i, j, srcAttribute.getComponent(i, j));
8535
+ }
8536
+ }
8537
+ return dstAttribute;
8142
8538
  }
8143
8539
  };
8144
8540
 
@@ -8193,7 +8589,7 @@ function localMatrix(object) {
8193
8589
  return object.matrixAutoUpdate ? new Matrix47().compose(object.position, object.quaternion, object.scale) : object.matrix.clone();
8194
8590
  }
8195
8591
  function createSnapshot(root, gltf, bakeColors = false) {
8196
- const scene = new Scene4();
8592
+ const scene = new Scene3();
8197
8593
  const geometries = [];
8198
8594
  const materials = [];
8199
8595
  const textures = [];
@@ -8288,7 +8684,7 @@ function createSnapshot(root, gltf, bakeColors = false) {
8288
8684
  material.color.copy(tint);
8289
8685
  }
8290
8686
  }
8291
- const copy = new Mesh5(geometry, material);
8687
+ const copy = new Mesh4(geometry, material);
8292
8688
  copy.name = mesh.name;
8293
8689
  copy.renderOrder = mesh.renderOrder;
8294
8690
  scene.add(copy);
@@ -8367,7 +8763,7 @@ function selectAlphaMode(material, geometry) {
8367
8763
  }
8368
8764
  function copyDataTexture(source) {
8369
8765
  const image = source.image;
8370
- if (source.format !== RGBAFormat3 || source.type !== UnsignedByteType) {
8766
+ if (!image.data || source.format !== RGBAFormat3 || source.type !== UnsignedByteType) {
8371
8767
  throw new MineRenderError("glTF export requires RGBA unsigned-byte data textures");
8372
8768
  }
8373
8769
  const canvas = createCanvas2(image.width, image.height);
@@ -8378,8 +8774,8 @@ function copyDataTexture(source) {
8378
8774
  context.putImageData(pixels, 0, 0);
8379
8775
  const copySource = Object.create(source);
8380
8776
  copySource.userData = {};
8381
- copySource.source = new Source2(canvas);
8382
- return new Texture4().copy(copySource);
8777
+ copySource.source = new TextureSource2(canvas);
8778
+ return new Texture3().copy(copySource);
8383
8779
  }
8384
8780
 
8385
8781
  // src/gui/GuiHelper.ts
@@ -8448,6 +8844,85 @@ var GuiHelper = class {
8448
8844
  }
8449
8845
  };
8450
8846
 
8847
+ // src/gui/GuiTextureGeometry.ts
8848
+ import { BufferGeometry as BufferGeometry2, Float32BufferAttribute as Float32BufferAttribute4, PlaneGeometry } from "three";
8849
+ function createGuiTextureGeometry(width, height, imageWidth, imageHeight, crop, scaling) {
8850
+ if (crop || !scaling || scaling.type === "stretch") {
8851
+ const [x, y, w, h] = crop ?? [0, 0, imageWidth, imageHeight];
8852
+ const geometry = new PlaneGeometry(width, height);
8853
+ const uv = geometry.getAttribute("uv");
8854
+ for (let i = 0; i < uv.count; i++) {
8855
+ uv.setXY(
8856
+ i,
8857
+ (x + uv.getX(i) * w) / imageWidth,
8858
+ 1 - (y + (1 - uv.getY(i)) * h) / imageHeight
8859
+ );
8860
+ }
8861
+ return geometry;
8862
+ }
8863
+ const sw = scaling.width, sh = scaling.height;
8864
+ if (![sw, sh].every((value) => Number.isInteger(value) && value > 0)) {
8865
+ throw new Error("GUI sprite dimensions must be positive integers");
8866
+ }
8867
+ if (![width, height].every((value) => Number.isFinite(value) && value >= 0)) {
8868
+ throw new Error("GUI output dimensions must be finite and nonnegative");
8869
+ }
8870
+ const positions = [], uvs = [], normals = [], indices = [];
8871
+ function quad(x, y, w, h, u, v, uw, vh) {
8872
+ if (w <= 0 || h <= 0) return;
8873
+ const index = positions.length / 3;
8874
+ const left = x - width / 2, top = height / 2 - y;
8875
+ positions.push(left, top, 0, left + w, top, 0, left, top - h, 0, left + w, top - h, 0);
8876
+ uvs.push(
8877
+ u / sw,
8878
+ 1 - v / sh,
8879
+ (u + uw) / sw,
8880
+ 1 - v / sh,
8881
+ u / sw,
8882
+ 1 - (v + vh) / sh,
8883
+ (u + uw) / sw,
8884
+ 1 - (v + vh) / sh
8885
+ );
8886
+ normals.push(0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1);
8887
+ indices.push(index, index + 2, index + 1, index + 2, index + 3, index + 1);
8888
+ }
8889
+ function tile(x, y, w, h, u, v, tw, th) {
8890
+ for (let dy = 0; dy < h; dy += th) {
8891
+ for (let dx = 0; dx < w; dx += tw) {
8892
+ const cw = Math.min(tw, w - dx), ch = Math.min(th, h - dy);
8893
+ quad(x + dx, y + dy, cw, ch, u, v, cw, ch);
8894
+ }
8895
+ }
8896
+ }
8897
+ if (scaling.type === "tile") {
8898
+ tile(0, 0, width, height, 0, 0, sw, sh);
8899
+ } else {
8900
+ let segments = function(size, sourceSize, start, end) {
8901
+ if (size === sourceSize) return [[0, size, 0, sourceSize]];
8902
+ start = Math.min(start, Math.floor(size / 2));
8903
+ end = Math.min(end, Math.floor(size / 2));
8904
+ return [
8905
+ [0, start, 0, start],
8906
+ [start, size - start - end, start, sourceSize - start - end],
8907
+ [size - end, end, sourceSize - end, end]
8908
+ ];
8909
+ };
8910
+ const border = typeof scaling.border === "number" ? { left: scaling.border, top: scaling.border, right: scaling.border, bottom: scaling.border } : scaling.border;
8911
+ 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) {
8912
+ throw new Error("GUI nine-slice borders must be nonnegative integers with a nonempty center");
8913
+ }
8914
+ const columns = segments(width, sw, border.left, border.right);
8915
+ const rows = segments(height, sh, border.top, border.bottom);
8916
+ for (const [y, h, v, vh] of rows) {
8917
+ for (const [x, w, u, uw] of columns) {
8918
+ if (w <= 0 || h <= 0) continue;
8919
+ (scaling.stretch_inner ? quad : tile)(x, y, w, h, u, v, uw, vh);
8920
+ }
8921
+ }
8922
+ }
8923
+ return new BufferGeometry2().setAttribute("position", new Float32BufferAttribute4(positions, 3)).setAttribute("normal", new Float32BufferAttribute4(normals, 3)).setAttribute("uv", new Float32BufferAttribute4(uvs, 2)).setIndex(indices);
8924
+ }
8925
+
8451
8926
  // src/gui/scene/GuiObject.ts
8452
8927
  init_AssetKey();
8453
8928
  init_ModelTextures();
@@ -8458,7 +8933,7 @@ init_Materials();
8458
8933
  init_ModelObject();
8459
8934
  init_DisplayPosition();
8460
8935
  init_GuiLight();
8461
- import { Box2, Box3 as Box32, Matrix4 as Matrix410, Mesh as Mesh7, PlaneGeometry as PlaneGeometry2, Vector2 as Vector23 } from "three";
8936
+ import { Box2, Box3 as Box32, Matrix4 as Matrix410, Mesh as Mesh6, Vector2 as Vector23 } from "three";
8462
8937
  var GuiObject = class extends SceneObject {
8463
8938
  constructor(textureLayers, options) {
8464
8939
  super({ ...options, instanceMeshes: false, mergeMeshes: false });
@@ -8499,19 +8974,11 @@ var GuiObject = class extends SceneObject {
8499
8974
  const key = typeof layer.texture === "string" ? AssetKey.parse("textures", layer.texture) : layer.texture;
8500
8975
  const material = await this.loadMaterial(key);
8501
8976
  const image = material.map.image;
8502
- const [cropX, cropY, cropWidth, cropHeight] = layer.crop ?? [0, 0, image.width, image.height];
8503
- const [width, height] = layer.size ?? [cropWidth, cropHeight];
8504
- const geometry = new PlaneGeometry2(width, height);
8977
+ const scaling = layer.crop ? void 0 : (await ModelTextures.getMeta(key))?.gui?.scaling;
8978
+ const [width, height] = layer.size ?? (layer.crop ? layer.crop.slice(2) : scaling && scaling.type !== "stretch" ? [scaling.width, scaling.height] : [image.width, image.height]);
8979
+ const geometry = createGuiTextureGeometry(width, height, image.width, image.height, layer.crop, scaling);
8505
8980
  this.geometries.add(geometry);
8506
- const uv = geometry.getAttribute("uv");
8507
- for (let i = 0; i < uv.count; i++) {
8508
- uv.setXY(
8509
- i,
8510
- (cropX + uv.getX(i) * cropWidth) / image.width,
8511
- 1 - (cropY + (1 - uv.getY(i)) * cropHeight) / image.height
8512
- );
8513
- }
8514
- const mesh = new Mesh7(geometry, material);
8981
+ const mesh = new Mesh6(geometry, material);
8515
8982
  mesh.name = `mesh:${layer.name ?? index}`;
8516
8983
  mesh.position.set(x + width / 2, -y - height / 2, depth);
8517
8984
  mesh.renderOrder = index;
@@ -9353,6 +9820,7 @@ var BlockObject = class _BlockObject extends SceneObject {
9353
9820
  replacement.setMatrix(matrix);
9354
9821
  } else {
9355
9822
  replacement.matrix.copy(matrix);
9823
+ replacement.matrixWorldNeedsUpdate = true;
9356
9824
  matrix.decompose(replacement.position, replacement.quaternion, replacement.scale);
9357
9825
  replacement.matrixAutoUpdate = object.matrixAutoUpdate;
9358
9826
  replacement.visible = object.visible;
@@ -11411,7 +11879,7 @@ init_nbt();
11411
11879
  init_SceneObject();
11412
11880
  var import_ts_deepmerge8 = __toESM(require_dist());
11413
11881
  init_ModelObject();
11414
- import { Scene as Scene5 } from "three";
11882
+ import { Scene as Scene4 } from "three";
11415
11883
 
11416
11884
  // src/skin/scene/SkinObject.ts
11417
11885
  init_SceneObject();
@@ -12144,7 +12612,7 @@ init_util();
12144
12612
  init_Caching();
12145
12613
  init_CacheKey();
12146
12614
  init_MineRenderError();
12147
- import { DataTexture as DataTexture2, DoubleSide as DoubleSide4, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial6, SRGBColorSpace as SRGBColorSpace5 } from "three";
12615
+ import { DataTexture as DataTexture2, DoubleSide as DoubleSide4, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial6, SRGBColorSpace as SRGBColorSpace6 } from "three";
12148
12616
 
12149
12617
  // src/skin/SkinImage.ts
12150
12618
  init_Caching();
@@ -12226,7 +12694,7 @@ var SkinTextures = class {
12226
12694
  }
12227
12695
  static createMaterial(pixels, width, height, transparent = true) {
12228
12696
  const texture = Textures.initTextureProps(new DataTexture2(pixels, width, height));
12229
- texture.colorSpace = SRGBColorSpace5;
12697
+ texture.colorSpace = SRGBColorSpace6;
12230
12698
  texture.flipY = true;
12231
12699
  texture.needsUpdate = true;
12232
12700
  return new MeshBasicMaterial6({ map: texture, transparent, side: transparent ? DoubleSide4 : FrontSide2, alphaTest: transparent ? 0.1 : 0 });
@@ -12459,7 +12927,7 @@ var SkinObject = class extends SceneObject {
12459
12927
  // src/renderer/MineRenderScene.ts
12460
12928
  init_EntityObject();
12461
12929
  init_ItemTints();
12462
- var MineRenderScene = class _MineRenderScene extends Scene5 {
12930
+ var MineRenderScene = class _MineRenderScene extends Scene4 {
12463
12931
  constructor(options) {
12464
12932
  super();
12465
12933
  this.isMineRenderScene = true;
@@ -12505,12 +12973,13 @@ var MineRenderScene = class _MineRenderScene extends Scene5 {
12505
12973
  }
12506
12974
  updateObjectRegistration(object, attached) {
12507
12975
  if (this.observedObjects.has(object) === attached) return;
12976
+ const observable = object;
12508
12977
  if (attached) {
12509
12978
  this.observedObjects.add(object);
12510
- object.addEventListener("change", this.onObjectChange);
12979
+ observable.addEventListener("change", this.onObjectChange);
12511
12980
  } else {
12512
12981
  this.observedObjects.delete(object);
12513
- object.removeEventListener("change", this.onObjectChange);
12982
+ observable.removeEventListener("change", this.onObjectChange);
12514
12983
  }
12515
12984
  const change = attached ? 1 : -1;
12516
12985
  this.stats.objectCount += change;
@@ -12588,7 +13057,7 @@ function isMineRenderScene(obj) {
12588
13057
  }
12589
13058
 
12590
13059
  // src/renderer/Renderer.ts
12591
- import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera as PerspectiveCamera2, SRGBColorSpace as SRGBColorSpace6, Vector3 as Vector314, WebGLRenderer as WebGLRenderer2 } from "three";
13060
+ import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace7, Vector3 as Vector314, WebGLRenderer } from "three";
12592
13061
  var import_ts_deepmerge9 = __toESM(require_dist());
12593
13062
  init_util();
12594
13063
  init_Model();
@@ -13333,7 +13802,7 @@ var Renderer = class _Renderer {
13333
13802
  switch (this.options.camera.type) {
13334
13803
  case "perspective":
13335
13804
  default:
13336
- return new PerspectiveCamera2(
13805
+ return new PerspectiveCamera(
13337
13806
  this.options.camera.perspective.fov,
13338
13807
  this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
13339
13808
  this.options.camera.near,
@@ -13351,7 +13820,7 @@ var Renderer = class _Renderer {
13351
13820
  }
13352
13821
  }
13353
13822
  createRenderer() {
13354
- const renderer = new WebGLRenderer2({
13823
+ const renderer = new WebGLRenderer({
13355
13824
  antialias: this.options.render.antialias,
13356
13825
  alpha: true,
13357
13826
  powerPreference: "high-performance",
@@ -13359,8 +13828,8 @@ var Renderer = class _Renderer {
13359
13828
  });
13360
13829
  renderer.setClearColor(0, 0);
13361
13830
  renderer.shadowMap.enabled = true;
13362
- renderer.shadowMap.type = PCFSoftShadowMap;
13363
- renderer.outputColorSpace = SRGBColorSpace6;
13831
+ renderer.shadowMap.type = PCFShadowMap;
13832
+ renderer.outputColorSpace = SRGBColorSpace7;
13364
13833
  renderer.setPixelRatio(this.options.render.pixelRatio ?? 1);
13365
13834
  renderer.setSize(this.viewWidth, this.viewHeight);
13366
13835
  return renderer;
@@ -14438,7 +14907,7 @@ init_Model();
14438
14907
  // src/world/SectionMesh.ts
14439
14908
  init_CanvasCompat();
14440
14909
  init_Materials();
14441
- import { BufferGeometry as BufferGeometry6, Float32BufferAttribute as Float32BufferAttribute6, Group, Mesh as Mesh10 } from "three";
14910
+ import { BufferGeometry as BufferGeometry7, Float32BufferAttribute as Float32BufferAttribute7, Group, Mesh as Mesh9 } from "three";
14442
14911
  var SectionMesh = class _SectionMesh extends Group {
14443
14912
  constructor() {
14444
14913
  super(...arguments);
@@ -14512,18 +14981,18 @@ var SectionMesh = class _SectionMesh extends Group {
14512
14981
  for (let corner = 0; corner < 6; corner++) indices.push(start + sourceIndices.getX(face * 6 + corner) - face * 4);
14513
14982
  }
14514
14983
  }
14515
- const geometry = new BufferGeometry6();
14516
- geometry.setAttribute("position", new Float32BufferAttribute6(positions, 3));
14517
- geometry.setAttribute("normal", new Float32BufferAttribute6(normals, 3));
14518
- geometry.setAttribute("uv", new Float32BufferAttribute6(uvs, 2));
14519
- geometry.setAttribute("color", new Float32BufferAttribute6(colors, 3));
14984
+ const geometry = new BufferGeometry7();
14985
+ geometry.setAttribute("position", new Float32BufferAttribute7(positions, 3));
14986
+ geometry.setAttribute("normal", new Float32BufferAttribute7(normals, 3));
14987
+ geometry.setAttribute("uv", new Float32BufferAttribute7(uvs, 2));
14988
+ geometry.setAttribute("color", new Float32BufferAttribute7(colors, 3));
14520
14989
  geometry.setIndex(indices);
14521
14990
  geometry.computeBoundingBox();
14522
14991
  geometry.computeBoundingSphere();
14523
14992
  const material = Materials.createShadedCanvasMaterial(canvas, false);
14524
14993
  material.vertexColors = true;
14525
14994
  const texture = material.uniforms?.map?.value ?? material.map;
14526
- const mesh = new Mesh10(geometry, material);
14995
+ const mesh = new Mesh9(geometry, material);
14527
14996
  section.add(mesh);
14528
14997
  section.ownedMeshes.push({ mesh, texture });
14529
14998
  }
@@ -14537,6 +15006,7 @@ var SectionMesh = class _SectionMesh extends Group {
14537
15006
  texture?.dispose();
14538
15007
  }
14539
15008
  this.removeFromParent();
15009
+ super.dispose();
14540
15010
  }
14541
15011
  };
14542
15012
 
@@ -14840,6 +15310,7 @@ export {
14840
15310
  computeTangents,
14841
15311
  createCanvas2 as createCanvas,
14842
15312
  createFluidGeometry,
15313
+ createGuiTextureGeometry,
14843
15314
  createImage,
14844
15315
  entityAnimationTime,
14845
15316
  estimateBytesUsed,