minerender 2.1.0-alpha.65 → 2.1.0-alpha.67

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.
@@ -2920,16 +2920,17 @@ var init_UVMapper = __esm({
2920
2920
  positions[textureKey] = [x, y];
2921
2921
  const [width, height] = sizes[textureKey];
2922
2922
  const sequence = frames[textureKey];
2923
- const drawFrame = (index) => {
2923
+ const getFrameData = (index) => {
2924
2924
  const columns = texture.width / width;
2925
- image.putData(texture.getSectionData(
2925
+ return texture.getSectionData(
2926
2926
  index % columns * width,
2927
2927
  Math.floor(index / columns) * height,
2928
2928
  width,
2929
2929
  height
2930
- ), x, y);
2930
+ );
2931
2931
  };
2932
- drawFrame(sequence?.[0].index ?? 0);
2932
+ const firstFrame = getFrameData(sequence?.[0].index ?? 0);
2933
+ image.putData(firstFrame, x, y);
2933
2934
  if (texture.hasTransparency) {
2934
2935
  hasTransparency = true;
2935
2936
  }
@@ -2937,13 +2938,28 @@ var init_UVMapper = __esm({
2937
2938
  hasAnimation = true;
2938
2939
  let t = 0;
2939
2940
  let f = 0;
2941
+ const interpolated = metaMap[textureKey]?.animation?.interpolate ? image.context.createImageData(width, height) : void 0;
2942
+ let currentFrame = firstFrame;
2943
+ let nextFrame = interpolated ? getFrameData(sequence[1].index) : firstFrame;
2940
2944
  animatorFunctions[textureKey] = () => {
2941
- if (++t < sequence[f].time) return false;
2942
- t = 0;
2943
- const previous = sequence[f].index;
2944
- f = (f + 1) % sequence.length;
2945
- if (sequence[f].index === previous) return false;
2946
- drawFrame(sequence[f].index);
2945
+ if (++t >= sequence[f].time) {
2946
+ t = 0;
2947
+ const previous = sequence[f].index;
2948
+ f = (f + 1) % sequence.length;
2949
+ if (interpolated) {
2950
+ currentFrame = nextFrame;
2951
+ nextFrame = getFrameData(sequence[(f + 1) % sequence.length].index);
2952
+ }
2953
+ if (sequence[f].index === previous) return false;
2954
+ image.putData(interpolated ? currentFrame : getFrameData(sequence[f].index), x, y);
2955
+ return true;
2956
+ }
2957
+ if (!interpolated || sequence[f].index === sequence[(f + 1) % sequence.length].index) return false;
2958
+ const progress = Math.floor(Math.fround(Math.fround(t / sequence[f].time) * 1e3)) / 1e3;
2959
+ for (let i = 0; i < interpolated.data.length; i++) {
2960
+ interpolated.data[i] = currentFrame.data[i] + (nextFrame.data[i] - currentFrame.data[i]) * progress;
2961
+ }
2962
+ image.putData(interpolated, x, y);
2947
2963
  return true;
2948
2964
  };
2949
2965
  }
@@ -3496,7 +3512,7 @@ var init_InstanceReference = __esm({
3496
3512
  });
3497
3513
 
3498
3514
  // src/renderer/SceneObject.ts
3499
- import { Color as Color2, Euler as Euler4, InstancedBufferAttribute, InstancedMesh, MathUtils, Matrix4 as Matrix44, Mesh as Mesh3, Object3D as Object3D2, Quaternion as Quaternion3, Vector3 as Vector36 } from "three";
3515
+ import { Color as Color2, Euler as Euler4, InstancedBufferAttribute, InstancedMesh, Matrix4 as Matrix44, Mesh as Mesh3, Object3D as Object3D2, Quaternion as Quaternion3, Vector3 as Vector36 } from "three";
3500
3516
  function isSceneObject(obj) {
3501
3517
  return obj.isSceneObject;
3502
3518
  }
@@ -3924,6 +3940,7 @@ var init_SceneObject = __esm({
3924
3940
  dispose() {
3925
3941
  this.disposeAndRemoveAllChildren();
3926
3942
  this.notifyDirty();
3943
+ super.dispose();
3927
3944
  }
3928
3945
  disposeAndRemoveAllChildren() {
3929
3946
  if (this.instanceMesh) {
@@ -4141,6 +4158,7 @@ var init_EntityObject = __esm({
4141
4158
  else matrix.makeRotationFromEuler(new Euler5(...op.rotate, "ZYX"));
4142
4159
  modelRoot.matrix.multiply(matrix);
4143
4160
  }
4161
+ modelRoot.matrixWorldNeedsUpdate = true;
4144
4162
  modelRoot.matrixAutoUpdate = false;
4145
4163
  } else if (this.options.flip ?? true) {
4146
4164
  modelRoot.scale.set(-1, -1, 1);
@@ -5056,6 +5074,7 @@ var init_ModelObject = __esm({
5056
5074
  for (const part of parts) {
5057
5075
  const object = new EntityObject(part.model, { flip: false, wireframe: this.options.wireframe });
5058
5076
  object.matrix.copy(transform).multiply(part.transform);
5077
+ object.matrixWorldNeedsUpdate = true;
5059
5078
  object.matrixAutoUpdate = false;
5060
5079
  this.add(object);
5061
5080
  await object.init();
@@ -5767,16 +5786,26 @@ init_EntityObject();
5767
5786
  init_MineRenderError();
5768
5787
 
5769
5788
  // src/export/SceneExporter.ts
5770
- import { ClampToEdgeWrapping as ClampToEdgeWrapping2, Color as Color7, Float32BufferAttribute as Float32BufferAttribute3, Matrix4 as Matrix47, Mesh as Mesh5, MeshBasicMaterial as MeshBasicMaterial2, NearestFilter as NearestFilter3, RGBAFormat as RGBAFormat3, Scene as Scene4, Source as Source2, Texture as Texture4, UnsignedByteType } from "three";
5789
+ import { ClampToEdgeWrapping as ClampToEdgeWrapping2, Color as Color7, Float32BufferAttribute as Float32BufferAttribute3, Matrix4 as Matrix47, Mesh as Mesh4, MeshBasicMaterial as MeshBasicMaterial2, NearestFilter as NearestFilter3, RGBAFormat as RGBAFormat3, Scene as Scene3, TextureSource as TextureSource2, Texture as Texture3, UnsignedByteType } from "three";
5771
5790
 
5772
5791
  // ../../node_modules/three/examples/jsm/exporters/OBJExporter.js
5773
5792
  import {
5774
5793
  Color as Color4,
5794
+ ColorManagement,
5775
5795
  Matrix3,
5796
+ SRGBColorSpace as SRGBColorSpace3,
5776
5797
  Vector2 as Vector22,
5777
5798
  Vector3 as Vector37
5778
5799
  } from "three";
5779
5800
  var OBJExporter = class {
5801
+ /**
5802
+ * Parses the given 3D object and generates the OBJ output.
5803
+ *
5804
+ * If the 3D object is composed of multiple children and geometry, they are merged into a single mesh in the file.
5805
+ *
5806
+ * @param {Object3D} object - The 3D object to export.
5807
+ * @return {string} The exported OBJ.
5808
+ */
5780
5809
  parse(object) {
5781
5810
  let output = "";
5782
5811
  let indexVertex = 0;
@@ -5882,7 +5911,8 @@ var OBJExporter = class {
5882
5911
  vertex.applyMatrix4(points.matrixWorld);
5883
5912
  output += "v " + vertex.x + " " + vertex.y + " " + vertex.z;
5884
5913
  if (colors !== void 0) {
5885
- color.fromBufferAttribute(colors, i).convertLinearToSRGB();
5914
+ color.fromBufferAttribute(colors, i);
5915
+ ColorManagement.workingToColorSpace(color, SRGBColorSpace3);
5886
5916
  output += " " + color.r + " " + color.g + " " + color.b;
5887
5917
  }
5888
5918
  output += "\n";
@@ -5914,9 +5944,21 @@ var OBJExporter = class {
5914
5944
  import {
5915
5945
  Matrix3 as Matrix32,
5916
5946
  Vector3 as Vector38,
5917
- Color as Color5
5947
+ Color as Color5,
5948
+ ColorManagement as ColorManagement2,
5949
+ SRGBColorSpace as SRGBColorSpace4
5918
5950
  } from "three";
5919
5951
  var PLYExporter = class {
5952
+ /**
5953
+ * Parses the given 3D object and generates the PLY output.
5954
+ *
5955
+ * If the 3D object is composed of multiple children and geometry, they are merged into a single mesh in the file.
5956
+ *
5957
+ * @param {Object3D} object - The 3D object to export.
5958
+ * @param {PLYExporter~OnDone} onDone - A callback function that is executed when the export has finished.
5959
+ * @param {PLYExporter~Options} options - The export options.
5960
+ * @return {?(string|ArrayBuffer)} The exported PLY.
5961
+ */
5920
5962
  parse(object, onDone, options = {}) {
5921
5963
  function traverseMeshes(cb) {
5922
5964
  object.traverse(function(child) {
@@ -5933,14 +5975,23 @@ var PLYExporter = class {
5933
5975
  binary: false,
5934
5976
  excludeAttributes: [],
5935
5977
  // normal, uv, color, index
5936
- littleEndian: false
5978
+ littleEndian: false,
5979
+ customPropertyMapping: {}
5937
5980
  };
5938
5981
  options = Object.assign(defaultOptions, options);
5939
5982
  const excludeAttributes = options.excludeAttributes;
5983
+ const customPropertyMapping = options.customPropertyMapping;
5984
+ const customAttributeNames = Object.keys(customPropertyMapping);
5940
5985
  let includeIndices = true;
5941
5986
  let includeNormals = false;
5942
5987
  let includeColors = false;
5943
5988
  let includeUVs = false;
5989
+ let positionType = "float";
5990
+ let normalType = "float";
5991
+ let uvType = "float";
5992
+ let colorType = "uchar";
5993
+ const customTypes = {};
5994
+ for (const name of customAttributeNames) customTypes[name] = "float";
5944
5995
  let vertexCount = 0;
5945
5996
  let faceCount = 0;
5946
5997
  object.traverse(function(child) {
@@ -5957,9 +6008,23 @@ var PLYExporter = class {
5957
6008
  }
5958
6009
  vertexCount += vertices.count;
5959
6010
  faceCount += indices ? indices.count / 3 : vertices.count / 3;
5960
- if (normals !== void 0) includeNormals = true;
5961
- if (uvs !== void 0) includeUVs = true;
5962
- if (colors !== void 0) includeColors = true;
6011
+ positionType = getPlyType(vertices.array);
6012
+ if (normals !== void 0) {
6013
+ includeNormals = true;
6014
+ normalType = getPlyType(normals.array);
6015
+ }
6016
+ if (uvs !== void 0) {
6017
+ includeUVs = true;
6018
+ uvType = getPlyType(uvs.array);
6019
+ }
6020
+ if (colors !== void 0) {
6021
+ includeColors = true;
6022
+ colorType = getPlyType(colors.array);
6023
+ }
6024
+ for (const name of customAttributeNames) {
6025
+ const attr = geometry.getAttribute(name);
6026
+ if (attr !== void 0) customTypes[name] = getPlyType(attr.array);
6027
+ }
5963
6028
  } else if (child.isPoints) {
5964
6029
  const mesh = child;
5965
6030
  const geometry = mesh.geometry;
@@ -5967,8 +6032,19 @@ var PLYExporter = class {
5967
6032
  const normals = geometry.getAttribute("normal");
5968
6033
  const colors = geometry.getAttribute("color");
5969
6034
  vertexCount += vertices.count;
5970
- if (normals !== void 0) includeNormals = true;
5971
- if (colors !== void 0) includeColors = true;
6035
+ positionType = getPlyType(vertices.array);
6036
+ if (normals !== void 0) {
6037
+ includeNormals = true;
6038
+ normalType = getPlyType(normals.array);
6039
+ }
6040
+ if (colors !== void 0) {
6041
+ includeColors = true;
6042
+ colorType = getPlyType(colors.array);
6043
+ }
6044
+ for (const name of customAttributeNames) {
6045
+ const attr = geometry.getAttribute(name);
6046
+ if (attr !== void 0) customTypes[name] = getPlyType(attr.array);
6047
+ }
5972
6048
  includeIndices = false;
5973
6049
  }
5974
6050
  });
@@ -5987,18 +6063,33 @@ var PLYExporter = class {
5987
6063
  let header = `ply
5988
6064
  format ${options.binary ? options.littleEndian ? "binary_little_endian" : "binary_big_endian" : "ascii"} 1.0
5989
6065
  element vertex ${vertexCount}
5990
- property float x
5991
- property float y
5992
- property float z
6066
+ property ${positionType} x
6067
+ property ${positionType} y
6068
+ property ${positionType} z
5993
6069
  `;
5994
6070
  if (includeNormals === true) {
5995
- header += "property float nx\nproperty float ny\nproperty float nz\n";
6071
+ header += `property ${normalType} nx
6072
+ property ${normalType} ny
6073
+ property ${normalType} nz
6074
+ `;
5996
6075
  }
5997
6076
  if (includeUVs === true) {
5998
- header += "property float s\nproperty float t\n";
6077
+ header += `property ${uvType} s
6078
+ property ${uvType} t
6079
+ `;
5999
6080
  }
6000
6081
  if (includeColors === true) {
6001
- header += "property uchar red\nproperty uchar green\nproperty uchar blue\n";
6082
+ header += `property ${colorType} red
6083
+ property ${colorType} green
6084
+ property ${colorType} blue
6085
+ `;
6086
+ }
6087
+ for (const name of customAttributeNames) {
6088
+ const type = customTypes[name];
6089
+ for (const propName of customPropertyMapping[name]) {
6090
+ header += `property ${type} ${propName}
6091
+ `;
6092
+ }
6002
6093
  }
6003
6094
  if (includeIndices === true) {
6004
6095
  header += `element face ${faceCount}
@@ -6011,7 +6102,23 @@ property list uchar int vertex_index
6011
6102
  let result = null;
6012
6103
  if (options.binary === true) {
6013
6104
  const headerBin = new TextEncoder().encode(header);
6014
- const vertexListLength = vertexCount * (4 * 3 + (includeNormals ? 4 * 3 : 0) + (includeColors ? 3 : 0) + (includeUVs ? 4 * 2 : 0));
6105
+ const posWriter = getBinaryWriter(positionType);
6106
+ const normalWriter = includeNormals ? getBinaryWriter(normalType) : null;
6107
+ const uvWriter = includeUVs ? getBinaryWriter(uvType) : null;
6108
+ const colorWriter = includeColors ? getBinaryWriter(colorType) : null;
6109
+ const colorIsFloat = isFloatType(colorType);
6110
+ const colorScale = getColorScale(colorType);
6111
+ const customWriters = {};
6112
+ const customIsFloat = {};
6113
+ let customStride = 0;
6114
+ for (const name of customAttributeNames) {
6115
+ const type = customTypes[name];
6116
+ const writer = getBinaryWriter(type);
6117
+ customWriters[name] = writer;
6118
+ customIsFloat[name] = isFloatType(type);
6119
+ customStride += customPropertyMapping[name].length * writer.size;
6120
+ }
6121
+ const vertexListLength = vertexCount * (3 * posWriter.size + (includeNormals ? 3 * normalWriter.size : 0) + (includeUVs ? 2 * uvWriter.size : 0) + (includeColors ? 3 * colorWriter.size : 0) + customStride);
6015
6122
  const faceListLength = includeIndices ? faceCount * (indexByteCount * 3 + 1) : 0;
6016
6123
  const output = new DataView(new ArrayBuffer(headerBin.length + vertexListLength + faceListLength));
6017
6124
  new Uint8Array(output.buffer).set(headerBin, 0);
@@ -6028,60 +6135,76 @@ property list uchar int vertex_index
6028
6135
  for (let i = 0, l = vertices.count; i < l; i++) {
6029
6136
  vertex.fromBufferAttribute(vertices, i);
6030
6137
  vertex.applyMatrix4(mesh.matrixWorld);
6031
- output.setFloat32(vOffset, vertex.x, options.littleEndian);
6032
- vOffset += 4;
6033
- output.setFloat32(vOffset, vertex.y, options.littleEndian);
6034
- vOffset += 4;
6035
- output.setFloat32(vOffset, vertex.z, options.littleEndian);
6036
- vOffset += 4;
6138
+ posWriter.write(output, vOffset, vertex.x, options.littleEndian);
6139
+ vOffset += posWriter.size;
6140
+ posWriter.write(output, vOffset, vertex.y, options.littleEndian);
6141
+ vOffset += posWriter.size;
6142
+ posWriter.write(output, vOffset, vertex.z, options.littleEndian);
6143
+ vOffset += posWriter.size;
6037
6144
  if (includeNormals === true) {
6038
6145
  if (normals != null) {
6039
6146
  vertex.fromBufferAttribute(normals, i);
6040
6147
  vertex.applyMatrix3(normalMatrixWorld).normalize();
6041
- output.setFloat32(vOffset, vertex.x, options.littleEndian);
6042
- vOffset += 4;
6043
- output.setFloat32(vOffset, vertex.y, options.littleEndian);
6044
- vOffset += 4;
6045
- output.setFloat32(vOffset, vertex.z, options.littleEndian);
6046
- vOffset += 4;
6148
+ normalWriter.write(output, vOffset, vertex.x, options.littleEndian);
6149
+ vOffset += normalWriter.size;
6150
+ normalWriter.write(output, vOffset, vertex.y, options.littleEndian);
6151
+ vOffset += normalWriter.size;
6152
+ normalWriter.write(output, vOffset, vertex.z, options.littleEndian);
6153
+ vOffset += normalWriter.size;
6047
6154
  } else {
6048
- output.setFloat32(vOffset, 0, options.littleEndian);
6049
- vOffset += 4;
6050
- output.setFloat32(vOffset, 0, options.littleEndian);
6051
- vOffset += 4;
6052
- output.setFloat32(vOffset, 0, options.littleEndian);
6053
- vOffset += 4;
6155
+ normalWriter.write(output, vOffset, 0, options.littleEndian);
6156
+ vOffset += normalWriter.size;
6157
+ normalWriter.write(output, vOffset, 0, options.littleEndian);
6158
+ vOffset += normalWriter.size;
6159
+ normalWriter.write(output, vOffset, 0, options.littleEndian);
6160
+ vOffset += normalWriter.size;
6054
6161
  }
6055
6162
  }
6056
6163
  if (includeUVs === true) {
6057
6164
  if (uvs != null) {
6058
- output.setFloat32(vOffset, uvs.getX(i), options.littleEndian);
6059
- vOffset += 4;
6060
- output.setFloat32(vOffset, uvs.getY(i), options.littleEndian);
6061
- vOffset += 4;
6165
+ uvWriter.write(output, vOffset, uvs.getX(i), options.littleEndian);
6166
+ vOffset += uvWriter.size;
6167
+ uvWriter.write(output, vOffset, uvs.getY(i), options.littleEndian);
6168
+ vOffset += uvWriter.size;
6062
6169
  } else {
6063
- output.setFloat32(vOffset, 0, options.littleEndian);
6064
- vOffset += 4;
6065
- output.setFloat32(vOffset, 0, options.littleEndian);
6066
- vOffset += 4;
6170
+ uvWriter.write(output, vOffset, 0, options.littleEndian);
6171
+ vOffset += uvWriter.size;
6172
+ uvWriter.write(output, vOffset, 0, options.littleEndian);
6173
+ vOffset += uvWriter.size;
6067
6174
  }
6068
6175
  }
6069
6176
  if (includeColors === true) {
6070
6177
  if (colors != null) {
6071
- tempColor.fromBufferAttribute(colors, i).convertLinearToSRGB();
6072
- output.setUint8(vOffset, Math.floor(tempColor.r * 255));
6073
- vOffset += 1;
6074
- output.setUint8(vOffset, Math.floor(tempColor.g * 255));
6075
- vOffset += 1;
6076
- output.setUint8(vOffset, Math.floor(tempColor.b * 255));
6077
- vOffset += 1;
6178
+ tempColor.fromBufferAttribute(colors, i);
6179
+ ColorManagement2.workingToColorSpace(tempColor, SRGBColorSpace4);
6180
+ const r = colorIsFloat ? tempColor.r : Math.round(tempColor.r * colorScale);
6181
+ const g = colorIsFloat ? tempColor.g : Math.round(tempColor.g * colorScale);
6182
+ const b = colorIsFloat ? tempColor.b : Math.round(tempColor.b * colorScale);
6183
+ colorWriter.write(output, vOffset, r, options.littleEndian);
6184
+ vOffset += colorWriter.size;
6185
+ colorWriter.write(output, vOffset, g, options.littleEndian);
6186
+ vOffset += colorWriter.size;
6187
+ colorWriter.write(output, vOffset, b, options.littleEndian);
6188
+ vOffset += colorWriter.size;
6078
6189
  } else {
6079
- output.setUint8(vOffset, 255);
6080
- vOffset += 1;
6081
- output.setUint8(vOffset, 255);
6082
- vOffset += 1;
6083
- output.setUint8(vOffset, 255);
6084
- vOffset += 1;
6190
+ const white = colorIsFloat ? 1 : colorScale;
6191
+ colorWriter.write(output, vOffset, white, options.littleEndian);
6192
+ vOffset += colorWriter.size;
6193
+ colorWriter.write(output, vOffset, white, options.littleEndian);
6194
+ vOffset += colorWriter.size;
6195
+ colorWriter.write(output, vOffset, white, options.littleEndian);
6196
+ vOffset += colorWriter.size;
6197
+ }
6198
+ }
6199
+ for (const name of customAttributeNames) {
6200
+ const writer = customWriters[name];
6201
+ const propCount = customPropertyMapping[name].length;
6202
+ const attr = geometry.getAttribute(name);
6203
+ const isFloat = customIsFloat[name];
6204
+ for (let c = 0; c < propCount; c++) {
6205
+ const raw = attr != null ? getAttributeComponent(attr, i, c) : 0;
6206
+ writer.write(output, vOffset, isFloat ? raw : Math.round(raw), options.littleEndian);
6207
+ vOffset += writer.size;
6085
6208
  }
6086
6209
  }
6087
6210
  }
@@ -6117,6 +6240,14 @@ property list uchar int vertex_index
6117
6240
  let writtenVertices = 0;
6118
6241
  let vertexList = "";
6119
6242
  let faceList = "";
6243
+ const positionIsFloat = isFloatType(positionType);
6244
+ const normalIsFloat = isFloatType(normalType);
6245
+ const uvIsFloat = isFloatType(uvType);
6246
+ const colorIsFloat = isFloatType(colorType);
6247
+ const colorScale = getColorScale(colorType);
6248
+ const customIsFloat = {};
6249
+ for (const name of customAttributeNames) customIsFloat[name] = isFloatType(customTypes[name]);
6250
+ const encode = (v, isFloat) => isFloat ? v : Math.round(v);
6120
6251
  traverseMeshes(function(mesh, geometry) {
6121
6252
  const vertices = geometry.getAttribute("position");
6122
6253
  const normals = geometry.getAttribute("normal");
@@ -6127,29 +6258,43 @@ property list uchar int vertex_index
6127
6258
  for (let i = 0, l = vertices.count; i < l; i++) {
6128
6259
  vertex.fromBufferAttribute(vertices, i);
6129
6260
  vertex.applyMatrix4(mesh.matrixWorld);
6130
- let line = vertex.x + " " + vertex.y + " " + vertex.z;
6261
+ let line = encode(vertex.x, positionIsFloat) + " " + encode(vertex.y, positionIsFloat) + " " + encode(vertex.z, positionIsFloat);
6131
6262
  if (includeNormals === true) {
6132
6263
  if (normals != null) {
6133
6264
  vertex.fromBufferAttribute(normals, i);
6134
6265
  vertex.applyMatrix3(normalMatrixWorld).normalize();
6135
- line += " " + vertex.x + " " + vertex.y + " " + vertex.z;
6266
+ line += " " + encode(vertex.x, normalIsFloat) + " " + encode(vertex.y, normalIsFloat) + " " + encode(vertex.z, normalIsFloat);
6136
6267
  } else {
6137
6268
  line += " 0 0 0";
6138
6269
  }
6139
6270
  }
6140
6271
  if (includeUVs === true) {
6141
6272
  if (uvs != null) {
6142
- line += " " + uvs.getX(i) + " " + uvs.getY(i);
6273
+ line += " " + encode(uvs.getX(i), uvIsFloat) + " " + encode(uvs.getY(i), uvIsFloat);
6143
6274
  } else {
6144
6275
  line += " 0 0";
6145
6276
  }
6146
6277
  }
6147
6278
  if (includeColors === true) {
6148
6279
  if (colors != null) {
6149
- tempColor.fromBufferAttribute(colors, i).convertLinearToSRGB();
6150
- line += " " + Math.floor(tempColor.r * 255) + " " + Math.floor(tempColor.g * 255) + " " + Math.floor(tempColor.b * 255);
6280
+ tempColor.fromBufferAttribute(colors, i);
6281
+ ColorManagement2.workingToColorSpace(tempColor, SRGBColorSpace4);
6282
+ const r = colorIsFloat ? tempColor.r : Math.round(tempColor.r * colorScale);
6283
+ const g = colorIsFloat ? tempColor.g : Math.round(tempColor.g * colorScale);
6284
+ const b = colorIsFloat ? tempColor.b : Math.round(tempColor.b * colorScale);
6285
+ line += ` ${r} ${g} ${b}`;
6151
6286
  } else {
6152
- line += " 255 255 255";
6287
+ const white = colorIsFloat ? 1 : colorScale;
6288
+ line += ` ${white} ${white} ${white}`;
6289
+ }
6290
+ }
6291
+ for (const name of customAttributeNames) {
6292
+ const propCount = customPropertyMapping[name].length;
6293
+ const attr = geometry.getAttribute(name);
6294
+ const isFloat = customIsFloat[name];
6295
+ for (let c = 0; c < propCount; c++) {
6296
+ const raw = attr != null ? getAttributeComponent(attr, i, c) : 0;
6297
+ line += " " + encode(raw, isFloat);
6153
6298
  }
6154
6299
  }
6155
6300
  vertexList += line + "\n";
@@ -6179,6 +6324,62 @@ property list uchar int vertex_index
6179
6324
  return result;
6180
6325
  }
6181
6326
  };
6327
+ function getPlyType(array) {
6328
+ if (array instanceof Int8Array) return "char";
6329
+ if (array instanceof Uint8Array || array instanceof Uint8ClampedArray) return "uchar";
6330
+ if (array instanceof Int16Array) return "short";
6331
+ if (array instanceof Uint16Array) return "ushort";
6332
+ if (array instanceof Int32Array) return "int";
6333
+ if (array instanceof Uint32Array) return "uint";
6334
+ if (array instanceof Float32Array) return "float";
6335
+ if (array instanceof Float64Array) return "double";
6336
+ return "float";
6337
+ }
6338
+ function getBinaryWriter(type) {
6339
+ switch (type) {
6340
+ case "char":
6341
+ return { write: (dv, at, v) => dv.setInt8(at, v), size: 1 };
6342
+ case "uchar":
6343
+ return { write: (dv, at, v) => dv.setUint8(at, v), size: 1 };
6344
+ case "short":
6345
+ return { write: (dv, at, v, le) => dv.setInt16(at, v, le), size: 2 };
6346
+ case "ushort":
6347
+ return { write: (dv, at, v, le) => dv.setUint16(at, v, le), size: 2 };
6348
+ case "int":
6349
+ return { write: (dv, at, v, le) => dv.setInt32(at, v, le), size: 4 };
6350
+ case "uint":
6351
+ return { write: (dv, at, v, le) => dv.setUint32(at, v, le), size: 4 };
6352
+ case "float":
6353
+ return { write: (dv, at, v, le) => dv.setFloat32(at, v, le), size: 4 };
6354
+ case "double":
6355
+ return { write: (dv, at, v, le) => dv.setFloat64(at, v, le), size: 8 };
6356
+ }
6357
+ }
6358
+ function isFloatType(type) {
6359
+ return type === "float" || type === "double";
6360
+ }
6361
+ function getAttributeComponent(attr, i, c) {
6362
+ switch (c) {
6363
+ case 0:
6364
+ return attr.getX(i);
6365
+ case 1:
6366
+ return attr.getY(i);
6367
+ case 2:
6368
+ return attr.getZ(i);
6369
+ case 3:
6370
+ return attr.getW(i);
6371
+ }
6372
+ }
6373
+ function getColorScale(type) {
6374
+ switch (type) {
6375
+ case "uchar":
6376
+ return 255;
6377
+ case "ushort":
6378
+ return 65535;
6379
+ default:
6380
+ return 1;
6381
+ }
6382
+ }
6182
6383
 
6183
6384
  // ../../node_modules/three/examples/jsm/exporters/GLTFExporter.js
6184
6385
  import {
@@ -6192,7 +6393,7 @@ import {
6192
6393
  LinearFilter,
6193
6394
  LinearMipmapLinearFilter,
6194
6395
  LinearMipmapNearestFilter,
6195
- MathUtils as MathUtils2,
6396
+ MathUtils,
6196
6397
  Matrix4 as Matrix46,
6197
6398
  MirroredRepeatWrapping,
6198
6399
  NearestFilter as NearestFilter2,
@@ -6201,84 +6402,15 @@ import {
6201
6402
  PropertyBinding,
6202
6403
  RGBAFormat as RGBAFormat2,
6203
6404
  RepeatWrapping as RepeatWrapping2,
6204
- Scene as Scene3,
6205
- Source,
6206
- SRGBColorSpace as SRGBColorSpace4,
6405
+ Scene as Scene2,
6406
+ SRGBColorSpace as SRGBColorSpace5,
6407
+ TextureSource,
6207
6408
  CompressedTexture,
6208
6409
  Vector3 as Vector39,
6209
- Quaternion as Quaternion4
6410
+ Quaternion as Quaternion4,
6411
+ REVISION,
6412
+ ImageUtils
6210
6413
  } from "three";
6211
-
6212
- // ../../node_modules/three/examples/jsm/utils/TextureUtils.js
6213
- import {
6214
- PlaneGeometry,
6215
- ShaderMaterial as ShaderMaterial2,
6216
- Uniform,
6217
- Mesh as Mesh4,
6218
- PerspectiveCamera,
6219
- Scene as Scene2,
6220
- WebGLRenderer,
6221
- Texture as Texture3,
6222
- SRGBColorSpace as SRGBColorSpace3
6223
- } from "three";
6224
- var _renderer;
6225
- var fullscreenQuadGeometry;
6226
- var fullscreenQuadMaterial;
6227
- var fullscreenQuad;
6228
- function decompress(texture, maxTextureSize = Infinity, renderer = null) {
6229
- if (!fullscreenQuadGeometry) fullscreenQuadGeometry = new PlaneGeometry(2, 2, 1, 1);
6230
- if (!fullscreenQuadMaterial) fullscreenQuadMaterial = new ShaderMaterial2({
6231
- uniforms: { blitTexture: new Uniform(texture) },
6232
- vertexShader: `
6233
- varying vec2 vUv;
6234
- void main(){
6235
- vUv = uv;
6236
- gl_Position = vec4(position.xy * 1.0,0.,.999999);
6237
- }`,
6238
- fragmentShader: `
6239
- uniform sampler2D blitTexture;
6240
- varying vec2 vUv;
6241
-
6242
- void main(){
6243
- gl_FragColor = vec4(vUv.xy, 0, 1);
6244
-
6245
- #ifdef IS_SRGB
6246
- gl_FragColor = LinearTosRGB( texture2D( blitTexture, vUv) );
6247
- #else
6248
- gl_FragColor = texture2D( blitTexture, vUv);
6249
- #endif
6250
- }`
6251
- });
6252
- fullscreenQuadMaterial.uniforms.blitTexture.value = texture;
6253
- fullscreenQuadMaterial.defines.IS_SRGB = texture.colorSpace == SRGBColorSpace3;
6254
- fullscreenQuadMaterial.needsUpdate = true;
6255
- if (!fullscreenQuad) {
6256
- fullscreenQuad = new Mesh4(fullscreenQuadGeometry, fullscreenQuadMaterial);
6257
- fullscreenQuad.frustrumCulled = false;
6258
- }
6259
- const _camera = new PerspectiveCamera();
6260
- const _scene = new Scene2();
6261
- _scene.add(fullscreenQuad);
6262
- if (!renderer) {
6263
- renderer = _renderer = new WebGLRenderer({ antialias: false });
6264
- }
6265
- renderer.setSize(Math.min(texture.image.width, maxTextureSize), Math.min(texture.image.height, maxTextureSize));
6266
- renderer.clear();
6267
- renderer.render(_scene, _camera);
6268
- const readableTexture = new Texture3(renderer.domElement);
6269
- readableTexture.minFilter = texture.minFilter;
6270
- readableTexture.magFilter = texture.magFilter;
6271
- readableTexture.wrapS = texture.wrapS;
6272
- readableTexture.wrapT = texture.wrapT;
6273
- readableTexture.name = texture.name;
6274
- if (_renderer) {
6275
- _renderer.dispose();
6276
- _renderer = null;
6277
- }
6278
- return readableTexture;
6279
- }
6280
-
6281
- // ../../node_modules/three/examples/jsm/exporters/GLTFExporter.js
6282
6414
  var KHR_mesh_quantization_ExtraAttrTypes = {
6283
6415
  POSITION: [
6284
6416
  "byte",
@@ -6308,7 +6440,11 @@ var KHR_mesh_quantization_ExtraAttrTypes = {
6308
6440
  ]
6309
6441
  };
6310
6442
  var GLTFExporter = class {
6443
+ /**
6444
+ * Constructs a new glTF exporter.
6445
+ */
6311
6446
  constructor() {
6447
+ this.textureUtils = null;
6312
6448
  this.pluginCallbacks = [];
6313
6449
  this.register(function(writer) {
6314
6450
  return new GLTFLightExtension(writer);
@@ -6331,6 +6467,9 @@ var GLTFExporter = class {
6331
6467
  this.register(function(writer) {
6332
6468
  return new GLTFMaterialsClearcoatExtension(writer);
6333
6469
  });
6470
+ this.register(function(writer) {
6471
+ return new GLTFMaterialsDispersionExtension(writer);
6472
+ });
6334
6473
  this.register(function(writer) {
6335
6474
  return new GLTFMaterialsIridescenceExtension(writer);
6336
6475
  });
@@ -6343,16 +6482,33 @@ var GLTFExporter = class {
6343
6482
  this.register(function(writer) {
6344
6483
  return new GLTFMaterialsEmissiveStrengthExtension(writer);
6345
6484
  });
6485
+ this.register(function(writer) {
6486
+ return new GLTFMaterialsBumpExtension(writer);
6487
+ });
6346
6488
  this.register(function(writer) {
6347
6489
  return new GLTFMeshGpuInstancing(writer);
6348
6490
  });
6349
6491
  }
6492
+ /**
6493
+ * Registers a plugin callback. This API is internally used to implement the various
6494
+ * glTF extensions but can also used by third-party code to add additional logic
6495
+ * to the exporter.
6496
+ *
6497
+ * @param {function(writer:GLTFWriter)} callback - The callback function to register.
6498
+ * @return {GLTFExporter} A reference to this exporter.
6499
+ */
6350
6500
  register(callback) {
6351
6501
  if (this.pluginCallbacks.indexOf(callback) === -1) {
6352
6502
  this.pluginCallbacks.push(callback);
6353
6503
  }
6354
6504
  return this;
6355
6505
  }
6506
+ /**
6507
+ * Unregisters a plugin callback.
6508
+ *
6509
+ * @param {Function} callback - The callback function to unregister.
6510
+ * @return {GLTFExporter} A reference to this exporter.
6511
+ */
6356
6512
  unregister(callback) {
6357
6513
  if (this.pluginCallbacks.indexOf(callback) !== -1) {
6358
6514
  this.pluginCallbacks.splice(this.pluginCallbacks.indexOf(callback), 1);
@@ -6360,11 +6516,25 @@ var GLTFExporter = class {
6360
6516
  return this;
6361
6517
  }
6362
6518
  /**
6363
- * Parse scenes and generate GLTF output
6364
- * @param {Scene or [THREE.Scenes]} input Scene or Array of THREE.Scenes
6365
- * @param {Function} onDone Callback on completed
6366
- * @param {Function} onError Callback on errors
6367
- * @param {Object} options options
6519
+ * Sets the texture utils for this exporter. Only relevant when compressed textures have to be exported.
6520
+ *
6521
+ * Depending on whether you use {@link WebGLRenderer} or {@link WebGPURenderer}, you must inject the
6522
+ * corresponding texture utils {@link module:WebGLTextureUtils} or {@link module:WebGPUTextureUtils}.
6523
+ *
6524
+ * @param {WebGLTextureUtils|WebGPUTextureUtils} utils - The texture utils.
6525
+ * @return {GLTFExporter} A reference to this exporter.
6526
+ */
6527
+ setTextureUtils(utils) {
6528
+ this.textureUtils = utils;
6529
+ return this;
6530
+ }
6531
+ /**
6532
+ * Parses the given scenes and generates the glTF output.
6533
+ *
6534
+ * @param {Scene|Array<Scene>} input - A scene or an array of scenes.
6535
+ * @param {GLTFExporter~OnDone} onDone - A callback function that is executed when the export has finished.
6536
+ * @param {GLTFExporter~OnError} onError - A callback function that is executed when an error happens.
6537
+ * @param {GLTFExporter~Options} options - options
6368
6538
  */
6369
6539
  parse(input, onDone, onError, options) {
6370
6540
  const writer = new GLTFWriter();
@@ -6373,8 +6543,16 @@ var GLTFExporter = class {
6373
6543
  plugins.push(this.pluginCallbacks[i](writer));
6374
6544
  }
6375
6545
  writer.setPlugins(plugins);
6376
- writer.write(input, onDone, options).catch(onError);
6546
+ writer.setTextureUtils(this.textureUtils);
6547
+ writer.writeAsync(input, onDone, options).catch(onError);
6377
6548
  }
6549
+ /**
6550
+ * Async version of {@link GLTFExporter#parse}.
6551
+ *
6552
+ * @param {Scene|Array<Scene>} input - A scene or an array of scenes.
6553
+ * @param {GLTFExporter~Options} options - options.
6554
+ * @return {Promise<ArrayBuffer|string>} A Promise that resolved with the exported glTF data.
6555
+ */
6378
6556
  parseAsync(input, options) {
6379
6557
  const scope = this;
6380
6558
  return new Promise(function(resolve, reject) {
@@ -6460,7 +6638,7 @@ function getMinMax(attribute, start, count) {
6460
6638
  else if (a === 2) value = attribute.getZ(i);
6461
6639
  else if (a === 3) value = attribute.getW(i);
6462
6640
  if (attribute.normalized === true) {
6463
- value = MathUtils2.normalize(value, attribute.array);
6641
+ value = MathUtils.normalize(value, attribute.array);
6464
6642
  }
6465
6643
  }
6466
6644
  output.min[a] = Math.min(output.min[a], value);
@@ -6493,19 +6671,20 @@ function getCanvas() {
6493
6671
  return document.createElement("canvas");
6494
6672
  }
6495
6673
  function getToBlobPromise(canvas, mimeType) {
6496
- if (canvas.toBlob !== void 0) {
6674
+ if (typeof OffscreenCanvas !== "undefined" && canvas instanceof OffscreenCanvas) {
6675
+ let quality;
6676
+ if (mimeType === "image/jpeg") {
6677
+ quality = 0.92;
6678
+ } else if (mimeType === "image/webp") {
6679
+ quality = 0.8;
6680
+ }
6681
+ return canvas.convertToBlob({
6682
+ type: mimeType,
6683
+ quality
6684
+ });
6685
+ } else {
6497
6686
  return new Promise((resolve) => canvas.toBlob(resolve, mimeType));
6498
6687
  }
6499
- let quality;
6500
- if (mimeType === "image/jpeg") {
6501
- quality = 0.92;
6502
- } else if (mimeType === "image/webp") {
6503
- quality = 0.8;
6504
- }
6505
- return canvas.convertToBlob({
6506
- type: mimeType,
6507
- quality
6508
- });
6509
6688
  }
6510
6689
  var GLTFWriter = class {
6511
6690
  constructor() {
@@ -6524,7 +6703,7 @@ var GLTFWriter = class {
6524
6703
  this.json = {
6525
6704
  asset: {
6526
6705
  version: "2.0",
6527
- generator: "THREE.GLTFExporter"
6706
+ generator: "THREE.GLTFExporter r" + REVISION
6528
6707
  }
6529
6708
  };
6530
6709
  this.cache = {
@@ -6533,19 +6712,25 @@ var GLTFWriter = class {
6533
6712
  attributesNormalized: /* @__PURE__ */ new Map(),
6534
6713
  materials: /* @__PURE__ */ new Map(),
6535
6714
  textures: /* @__PURE__ */ new Map(),
6536
- images: /* @__PURE__ */ new Map()
6715
+ images: /* @__PURE__ */ new Map(),
6716
+ normalMaps: /* @__PURE__ */ new Map()
6537
6717
  };
6718
+ this.textureUtils = null;
6538
6719
  }
6539
6720
  setPlugins(plugins) {
6540
6721
  this.plugins = plugins;
6541
6722
  }
6723
+ setTextureUtils(utils) {
6724
+ this.textureUtils = utils;
6725
+ }
6542
6726
  /**
6543
6727
  * Parse scenes and generate GLTF output
6544
- * @param {Scene or [THREE.Scenes]} input Scene or Array of THREE.Scenes
6545
- * @param {Function} onDone Callback on completed
6546
- * @param {Object} options options
6728
+ *
6729
+ * @param {Scene|Array<Scene>} input Scene or Array of THREE.Scenes
6730
+ * @param {Function} onDone Callback on completed
6731
+ * @param {Object} options options
6547
6732
  */
6548
- async write(input, onDone, options = {}) {
6733
+ async writeAsync(input, onDone, options = {}) {
6549
6734
  this.options = Object.assign({
6550
6735
  // default options
6551
6736
  binary: false,
@@ -6553,12 +6738,13 @@ var GLTFWriter = class {
6553
6738
  onlyVisible: true,
6554
6739
  maxTextureSize: Infinity,
6555
6740
  animations: [],
6556
- includeCustomExtensions: false
6741
+ includeCustomExtensions: false,
6742
+ copyright: null
6557
6743
  }, options);
6558
6744
  if (this.options.animations.length > 0) {
6559
6745
  this.options.trs = true;
6560
6746
  }
6561
- this.processInput(input);
6747
+ await this.processInputAsync(input);
6562
6748
  await Promise.all(this.pending);
6563
6749
  const writer = this;
6564
6750
  const buffers = writer.buffers;
@@ -6572,6 +6758,7 @@ var GLTFWriter = class {
6572
6758
  if (extensionsUsedList.length > 0) json.extensionsUsed = extensionsUsedList;
6573
6759
  if (extensionsRequiredList.length > 0) json.extensionsRequired = extensionsRequiredList;
6574
6760
  if (json.buffers && json.buffers.length > 0) json.buffers[0].byteLength = blob.size;
6761
+ if (options.copyright) json.asset.copyright = options.copyright;
6575
6762
  if (options.binary === true) {
6576
6763
  const reader = new FileReader();
6577
6764
  reader.readAsArrayBuffer(blob);
@@ -6620,7 +6807,7 @@ var GLTFWriter = class {
6620
6807
  /**
6621
6808
  * Serializes a userData.
6622
6809
  *
6623
- * @param {THREE.Object3D|THREE.Material} object
6810
+ * @param {THREE.Object3D|THREE.Material|THREE.BufferGeometry|THREE.AnimationClip} object
6624
6811
  * @param {Object} objectDef
6625
6812
  */
6626
6813
  serializeUserData(object, objectDef) {
@@ -6644,8 +6831,10 @@ var GLTFWriter = class {
6644
6831
  }
6645
6832
  /**
6646
6833
  * Returns ids for buffer attributes.
6647
- * @param {Object} object
6648
- * @return {Integer}
6834
+ *
6835
+ * @param {Object} attribute
6836
+ * @param {boolean} [isRelativeCopy=false]
6837
+ * @return {number} An integer
6649
6838
  */
6650
6839
  getUID(attribute, isRelativeCopy = false) {
6651
6840
  if (this.uids.has(attribute) === false) {
@@ -6661,7 +6850,7 @@ var GLTFWriter = class {
6661
6850
  * Checks if normal attribute values are normalized.
6662
6851
  *
6663
6852
  * @param {BufferAttribute} normal
6664
- * @returns {Boolean}
6853
+ * @returns {boolean}
6665
6854
  */
6666
6855
  isNormalizedNormalAttribute(normal) {
6667
6856
  const cache = this.cache;
@@ -6724,10 +6913,10 @@ var GLTFWriter = class {
6724
6913
  this.extensionsUsed["KHR_texture_transform"] = true;
6725
6914
  }
6726
6915
  }
6727
- buildMetalRoughTexture(metalnessMap, roughnessMap) {
6916
+ async buildMetalRoughTextureAsync(metalnessMap, roughnessMap) {
6728
6917
  if (metalnessMap === roughnessMap) return metalnessMap;
6729
6918
  function getEncodingConversion(map) {
6730
- if (map.colorSpace === SRGBColorSpace4) {
6919
+ if (map.colorSpace === SRGBColorSpace5) {
6731
6920
  return function SRGBToLinear(c) {
6732
6921
  return c < 0.04045 ? c * 0.0773993808 : Math.pow(c * 0.9478672986 + 0.0521327014, 2.4);
6733
6922
  };
@@ -6736,12 +6925,11 @@ var GLTFWriter = class {
6736
6925
  return c;
6737
6926
  };
6738
6927
  }
6739
- console.warn("THREE.GLTFExporter: Merged metalnessMap and roughnessMap textures.");
6740
6928
  if (metalnessMap instanceof CompressedTexture) {
6741
- metalnessMap = decompress(metalnessMap);
6929
+ metalnessMap = await this.decompressTextureAsync(metalnessMap);
6742
6930
  }
6743
6931
  if (roughnessMap instanceof CompressedTexture) {
6744
- roughnessMap = decompress(roughnessMap);
6932
+ roughnessMap = await this.decompressTextureAsync(roughnessMap);
6745
6933
  }
6746
6934
  const metalness = metalnessMap ? metalnessMap.image : null;
6747
6935
  const roughness = roughnessMap ? roughnessMap.image : null;
@@ -6750,7 +6938,9 @@ var GLTFWriter = class {
6750
6938
  const canvas = getCanvas();
6751
6939
  canvas.width = width;
6752
6940
  canvas.height = height;
6753
- const context = canvas.getContext("2d");
6941
+ const context = canvas.getContext("2d", {
6942
+ willReadFrequently: true
6943
+ });
6754
6944
  context.fillStyle = "#00ffff";
6755
6945
  context.fillRect(0, 0, width, height);
6756
6946
  const composite = context.getImageData(0, 0, width, height);
@@ -6773,18 +6963,60 @@ var GLTFWriter = class {
6773
6963
  context.putImageData(composite, 0, 0);
6774
6964
  const reference = metalnessMap || roughnessMap;
6775
6965
  const texture = reference.clone();
6776
- texture.source = new Source(canvas);
6966
+ texture.source = new TextureSource(canvas);
6777
6967
  texture.colorSpace = NoColorSpace;
6778
6968
  texture.channel = (metalnessMap || roughnessMap).channel;
6779
6969
  if (metalnessMap && roughnessMap && metalnessMap.channel !== roughnessMap.channel) {
6780
6970
  console.warn("THREE.GLTFExporter: UV channels for metalnessMap and roughnessMap textures must match.");
6781
6971
  }
6972
+ console.warn("THREE.GLTFExporter: Merged metalnessMap and roughnessMap textures.");
6782
6973
  return texture;
6783
6974
  }
6975
+ /**
6976
+ * Builds a copy of the given normal map with the red and/or green channels
6977
+ * inverted (`color = 255 - color`). This is used to bake the sign of
6978
+ * `material.normalScale` and the tangent-space convention into the texture,
6979
+ * since glTF only supports OpenGL-style normal maps with a univariate,
6980
+ * positive scale.
6981
+ *
6982
+ * @param {THREE.Texture} normalMap The source normal map.
6983
+ * @param {boolean} flipX Whether to invert the red channel (normal X).
6984
+ * @param {boolean} flipY Whether to invert the green channel (normal Y).
6985
+ * @return {Promise<THREE.Texture>} The derived normal map texture.
6986
+ */
6987
+ async buildNormalMapTextureAsync(normalMap, flipX, flipY) {
6988
+ if (normalMap instanceof CompressedTexture) {
6989
+ normalMap = await this.decompressTextureAsync(normalMap);
6990
+ }
6991
+ const image = normalMap.image;
6992
+ const canvas = getCanvas();
6993
+ canvas.width = image.width;
6994
+ canvas.height = image.height;
6995
+ const context = canvas.getContext("2d", {
6996
+ willReadFrequently: true
6997
+ });
6998
+ context.drawImage(image, 0, 0, canvas.width, canvas.height);
6999
+ const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
7000
+ const data = imageData.data;
7001
+ for (let i = 0; i < data.length; i += 4) {
7002
+ if (flipX) data[i + 0] = 255 - data[i + 0];
7003
+ if (flipY) data[i + 1] = 255 - data[i + 1];
7004
+ }
7005
+ context.putImageData(imageData, 0, 0);
7006
+ const texture = normalMap.clone();
7007
+ texture.source = new TextureSource(canvas);
7008
+ return texture;
7009
+ }
7010
+ async decompressTextureAsync(texture, maxTextureSize = Infinity) {
7011
+ if (this.textureUtils === null) {
7012
+ throw new Error("THREE.GLTFExporter: setTextureUtils() must be called to process compressed textures.");
7013
+ }
7014
+ return await this.textureUtils.decompress(texture, maxTextureSize);
7015
+ }
6784
7016
  /**
6785
7017
  * Process a buffer to append to the default one.
6786
- * @param {ArrayBuffer} buffer
6787
- * @return {Integer}
7018
+ * @param {ArrayBuffer} buffer
7019
+ * @return {0}
6788
7020
  */
6789
7021
  processBuffer(buffer) {
6790
7022
  const json = this.json;
@@ -6795,11 +7027,11 @@ var GLTFWriter = class {
6795
7027
  }
6796
7028
  /**
6797
7029
  * Process and generate a BufferView
6798
- * @param {BufferAttribute} attribute
6799
- * @param {number} componentType
6800
- * @param {number} start
6801
- * @param {number} count
6802
- * @param {number} target (Optional) Target usage of the BufferView
7030
+ * @param {BufferAttribute} attribute
7031
+ * @param {number} componentType
7032
+ * @param {number} start
7033
+ * @param {number} count
7034
+ * @param {number} [target] Target usage of the BufferView
6803
7035
  * @return {Object}
6804
7036
  */
6805
7037
  processBufferView(attribute, componentType, start, count, target) {
@@ -6818,7 +7050,11 @@ var GLTFWriter = class {
6818
7050
  default:
6819
7051
  componentSize = 4;
6820
7052
  }
6821
- const byteLength = getPaddedBufferSize(count * attribute.itemSize * componentSize);
7053
+ let byteStride = attribute.itemSize * componentSize;
7054
+ if (target === WEBGL_CONSTANTS.ARRAY_BUFFER) {
7055
+ byteStride = Math.ceil(byteStride / 4) * 4;
7056
+ }
7057
+ const byteLength = getPaddedBufferSize(count * byteStride);
6822
7058
  const dataView = new DataView(new ArrayBuffer(byteLength));
6823
7059
  let offset = 0;
6824
7060
  for (let i = start; i < start + count; i++) {
@@ -6832,7 +7068,7 @@ var GLTFWriter = class {
6832
7068
  else if (a === 2) value = attribute.getZ(i);
6833
7069
  else if (a === 3) value = attribute.getW(i);
6834
7070
  if (attribute.normalized === true) {
6835
- value = MathUtils2.normalize(value, attribute.array);
7071
+ value = MathUtils.normalize(value, attribute.array);
6836
7072
  }
6837
7073
  }
6838
7074
  if (componentType === WEBGL_CONSTANTS.FLOAT) {
@@ -6852,6 +7088,9 @@ var GLTFWriter = class {
6852
7088
  }
6853
7089
  offset += componentSize;
6854
7090
  }
7091
+ if (offset % byteStride !== 0) {
7092
+ offset += byteStride - offset % byteStride;
7093
+ }
6855
7094
  }
6856
7095
  const bufferViewDef = {
6857
7096
  buffer: this.processBuffer(dataView.buffer),
@@ -6860,7 +7099,7 @@ var GLTFWriter = class {
6860
7099
  };
6861
7100
  if (target !== void 0) bufferViewDef.target = target;
6862
7101
  if (target === WEBGL_CONSTANTS.ARRAY_BUFFER) {
6863
- bufferViewDef.byteStride = attribute.itemSize * componentSize;
7102
+ bufferViewDef.byteStride = byteStride;
6864
7103
  }
6865
7104
  this.byteOffset += byteLength;
6866
7105
  json.bufferViews.push(bufferViewDef);
@@ -6873,7 +7112,7 @@ var GLTFWriter = class {
6873
7112
  /**
6874
7113
  * Process and generate a BufferView from an image Blob.
6875
7114
  * @param {Blob} blob
6876
- * @return {Promise<Integer>}
7115
+ * @return {Promise<number>} An integer
6877
7116
  */
6878
7117
  processBufferViewImage(blob) {
6879
7118
  const writer = this;
@@ -6896,11 +7135,11 @@ var GLTFWriter = class {
6896
7135
  }
6897
7136
  /**
6898
7137
  * Process attribute to generate an accessor
6899
- * @param {BufferAttribute} attribute Attribute to process
6900
- * @param {THREE.BufferGeometry} geometry (Optional) Geometry used for truncated draw range
6901
- * @param {Integer} start (Optional)
6902
- * @param {Integer} count (Optional)
6903
- * @return {Integer|null} Index of the processed accessor on the "accessors" array
7138
+ * @param {BufferAttribute} attribute Attribute to process
7139
+ * @param {?BufferGeometry} [geometry] Geometry used for truncated draw range
7140
+ * @param {number} [start=0]
7141
+ * @param {number} [count=Infinity]
7142
+ * @return {?number} Index of the processed accessor on the "accessors" array
6904
7143
  */
6905
7144
  processAccessor(attribute, geometry, start, count) {
6906
7145
  const json = this.json;
@@ -6954,11 +7193,11 @@ var GLTFWriter = class {
6954
7193
  }
6955
7194
  /**
6956
7195
  * Process image
6957
- * @param {Image} image to process
6958
- * @param {Integer} format of the image (RGBAFormat)
6959
- * @param {Boolean} flipY before writing out the image
6960
- * @param {String} mimeType export format
6961
- * @return {Integer} Index of the processed texture in the "images" array
7196
+ * @param {Image} image to process
7197
+ * @param {number} format Identifier of the format (RGBAFormat)
7198
+ * @param {boolean} flipY before writing out the image
7199
+ * @param {string} mimeType export format
7200
+ * @return {number} Index of the processed texture in the "images" array
6962
7201
  */
6963
7202
  processImage(image, format, flipY, mimeType = "image/png") {
6964
7203
  if (image !== null) {
@@ -6976,7 +7215,9 @@ var GLTFWriter = class {
6976
7215
  const canvas = getCanvas();
6977
7216
  canvas.width = Math.min(image.width, options.maxTextureSize);
6978
7217
  canvas.height = Math.min(image.height, options.maxTextureSize);
6979
- const ctx = canvas.getContext("2d");
7218
+ const ctx = canvas.getContext("2d", {
7219
+ willReadFrequently: true
7220
+ });
6980
7221
  if (flipY === true) {
6981
7222
  ctx.translate(0, canvas.height);
6982
7223
  ctx.scale(1, -1);
@@ -6997,7 +7238,11 @@ var GLTFWriter = class {
6997
7238
  }
6998
7239
  ctx.putImageData(new ImageData(data, image.width, image.height), 0, 0);
6999
7240
  } else {
7000
- ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
7241
+ if (typeof HTMLImageElement !== "undefined" && image instanceof HTMLImageElement || typeof HTMLCanvasElement !== "undefined" && image instanceof HTMLCanvasElement || typeof ImageBitmap !== "undefined" && image instanceof ImageBitmap || typeof OffscreenCanvas !== "undefined" && image instanceof OffscreenCanvas) {
7242
+ ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
7243
+ } else {
7244
+ throw new Error("THREE.GLTFExporter: Invalid image type. Use HTMLImageElement, HTMLCanvasElement, ImageBitmap or OffscreenCanvas.");
7245
+ }
7001
7246
  }
7002
7247
  if (options.binary === true) {
7003
7248
  pending.push(
@@ -7006,15 +7251,7 @@ var GLTFWriter = class {
7006
7251
  })
7007
7252
  );
7008
7253
  } else {
7009
- if (canvas.toDataURL !== void 0) {
7010
- imageDef.uri = canvas.toDataURL(mimeType);
7011
- } else {
7012
- pending.push(
7013
- getToBlobPromise(canvas, mimeType).then((blob) => new FileReader().readAsDataURL(blob)).then((dataURL) => {
7014
- imageDef.uri = dataURL;
7015
- })
7016
- );
7017
- }
7254
+ imageDef.uri = ImageUtils.getDataURL(canvas, mimeType);
7018
7255
  }
7019
7256
  const index = json.images.push(imageDef) - 1;
7020
7257
  cachedImages[key] = index;
@@ -7025,8 +7262,8 @@ var GLTFWriter = class {
7025
7262
  }
7026
7263
  /**
7027
7264
  * Process sampler
7028
- * @param {Texture} map Texture to process
7029
- * @return {Integer} Index of the processed texture in the "samplers" array
7265
+ * @param {Texture} map Texture to process
7266
+ * @return {number} Index of the processed texture in the "samplers" array
7030
7267
  */
7031
7268
  processSampler(map) {
7032
7269
  const json = this.json;
@@ -7041,10 +7278,10 @@ var GLTFWriter = class {
7041
7278
  }
7042
7279
  /**
7043
7280
  * Process texture
7044
- * @param {Texture} map Map to process
7045
- * @return {Integer} Index of the processed texture in the "textures" array
7281
+ * @param {Texture} map Map to process
7282
+ * @return {Promise<number>} Index of the processed texture in the "textures" array
7046
7283
  */
7047
- processTexture(map) {
7284
+ async processTextureAsync(map) {
7048
7285
  const writer = this;
7049
7286
  const options = writer.options;
7050
7287
  const cache = this.cache;
@@ -7052,17 +7289,26 @@ var GLTFWriter = class {
7052
7289
  if (cache.textures.has(map)) return cache.textures.get(map);
7053
7290
  if (!json.textures) json.textures = [];
7054
7291
  if (map instanceof CompressedTexture) {
7055
- map = decompress(map, options.maxTextureSize);
7292
+ map = await this.decompressTextureAsync(map, options.maxTextureSize);
7056
7293
  }
7057
- let mimeType = map.userData.mimeType;
7058
- if (mimeType === "image/webp") mimeType = "image/png";
7294
+ const mimeType = map.userData.mimeType;
7295
+ const imageIndex = this.processImage(map.image, map.format, map.flipY, mimeType);
7059
7296
  const textureDef = {
7060
- sampler: this.processSampler(map),
7061
- source: this.processImage(map.image, map.format, map.flipY, mimeType)
7297
+ sampler: this.processSampler(map)
7062
7298
  };
7299
+ if (mimeType === "image/webp") {
7300
+ textureDef.extensions = textureDef.extensions || {};
7301
+ textureDef.extensions["EXT_texture_webp"] = {
7302
+ source: imageIndex
7303
+ };
7304
+ this.extensionsUsed["EXT_texture_webp"] = true;
7305
+ this.extensionsRequired["EXT_texture_webp"] = true;
7306
+ } else {
7307
+ textureDef.source = imageIndex;
7308
+ }
7063
7309
  if (map.name) textureDef.name = map.name;
7064
- this._invokeAll(function(ext) {
7065
- ext.writeTexture && ext.writeTexture(map, textureDef);
7310
+ await this._invokeAllAsync(async function(ext) {
7311
+ ext.writeTexture && await ext.writeTexture(map, textureDef);
7066
7312
  });
7067
7313
  const index = json.textures.push(textureDef) - 1;
7068
7314
  cache.textures.set(map, index);
@@ -7070,13 +7316,16 @@ var GLTFWriter = class {
7070
7316
  }
7071
7317
  /**
7072
7318
  * Process material
7073
- * @param {THREE.Material} material Material to process
7074
- * @return {Integer|null} Index of the processed material in the "materials" array
7319
+ * @param {THREE.Material} material Material to process
7320
+ * @param {THREE.BufferGeometry} [geometry] Geometry the material is used with.
7321
+ * @return {Promise<?number>} Index of the processed material in the "materials" array
7075
7322
  */
7076
- processMaterial(material) {
7323
+ async processMaterialAsync(material, geometry) {
7077
7324
  const cache = this.cache;
7078
7325
  const json = this.json;
7079
- if (cache.materials.has(material)) return cache.materials.get(material);
7326
+ const hasTangent = geometry !== void 0 && geometry.hasAttribute("tangent");
7327
+ const cacheKey = material.normalMap ? material.uuid + ":" + hasTangent : material.uuid;
7328
+ if (cache.materials.has(cacheKey)) return cache.materials.get(cacheKey);
7080
7329
  if (material.isShaderMaterial) {
7081
7330
  console.warn("GLTFExporter: THREE.ShaderMaterial not supported.");
7082
7331
  return null;
@@ -7094,21 +7343,21 @@ var GLTFWriter = class {
7094
7343
  materialDef.pbrMetallicRoughness.metallicFactor = material.metalness;
7095
7344
  materialDef.pbrMetallicRoughness.roughnessFactor = material.roughness;
7096
7345
  } else {
7097
- materialDef.pbrMetallicRoughness.metallicFactor = 0.5;
7098
- materialDef.pbrMetallicRoughness.roughnessFactor = 0.5;
7346
+ materialDef.pbrMetallicRoughness.metallicFactor = 0;
7347
+ materialDef.pbrMetallicRoughness.roughnessFactor = 1;
7099
7348
  }
7100
7349
  if (material.metalnessMap || material.roughnessMap) {
7101
- const metalRoughTexture = this.buildMetalRoughTexture(material.metalnessMap, material.roughnessMap);
7350
+ const metalRoughTexture = await this.buildMetalRoughTextureAsync(material.metalnessMap, material.roughnessMap);
7102
7351
  const metalRoughMapDef = {
7103
- index: this.processTexture(metalRoughTexture),
7104
- channel: metalRoughTexture.channel
7352
+ index: await this.processTextureAsync(metalRoughTexture),
7353
+ texCoord: metalRoughTexture.channel
7105
7354
  };
7106
7355
  this.applyTextureTransform(metalRoughMapDef, metalRoughTexture);
7107
7356
  materialDef.pbrMetallicRoughness.metallicRoughnessTexture = metalRoughMapDef;
7108
7357
  }
7109
7358
  if (material.map) {
7110
7359
  const baseColorMapDef = {
7111
- index: this.processTexture(material.map),
7360
+ index: await this.processTextureAsync(material.map),
7112
7361
  texCoord: material.map.channel
7113
7362
  };
7114
7363
  this.applyTextureTransform(baseColorMapDef, material.map);
@@ -7122,7 +7371,7 @@ var GLTFWriter = class {
7122
7371
  }
7123
7372
  if (material.emissiveMap) {
7124
7373
  const emissiveMapDef = {
7125
- index: this.processTexture(material.emissiveMap),
7374
+ index: await this.processTextureAsync(material.emissiveMap),
7126
7375
  texCoord: material.emissiveMap.channel
7127
7376
  };
7128
7377
  this.applyTextureTransform(emissiveMapDef, material.emissiveMap);
@@ -7130,19 +7379,32 @@ var GLTFWriter = class {
7130
7379
  }
7131
7380
  }
7132
7381
  if (material.normalMap) {
7382
+ const normalScale = material.normalScale;
7383
+ const flipX = normalScale.x < 0;
7384
+ const flipY = hasTangent ? normalScale.y < 0 : normalScale.y > 0;
7385
+ let normalMap = material.normalMap;
7386
+ if (flipX || flipY) {
7387
+ if (cache.normalMaps.has(material.normalMap) === false) cache.normalMaps.set(material.normalMap, {});
7388
+ const cachedVariants = cache.normalMaps.get(material.normalMap);
7389
+ const cacheKey2 = `${flipX}:${flipY}`;
7390
+ if (cachedVariants[cacheKey2] === void 0) {
7391
+ cachedVariants[cacheKey2] = await this.buildNormalMapTextureAsync(material.normalMap, flipX, flipY);
7392
+ }
7393
+ normalMap = cachedVariants[cacheKey2];
7394
+ }
7133
7395
  const normalMapDef = {
7134
- index: this.processTexture(material.normalMap),
7396
+ index: await this.processTextureAsync(normalMap),
7135
7397
  texCoord: material.normalMap.channel
7136
7398
  };
7137
- if (material.normalScale && material.normalScale.x !== 1) {
7138
- normalMapDef.scale = material.normalScale.x;
7399
+ if (Math.abs(normalScale.x) !== 1) {
7400
+ normalMapDef.scale = Math.abs(normalScale.x);
7139
7401
  }
7140
7402
  this.applyTextureTransform(normalMapDef, material.normalMap);
7141
7403
  materialDef.normalTexture = normalMapDef;
7142
7404
  }
7143
7405
  if (material.aoMap) {
7144
7406
  const occlusionMapDef = {
7145
- index: this.processTexture(material.aoMap),
7407
+ index: await this.processTextureAsync(material.aoMap),
7146
7408
  texCoord: material.aoMap.channel
7147
7409
  };
7148
7410
  if (material.aoMapIntensity !== 1) {
@@ -7162,19 +7424,19 @@ var GLTFWriter = class {
7162
7424
  if (material.side === DoubleSide2) materialDef.doubleSided = true;
7163
7425
  if (material.name !== "") materialDef.name = material.name;
7164
7426
  this.serializeUserData(material, materialDef);
7165
- this._invokeAll(function(ext) {
7166
- ext.writeMaterial && ext.writeMaterial(material, materialDef);
7427
+ await this._invokeAllAsync(async function(ext) {
7428
+ ext.writeMaterialAsync && await ext.writeMaterialAsync(material, materialDef);
7167
7429
  });
7168
7430
  const index = json.materials.push(materialDef) - 1;
7169
- cache.materials.set(material, index);
7431
+ cache.materials.set(cacheKey, index);
7170
7432
  return index;
7171
7433
  }
7172
7434
  /**
7173
7435
  * Process mesh
7174
- * @param {THREE.Mesh} mesh Mesh to process
7175
- * @return {Integer|null} Index of the processed mesh in the "meshes" array
7436
+ * @param {THREE.Mesh} mesh Mesh to process
7437
+ * @return {Promise<?number>} Index of the processed mesh in the "meshes" array
7176
7438
  */
7177
- processMesh(mesh) {
7439
+ async processMeshAsync(mesh) {
7178
7440
  const cache = this.cache;
7179
7441
  const json = this.json;
7180
7442
  const meshCacheKeyParts = [mesh.geometry.uuid];
@@ -7224,7 +7486,7 @@ var GLTFWriter = class {
7224
7486
  const attribute = geometry.attributes[attributeName];
7225
7487
  attributeName = nameConversion[attributeName] || attributeName.toUpperCase();
7226
7488
  const validVertexAttributes = /^(POSITION|NORMAL|TANGENT|TEXCOORD_\d+|COLOR_\d+|JOINTS_\d+|WEIGHTS_\d+)$/;
7227
- if (!validVertexAttributes.test(attributeName)) attributeName = "_" + attributeName;
7489
+ if (!validVertexAttributes.test(attributeName) && !attributeName.startsWith("_")) attributeName = "_" + attributeName;
7228
7490
  if (cache.attributes.has(this.getUID(attribute))) {
7229
7491
  attributes[attributeName] = cache.attributes.get(this.getUID(attribute));
7230
7492
  continue;
@@ -7233,7 +7495,10 @@ var GLTFWriter = class {
7233
7495
  const array = attribute.array;
7234
7496
  if (attributeName === "JOINTS_0" && !(array instanceof Uint16Array) && !(array instanceof Uint8Array)) {
7235
7497
  console.warn('GLTFExporter: Attribute "skinIndex" converted to type UNSIGNED_SHORT.');
7236
- modifiedAttribute = new BufferAttribute3(new Uint16Array(array), attribute.itemSize, attribute.normalized);
7498
+ modifiedAttribute = GLTFExporter.Utils.toTypedBufferAttribute(attribute, Uint16Array);
7499
+ } else if ((array instanceof Uint32Array || array instanceof Int32Array) && !attributeName.startsWith("_")) {
7500
+ console.warn(`GLTFExporter: Attribute "${attributeName}" converted to type FLOAT.`);
7501
+ modifiedAttribute = GLTFExporter.Utils.toTypedBufferAttribute(attribute, Float32Array);
7237
7502
  }
7238
7503
  const accessor = this.processAccessor(modifiedAttribute || attribute, geometry);
7239
7504
  if (accessor !== null) {
@@ -7299,6 +7564,15 @@ var GLTFWriter = class {
7299
7564
  }
7300
7565
  const isMultiMaterial = Array.isArray(mesh.material);
7301
7566
  if (isMultiMaterial && geometry.groups.length === 0) return null;
7567
+ let didForceIndices = false;
7568
+ if (isMultiMaterial && geometry.index === null) {
7569
+ const indices = [];
7570
+ for (let i = 0, il = geometry.attributes.position.count; i < il; i++) {
7571
+ indices[i] = i;
7572
+ }
7573
+ geometry.setIndex(indices);
7574
+ didForceIndices = true;
7575
+ }
7302
7576
  const materials = isMultiMaterial ? mesh.material : [mesh.material];
7303
7577
  const groups = isMultiMaterial ? geometry.groups : [{ materialIndex: 0, start: void 0, count: void 0 }];
7304
7578
  for (let i = 0, il = groups.length; i < il; i++) {
@@ -7321,13 +7595,16 @@ var GLTFWriter = class {
7321
7595
  }
7322
7596
  if (primitive.indices === null) delete primitive.indices;
7323
7597
  }
7324
- const material = this.processMaterial(materials[groups[i].materialIndex]);
7598
+ const material = await this.processMaterialAsync(materials[groups[i].materialIndex], geometry);
7325
7599
  if (material !== null) primitive.material = material;
7326
7600
  primitives.push(primitive);
7327
7601
  }
7602
+ if (didForceIndices === true) {
7603
+ geometry.setIndex(null);
7604
+ }
7328
7605
  meshDef.primitives = primitives;
7329
7606
  if (!json.meshes) json.meshes = [];
7330
- this._invokeAll(function(ext) {
7607
+ await this._invokeAllAsync(function(ext) {
7331
7608
  ext.writeMesh && ext.writeMesh(mesh, meshDef);
7332
7609
  });
7333
7610
  const index = json.meshes.push(meshDef) - 1;
@@ -7373,8 +7650,8 @@ var GLTFWriter = class {
7373
7650
  }
7374
7651
  /**
7375
7652
  * Process camera
7376
- * @param {THREE.Camera} camera Camera to process
7377
- * @return {Integer} Index of the processed mesh in the "camera" array
7653
+ * @param {THREE.Camera} camera Camera to process
7654
+ * @return {number} Index of the processed mesh in the "camera" array
7378
7655
  */
7379
7656
  processCamera(camera) {
7380
7657
  const json = this.json;
@@ -7393,7 +7670,7 @@ var GLTFWriter = class {
7393
7670
  } else {
7394
7671
  cameraDef.perspective = {
7395
7672
  aspectRatio: camera.aspect,
7396
- yfov: MathUtils2.degToRad(camera.fov),
7673
+ yfov: MathUtils.degToRad(camera.fov),
7397
7674
  zfar: camera.far <= 0 ? 1e-3 : camera.far,
7398
7675
  znear: camera.near < 0 ? 0 : camera.near
7399
7676
  };
@@ -7409,7 +7686,7 @@ var GLTFWriter = class {
7409
7686
  *
7410
7687
  * @param {THREE.AnimationClip} clip
7411
7688
  * @param {THREE.Object3D} root
7412
- * @return {number|null}
7689
+ * @return {?number}
7413
7690
  */
7414
7691
  processAnimation(clip, root) {
7415
7692
  const json = this.json;
@@ -7433,7 +7710,7 @@ var GLTFWriter = class {
7433
7710
  }
7434
7711
  if (!trackNode || !trackProperty) {
7435
7712
  console.warn('THREE.GLTFExporter: Could not export animation track "%s".', track.name);
7436
- return null;
7713
+ continue;
7437
7714
  }
7438
7715
  const inputItemSize = 1;
7439
7716
  let outputItemSize = track.values.length / track.times.length;
@@ -7462,16 +7739,18 @@ var GLTFWriter = class {
7462
7739
  }
7463
7740
  });
7464
7741
  }
7465
- json.animations.push({
7742
+ const animationDef = {
7466
7743
  name: clip.name || "clip_" + json.animations.length,
7467
7744
  samplers,
7468
7745
  channels
7469
- });
7746
+ };
7747
+ this.serializeUserData(clip, animationDef);
7748
+ json.animations.push(animationDef);
7470
7749
  return json.animations.length - 1;
7471
7750
  }
7472
7751
  /**
7473
7752
  * @param {THREE.Object3D} object
7474
- * @return {number|null}
7753
+ * @return {?number}
7475
7754
  */
7476
7755
  processSkin(object) {
7477
7756
  const json = this.json;
@@ -7500,14 +7779,17 @@ var GLTFWriter = class {
7500
7779
  }
7501
7780
  /**
7502
7781
  * Process Object3D node
7503
- * @param {THREE.Object3D} node Object3D to processNode
7504
- * @return {Integer} Index of the node in the nodes list
7782
+ * @param {THREE.Object3D} object Object3D to processNodeAsync
7783
+ * @return {Promise<number>} Index of the node in the nodes list
7505
7784
  */
7506
- processNode(object) {
7785
+ async processNodeAsync(object) {
7507
7786
  const json = this.json;
7508
7787
  const options = this.options;
7509
7788
  const nodeMap = this.nodeMap;
7510
7789
  if (!json.nodes) json.nodes = [];
7790
+ if (object.pivot !== null) {
7791
+ return await this._processNodeWithPivotAsync(object);
7792
+ }
7511
7793
  const nodeDef = {};
7512
7794
  if (options.trs) {
7513
7795
  const rotation = object.quaternion.toArray();
@@ -7533,35 +7815,98 @@ var GLTFWriter = class {
7533
7815
  if (object.name !== "") nodeDef.name = String(object.name);
7534
7816
  this.serializeUserData(object, nodeDef);
7535
7817
  if (object.isMesh || object.isLine || object.isPoints) {
7536
- const meshIndex = this.processMesh(object);
7818
+ const meshIndex = await this.processMeshAsync(object);
7537
7819
  if (meshIndex !== null) nodeDef.mesh = meshIndex;
7538
7820
  } else if (object.isCamera) {
7539
7821
  nodeDef.camera = this.processCamera(object);
7540
7822
  }
7541
7823
  if (object.isSkinnedMesh) this.skins.push(object);
7824
+ const nodeIndex = json.nodes.push(nodeDef) - 1;
7825
+ nodeMap.set(object, nodeIndex);
7542
7826
  if (object.children.length > 0) {
7543
7827
  const children = [];
7544
7828
  for (let i = 0, l = object.children.length; i < l; i++) {
7545
7829
  const child = object.children[i];
7546
7830
  if (child.visible || options.onlyVisible === false) {
7547
- const nodeIndex2 = this.processNode(child);
7548
- if (nodeIndex2 !== null) children.push(nodeIndex2);
7831
+ const childNodeIndex = await this.processNodeAsync(child);
7832
+ if (childNodeIndex !== null) children.push(childNodeIndex);
7549
7833
  }
7550
7834
  }
7551
7835
  if (children.length > 0) nodeDef.children = children;
7552
7836
  }
7553
- this._invokeAll(function(ext) {
7837
+ await this._invokeAllAsync(function(ext) {
7554
7838
  ext.writeNode && ext.writeNode(object, nodeDef);
7555
7839
  });
7556
- const nodeIndex = json.nodes.push(nodeDef) - 1;
7557
- nodeMap.set(object, nodeIndex);
7558
7840
  return nodeIndex;
7559
7841
  }
7842
+ /**
7843
+ * Process Object3D node with pivot using container approach
7844
+ * @param {THREE.Object3D} object Object3D with pivot
7845
+ * @return {Promise<number>} Index of the container node
7846
+ */
7847
+ async _processNodeWithPivotAsync(object) {
7848
+ const json = this.json;
7849
+ const options = this.options;
7850
+ const nodeMap = this.nodeMap;
7851
+ const pivot = object.pivot;
7852
+ const containerDef = {};
7853
+ const rotation = object.quaternion.toArray();
7854
+ const position = [
7855
+ object.position.x + pivot.x,
7856
+ object.position.y + pivot.y,
7857
+ object.position.z + pivot.z
7858
+ ];
7859
+ const scale = object.scale.toArray();
7860
+ if (!equalArray(rotation, [0, 0, 0, 1])) {
7861
+ containerDef.rotation = rotation;
7862
+ }
7863
+ if (!equalArray(position, [0, 0, 0])) {
7864
+ containerDef.translation = position;
7865
+ }
7866
+ if (!equalArray(scale, [1, 1, 1])) {
7867
+ containerDef.scale = scale;
7868
+ }
7869
+ containerDef.extras = { pivot: pivot.toArray() };
7870
+ if (object.name !== "") containerDef.name = String(object.name);
7871
+ this.serializeUserData(object, containerDef);
7872
+ const containerIndex = json.nodes.push(containerDef) - 1;
7873
+ nodeMap.set(object, containerIndex);
7874
+ const childDef = {};
7875
+ const childPosition = [-pivot.x, -pivot.y, -pivot.z];
7876
+ if (!equalArray(childPosition, [0, 0, 0])) {
7877
+ childDef.translation = childPosition;
7878
+ }
7879
+ if (object.isMesh || object.isLine || object.isPoints) {
7880
+ const meshIndex = await this.processMeshAsync(object);
7881
+ if (meshIndex !== null) childDef.mesh = meshIndex;
7882
+ } else if (object.isCamera) {
7883
+ childDef.camera = this.processCamera(object);
7884
+ }
7885
+ if (object.isSkinnedMesh) this.skins.push(object);
7886
+ const childIndex = json.nodes.push(childDef) - 1;
7887
+ const containerChildren = [childIndex];
7888
+ if (object.children.length > 0) {
7889
+ const grandchildren = [];
7890
+ for (let i = 0, l = object.children.length; i < l; i++) {
7891
+ const child = object.children[i];
7892
+ if (child.visible || options.onlyVisible === false) {
7893
+ const childNodeIndex = await this.processNodeAsync(child);
7894
+ if (childNodeIndex !== null) grandchildren.push(childNodeIndex);
7895
+ }
7896
+ }
7897
+ if (grandchildren.length > 0) childDef.children = grandchildren;
7898
+ }
7899
+ containerDef.children = containerChildren;
7900
+ await this._invokeAllAsync(function(ext) {
7901
+ ext.writeNode && ext.writeNode(object, containerDef);
7902
+ });
7903
+ return containerIndex;
7904
+ }
7560
7905
  /**
7561
7906
  * Process Scene
7562
- * @param {Scene} node Scene to process
7907
+ * @param {Scene} scene Scene to process
7563
7908
  */
7564
- processScene(scene) {
7909
+ async processSceneAsync(scene) {
7565
7910
  const json = this.json;
7566
7911
  const options = this.options;
7567
7912
  if (!json.scenes) {
@@ -7575,7 +7920,7 @@ var GLTFWriter = class {
7575
7920
  for (let i = 0, l = scene.children.length; i < l; i++) {
7576
7921
  const child = scene.children[i];
7577
7922
  if (child.visible || options.onlyVisible === false) {
7578
- const nodeIndex = this.processNode(child);
7923
+ const nodeIndex = await this.processNodeAsync(child);
7579
7924
  if (nodeIndex !== null) nodes.push(nodeIndex);
7580
7925
  }
7581
7926
  }
@@ -7584,47 +7929,58 @@ var GLTFWriter = class {
7584
7929
  }
7585
7930
  /**
7586
7931
  * Creates a Scene to hold a list of objects and parse it
7587
- * @param {Array} objects List of objects to process
7932
+ * @param {Array<THREE.Object3D>} objects List of objects to process
7588
7933
  */
7589
- processObjects(objects) {
7590
- const scene = new Scene3();
7934
+ async processObjectsAsync(objects) {
7935
+ const scene = new Scene2();
7591
7936
  scene.name = "AuxScene";
7592
7937
  for (let i = 0; i < objects.length; i++) {
7593
7938
  scene.children.push(objects[i]);
7594
7939
  }
7595
- this.processScene(scene);
7940
+ await this.processSceneAsync(scene);
7596
7941
  }
7597
7942
  /**
7598
7943
  * @param {THREE.Object3D|Array<THREE.Object3D>} input
7599
7944
  */
7600
- processInput(input) {
7945
+ async processInputAsync(input) {
7601
7946
  const options = this.options;
7602
7947
  input = input instanceof Array ? input : [input];
7603
- this._invokeAll(function(ext) {
7948
+ await this._invokeAllAsync(function(ext) {
7604
7949
  ext.beforeParse && ext.beforeParse(input);
7605
7950
  });
7606
7951
  const objectsWithoutScene = [];
7607
7952
  for (let i = 0; i < input.length; i++) {
7608
- if (input[i] instanceof Scene3) {
7609
- this.processScene(input[i]);
7953
+ if (input[i] instanceof Scene2) {
7954
+ await this.processSceneAsync(input[i]);
7610
7955
  } else {
7611
7956
  objectsWithoutScene.push(input[i]);
7612
7957
  }
7613
7958
  }
7614
- if (objectsWithoutScene.length > 0) this.processObjects(objectsWithoutScene);
7959
+ if (objectsWithoutScene.length > 0) {
7960
+ await this.processObjectsAsync(objectsWithoutScene);
7961
+ }
7615
7962
  for (let i = 0; i < this.skins.length; ++i) {
7616
7963
  this.processSkin(this.skins[i]);
7617
7964
  }
7618
- for (let i = 0; i < options.animations.length; ++i) {
7619
- this.processAnimation(options.animations[i], input[0]);
7965
+ if (input.length === 1) {
7966
+ for (let i = 0; i < options.animations.length; ++i) {
7967
+ this.processAnimation(options.animations[i], input[0]);
7968
+ }
7969
+ } else {
7970
+ for (let i = 0; i < input.length; i++) {
7971
+ const animations = options.animations[i] || [];
7972
+ for (let j = 0; j < animations.length; ++j) {
7973
+ this.processAnimation(animations[j], input[i]);
7974
+ }
7975
+ }
7620
7976
  }
7621
- this._invokeAll(function(ext) {
7977
+ await this._invokeAllAsync(function(ext) {
7622
7978
  ext.afterParse && ext.afterParse(input);
7623
7979
  });
7624
7980
  }
7625
- _invokeAll(func) {
7981
+ async _invokeAllAsync(func) {
7626
7982
  for (let i = 0, il = this.plugins.length; i < il; i++) {
7627
- func(this.plugins[i]);
7983
+ await func(this.plugins[i]);
7628
7984
  }
7629
7985
  }
7630
7986
  };
@@ -7680,7 +8036,7 @@ var GLTFMaterialsUnlitExtension = class {
7680
8036
  this.writer = writer;
7681
8037
  this.name = "KHR_materials_unlit";
7682
8038
  }
7683
- writeMaterial(material, materialDef) {
8039
+ async writeMaterialAsync(material, materialDef) {
7684
8040
  if (!material.isMeshBasicMaterial) return;
7685
8041
  const writer = this.writer;
7686
8042
  const extensionsUsed = writer.extensionsUsed;
@@ -7696,7 +8052,7 @@ var GLTFMaterialsClearcoatExtension = class {
7696
8052
  this.writer = writer;
7697
8053
  this.name = "KHR_materials_clearcoat";
7698
8054
  }
7699
- writeMaterial(material, materialDef) {
8055
+ async writeMaterialAsync(material, materialDef) {
7700
8056
  if (!material.isMeshPhysicalMaterial || material.clearcoat === 0) return;
7701
8057
  const writer = this.writer;
7702
8058
  const extensionsUsed = writer.extensionsUsed;
@@ -7704,7 +8060,7 @@ var GLTFMaterialsClearcoatExtension = class {
7704
8060
  extensionDef.clearcoatFactor = material.clearcoat;
7705
8061
  if (material.clearcoatMap) {
7706
8062
  const clearcoatMapDef = {
7707
- index: writer.processTexture(material.clearcoatMap),
8063
+ index: await writer.processTextureAsync(material.clearcoatMap),
7708
8064
  texCoord: material.clearcoatMap.channel
7709
8065
  };
7710
8066
  writer.applyTextureTransform(clearcoatMapDef, material.clearcoatMap);
@@ -7713,7 +8069,7 @@ var GLTFMaterialsClearcoatExtension = class {
7713
8069
  extensionDef.clearcoatRoughnessFactor = material.clearcoatRoughness;
7714
8070
  if (material.clearcoatRoughnessMap) {
7715
8071
  const clearcoatRoughnessMapDef = {
7716
- index: writer.processTexture(material.clearcoatRoughnessMap),
8072
+ index: await writer.processTextureAsync(material.clearcoatRoughnessMap),
7717
8073
  texCoord: material.clearcoatRoughnessMap.channel
7718
8074
  };
7719
8075
  writer.applyTextureTransform(clearcoatRoughnessMapDef, material.clearcoatRoughnessMap);
@@ -7721,9 +8077,10 @@ var GLTFMaterialsClearcoatExtension = class {
7721
8077
  }
7722
8078
  if (material.clearcoatNormalMap) {
7723
8079
  const clearcoatNormalMapDef = {
7724
- index: writer.processTexture(material.clearcoatNormalMap),
8080
+ index: await writer.processTextureAsync(material.clearcoatNormalMap),
7725
8081
  texCoord: material.clearcoatNormalMap.channel
7726
8082
  };
8083
+ if (material.clearcoatNormalScale.x !== 1) clearcoatNormalMapDef.scale = material.clearcoatNormalScale.x;
7727
8084
  writer.applyTextureTransform(clearcoatNormalMapDef, material.clearcoatNormalMap);
7728
8085
  extensionDef.clearcoatNormalTexture = clearcoatNormalMapDef;
7729
8086
  }
@@ -7732,12 +8089,28 @@ var GLTFMaterialsClearcoatExtension = class {
7732
8089
  extensionsUsed[this.name] = true;
7733
8090
  }
7734
8091
  };
8092
+ var GLTFMaterialsDispersionExtension = class {
8093
+ constructor(writer) {
8094
+ this.writer = writer;
8095
+ this.name = "KHR_materials_dispersion";
8096
+ }
8097
+ async writeMaterialAsync(material, materialDef) {
8098
+ if (!material.isMeshPhysicalMaterial || material.dispersion === 0) return;
8099
+ const writer = this.writer;
8100
+ const extensionsUsed = writer.extensionsUsed;
8101
+ const extensionDef = {};
8102
+ extensionDef.dispersion = material.dispersion;
8103
+ materialDef.extensions = materialDef.extensions || {};
8104
+ materialDef.extensions[this.name] = extensionDef;
8105
+ extensionsUsed[this.name] = true;
8106
+ }
8107
+ };
7735
8108
  var GLTFMaterialsIridescenceExtension = class {
7736
8109
  constructor(writer) {
7737
8110
  this.writer = writer;
7738
8111
  this.name = "KHR_materials_iridescence";
7739
8112
  }
7740
- writeMaterial(material, materialDef) {
8113
+ async writeMaterialAsync(material, materialDef) {
7741
8114
  if (!material.isMeshPhysicalMaterial || material.iridescence === 0) return;
7742
8115
  const writer = this.writer;
7743
8116
  const extensionsUsed = writer.extensionsUsed;
@@ -7745,7 +8118,7 @@ var GLTFMaterialsIridescenceExtension = class {
7745
8118
  extensionDef.iridescenceFactor = material.iridescence;
7746
8119
  if (material.iridescenceMap) {
7747
8120
  const iridescenceMapDef = {
7748
- index: writer.processTexture(material.iridescenceMap),
8121
+ index: await writer.processTextureAsync(material.iridescenceMap),
7749
8122
  texCoord: material.iridescenceMap.channel
7750
8123
  };
7751
8124
  writer.applyTextureTransform(iridescenceMapDef, material.iridescenceMap);
@@ -7756,7 +8129,7 @@ var GLTFMaterialsIridescenceExtension = class {
7756
8129
  extensionDef.iridescenceThicknessMaximum = material.iridescenceThicknessRange[1];
7757
8130
  if (material.iridescenceThicknessMap) {
7758
8131
  const iridescenceThicknessMapDef = {
7759
- index: writer.processTexture(material.iridescenceThicknessMap),
8132
+ index: await writer.processTextureAsync(material.iridescenceThicknessMap),
7760
8133
  texCoord: material.iridescenceThicknessMap.channel
7761
8134
  };
7762
8135
  writer.applyTextureTransform(iridescenceThicknessMapDef, material.iridescenceThicknessMap);
@@ -7772,7 +8145,7 @@ var GLTFMaterialsTransmissionExtension = class {
7772
8145
  this.writer = writer;
7773
8146
  this.name = "KHR_materials_transmission";
7774
8147
  }
7775
- writeMaterial(material, materialDef) {
8148
+ async writeMaterialAsync(material, materialDef) {
7776
8149
  if (!material.isMeshPhysicalMaterial || material.transmission === 0) return;
7777
8150
  const writer = this.writer;
7778
8151
  const extensionsUsed = writer.extensionsUsed;
@@ -7780,7 +8153,7 @@ var GLTFMaterialsTransmissionExtension = class {
7780
8153
  extensionDef.transmissionFactor = material.transmission;
7781
8154
  if (material.transmissionMap) {
7782
8155
  const transmissionMapDef = {
7783
- index: writer.processTexture(material.transmissionMap),
8156
+ index: await writer.processTextureAsync(material.transmissionMap),
7784
8157
  texCoord: material.transmissionMap.channel
7785
8158
  };
7786
8159
  writer.applyTextureTransform(transmissionMapDef, material.transmissionMap);
@@ -7796,7 +8169,7 @@ var GLTFMaterialsVolumeExtension = class {
7796
8169
  this.writer = writer;
7797
8170
  this.name = "KHR_materials_volume";
7798
8171
  }
7799
- writeMaterial(material, materialDef) {
8172
+ async writeMaterialAsync(material, materialDef) {
7800
8173
  if (!material.isMeshPhysicalMaterial || material.transmission === 0) return;
7801
8174
  const writer = this.writer;
7802
8175
  const extensionsUsed = writer.extensionsUsed;
@@ -7804,13 +8177,15 @@ var GLTFMaterialsVolumeExtension = class {
7804
8177
  extensionDef.thicknessFactor = material.thickness;
7805
8178
  if (material.thicknessMap) {
7806
8179
  const thicknessMapDef = {
7807
- index: writer.processTexture(material.thicknessMap),
8180
+ index: await writer.processTextureAsync(material.thicknessMap),
7808
8181
  texCoord: material.thicknessMap.channel
7809
8182
  };
7810
8183
  writer.applyTextureTransform(thicknessMapDef, material.thicknessMap);
7811
8184
  extensionDef.thicknessTexture = thicknessMapDef;
7812
8185
  }
7813
- extensionDef.attenuationDistance = material.attenuationDistance;
8186
+ if (material.attenuationDistance !== Infinity) {
8187
+ extensionDef.attenuationDistance = material.attenuationDistance;
8188
+ }
7814
8189
  extensionDef.attenuationColor = material.attenuationColor.toArray();
7815
8190
  materialDef.extensions = materialDef.extensions || {};
7816
8191
  materialDef.extensions[this.name] = extensionDef;
@@ -7822,7 +8197,7 @@ var GLTFMaterialsIorExtension = class {
7822
8197
  this.writer = writer;
7823
8198
  this.name = "KHR_materials_ior";
7824
8199
  }
7825
- writeMaterial(material, materialDef) {
8200
+ async writeMaterialAsync(material, materialDef) {
7826
8201
  if (!material.isMeshPhysicalMaterial || material.ior === 1.5) return;
7827
8202
  const writer = this.writer;
7828
8203
  const extensionsUsed = writer.extensionsUsed;
@@ -7838,14 +8213,14 @@ var GLTFMaterialsSpecularExtension = class {
7838
8213
  this.writer = writer;
7839
8214
  this.name = "KHR_materials_specular";
7840
8215
  }
7841
- writeMaterial(material, materialDef) {
7842
- if (!material.isMeshPhysicalMaterial || material.specularIntensity === 1 && material.specularColor.equals(DEFAULT_SPECULAR_COLOR) && !material.specularIntensityMap && !material.specularColorTexture) return;
8216
+ async writeMaterialAsync(material, materialDef) {
8217
+ if (!material.isMeshPhysicalMaterial || material.specularIntensity === 1 && material.specularColor.equals(DEFAULT_SPECULAR_COLOR) && !material.specularIntensityMap && !material.specularColorMap) return;
7843
8218
  const writer = this.writer;
7844
8219
  const extensionsUsed = writer.extensionsUsed;
7845
8220
  const extensionDef = {};
7846
8221
  if (material.specularIntensityMap) {
7847
8222
  const specularIntensityMapDef = {
7848
- index: writer.processTexture(material.specularIntensityMap),
8223
+ index: await writer.processTextureAsync(material.specularIntensityMap),
7849
8224
  texCoord: material.specularIntensityMap.channel
7850
8225
  };
7851
8226
  writer.applyTextureTransform(specularIntensityMapDef, material.specularIntensityMap);
@@ -7853,7 +8228,7 @@ var GLTFMaterialsSpecularExtension = class {
7853
8228
  }
7854
8229
  if (material.specularColorMap) {
7855
8230
  const specularColorMapDef = {
7856
- index: writer.processTexture(material.specularColorMap),
8231
+ index: await writer.processTextureAsync(material.specularColorMap),
7857
8232
  texCoord: material.specularColorMap.channel
7858
8233
  };
7859
8234
  writer.applyTextureTransform(specularColorMapDef, material.specularColorMap);
@@ -7871,14 +8246,14 @@ var GLTFMaterialsSheenExtension = class {
7871
8246
  this.writer = writer;
7872
8247
  this.name = "KHR_materials_sheen";
7873
8248
  }
7874
- writeMaterial(material, materialDef) {
8249
+ async writeMaterialAsync(material, materialDef) {
7875
8250
  if (!material.isMeshPhysicalMaterial || material.sheen == 0) return;
7876
8251
  const writer = this.writer;
7877
8252
  const extensionsUsed = writer.extensionsUsed;
7878
8253
  const extensionDef = {};
7879
8254
  if (material.sheenRoughnessMap) {
7880
8255
  const sheenRoughnessMapDef = {
7881
- index: writer.processTexture(material.sheenRoughnessMap),
8256
+ index: await writer.processTextureAsync(material.sheenRoughnessMap),
7882
8257
  texCoord: material.sheenRoughnessMap.channel
7883
8258
  };
7884
8259
  writer.applyTextureTransform(sheenRoughnessMapDef, material.sheenRoughnessMap);
@@ -7886,7 +8261,7 @@ var GLTFMaterialsSheenExtension = class {
7886
8261
  }
7887
8262
  if (material.sheenColorMap) {
7888
8263
  const sheenColorMapDef = {
7889
- index: writer.processTexture(material.sheenColorMap),
8264
+ index: await writer.processTextureAsync(material.sheenColorMap),
7890
8265
  texCoord: material.sheenColorMap.channel
7891
8266
  };
7892
8267
  writer.applyTextureTransform(sheenColorMapDef, material.sheenColorMap);
@@ -7904,13 +8279,13 @@ var GLTFMaterialsAnisotropyExtension = class {
7904
8279
  this.writer = writer;
7905
8280
  this.name = "KHR_materials_anisotropy";
7906
8281
  }
7907
- writeMaterial(material, materialDef) {
8282
+ async writeMaterialAsync(material, materialDef) {
7908
8283
  if (!material.isMeshPhysicalMaterial || material.anisotropy == 0) return;
7909
8284
  const writer = this.writer;
7910
8285
  const extensionsUsed = writer.extensionsUsed;
7911
8286
  const extensionDef = {};
7912
8287
  if (material.anisotropyMap) {
7913
- const anisotropyMapDef = { index: writer.processTexture(material.anisotropyMap) };
8288
+ const anisotropyMapDef = { index: await writer.processTextureAsync(material.anisotropyMap) };
7914
8289
  writer.applyTextureTransform(anisotropyMapDef, material.anisotropyMap);
7915
8290
  extensionDef.anisotropyTexture = anisotropyMapDef;
7916
8291
  }
@@ -7926,7 +8301,7 @@ var GLTFMaterialsEmissiveStrengthExtension = class {
7926
8301
  this.writer = writer;
7927
8302
  this.name = "KHR_materials_emissive_strength";
7928
8303
  }
7929
- writeMaterial(material, materialDef) {
8304
+ async writeMaterialAsync(material, materialDef) {
7930
8305
  if (!material.isMeshStandardMaterial || material.emissiveIntensity === 1) return;
7931
8306
  const writer = this.writer;
7932
8307
  const extensionsUsed = writer.extensionsUsed;
@@ -7937,6 +8312,30 @@ var GLTFMaterialsEmissiveStrengthExtension = class {
7937
8312
  extensionsUsed[this.name] = true;
7938
8313
  }
7939
8314
  };
8315
+ var GLTFMaterialsBumpExtension = class {
8316
+ constructor(writer) {
8317
+ this.writer = writer;
8318
+ this.name = "EXT_materials_bump";
8319
+ }
8320
+ async writeMaterialAsync(material, materialDef) {
8321
+ if (!material.isMeshStandardMaterial || material.bumpScale === 1 && !material.bumpMap) return;
8322
+ const writer = this.writer;
8323
+ const extensionsUsed = writer.extensionsUsed;
8324
+ const extensionDef = {};
8325
+ if (material.bumpMap) {
8326
+ const bumpMapDef = {
8327
+ index: await writer.processTextureAsync(material.bumpMap),
8328
+ texCoord: material.bumpMap.channel
8329
+ };
8330
+ writer.applyTextureTransform(bumpMapDef, material.bumpMap);
8331
+ extensionDef.bumpTexture = bumpMapDef;
8332
+ }
8333
+ extensionDef.bumpFactor = material.bumpScale;
8334
+ materialDef.extensions = materialDef.extensions || {};
8335
+ materialDef.extensions[this.name] = extensionDef;
8336
+ extensionsUsed[this.name] = true;
8337
+ }
8338
+ };
7940
8339
  var GLTFMeshGpuInstancing = class {
7941
8340
  constructor(writer) {
7942
8341
  this.writer = writer;
@@ -8072,6 +8471,19 @@ GLTFExporter.Utils = {
8072
8471
  }
8073
8472
  clip.tracks = tracks;
8074
8473
  return clip;
8474
+ },
8475
+ toTypedBufferAttribute: function(srcAttribute, TypedArray) {
8476
+ const dstAttribute = new BufferAttribute3(new TypedArray(srcAttribute.count * srcAttribute.itemSize), srcAttribute.itemSize, false);
8477
+ if (!srcAttribute.normalized && !srcAttribute.isInterleavedBufferAttribute) {
8478
+ dstAttribute.array.set(srcAttribute.array);
8479
+ return dstAttribute;
8480
+ }
8481
+ for (let i = 0, il = srcAttribute.count; i < il; i++) {
8482
+ for (let j = 0; j < srcAttribute.itemSize; j++) {
8483
+ dstAttribute.setComponent(i, j, srcAttribute.getComponent(i, j));
8484
+ }
8485
+ }
8486
+ return dstAttribute;
8075
8487
  }
8076
8488
  };
8077
8489
 
@@ -8126,7 +8538,7 @@ function localMatrix(object) {
8126
8538
  return object.matrixAutoUpdate ? new Matrix47().compose(object.position, object.quaternion, object.scale) : object.matrix.clone();
8127
8539
  }
8128
8540
  function createSnapshot(root, gltf, bakeColors = false) {
8129
- const scene = new Scene4();
8541
+ const scene = new Scene3();
8130
8542
  const geometries = [];
8131
8543
  const materials = [];
8132
8544
  const textures = [];
@@ -8221,7 +8633,7 @@ function createSnapshot(root, gltf, bakeColors = false) {
8221
8633
  material.color.copy(tint);
8222
8634
  }
8223
8635
  }
8224
- const copy = new Mesh5(geometry, material);
8636
+ const copy = new Mesh4(geometry, material);
8225
8637
  copy.name = mesh.name;
8226
8638
  copy.renderOrder = mesh.renderOrder;
8227
8639
  scene.add(copy);
@@ -8300,7 +8712,7 @@ function selectAlphaMode(material, geometry) {
8300
8712
  }
8301
8713
  function copyDataTexture(source) {
8302
8714
  const image = source.image;
8303
- if (source.format !== RGBAFormat3 || source.type !== UnsignedByteType) {
8715
+ if (!image.data || source.format !== RGBAFormat3 || source.type !== UnsignedByteType) {
8304
8716
  throw new MineRenderError("glTF export requires RGBA unsigned-byte data textures");
8305
8717
  }
8306
8718
  const canvas = createCanvas(image.width, image.height);
@@ -8311,8 +8723,8 @@ function copyDataTexture(source) {
8311
8723
  context.putImageData(pixels, 0, 0);
8312
8724
  const copySource = Object.create(source);
8313
8725
  copySource.userData = {};
8314
- copySource.source = new Source2(canvas);
8315
- return new Texture4().copy(copySource);
8726
+ copySource.source = new TextureSource2(canvas);
8727
+ return new Texture3().copy(copySource);
8316
8728
  }
8317
8729
 
8318
8730
  // src/gui/GuiHelper.ts
@@ -8391,7 +8803,7 @@ init_Materials();
8391
8803
  init_ModelObject();
8392
8804
  init_DisplayPosition();
8393
8805
  init_GuiLight();
8394
- import { Box2, Box3 as Box32, Matrix4 as Matrix410, Mesh as Mesh7, PlaneGeometry as PlaneGeometry2, Vector2 as Vector23 } from "three";
8806
+ import { Box2, Box3 as Box32, Matrix4 as Matrix410, Mesh as Mesh6, PlaneGeometry, Vector2 as Vector23 } from "three";
8395
8807
  var GuiObject = class extends SceneObject {
8396
8808
  constructor(textureLayers, options) {
8397
8809
  super({ ...options, instanceMeshes: false, mergeMeshes: false });
@@ -8434,7 +8846,7 @@ var GuiObject = class extends SceneObject {
8434
8846
  const image = material.map.image;
8435
8847
  const [cropX, cropY, cropWidth, cropHeight] = layer.crop ?? [0, 0, image.width, image.height];
8436
8848
  const [width, height] = layer.size ?? [cropWidth, cropHeight];
8437
- const geometry = new PlaneGeometry2(width, height);
8849
+ const geometry = new PlaneGeometry(width, height);
8438
8850
  this.geometries.add(geometry);
8439
8851
  const uv = geometry.getAttribute("uv");
8440
8852
  for (let i = 0; i < uv.count; i++) {
@@ -8444,7 +8856,7 @@ var GuiObject = class extends SceneObject {
8444
8856
  1 - (cropY + (1 - uv.getY(i)) * cropHeight) / image.height
8445
8857
  );
8446
8858
  }
8447
- const mesh = new Mesh7(geometry, material);
8859
+ const mesh = new Mesh6(geometry, material);
8448
8860
  mesh.name = `mesh:${layer.name ?? index}`;
8449
8861
  mesh.position.set(x + width / 2, -y - height / 2, depth);
8450
8862
  mesh.renderOrder = index;
@@ -9281,6 +9693,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
9281
9693
  replacement.setMatrix(matrix);
9282
9694
  } else {
9283
9695
  replacement.matrix.copy(matrix);
9696
+ replacement.matrixWorldNeedsUpdate = true;
9284
9697
  matrix.decompose(replacement.position, replacement.quaternion, replacement.scale);
9285
9698
  replacement.matrixAutoUpdate = object.matrixAutoUpdate;
9286
9699
  replacement.visible = object.visible;
@@ -11343,7 +11756,7 @@ init_nbt();
11343
11756
  init_SceneObject();
11344
11757
  var import_ts_deepmerge8 = __toESM(require_dist());
11345
11758
  init_ModelObject();
11346
- import { Scene as Scene5 } from "three";
11759
+ import { Scene as Scene4 } from "three";
11347
11760
 
11348
11761
  // src/skin/scene/SkinObject.ts
11349
11762
  init_SceneObject();
@@ -12076,7 +12489,7 @@ init_util();
12076
12489
  init_Caching();
12077
12490
  init_CacheKey();
12078
12491
  init_MineRenderError();
12079
- import { DataTexture as DataTexture2, DoubleSide as DoubleSide4, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial6, SRGBColorSpace as SRGBColorSpace5 } from "three";
12492
+ import { DataTexture as DataTexture2, DoubleSide as DoubleSide4, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial6, SRGBColorSpace as SRGBColorSpace6 } from "three";
12080
12493
 
12081
12494
  // src/skin/SkinImage.ts
12082
12495
  init_Caching();
@@ -12158,7 +12571,7 @@ var SkinTextures = class {
12158
12571
  }
12159
12572
  static createMaterial(pixels, width, height, transparent = true) {
12160
12573
  const texture = Textures.initTextureProps(new DataTexture2(pixels, width, height));
12161
- texture.colorSpace = SRGBColorSpace5;
12574
+ texture.colorSpace = SRGBColorSpace6;
12162
12575
  texture.flipY = true;
12163
12576
  texture.needsUpdate = true;
12164
12577
  return new MeshBasicMaterial6({ map: texture, transparent, side: transparent ? DoubleSide4 : FrontSide2, alphaTest: transparent ? 0.1 : 0 });
@@ -12391,7 +12804,7 @@ var SkinObject = class extends SceneObject {
12391
12804
  // src/renderer/MineRenderScene.ts
12392
12805
  init_EntityObject();
12393
12806
  init_ItemTints();
12394
- var _MineRenderScene = class _MineRenderScene extends Scene5 {
12807
+ var _MineRenderScene = class _MineRenderScene extends Scene4 {
12395
12808
  constructor(options) {
12396
12809
  super();
12397
12810
  this.isMineRenderScene = true;
@@ -12434,12 +12847,13 @@ var _MineRenderScene = class _MineRenderScene extends Scene5 {
12434
12847
  }
12435
12848
  updateObjectRegistration(object, attached) {
12436
12849
  if (this.observedObjects.has(object) === attached) return;
12850
+ const observable = object;
12437
12851
  if (attached) {
12438
12852
  this.observedObjects.add(object);
12439
- object.addEventListener("change", this.onObjectChange);
12853
+ observable.addEventListener("change", this.onObjectChange);
12440
12854
  } else {
12441
12855
  this.observedObjects.delete(object);
12442
- object.removeEventListener("change", this.onObjectChange);
12856
+ observable.removeEventListener("change", this.onObjectChange);
12443
12857
  }
12444
12858
  const change = attached ? 1 : -1;
12445
12859
  this.stats.objectCount += change;
@@ -12519,7 +12933,7 @@ function isMineRenderScene(obj) {
12519
12933
  }
12520
12934
 
12521
12935
  // src/renderer/Renderer.ts
12522
- import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera as PerspectiveCamera2, SRGBColorSpace as SRGBColorSpace6, Vector3 as Vector314, WebGLRenderer as WebGLRenderer2 } from "three";
12936
+ import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace7, Vector3 as Vector314, WebGLRenderer } from "three";
12523
12937
  var import_ts_deepmerge9 = __toESM(require_dist());
12524
12938
  init_util();
12525
12939
  init_Model();
@@ -13224,7 +13638,7 @@ var _Renderer = class _Renderer {
13224
13638
  switch (this.options.camera.type) {
13225
13639
  case "perspective":
13226
13640
  default:
13227
- return new PerspectiveCamera2(
13641
+ return new PerspectiveCamera(
13228
13642
  this.options.camera.perspective.fov,
13229
13643
  this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
13230
13644
  this.options.camera.near,
@@ -13242,7 +13656,7 @@ var _Renderer = class _Renderer {
13242
13656
  }
13243
13657
  }
13244
13658
  createRenderer() {
13245
- const renderer = new WebGLRenderer2({
13659
+ const renderer = new WebGLRenderer({
13246
13660
  antialias: this.options.render.antialias,
13247
13661
  alpha: true,
13248
13662
  powerPreference: "high-performance",
@@ -13250,8 +13664,8 @@ var _Renderer = class _Renderer {
13250
13664
  });
13251
13665
  renderer.setClearColor(0, 0);
13252
13666
  renderer.shadowMap.enabled = true;
13253
- renderer.shadowMap.type = PCFSoftShadowMap;
13254
- renderer.outputColorSpace = SRGBColorSpace6;
13667
+ renderer.shadowMap.type = PCFShadowMap;
13668
+ renderer.outputColorSpace = SRGBColorSpace7;
13255
13669
  renderer.setPixelRatio(this.options.render.pixelRatio ?? 1);
13256
13670
  renderer.setSize(this.viewWidth, this.viewHeight);
13257
13671
  return renderer;
@@ -14368,7 +14782,7 @@ init_Model();
14368
14782
  // src/world/SectionMesh.ts
14369
14783
  init_CanvasCompat();
14370
14784
  init_Materials();
14371
- import { BufferGeometry as BufferGeometry6, Float32BufferAttribute as Float32BufferAttribute6, Group, Mesh as Mesh10 } from "three";
14785
+ import { BufferGeometry as BufferGeometry6, Float32BufferAttribute as Float32BufferAttribute6, Group, Mesh as Mesh9 } from "three";
14372
14786
  var SectionMesh = class _SectionMesh extends Group {
14373
14787
  constructor() {
14374
14788
  super(...arguments);
@@ -14453,7 +14867,7 @@ var SectionMesh = class _SectionMesh extends Group {
14453
14867
  const material = Materials.createShadedCanvasMaterial(canvas, false);
14454
14868
  material.vertexColors = true;
14455
14869
  const texture = material.uniforms?.map?.value ?? material.map;
14456
- const mesh = new Mesh10(geometry, material);
14870
+ const mesh = new Mesh9(geometry, material);
14457
14871
  section.add(mesh);
14458
14872
  section.ownedMeshes.push({ mesh, texture });
14459
14873
  }
@@ -14467,6 +14881,7 @@ var SectionMesh = class _SectionMesh extends Group {
14467
14881
  texture?.dispose();
14468
14882
  }
14469
14883
  this.removeFromParent();
14884
+ super.dispose();
14470
14885
  }
14471
14886
  };
14472
14887