@babylonjs/serializers 5.32.0 → 5.32.2

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