@babylonjs/serializers 5.32.1 → 5.33.0

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.
@@ -6,6 +6,17 @@ import { TextureTools } from "@babylonjs/core/Misc/textureTools.js";
6
6
  import { Texture } from "@babylonjs/core/Materials/Textures/texture.js";
7
7
  import { RawTexture } from "@babylonjs/core/Materials/Textures/rawTexture.js";
8
8
  import { Constants } from "@babylonjs/core/Engines/constants.js";
9
+ import { DumpTools } from "@babylonjs/core/Misc/dumpTools.js";
10
+ function getFileExtensionFromMimeType(mimeType) {
11
+ switch (mimeType) {
12
+ case "image/jpeg" /* JPEG */:
13
+ return ".jpg";
14
+ case "image/png" /* PNG */:
15
+ return ".png";
16
+ case "image/webp" /* WEBP */:
17
+ return ".webp";
18
+ }
19
+ }
9
20
  /**
10
21
  * Utility methods for working with glTF material conversion properties. This class should only be used internally
11
22
  * @internal
@@ -16,6 +27,8 @@ export class _GLTFMaterialExporter {
16
27
  * Mapping to store textures
17
28
  */
18
29
  this._textureMap = {};
30
+ // Mapping of internal textures to images to avoid exporting duplicate images.
31
+ this._internalTextureToImage = {};
19
32
  this._textureMap = {};
20
33
  this._exporter = exporter;
21
34
  }
@@ -199,68 +212,68 @@ export class _GLTFMaterialExporter {
199
212
  const materialMap = this._exporter._materialMap;
200
213
  const materials = this._exporter._materials;
201
214
  const promises = [];
202
- const glTFPbrMetallicRoughness = this._convertToGLTFPBRMetallicRoughness(babylonStandardMaterial);
203
- const glTFMaterial = { name: babylonStandardMaterial.name };
215
+ const pbrMetallicRoughness = this._convertToGLTFPBRMetallicRoughness(babylonStandardMaterial);
216
+ const material = { name: babylonStandardMaterial.name };
204
217
  if (babylonStandardMaterial.backFaceCulling != null && !babylonStandardMaterial.backFaceCulling) {
205
218
  if (!babylonStandardMaterial.twoSidedLighting) {
206
219
  Tools.Warn(babylonStandardMaterial.name + ": Back-face culling disabled and two-sided lighting disabled is not supported in glTF.");
207
220
  }
208
- glTFMaterial.doubleSided = true;
221
+ material.doubleSided = true;
209
222
  }
210
223
  if (hasTextureCoords) {
211
224
  if (babylonStandardMaterial.diffuseTexture) {
212
- promises.push(this._exportTextureAsync(babylonStandardMaterial.diffuseTexture, mimeType).then((glTFTexture) => {
213
- if (glTFTexture) {
214
- glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
225
+ promises.push(this._exportTextureAsync(babylonStandardMaterial.diffuseTexture, mimeType).then((textureInfo) => {
226
+ if (textureInfo) {
227
+ pbrMetallicRoughness.baseColorTexture = textureInfo;
215
228
  }
216
229
  }));
217
230
  }
218
- if (babylonStandardMaterial.bumpTexture) {
219
- promises.push(this._exportTextureAsync(babylonStandardMaterial.bumpTexture, mimeType).then((glTFTexture) => {
220
- if (glTFTexture) {
221
- glTFMaterial.normalTexture = glTFTexture;
222
- if (babylonStandardMaterial.bumpTexture != null && babylonStandardMaterial.bumpTexture.level !== 1) {
223
- glTFMaterial.normalTexture.scale = babylonStandardMaterial.bumpTexture.level;
231
+ const bumpTexture = babylonStandardMaterial.bumpTexture;
232
+ if (bumpTexture) {
233
+ promises.push(this._exportTextureAsync(bumpTexture, mimeType).then((textureInfo) => {
234
+ if (textureInfo) {
235
+ material.normalTexture = textureInfo;
236
+ if (bumpTexture.level !== 1) {
237
+ material.normalTexture.scale = bumpTexture.level;
224
238
  }
225
239
  }
226
240
  }));
227
241
  }
228
242
  if (babylonStandardMaterial.emissiveTexture) {
229
- glTFMaterial.emissiveFactor = [1.0, 1.0, 1.0];
230
- promises.push(this._exportTextureAsync(babylonStandardMaterial.emissiveTexture, mimeType).then((glTFEmissiveTexture) => {
231
- if (glTFEmissiveTexture) {
232
- glTFMaterial.emissiveTexture = glTFEmissiveTexture;
243
+ material.emissiveFactor = [1.0, 1.0, 1.0];
244
+ promises.push(this._exportTextureAsync(babylonStandardMaterial.emissiveTexture, mimeType).then((textureInfo) => {
245
+ if (textureInfo) {
246
+ material.emissiveTexture = textureInfo;
233
247
  }
234
248
  }));
235
249
  }
236
250
  if (babylonStandardMaterial.ambientTexture) {
237
- promises.push(this._exportTextureAsync(babylonStandardMaterial.ambientTexture, mimeType).then((glTFTexture) => {
238
- if (glTFTexture) {
251
+ promises.push(this._exportTextureAsync(babylonStandardMaterial.ambientTexture, mimeType).then((textureInfo) => {
252
+ if (textureInfo) {
239
253
  const occlusionTexture = {
240
- index: glTFTexture.index,
254
+ index: textureInfo.index,
241
255
  };
242
- glTFMaterial.occlusionTexture = occlusionTexture;
243
- occlusionTexture.strength = 1.0;
256
+ material.occlusionTexture = occlusionTexture;
244
257
  }
245
258
  }));
246
259
  }
247
260
  }
248
261
  if (babylonStandardMaterial.alpha < 1.0 || babylonStandardMaterial.opacityTexture) {
249
262
  if (babylonStandardMaterial.alphaMode === Constants.ALPHA_COMBINE) {
250
- glTFMaterial.alphaMode = "BLEND" /* BLEND */;
263
+ material.alphaMode = "BLEND" /* BLEND */;
251
264
  }
252
265
  else {
253
266
  Tools.Warn(babylonStandardMaterial.name + ": glTF 2.0 does not support alpha mode: " + babylonStandardMaterial.alphaMode.toString());
254
267
  }
255
268
  }
256
269
  if (babylonStandardMaterial.emissiveColor && !_GLTFMaterialExporter._FuzzyEquals(babylonStandardMaterial.emissiveColor, Color3.Black(), _GLTFMaterialExporter._Epsilon)) {
257
- glTFMaterial.emissiveFactor = babylonStandardMaterial.emissiveColor.asArray();
270
+ material.emissiveFactor = babylonStandardMaterial.emissiveColor.asArray();
258
271
  }
259
- glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
260
- _GLTFMaterialExporter._SetAlphaMode(glTFMaterial, babylonStandardMaterial);
261
- materials.push(glTFMaterial);
272
+ material.pbrMetallicRoughness = pbrMetallicRoughness;
273
+ _GLTFMaterialExporter._SetAlphaMode(material, babylonStandardMaterial);
274
+ materials.push(material);
262
275
  materialMap[babylonStandardMaterial.uniqueId] = materials.length - 1;
263
- return this._finishMaterial(promises, glTFMaterial, babylonStandardMaterial, mimeType);
276
+ return this._finishMaterial(promises, material, babylonStandardMaterial, mimeType);
264
277
  }
265
278
  _finishMaterial(promises, glTFMaterial, babylonMaterial, mimeType) {
266
279
  return Promise.all(promises).then(() => {
@@ -292,19 +305,15 @@ export class _GLTFMaterialExporter {
292
305
  * @param mimeType mimetype of the image
293
306
  * @returns base64 image string
294
307
  */
295
- _createBase64FromCanvasAsync(buffer, width, height, mimeType) {
296
- // eslint-disable-next-line no-async-promise-executor
297
- return new Promise(async (resolve) => {
298
- const textureType = Constants.TEXTURETYPE_UNSIGNED_INT;
299
- const hostingScene = this._exporter._babylonScene;
300
- const engine = hostingScene.getEngine();
301
- // Create a temporary texture with the texture buffer data
302
- const tempTexture = engine.createRawTexture(buffer, width, height, Constants.TEXTUREFORMAT_RGBA, false, true, Texture.NEAREST_SAMPLINGMODE, null, textureType);
303
- await TextureTools.ApplyPostProcess("pass", tempTexture, hostingScene, textureType, Constants.TEXTURE_NEAREST_SAMPLINGMODE, Constants.TEXTUREFORMAT_RGBA);
304
- const data = await engine._readTexturePixels(tempTexture, width, height);
305
- const base64 = await Tools.DumpDataAsync(width, height, data, mimeType, undefined, true, false);
306
- resolve(base64);
307
- });
308
+ async _getImageDataAsync(buffer, width, height, mimeType) {
309
+ const textureType = Constants.TEXTURETYPE_UNSIGNED_INT;
310
+ const hostingScene = this._exporter._babylonScene;
311
+ const engine = hostingScene.getEngine();
312
+ // Create a temporary texture with the texture buffer data
313
+ const tempTexture = engine.createRawTexture(buffer, width, height, Constants.TEXTUREFORMAT_RGBA, false, true, Texture.NEAREST_SAMPLINGMODE, null, textureType);
314
+ await TextureTools.ApplyPostProcess("pass", tempTexture, hostingScene, textureType, Constants.TEXTURE_NEAREST_SAMPLINGMODE, Constants.TEXTUREFORMAT_RGBA);
315
+ const data = await engine._readTexturePixels(tempTexture, width, height);
316
+ return (await DumpTools.DumpDataAsync(width, height, data, mimeType, undefined, true, true));
308
317
  }
309
318
  /**
310
319
  * Generates a white texture based on the specified width and height
@@ -394,7 +403,7 @@ export class _GLTFMaterialExporter {
394
403
  */
395
404
  async _convertSpecularGlossinessTexturesToMetallicRoughnessAsync(diffuseTexture, specularGlossinessTexture, factors, mimeType) {
396
405
  var _a;
397
- const promises = [];
406
+ const promises = new Array();
398
407
  if (!(diffuseTexture || specularGlossinessTexture)) {
399
408
  return Promise.reject("_ConvertSpecularGlosinessTexturesToMetallicRoughness: diffuse and specular glossiness textures are not defined!");
400
409
  }
@@ -488,16 +497,14 @@ export class _GLTFMaterialExporter {
488
497
  }
489
498
  }
490
499
  if (writeOutMetallicRoughnessTexture) {
491
- const promise = this._createBase64FromCanvasAsync(metallicRoughnessBuffer, width, height, mimeType).then((metallicRoughnessBase64) => {
492
- metallicRoughnessFactors.metallicRoughnessTextureBase64 = metallicRoughnessBase64;
493
- });
494
- promises.push(promise);
500
+ promises.push(this._getImageDataAsync(metallicRoughnessBuffer, width, height, mimeType).then((data) => {
501
+ metallicRoughnessFactors.metallicRoughnessTextureData = data;
502
+ }));
495
503
  }
496
504
  if (writeOutBaseColorTexture) {
497
- const promise = this._createBase64FromCanvasAsync(baseColorBuffer, width, height, mimeType).then((baseColorBase64) => {
498
- metallicRoughnessFactors.baseColorTextureBase64 = baseColorBase64;
499
- });
500
- promises.push(promise);
505
+ promises.push(this._getImageDataAsync(baseColorBuffer, width, height, mimeType).then((data) => {
506
+ metallicRoughnessFactors.baseColorTextureData = data;
507
+ }));
501
508
  }
502
509
  return Promise.all(promises).then(() => {
503
510
  return metallicRoughnessFactors;
@@ -592,71 +599,79 @@ export class _GLTFMaterialExporter {
592
599
  return metallicRoughness;
593
600
  });
594
601
  }
595
- _getGLTFTextureSampler(texture) {
596
- const sampler = this._getGLTFTextureWrapModesSampler(texture);
597
- const samplingMode = texture instanceof Texture ? texture.samplingMode : null;
598
- if (samplingMode != null) {
599
- switch (samplingMode) {
600
- case Texture.LINEAR_LINEAR: {
601
- sampler.magFilter = 9729 /* LINEAR */;
602
- sampler.minFilter = 9729 /* LINEAR */;
603
- break;
604
- }
605
- case Texture.LINEAR_NEAREST: {
606
- sampler.magFilter = 9729 /* LINEAR */;
607
- sampler.minFilter = 9728 /* NEAREST */;
608
- break;
609
- }
610
- case Texture.NEAREST_LINEAR: {
611
- sampler.magFilter = 9728 /* NEAREST */;
612
- sampler.minFilter = 9729 /* LINEAR */;
613
- break;
614
- }
615
- case Texture.NEAREST_LINEAR_MIPLINEAR: {
616
- sampler.magFilter = 9728 /* NEAREST */;
617
- sampler.minFilter = 9987 /* LINEAR_MIPMAP_LINEAR */;
618
- break;
619
- }
620
- case Texture.NEAREST_NEAREST: {
621
- sampler.magFilter = 9728 /* NEAREST */;
622
- sampler.minFilter = 9728 /* NEAREST */;
623
- break;
624
- }
625
- case Texture.NEAREST_LINEAR_MIPNEAREST: {
626
- sampler.magFilter = 9728 /* NEAREST */;
627
- sampler.minFilter = 9985 /* LINEAR_MIPMAP_NEAREST */;
628
- break;
629
- }
630
- case Texture.LINEAR_NEAREST_MIPNEAREST: {
631
- sampler.magFilter = 9729 /* LINEAR */;
632
- sampler.minFilter = 9984 /* NEAREST_MIPMAP_NEAREST */;
633
- break;
634
- }
635
- case Texture.LINEAR_NEAREST_MIPLINEAR: {
636
- sampler.magFilter = 9729 /* LINEAR */;
637
- sampler.minFilter = 9986 /* NEAREST_MIPMAP_LINEAR */;
638
- break;
639
- }
640
- case Texture.NEAREST_NEAREST_MIPLINEAR: {
641
- sampler.magFilter = 9728 /* NEAREST */;
642
- sampler.minFilter = 9986 /* NEAREST_MIPMAP_LINEAR */;
643
- break;
644
- }
645
- case Texture.LINEAR_LINEAR_MIPLINEAR: {
646
- sampler.magFilter = 9729 /* LINEAR */;
647
- sampler.minFilter = 9987 /* LINEAR_MIPMAP_LINEAR */;
648
- break;
649
- }
650
- case Texture.LINEAR_LINEAR_MIPNEAREST: {
651
- sampler.magFilter = 9729 /* LINEAR */;
652
- sampler.minFilter = 9985 /* LINEAR_MIPMAP_NEAREST */;
653
- break;
654
- }
655
- case Texture.NEAREST_NEAREST_MIPNEAREST: {
656
- sampler.magFilter = 9728 /* NEAREST */;
657
- sampler.minFilter = 9984 /* NEAREST_MIPMAP_NEAREST */;
658
- break;
659
- }
602
+ _getTextureSampler(texture) {
603
+ const sampler = {};
604
+ if (!texture || !(texture instanceof Texture)) {
605
+ return sampler;
606
+ }
607
+ const wrapS = this._getGLTFTextureWrapMode(texture.wrapU);
608
+ if (wrapS !== 10497 /* REPEAT */) {
609
+ sampler.wrapS = wrapS;
610
+ }
611
+ const wrapT = this._getGLTFTextureWrapMode(texture.wrapV);
612
+ if (wrapT !== 10497 /* REPEAT */) {
613
+ sampler.wrapT = wrapT;
614
+ }
615
+ switch (texture.samplingMode) {
616
+ case Texture.LINEAR_LINEAR: {
617
+ sampler.magFilter = 9729 /* LINEAR */;
618
+ sampler.minFilter = 9729 /* LINEAR */;
619
+ break;
620
+ }
621
+ case Texture.LINEAR_NEAREST: {
622
+ sampler.magFilter = 9729 /* LINEAR */;
623
+ sampler.minFilter = 9728 /* NEAREST */;
624
+ break;
625
+ }
626
+ case Texture.NEAREST_LINEAR: {
627
+ sampler.magFilter = 9728 /* NEAREST */;
628
+ sampler.minFilter = 9729 /* LINEAR */;
629
+ break;
630
+ }
631
+ case Texture.NEAREST_LINEAR_MIPLINEAR: {
632
+ sampler.magFilter = 9728 /* NEAREST */;
633
+ sampler.minFilter = 9987 /* LINEAR_MIPMAP_LINEAR */;
634
+ break;
635
+ }
636
+ case Texture.NEAREST_NEAREST: {
637
+ sampler.magFilter = 9728 /* NEAREST */;
638
+ sampler.minFilter = 9728 /* NEAREST */;
639
+ break;
640
+ }
641
+ case Texture.NEAREST_LINEAR_MIPNEAREST: {
642
+ sampler.magFilter = 9728 /* NEAREST */;
643
+ sampler.minFilter = 9985 /* LINEAR_MIPMAP_NEAREST */;
644
+ break;
645
+ }
646
+ case Texture.LINEAR_NEAREST_MIPNEAREST: {
647
+ sampler.magFilter = 9729 /* LINEAR */;
648
+ sampler.minFilter = 9984 /* NEAREST_MIPMAP_NEAREST */;
649
+ break;
650
+ }
651
+ case Texture.LINEAR_NEAREST_MIPLINEAR: {
652
+ sampler.magFilter = 9729 /* LINEAR */;
653
+ sampler.minFilter = 9986 /* NEAREST_MIPMAP_LINEAR */;
654
+ break;
655
+ }
656
+ case Texture.NEAREST_NEAREST_MIPLINEAR: {
657
+ sampler.magFilter = 9728 /* NEAREST */;
658
+ sampler.minFilter = 9986 /* NEAREST_MIPMAP_LINEAR */;
659
+ break;
660
+ }
661
+ case Texture.LINEAR_LINEAR_MIPLINEAR: {
662
+ sampler.magFilter = 9729 /* LINEAR */;
663
+ sampler.minFilter = 9987 /* LINEAR_MIPMAP_LINEAR */;
664
+ break;
665
+ }
666
+ case Texture.LINEAR_LINEAR_MIPNEAREST: {
667
+ sampler.magFilter = 9729 /* LINEAR */;
668
+ sampler.minFilter = 9985 /* LINEAR_MIPMAP_NEAREST */;
669
+ break;
670
+ }
671
+ case Texture.NEAREST_NEAREST_MIPNEAREST: {
672
+ sampler.magFilter = 9728 /* NEAREST */;
673
+ sampler.minFilter = 9984 /* NEAREST_MIPMAP_NEAREST */;
674
+ break;
660
675
  }
661
676
  }
662
677
  return sampler;
@@ -678,15 +693,6 @@ export class _GLTFMaterialExporter {
678
693
  }
679
694
  }
680
695
  }
681
- _getGLTFTextureWrapModesSampler(texture) {
682
- const wrapS = this._getGLTFTextureWrapMode(texture instanceof Texture ? texture.wrapU : Texture.WRAP_ADDRESSMODE);
683
- const wrapT = this._getGLTFTextureWrapMode(texture instanceof Texture ? texture.wrapV : Texture.WRAP_ADDRESSMODE);
684
- if (wrapS === 10497 /* REPEAT */ && wrapT === 10497 /* REPEAT */) {
685
- // default wrapping mode in glTF, so omitting
686
- return {};
687
- }
688
- return { wrapS: wrapS, wrapT: wrapT };
689
- }
690
696
  /**
691
697
  * Convert a PBRMaterial (Specular/Glossiness) to Metallic Roughness factors
692
698
  * @param babylonPBRMaterial BJS PBR Metallic Roughness Material
@@ -695,45 +701,30 @@ export class _GLTFMaterialExporter {
695
701
  * @param hasTextureCoords specifies if texture coordinates are present on the submesh to determine if textures should be applied
696
702
  * @returns glTF PBR Metallic Roughness factors
697
703
  */
698
- _convertSpecGlossFactorsToMetallicRoughnessAsync(babylonPBRMaterial, mimeType, glTFPbrMetallicRoughness, hasTextureCoords) {
704
+ _convertSpecGlossFactorsToMetallicRoughnessAsync(babylonPBRMaterial, mimeType, pbrMetallicRoughness, hasTextureCoords) {
699
705
  return Promise.resolve().then(() => {
700
- const samplers = this._exporter._samplers;
701
- const textures = this._exporter._textures;
702
- const diffuseColor = babylonPBRMaterial._albedoColor;
703
- const specularColor = babylonPBRMaterial._reflectivityColor;
704
- const glossiness = babylonPBRMaterial._microSurface;
705
706
  const specGloss = {
706
- diffuseColor: diffuseColor,
707
- specularColor: specularColor,
708
- glossiness: glossiness,
707
+ diffuseColor: babylonPBRMaterial._albedoColor,
708
+ specularColor: babylonPBRMaterial._reflectivityColor,
709
+ glossiness: babylonPBRMaterial._microSurface,
709
710
  };
710
- let samplerIndex = null;
711
711
  const albedoTexture = babylonPBRMaterial._albedoTexture;
712
712
  const reflectivityTexture = babylonPBRMaterial._reflectivityTexture;
713
- if (albedoTexture) {
714
- const sampler = this._getGLTFTextureSampler(albedoTexture);
715
- if (sampler.magFilter != null && sampler.minFilter != null && sampler.wrapS != null && sampler.wrapT != null) {
716
- samplers.push(sampler);
717
- samplerIndex = samplers.length - 1;
718
- }
719
- }
720
713
  const useMicrosurfaceFromReflectivityMapAlpha = babylonPBRMaterial._useMicroSurfaceFromReflectivityMapAlpha;
721
714
  if (reflectivityTexture && !useMicrosurfaceFromReflectivityMapAlpha) {
722
715
  return Promise.reject("_ConvertPBRMaterial: Glossiness values not included in the reflectivity texture are currently not supported");
723
716
  }
724
717
  if ((albedoTexture || reflectivityTexture) && hasTextureCoords) {
718
+ const samplerIndex = this._exportTextureSampler(albedoTexture || reflectivityTexture);
725
719
  return this._convertSpecularGlossinessTexturesToMetallicRoughnessAsync(albedoTexture, reflectivityTexture, specGloss, mimeType).then((metallicRoughnessFactors) => {
726
- if (metallicRoughnessFactors.baseColorTextureBase64) {
727
- const glTFBaseColorTexture = this._getTextureInfoFromBase64(metallicRoughnessFactors.baseColorTextureBase64, "bjsBaseColorTexture_" + textures.length + ".png", mimeType, albedoTexture ? albedoTexture.coordinatesIndex : null, samplerIndex);
728
- if (glTFBaseColorTexture) {
729
- glTFPbrMetallicRoughness.baseColorTexture = glTFBaseColorTexture;
730
- }
720
+ const textures = this._exporter._textures;
721
+ if (metallicRoughnessFactors.baseColorTextureData) {
722
+ const imageIndex = this._exportImage(`baseColor${textures.length}`, mimeType, metallicRoughnessFactors.baseColorTextureData);
723
+ pbrMetallicRoughness.baseColorTexture = this._exportTextureInfo(imageIndex, samplerIndex, albedoTexture === null || albedoTexture === void 0 ? void 0 : albedoTexture.coordinatesIndex);
731
724
  }
732
- if (metallicRoughnessFactors.metallicRoughnessTextureBase64) {
733
- const glTFMRColorTexture = this._getTextureInfoFromBase64(metallicRoughnessFactors.metallicRoughnessTextureBase64, "bjsMetallicRoughnessTexture_" + textures.length + ".png", mimeType, reflectivityTexture ? reflectivityTexture.coordinatesIndex : null, samplerIndex);
734
- if (glTFMRColorTexture) {
735
- glTFPbrMetallicRoughness.metallicRoughnessTexture = glTFMRColorTexture;
736
- }
725
+ if (metallicRoughnessFactors.metallicRoughnessTextureData) {
726
+ const imageIndex = this._exportImage(`metallicRoughness${textures.length}`, mimeType, metallicRoughnessFactors.metallicRoughnessTextureData);
727
+ pbrMetallicRoughness.metallicRoughnessTexture = this._exportTextureInfo(imageIndex, samplerIndex, reflectivityTexture === null || reflectivityTexture === void 0 ? void 0 : reflectivityTexture.coordinatesIndex);
737
728
  }
738
729
  return metallicRoughnessFactors;
739
730
  });
@@ -867,129 +858,92 @@ export class _GLTFMaterialExporter {
867
858
  return this._exportTextureInfoAsync(texture, mimeType);
868
859
  });
869
860
  }
870
- _exportTextureInfoAsync(babylonTexture, mimeType) {
871
- return Promise.resolve().then(async () => {
872
- const textureUid = babylonTexture.uid;
873
- if (textureUid in this._textureMap) {
874
- return this._textureMap[textureUid];
875
- }
876
- else {
877
- const pixels = await this._getPixelsFromTexture(babylonTexture);
878
- if (!pixels) {
879
- return null;
880
- }
881
- const samplers = this._exporter._samplers;
882
- const sampler = this._getGLTFTextureSampler(babylonTexture);
883
- let samplerIndex = null;
884
- // if a pre-existing sampler with identical parameters exists, then reuse the previous sampler
885
- let foundSamplerIndex = null;
886
- for (let i = 0; i < samplers.length; ++i) {
887
- const s = samplers[i];
888
- if (s.minFilter === sampler.minFilter && s.magFilter === sampler.magFilter && s.wrapS === sampler.wrapS && s.wrapT === sampler.wrapT) {
889
- foundSamplerIndex = i;
861
+ async _exportTextureInfoAsync(babylonTexture, mimeType) {
862
+ const textureUid = babylonTexture.uid;
863
+ if (textureUid in this._textureMap) {
864
+ return this._textureMap[textureUid];
865
+ }
866
+ else {
867
+ const pixels = await this._getPixelsFromTexture(babylonTexture);
868
+ if (!pixels) {
869
+ return null;
870
+ }
871
+ const samplerIndex = this._exportTextureSampler(babylonTexture);
872
+ // Preserve texture mime type if defined
873
+ const textureMimeType = babylonTexture.mimeType;
874
+ if (textureMimeType) {
875
+ switch (textureMimeType) {
876
+ case "image/jpeg":
877
+ case "image/png":
878
+ case "image/webp":
879
+ mimeType = textureMimeType;
880
+ break;
881
+ default:
882
+ Tools.Warn("Unsupported media type: ${textureMimeType}");
890
883
  break;
891
- }
892
- }
893
- if (foundSamplerIndex == null) {
894
- samplers.push(sampler);
895
- samplerIndex = samplers.length - 1;
896
- }
897
- else {
898
- samplerIndex = foundSamplerIndex;
899
884
  }
885
+ }
886
+ const internalTextureToImage = this._internalTextureToImage;
887
+ const internalTextureUniqueId = babylonTexture.getInternalTexture().uniqueId;
888
+ internalTextureToImage[internalTextureUniqueId] || (internalTextureToImage[internalTextureUniqueId] = {});
889
+ let imageIndex = internalTextureToImage[internalTextureUniqueId][mimeType];
890
+ if (imageIndex === undefined) {
900
891
  const size = babylonTexture.getSize();
901
- // Preserve texture mime type if defined
902
- if (babylonTexture.mimeType) {
903
- switch (babylonTexture.mimeType) {
904
- case "image/jpeg":
905
- mimeType = "image/jpeg" /* JPEG */;
906
- break;
907
- case "image/png":
908
- mimeType = "image/png" /* PNG */;
909
- break;
910
- case "image/webp":
911
- mimeType = "image/webp" /* WEBP */;
912
- break;
913
- }
914
- }
915
- return this._createBase64FromCanvasAsync(pixels, size.width, size.height, mimeType).then((base64Data) => {
916
- const textureInfo = this._getTextureInfoFromBase64(base64Data, babylonTexture.name.replace(/\.\/|\/|\.\\|\\/g, "_"), mimeType, babylonTexture.coordinatesIndex, samplerIndex);
917
- if (textureInfo) {
918
- this._textureMap[textureUid] = textureInfo;
919
- this._exporter._extensionsPostExportTextures("linkTextureInfo", textureInfo, babylonTexture);
920
- }
921
- return textureInfo;
922
- });
892
+ const data = await this._getImageDataAsync(pixels, size.width, size.height, mimeType);
893
+ imageIndex = this._exportImage(babylonTexture.name, mimeType, data);
894
+ internalTextureToImage[internalTextureUniqueId][mimeType] = imageIndex;
923
895
  }
924
- });
896
+ const textureInfo = this._exportTextureInfo(imageIndex, samplerIndex, babylonTexture.coordinatesIndex);
897
+ this._textureMap[textureUid] = textureInfo;
898
+ return textureInfo;
899
+ }
925
900
  }
926
- /**
927
- * Builds a texture from base64 string
928
- * @param base64Texture base64 texture string
929
- * @param baseTextureName Name to use for the texture
930
- * @param mimeType image mime type for the texture
931
- * @param texCoordIndex
932
- * @param samplerIndex
933
- * @returns glTF texture info, or null if the texture format is not supported
934
- */
935
- _getTextureInfoFromBase64(base64Texture, baseTextureName, mimeType, texCoordIndex, samplerIndex) {
936
- const textures = this._exporter._textures;
937
- const images = this._exporter._images;
901
+ _exportImage(name, mimeType, data) {
938
902
  const imageData = this._exporter._imageData;
939
- let textureInfo = null;
940
- const glTFTexture = {
941
- source: images.length,
942
- name: baseTextureName,
903
+ const baseName = name.replace(/\.\/|\/|\.\\|\\/g, "_");
904
+ const extension = getFileExtensionFromMimeType(mimeType);
905
+ let fileName = baseName + extension;
906
+ if (fileName in imageData) {
907
+ fileName = `${baseName}_${Tools.RandomId()}${extension}`;
908
+ }
909
+ imageData[fileName] = {
910
+ data: data,
911
+ mimeType: mimeType,
943
912
  };
944
- if (samplerIndex != null) {
945
- glTFTexture.sampler = samplerIndex;
946
- }
947
- const binStr = atob(base64Texture.split(",")[1]);
948
- const arrBuff = new ArrayBuffer(binStr.length);
949
- const arr = new Uint8Array(arrBuff);
950
- for (let i = 0, length = binStr.length; i < length; ++i) {
951
- arr[i] = binStr.charCodeAt(i);
952
- }
953
- const imageValues = { data: arr, mimeType: mimeType };
954
- const extension = mimeType === "image/jpeg" /* JPEG */ ? ".jpeg" : ".png";
955
- let textureName = baseTextureName + extension;
956
- const originalTextureName = textureName;
957
- if (textureName in imageData) {
958
- textureName = `${baseTextureName}_${Tools.RandomId()}${extension}`;
959
- }
960
- imageData[textureName] = imageValues;
961
- if (mimeType === "image/jpeg" /* JPEG */ || mimeType === "image/png" /* PNG */ || mimeType === "image/webp" /* WEBP */) {
962
- const glTFImage = {
963
- name: baseTextureName,
964
- uri: textureName,
965
- };
966
- let foundIndex = null;
967
- for (let i = 0; i < images.length; ++i) {
968
- if (images[i].uri === originalTextureName) {
969
- foundIndex = i;
970
- break;
971
- }
972
- }
973
- if (foundIndex == null) {
974
- images.push(glTFImage);
975
- glTFTexture.source = images.length - 1;
976
- }
977
- else {
978
- glTFTexture.source = foundIndex;
979
- }
980
- textures.push(glTFTexture);
981
- textureInfo = {
982
- index: textures.length - 1,
983
- };
984
- if (texCoordIndex != null) {
985
- textureInfo.texCoord = texCoordIndex;
986
- }
913
+ const images = this._exporter._images;
914
+ images.push({
915
+ name: name,
916
+ uri: fileName,
917
+ });
918
+ return images.length - 1;
919
+ }
920
+ _exportTextureInfo(imageIndex, samplerIndex, coordinatesIndex) {
921
+ const textures = this._exporter._textures;
922
+ let textureIndex = textures.findIndex((t) => t.sampler == samplerIndex && t.source === imageIndex);
923
+ if (textureIndex === -1) {
924
+ textureIndex = textures.length;
925
+ textures.push({
926
+ source: imageIndex,
927
+ sampler: samplerIndex,
928
+ });
987
929
  }
988
- else {
989
- Tools.Error(`Unsupported texture mime type ${mimeType}`);
930
+ const textureInfo = { index: textureIndex };
931
+ if (coordinatesIndex) {
932
+ textureInfo.texCoord = coordinatesIndex;
990
933
  }
991
934
  return textureInfo;
992
935
  }
936
+ _exportTextureSampler(texture) {
937
+ const sampler = this._getTextureSampler(texture);
938
+ // if a pre-existing sampler with identical parameters exists, then reuse the previous sampler
939
+ const samplers = this._exporter._samplers;
940
+ const samplerIndex = samplers.findIndex((s) => s.minFilter === sampler.minFilter && s.magFilter === sampler.magFilter && s.wrapS === sampler.wrapS && s.wrapT === sampler.wrapT);
941
+ if (samplerIndex !== -1) {
942
+ return samplerIndex;
943
+ }
944
+ samplers.push(sampler);
945
+ return samplers.length - 1;
946
+ }
993
947
  }
994
948
  /**
995
949
  * Represents the dielectric specular values for R, G and B