@xeokit/xeokit-sdk 2.3.0-beta-11 → 2.3.0-beta-14

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.
@@ -15295,7 +15295,7 @@ class RenderBufferManager {
15295
15295
  /**
15296
15296
  * @private
15297
15297
  */
15298
- function getExtension$1 (gl, name) {
15298
+ function getExtension (gl, name) {
15299
15299
  if (gl._cachedExtensions === undefined) {
15300
15300
  gl._cachedExtensions = {};
15301
15301
  }
@@ -15361,12 +15361,12 @@ const Renderer = function (scene, options) {
15361
15361
  this._occlusionTester = null; // Lazy-created in #addMarker()
15362
15362
 
15363
15363
  this.capabilities = {
15364
- astcSupported: !!getExtension$1(gl, 'WEBGL_compressed_texture_astc'),
15364
+ astcSupported: !!getExtension(gl, 'WEBGL_compressed_texture_astc'),
15365
15365
  etc1Supported: true, // WebGL2
15366
- etc2Supported: !!getExtension$1(gl, 'WEBGL_compressed_texture_etc'),
15367
- dxtSupported: !!getExtension$1(gl, 'WEBGL_compressed_texture_s3tc'),
15368
- bptcSupported: !!getExtension$1(gl, 'EXT_texture_compression_bptc'),
15369
- pvrtcSupported: !!(getExtension$1(gl, 'WEBGL_compressed_texture_pvrtc') || getExtension$1(gl, 'WEBKIT_WEBGL_compressed_texture_pvrtc'))
15366
+ etc2Supported: !!getExtension(gl, 'WEBGL_compressed_texture_etc'),
15367
+ dxtSupported: !!getExtension(gl, 'WEBGL_compressed_texture_s3tc'),
15368
+ bptcSupported: !!getExtension(gl, 'EXT_texture_compression_bptc'),
15369
+ pvrtcSupported: !!(getExtension(gl, 'WEBGL_compressed_texture_pvrtc') || getExtension(gl, 'WEBKIT_WEBGL_compressed_texture_pvrtc'))
15370
15370
  };
15371
15371
 
15372
15372
  this.setTransparentEnabled = function (enabled) {
@@ -27797,6 +27797,7 @@ const ClampToEdgeWrapping = 1001;
27797
27797
  const MirroredRepeatWrapping = 1002;
27798
27798
  const NearestFilter = 1003;
27799
27799
  const NearestMipMapNearestFilter = 1004;
27800
+ const NearestMipmapNearestFilter = 1004;
27800
27801
  const NearestMipmapLinearFilter = 1005;
27801
27802
  const NearestMipMapLinearFilter = 1005;
27802
27803
  const LinearFilter = 1006;
@@ -64413,7 +64414,7 @@ function convertConstant(gl, constantVal, encoding = null) {
64413
64414
 
64414
64415
  if (p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format) {
64415
64416
  if (encoding === sRGBEncoding) {
64416
- const extension = getExtension$1(gl, 'WEBGL_compressed_texture_s3tc_srgb');
64417
+ const extension = getExtension(gl, 'WEBGL_compressed_texture_s3tc_srgb');
64417
64418
  if (extension !== null) {
64418
64419
  if (p === RGB_S3TC_DXT1_Format) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT;
64419
64420
  if (p === RGBA_S3TC_DXT1_Format) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
@@ -64423,7 +64424,7 @@ function convertConstant(gl, constantVal, encoding = null) {
64423
64424
  return null;
64424
64425
  }
64425
64426
  } else {
64426
- extension = getExtension$1(gl, 'WEBGL_compressed_texture_s3tc');
64427
+ extension = getExtension(gl, 'WEBGL_compressed_texture_s3tc');
64427
64428
  if (extension !== null) {
64428
64429
  if (p === RGB_S3TC_DXT1_Format) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
64429
64430
  if (p === RGBA_S3TC_DXT1_Format) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
@@ -64438,7 +64439,7 @@ function convertConstant(gl, constantVal, encoding = null) {
64438
64439
  // PVRTC
64439
64440
 
64440
64441
  if (p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format) {
64441
- const extension = getExtension$1(gl, 'WEBGL_compressed_texture_pvrtc');
64442
+ const extension = getExtension(gl, 'WEBGL_compressed_texture_pvrtc');
64442
64443
  if (extension !== null) {
64443
64444
  if (p === RGB_PVRTC_4BPPV1_Format) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
64444
64445
  if (p === RGB_PVRTC_2BPPV1_Format) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
@@ -64452,7 +64453,7 @@ function convertConstant(gl, constantVal, encoding = null) {
64452
64453
  // ETC1
64453
64454
 
64454
64455
  if (p === RGB_ETC1_Format) {
64455
- const extension = getExtension$1(gl, 'WEBGL_compressed_texture_etc1');
64456
+ const extension = getExtension(gl, 'WEBGL_compressed_texture_etc1');
64456
64457
  if (extension !== null) {
64457
64458
  return extension.COMPRESSED_RGB_ETC1_WEBGL;
64458
64459
  } else {
@@ -64463,7 +64464,7 @@ function convertConstant(gl, constantVal, encoding = null) {
64463
64464
  // ETC2
64464
64465
 
64465
64466
  if (p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format) {
64466
- const extension = getExtension$1(gl, 'WEBGL_compressed_texture_etc');
64467
+ const extension = getExtension(gl, 'WEBGL_compressed_texture_etc');
64467
64468
  if (extension !== null) {
64468
64469
  if (p === RGB_ETC2_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2;
64469
64470
  if (p === RGBA_ETC2_EAC_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC;
@@ -64479,7 +64480,7 @@ function convertConstant(gl, constantVal, encoding = null) {
64479
64480
  p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format ||
64480
64481
  p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format ||
64481
64482
  p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format) {
64482
- const extension = getExtension$1(gl, 'WEBGL_compressed_texture_astc');
64483
+ const extension = getExtension(gl, 'WEBGL_compressed_texture_astc');
64483
64484
  if (extension !== null) {
64484
64485
  if (p === RGBA_ASTC_4x4_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR;
64485
64486
  if (p === RGBA_ASTC_5x4_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR;
@@ -64503,7 +64504,7 @@ function convertConstant(gl, constantVal, encoding = null) {
64503
64504
  // BPTC
64504
64505
 
64505
64506
  if (p === RGBA_BPTC_Format) {
64506
- const extension = getExtension$1(gl, 'EXT_texture_compression_bptc');
64507
+ const extension = getExtension(gl, 'EXT_texture_compression_bptc');
64507
64508
  if (extension !== null) {
64508
64509
  if (p === RGBA_BPTC_Format) {
64509
64510
  return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT;
@@ -64536,9 +64537,6 @@ function convertConstant(gl, constantVal, encoding = null) {
64536
64537
  if (p === LinearMipMapLinearFilter) {
64537
64538
  return gl.LINEAR_MIPMAP_LINEAR;
64538
64539
  }
64539
- if (p === NearestMipMapLinearFilter) {
64540
- return gl.NEAREST_MIPMAP_LINEAR;
64541
- }
64542
64540
  if (p === NearestFilter) {
64543
64541
  return gl.NEAREST;
64544
64542
  }
@@ -64576,7 +64574,7 @@ class Texture2D {
64576
64574
  this.texture = gl.createTexture();
64577
64575
 
64578
64576
  if (preloadColor) {
64579
- this.setPreloadColor(preloadColor || [0, 0, 0, 1]); // Prevents "there is no texture bound to the unit 0" error
64577
+ this.setPreloadColor(preloadColor); // Prevents "there is no texture bound to the unit 0" error
64580
64578
  }
64581
64579
 
64582
64580
  this.allocated = true;
@@ -64595,9 +64593,6 @@ class Texture2D {
64595
64593
  color$2[3] = Math.floor((value[3] !== undefined ? value[3] : 1) * 255);
64596
64594
  }
64597
64595
  const gl = this.gl;
64598
- const glFormat = convertConstant(gl, this.format, this.encoding);
64599
- const glType = convertConstant(gl, this.type);
64600
- const glInternalFormat = getInternalFormat(gl, this.internalFormat, glFormat, glType, this.encoding, false);
64601
64596
  gl.bindTexture(this.target, this.texture);
64602
64597
  if (this.target === gl.TEXTURE_CUBE_MAP) {
64603
64598
  const faces = [
@@ -64609,10 +64604,10 @@ class Texture2D {
64609
64604
  gl.TEXTURE_CUBE_MAP_NEGATIVE_Z
64610
64605
  ];
64611
64606
  for (let i = 0, len = faces.length; i < len; i++) {
64612
- gl.texImage2D(faces[i], 0, glInternalFormat, 1, 1, 0, glFormat, glType, color$2);
64607
+ gl.texImage2D(faces[i], 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, color$2);
64613
64608
  }
64614
64609
  } else {
64615
- gl.texImage2D(this.target, 0, glInternalFormat, 1, 1, 0, glFormat, glType, color$2);
64610
+ gl.texImage2D(this.target, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, color$2);
64616
64611
  }
64617
64612
  gl.bindTexture(this.target, null);
64618
64613
  }
@@ -64772,44 +64767,38 @@ class Texture2D {
64772
64767
  gl.activeTexture(gl.TEXTURE0 + 0);
64773
64768
  gl.bindTexture(this.target, this.texture);
64774
64769
 
64775
- let generateMipMap = false;
64770
+ let supportsMips = mipmaps.length > 1;
64776
64771
 
64777
64772
  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, this.flipY);
64778
64773
  gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.premultiplyAlpha);
64779
64774
  gl.pixelStorei(gl.UNPACK_ALIGNMENT, this.unpackAlignment);
64780
64775
  gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
64781
64776
 
64782
- {
64783
-
64784
- const minFilter = convertConstant(gl, this.minFilter);
64785
- gl.texParameteri(this.target, gl.TEXTURE_MIN_FILTER, minFilter);
64786
- if (minFilter === gl.NEAREST_MIPMAP_NEAREST || minFilter === gl.LINEAR_MIPMAP_NEAREST || minFilter === gl.NEAREST_MIPMAP_LINEAR || minFilter === gl.LINEAR_MIPMAP_LINEAR) {
64787
- generateMipMap = true;
64788
- }
64789
-
64790
- const magFilter = convertConstant(gl, this.magFilter);
64791
- if (magFilter) {
64792
- gl.texParameteri(this.target, gl.TEXTURE_MAG_FILTER, magFilter);
64793
- }
64777
+ const wrapS = convertConstant(gl, this.wrapS);
64778
+ if (wrapS) {
64779
+ gl.texParameteri(this.target, gl.TEXTURE_WRAP_S, wrapS);
64780
+ }
64794
64781
 
64795
- const wrapS = convertConstant(gl, this.wrapS);
64796
- if (wrapS) {
64797
- gl.texParameteri(this.target, gl.TEXTURE_WRAP_S, wrapS);
64798
- }
64782
+ const wrapT = convertConstant(gl, this.wrapT);
64783
+ if (wrapT) {
64784
+ gl.texParameteri(this.target, gl.TEXTURE_WRAP_T, wrapT);
64785
+ }
64799
64786
 
64800
- const wrapT = convertConstant(gl, this.wrapT);
64801
- if (wrapT) {
64802
- gl.texParameteri(this.target, gl.TEXTURE_WRAP_T, wrapT);
64787
+ if (this.type === gl.TEXTURE_3D || this.type === gl.TEXTURE_2D_ARRAY) {
64788
+ const wrapR = convertConstant(gl, this.wrapR);
64789
+ if (wrapR) {
64790
+ gl.texParameteri(this.target, gl.TEXTURE_WRAP_R, wrapR);
64803
64791
  }
64792
+ gl.texParameteri(this.type, gl.TEXTURE_WRAP_R, wrapR);
64793
+ }
64804
64794
 
64805
- if (this.type === gl.TEXTURE_3D || this.type === gl.TEXTURE_2D_ARRAY) {
64806
- const wrapR = convertConstant(gl, this.wrapR);
64807
- if (wrapR) {
64808
- gl.texParameteri(this.target, gl.TEXTURE_WRAP_R, wrapR);
64809
- }
64810
- gl.texParameteri(this.type, gl.TEXTURE_WRAP_R, wrapR);
64811
- }
64795
+ if (supportsMips) {
64796
+ gl.texParameteri(this.target, gl.TEXTURE_MIN_FILTER, filterFallback(gl, this.minFilter));
64797
+ gl.texParameteri(this.target, gl.TEXTURE_MAG_FILTER, filterFallback(gl, this.magFilter));
64812
64798
 
64799
+ } else {
64800
+ gl.texParameteri(this.target, gl.TEXTURE_MIN_FILTER, convertConstant(gl, this.minFilter));
64801
+ gl.texParameteri(this.target, gl.TEXTURE_MAG_FILTER, convertConstant(gl, this.magFilter));
64813
64802
  }
64814
64803
 
64815
64804
  const glFormat = convertConstant(gl, this.format, this.encoding);
@@ -64829,13 +64818,13 @@ class Texture2D {
64829
64818
  console.warn('Attempt to load unsupported compressed texture format in .setCompressedData()');
64830
64819
  }
64831
64820
  } else {
64832
- gl.texSubImage2D(gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data);
64821
+ gl.texSubImage2D(gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data);
64833
64822
  }
64834
64823
  }
64835
64824
 
64836
- if (generateMipMap) {
64837
- gl.generateMipmap(this.target);
64838
- }
64825
+ // if (generateMipMap) {
64826
+ // // gl.generateMipmap(this.target); // Only for roughness textures?
64827
+ // }
64839
64828
 
64840
64829
  gl.bindTexture(this.target, null);
64841
64830
  }
@@ -64962,6 +64951,14 @@ function getInternalFormat(gl, internalFormatName, glFormat, glType, encoding, i
64962
64951
  return internalFormat;
64963
64952
  }
64964
64953
 
64954
+ function filterFallback(gl, f) {
64955
+ if (f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter) {
64956
+ return gl.NEAREST;
64957
+ }
64958
+ return gl.LINEAR;
64959
+
64960
+ }
64961
+
64965
64962
  /**
64966
64963
  * Instantiated by VBOSceneModel#createTexture
64967
64964
  *
@@ -65882,6 +65879,1059 @@ class SceneModel {
65882
65879
  }
65883
65880
  }
65884
65881
 
65882
+ class LoadingManager {
65883
+
65884
+ constructor(onLoad, onProgress, onError) {
65885
+
65886
+ this.isLoading = false;
65887
+ this.itemsLoaded = 0;
65888
+ this.itemsTotal = 0;
65889
+ this.urlModifier = undefined;
65890
+ this.handlers = [];
65891
+
65892
+ this.onStart = undefined;
65893
+ this.onLoad = onLoad;
65894
+ this.onProgress = onProgress;
65895
+ this.onError = onError;
65896
+ }
65897
+
65898
+ itemStart(url) {
65899
+ this.itemsTotal++;
65900
+ if (this.isLoading === false) {
65901
+ if (this.onStart !== undefined) {
65902
+ this.onStart(url, this.itemsLoaded, this.itemsTotal);
65903
+ }
65904
+ }
65905
+ this.isLoading = true;
65906
+ }
65907
+
65908
+ itemEnd(url) {
65909
+ this.itemsLoaded++;
65910
+ if (this.onProgress !== undefined) {
65911
+ this.onProgress(url, this.itemsLoaded, this.itemsTotal);
65912
+ }
65913
+ if (this.itemsLoaded === this.itemsTotal) {
65914
+ this.isLoading = false;
65915
+ if (this.onLoad !== undefined) {
65916
+ this.onLoad();
65917
+ }
65918
+ }
65919
+ }
65920
+
65921
+ itemError(url) {
65922
+ if (this.onError !== undefined) {
65923
+ this.onError(url);
65924
+ }
65925
+ }
65926
+
65927
+ resolveURL(url) {
65928
+ if (this.urlModifier) {
65929
+ return this.urlModifier(url);
65930
+ }
65931
+ return url;
65932
+ }
65933
+
65934
+ setURLModifier(transform) {
65935
+ this.urlModifier = transform;
65936
+ return this;
65937
+ }
65938
+
65939
+ addHandler(regex, loader) {
65940
+ this.handlers.push(regex, loader);
65941
+ return this;
65942
+ }
65943
+
65944
+ removeHandler(regex) {
65945
+ const index = this.handlers.indexOf(regex);
65946
+ if (index !== -1) {
65947
+ this.handlers.splice(index, 2);
65948
+ }
65949
+ return this;
65950
+ }
65951
+
65952
+ getHandler(file) {
65953
+ for (let i = 0, l = this.handlers.length; i < l; i += 2) {
65954
+ const regex = this.handlers[i];
65955
+ const loader = this.handlers[i + 1];
65956
+ if (regex.global) regex.lastIndex = 0; // see #17920
65957
+ if (regex.test(file)) {
65958
+ return loader;
65959
+ }
65960
+ }
65961
+ return null;
65962
+ }
65963
+ }
65964
+
65965
+ const DefaultLoadingManager = new LoadingManager();
65966
+
65967
+ class Loader {
65968
+
65969
+ constructor(manager) {
65970
+
65971
+ this.manager = (manager !== undefined) ? manager : DefaultLoadingManager;
65972
+
65973
+ this.crossOrigin = 'anonymous';
65974
+ this.withCredentials = false;
65975
+ this.path = '';
65976
+ this.resourcePath = '';
65977
+ this.requestHeader = {};
65978
+ }
65979
+
65980
+ load( /* url, onLoad, onProgress, onError */) {
65981
+ }
65982
+
65983
+ loadAsync(url, onProgress) {
65984
+ const scope = this;
65985
+ return new Promise(function (resolve, reject) {
65986
+ scope.load(url, resolve, onProgress, reject);
65987
+ });
65988
+ }
65989
+
65990
+ parse( /* data */) {
65991
+ }
65992
+
65993
+ setCrossOrigin(crossOrigin) {
65994
+ this.crossOrigin = crossOrigin;
65995
+ return this;
65996
+ }
65997
+
65998
+ setWithCredentials(value) {
65999
+ this.withCredentials = value;
66000
+ return this;
66001
+ }
66002
+
66003
+ setPath(path) {
66004
+ this.path = path;
66005
+ return this;
66006
+ }
66007
+
66008
+ setResourcePath(resourcePath) {
66009
+ this.resourcePath = resourcePath;
66010
+ return this;
66011
+ }
66012
+
66013
+ setRequestHeader(requestHeader) {
66014
+ this.requestHeader = requestHeader;
66015
+ return this;
66016
+ }
66017
+ }
66018
+
66019
+ /**
66020
+ * @author Deepkolos / https://github.com/deepkolos
66021
+ */
66022
+
66023
+ class WorkerPool$1 {
66024
+
66025
+ constructor(pool = 4) {
66026
+ this.pool = pool;
66027
+ this.queue = [];
66028
+ this.workers = [];
66029
+ this.workersResolve = [];
66030
+ this.workerStatus = 0;
66031
+ }
66032
+
66033
+ _initWorker(workerId) {
66034
+ if (!this.workers[workerId]) {
66035
+ const worker = this.workerCreator();
66036
+ worker.addEventListener('message', this._onMessage.bind(this, workerId));
66037
+ this.workers[workerId] = worker;
66038
+ }
66039
+ }
66040
+
66041
+ _getIdleWorker() {
66042
+ for (let i = 0; i < this.pool; i++)
66043
+ if (!(this.workerStatus & (1 << i))) return i;
66044
+ return -1;
66045
+ }
66046
+
66047
+ _onMessage(workerId, msg) {
66048
+ const resolve = this.workersResolve[workerId];
66049
+ resolve && resolve(msg);
66050
+ if (this.queue.length) {
66051
+ const {resolve, msg, transfer} = this.queue.shift();
66052
+ this.workersResolve[workerId] = resolve;
66053
+ this.workers[workerId].postMessage(msg, transfer);
66054
+ } else {
66055
+ this.workerStatus ^= 1 << workerId;
66056
+ }
66057
+ }
66058
+
66059
+ setWorkerCreator(workerCreator) {
66060
+ this.workerCreator = workerCreator;
66061
+ }
66062
+
66063
+ setWorkerLimit(pool) {
66064
+ this.pool = pool;
66065
+ }
66066
+
66067
+ postMessage(msg, transfer) {
66068
+ return new Promise((resolve) => {
66069
+ const workerId = this._getIdleWorker();
66070
+ if (workerId !== -1) {
66071
+ this._initWorker(workerId);
66072
+ this.workerStatus |= 1 << workerId;
66073
+ this.workersResolve[workerId] = resolve;
66074
+ this.workers[workerId].postMessage(msg, transfer);
66075
+ } else {
66076
+ this.queue.push({resolve, msg, transfer});
66077
+ }
66078
+ });
66079
+ }
66080
+
66081
+ destroy() {
66082
+
66083
+ this.workers.forEach((worker) => worker.terminate());
66084
+ this.workersResolve.length = 0;
66085
+ this.workers.length = 0;
66086
+ this.queue.length = 0;
66087
+ this.workerStatus = 0;
66088
+
66089
+ }
66090
+
66091
+ }
66092
+
66093
+ /**
66094
+ * Transcodes texture data.
66095
+ *
66096
+ * A {@link SceneModel} configured with an appropriate TextureTranscoder will allow us to add textures from
66097
+ * transcoded buffers or files. For a concrete example, see {@link VBOSceneModel}, which can be configured with
66098
+ * a {@link KTX2TextureTranscoder}, which allows us to add textures from KTX2 buffers and files.
66099
+ *
66100
+ * @interface
66101
+ */
66102
+ class TextureTranscoder {
66103
+
66104
+ /**
66105
+ * Transcodes texture data from transcoded buffers into a {@link Texture2D}.
66106
+ *
66107
+ * @param {ArrayBuffer[]} buffers Transcoded texture data. Given as an array of buffers so that we can support
66108
+ * multi-image textures, such as cube maps.
66109
+ * @param {*} config Transcoding options.
66110
+ * @param {Texture2D} texture The texture to load.
66111
+ * @returns {Promise} Resolves when the texture has loaded.
66112
+ */
66113
+ transcode(buffers, texture, config = {}) {
66114
+ }
66115
+
66116
+ /**
66117
+ * Destroys this transcoder.
66118
+ */
66119
+ destroy() {
66120
+ }
66121
+ }
66122
+
66123
+ const Cache = {
66124
+
66125
+ enabled: false,
66126
+ files: {},
66127
+
66128
+ add: function (key, file) {
66129
+ if (this.enabled === false) {
66130
+ return;
66131
+ }
66132
+ this.files[key] = file;
66133
+ },
66134
+
66135
+ get: function (key) {
66136
+ if (this.enabled === false) {
66137
+ return;
66138
+ }
66139
+ return this.files[key];
66140
+ },
66141
+
66142
+ remove: function (key) {
66143
+ delete this.files[key];
66144
+ },
66145
+
66146
+ clear: function () {
66147
+ this.files = {};
66148
+ }
66149
+ };
66150
+
66151
+ const loading = {};
66152
+
66153
+ class FileLoader extends Loader {
66154
+
66155
+ constructor(manager) {
66156
+ super(manager);
66157
+ }
66158
+
66159
+ load(url, onLoad, onProgress, onError) {
66160
+ if (url === undefined) {
66161
+ url = '';
66162
+ }
66163
+ if (this.path !== undefined) {
66164
+ url = this.path + url;
66165
+ }
66166
+ url = this.manager.resolveURL(url);
66167
+ const cached = Cache.get(url);
66168
+ if (cached !== undefined) {
66169
+ this.manager.itemStart(url);
66170
+ setTimeout(() => {
66171
+ if (onLoad) {
66172
+ onLoad(cached);
66173
+ }
66174
+ this.manager.itemEnd(url);
66175
+ }, 0);
66176
+ return cached;
66177
+ }
66178
+ if (loading[url] !== undefined) {
66179
+ loading[url].push({onLoad, onProgress, onError});
66180
+ return;
66181
+ }
66182
+ loading[url] = [];
66183
+ loading[url].push({onLoad, onProgress, onError});
66184
+ const req = new Request(url, {
66185
+ headers: new Headers(this.requestHeader),
66186
+ credentials: this.withCredentials ? 'include' : 'same-origin'
66187
+ });
66188
+ const mimeType = this.mimeType;
66189
+ const responseType = this.responseType;
66190
+ fetch(req).then(response => {
66191
+ if (response.status === 200 || response.status === 0) {
66192
+ // Some browsers return HTTP Status 0 when using non-http protocol
66193
+ // e.g. 'file://' or 'data://'. Handle as success.
66194
+ if (response.status === 0) {
66195
+ console.warn('FileLoader: HTTP Status 0 received.');
66196
+ }
66197
+ if (typeof ReadableStream === 'undefined' || response.body.getReader === undefined) {
66198
+ return response;
66199
+ }
66200
+ const callbacks = loading[url];
66201
+ const reader = response.body.getReader();
66202
+ const contentLength = response.headers.get('Content-Length');
66203
+ const total = contentLength ? parseInt(contentLength) : 0;
66204
+ const lengthComputable = total !== 0;
66205
+ let loaded = 0;
66206
+ const stream = new ReadableStream({
66207
+ start(controller) {
66208
+ readData();
66209
+
66210
+ function readData() {
66211
+ reader.read().then(({done, value}) => {
66212
+ if (done) {
66213
+ controller.close();
66214
+ } else {
66215
+ loaded += value.byteLength;
66216
+ const event = new ProgressEvent('progress', {lengthComputable, loaded, total});
66217
+ for (let i = 0, il = callbacks.length; i < il; i++) {
66218
+ const callback = callbacks[i];
66219
+ if (callback.onProgress) {
66220
+ callback.onProgress(event);
66221
+ }
66222
+ }
66223
+ controller.enqueue(value);
66224
+ readData();
66225
+ }
66226
+ });
66227
+ }
66228
+ }
66229
+ });
66230
+ return new Response(stream);
66231
+ } else {
66232
+ throw Error(`fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`);
66233
+ }
66234
+ }).then(response => {
66235
+ switch (responseType) {
66236
+ case 'arraybuffer':
66237
+ return response.arrayBuffer();
66238
+ case 'blob':
66239
+ return response.blob();
66240
+ case 'document':
66241
+ return response.text()
66242
+ .then(text => {
66243
+ const parser = new DOMParser();
66244
+ return parser.parseFromString(text, mimeType);
66245
+ });
66246
+ case 'json':
66247
+ return response.json();
66248
+ default:
66249
+ if (mimeType === undefined) {
66250
+ return response.text();
66251
+ } else {
66252
+ // sniff encoding
66253
+ const re = /charset="?([^;"\s]*)"?/i;
66254
+ const exec = re.exec(mimeType);
66255
+ const label = exec && exec[1] ? exec[1].toLowerCase() : undefined;
66256
+ const decoder = new TextDecoder(label);
66257
+ return response.arrayBuffer().then(ab => decoder.decode(ab));
66258
+ }
66259
+ }
66260
+ }).then(data => {
66261
+ // Add to cache only on HTTP success, so that we do not cache
66262
+ // error response bodies as proper responses to requests.
66263
+ Cache.add(url, data);
66264
+ const callbacks = loading[url];
66265
+ delete loading[url];
66266
+ for (let i = 0, il = callbacks.length; i < il; i++) {
66267
+ const callback = callbacks[i];
66268
+ if (callback.onLoad) {
66269
+ callback.onLoad(data);
66270
+ }
66271
+ }
66272
+ }).catch(err => {
66273
+ // Abort errors and other errors are handled the same
66274
+ const callbacks = loading[url];
66275
+ if (callbacks === undefined) {
66276
+ // When onLoad was called and url was deleted in `loading`
66277
+ this.manager.itemError(url);
66278
+ throw err;
66279
+
66280
+ }
66281
+ delete loading[url];
66282
+ for (let i = 0, il = callbacks.length; i < il; i++) {
66283
+ const callback = callbacks[i];
66284
+ if (callback.onError) {
66285
+ callback.onError(err);
66286
+ }
66287
+ }
66288
+ this.manager.itemError(url);
66289
+ }).finally(() => {
66290
+ this.manager.itemEnd(url);
66291
+ });
66292
+ this.manager.itemStart(url);
66293
+ }
66294
+
66295
+ setResponseType(value) {
66296
+ this.responseType = value;
66297
+ return this;
66298
+ }
66299
+
66300
+ setMimeType(value) {
66301
+ this.mimeType = value;
66302
+ return this;
66303
+ }
66304
+ }
66305
+
66306
+ const KTX2TransferSRGB = 2;
66307
+ const KTX2_ALPHA_PREMULTIPLIED = 1;
66308
+
66309
+ let activeTranscoders = 0;
66310
+
66311
+ /**
66312
+ * Transcodes texture data from KTX2.
66313
+ *
66314
+ * ## Overview
66315
+ *
66316
+ * * Uses the [Basis Universal GPU Texture Codec](https://github.com/BinomialLLC/basis_universal) to
66317
+ * transcode [KTX2](https://github.khronos.org/KTX-Specification/) textures.
66318
+ * * {@link XKTLoaderPlugin} uses a KTX2TextureTranscoder to load textures in XKT files.
66319
+ * * {@link VBOSceneModel} uses a KTX2TextureTranscoder to enable us to add KTX2-encoded textures.
66320
+ * * Loads the Basis Codec from [CDN](https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/) by default, but can
66321
+ * also be configured to load the Codec from local files.
66322
+ * * We also bundle the Basis Codec with the xeokit-sdk npm package, and in the [repository](https://github.com/xeokit/xeokit-sdk/tree/master/dist/basis).
66323
+ *
66324
+ * ## What is KTX2?
66325
+ *
66326
+ * A [KTX2](https://github.khronos.org/KTX-Specification/) file stores GPU texture data in the Khronos Texture 2.0 (KTX2) container format. It contains image data for
66327
+ * a texture asset compressed with Basis Universal (BasisU) supercompression that can be transcoded to different formats
66328
+ * depending on the support provided by the target devices. KTX2 provides a lightweight format for distributing texture
66329
+ * assets to GPUs. Due to BasisU compression, KTX2 files can store any image format supported by GPUs.
66330
+ *
66331
+ * ## Loading XKT files containing KTX2 textures
66332
+ *
66333
+ * {@link XKTLoaderPlugin} uses a KTX2TextureTranscoder to load textures in XKT files. An XKTLoaderPlugin has its own
66334
+ * default KTX2TextureTranscoder, configured to load the Basis Codec from the [CDN](https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/). If we wish, we can override that with our own
66335
+ * KTX2TextureTranscoder, configured to load the Codec locally.
66336
+ *
66337
+ * In the example below, we'll create a {@link Viewer} and add an {@link XKTLoaderPlugin}
66338
+ * configured with a KTX2TextureTranscoder. Then we'll use the XKTLoaderPlugin to load an
66339
+ * XKT file that contains KTX2 textures, which the plugin will transcode using
66340
+ * its KTX2TextureTranscoder.
66341
+ *
66342
+ * We'll configure our KTX2TextureTranscoder to load the Basis Codec from a local directory. If we were happy with loading the
66343
+ * Codec from our [CDN](https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/) (ie. our app will always have an Internet connection) then we could just leave out the
66344
+ * KTX2TextureTranscoder altogether, and let the XKTLoaderPlugin use its internal default KTX2TextureTranscoder, which is configured to
66345
+ * load the Codec from the CDN. We'll stick with loading our own Codec, in case we want to run our app without an Internet connection.
66346
+ *
66347
+ * <a href="https://xeokit.github.io/xeokit-sdk/examples/#loading_XKT_Textures_HousePlan"><img src="https://xeokit.github.io/xeokit-sdk/assets/images/xktWithTextures.png"></a>
66348
+ *
66349
+ * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_XKT_Textures_HousePlan)]
66350
+ *
66351
+ * ````javascript
66352
+ * const viewer = new Viewer({
66353
+ * canvasId: "myCanvas",
66354
+ * transparent: true
66355
+ * });
66356
+ *
66357
+ * viewer.camera.eye = [-2.56, 8.38, 8.27];
66358
+ * viewer.camera.look = [13.44, 3.31, -14.83];
66359
+ * viewer.camera.up = [0.10, 0.98, -0.14];
66360
+ *
66361
+ * const textureTranscoder = new KTX2TextureTranscoder({
66362
+ * viewer,
66363
+ * transcoderPath: "./../dist/basis/" // <------ Path to Basis Universal transcoder
66364
+ * });
66365
+ *
66366
+ * const xktLoader = new XKTLoaderPlugin(viewer, {
66367
+ * textureTranscoder // <<------------- Transcodes KTX2 textures in XKT files
66368
+ * });
66369
+ *
66370
+ * const sceneModel = xktLoader.load({
66371
+ * id: "myModel",
66372
+ * src: "./HousePlan.xkt" // <<------ XKT file with KTX2 textures
66373
+ * });
66374
+ * ````
66375
+ *
66376
+ * ## Loading KTX2 files into a VBOSceneModel
66377
+ *
66378
+ * A {@link SceneModel} that is configured with a KTX2TextureTranscoder will
66379
+ * allow us to load textures into it from KTX2-transcoded buffers or files.
66380
+ *
66381
+ * In the example below, we'll create a {@link Viewer}, containing a {@link VBOSceneModel} configured with a
66382
+ * KTX2TextureTranscoder.
66383
+ *
66384
+ * We'll then programmatically create a simple object within the VBOSceneModel, consisting of
66385
+ * a single box mesh with a texture loaded from a KTX2 file, which our VBOSceneModel internally transcodes, using
66386
+ * its KTX2TextureTranscoder.
66387
+ *
66388
+ * As in the previous example, we'll configure our KTX2TextureTranscoder to load the Basis Codec from a local directory.
66389
+ *
66390
+ * * [Run a similar example](http://localhost:8080/examples/sceneRepresentation_VBOSceneModel_batching_textures_ktx2.html)
66391
+ *
66392
+ * ````javascript
66393
+ * const viewer = new Viewer({
66394
+ * canvasId: "myCanvas",
66395
+ * transparent: true
66396
+ * });
66397
+ *
66398
+ * viewer.scene.camera.eye = [-21.80, 4.01, 6.56];
66399
+ * viewer.scene.camera.look = [0, -5.75, 0];
66400
+ * viewer.scene.camera.up = [0.37, 0.91, -0.11];
66401
+ *
66402
+ * const textureTranscoder = new KTX2TextureTranscoder({
66403
+ * viewer,
66404
+ * transcoderPath: "./../dist/basis/" // <------ Path to BasisU transcoder module
66405
+ * });
66406
+ *
66407
+ * const vboSceneModel = new VBOSceneModel(viewer.scene, {
66408
+ * id: "myModel",
66409
+ * textureTranscoder // <<-------------------- Configure model with our transcoder
66410
+ * });
66411
+ *
66412
+ * vboSceneModel.createTexture({
66413
+ * id: "myColorTexture",
66414
+ * src: "../assets/textures/compressed/sample_uastc_zstd.ktx2" // <<----- KTX2 texture asset
66415
+ * });
66416
+ *
66417
+ * vboSceneModel.createTexture({
66418
+ * id: "myMetallicRoughnessTexture",
66419
+ * src: "../assets/textures/alpha/crosshatchAlphaMap.jpg" // <<----- JPEG texture asset
66420
+ * });
66421
+ *
66422
+ * vboSceneModel.createTextureSet({
66423
+ * id: "myTextureSet",
66424
+ * colorTextureId: "myColorTexture",
66425
+ * metallicRoughnessTextureId: "myMetallicRoughnessTexture"
66426
+ * });
66427
+ *
66428
+ * vboSceneModel.createMesh({
66429
+ * id: "myMesh",
66430
+ * textureSetId: "myTextureSet",
66431
+ * primitive: "triangles",
66432
+ * positions: [1, 1, 1, ...],
66433
+ * normals: [0, 0, 1, 0, ...],
66434
+ * uv: [1, 0, 0, ...],
66435
+ * indices: [0, 1, 2, ...],
66436
+ * });
66437
+ *
66438
+ * vboSceneModel.createEntity({
66439
+ * id: "myEntity",
66440
+ * meshIds: ["myMesh"]
66441
+ * });
66442
+ *
66443
+ * vboSceneModel.finalize();
66444
+ * ````
66445
+ *
66446
+ * ## Loading KTX2 ArrayBuffers into a VBOSceneModel
66447
+ *
66448
+ * A {@link SceneModel} that is configured with a KTX2TextureTranscoder will also allow us to load textures into
66449
+ * it from KTX2 ArrayBuffers.
66450
+ *
66451
+ * In the example below, we'll create a {@link Viewer}, containing a {@link VBOSceneModel} configured with a
66452
+ * KTX2TextureTranscoder.
66453
+ *
66454
+ * We'll then programmatically create a simple object within the VBOSceneModel, consisting of
66455
+ * a single mesh with a texture loaded from a KTX2 ArrayBuffer, which our VBOSceneModel internally transcodes, using
66456
+ * its KTX2TextureTranscoder.
66457
+ *
66458
+ * ````javascript
66459
+ * const viewer = new Viewer({
66460
+ * canvasId: "myCanvas",
66461
+ * transparent: true
66462
+ * });
66463
+ *
66464
+ * viewer.scene.camera.eye = [-21.80, 4.01, 6.56];
66465
+ * viewer.scene.camera.look = [0, -5.75, 0];
66466
+ * viewer.scene.camera.up = [0.37, 0.91, -0.11];
66467
+ *
66468
+ * const textureTranscoder = new KTX2TextureTranscoder({
66469
+ * viewer,
66470
+ * transcoderPath: "./../dist/basis/" // <------ Path to BasisU transcoder module
66471
+ * });
66472
+ *
66473
+ * const vboSceneModel = new VBOSceneModel(viewer.scene, {
66474
+ * id: "myModel",
66475
+ * textureTranscoder // <<-------------------- Configure model with our transcoder
66476
+ * });
66477
+ *
66478
+ * utils.loadArraybuffer("../assets/textures/compressed/sample_uastc_zstd.ktx2",(arrayBuffer) => {
66479
+ *
66480
+ * vboSceneModel.createTexture({
66481
+ * id: "myColorTexture",
66482
+ * buffers: [arrayBuffer] // <<----- KTX2 texture asset
66483
+ * });
66484
+ *
66485
+ * vboSceneModel.createTexture({
66486
+ * id: "myMetallicRoughnessTexture",
66487
+ * src: "../assets/textures/alpha/crosshatchAlphaMap.jpg" // <<----- JPEG texture asset
66488
+ * });
66489
+ *
66490
+ * vboSceneModel.createTextureSet({
66491
+ * id: "myTextureSet",
66492
+ * colorTextureId: "myColorTexture",
66493
+ * metallicRoughnessTextureId: "myMetallicRoughnessTexture"
66494
+ * });
66495
+ *
66496
+ * vboSceneModel.createMesh({
66497
+ * id: "myMesh",
66498
+ * textureSetId: "myTextureSet",
66499
+ * primitive: "triangles",
66500
+ * positions: [1, 1, 1, ...],
66501
+ * normals: [0, 0, 1, 0, ...],
66502
+ * uv: [1, 0, 0, ...],
66503
+ * indices: [0, 1, 2, ...],
66504
+ * });
66505
+ *
66506
+ * vboSceneModel.createEntity({
66507
+ * id: "myEntity",
66508
+ * meshIds: ["myMesh"]
66509
+ * });
66510
+ *
66511
+ * vboSceneModel.finalize();
66512
+ * });
66513
+ * ````
66514
+ *
66515
+ * @implements {TextureTranscoder}
66516
+ */
66517
+ class KTX2TextureTranscoder {
66518
+
66519
+ /**
66520
+ * Creates a new KTX2TextureTranscoder.
66521
+ *
66522
+ * @param {Viewer} viewer The Viewer that our KTX2TextureTranscoder will be used with. This KTX2TextureTranscoder
66523
+ * must only be used to transcode textures for this Viewer. This is because the Viewer's capabilities will decide
66524
+ * what target GPU formats this KTX2TextureTranscoder will transcode to.
66525
+ * @param {String} [transcoderPath="https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/"] Path to the Basis
66526
+ * transcoder module that internally does the heavy lifting for our KTX2TextureTranscoder. If we omit this configuration,
66527
+ * then our KTX2TextureTranscoder will load it from ````https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/```` by
66528
+ * default. Therefore, make sure your application is connected to the internet if you wish to use the default transcoder path.
66529
+ * @param {Number} [workerLimit] The maximum number of Workers to use for transcoding.
66530
+ */
66531
+ constructor({viewer, transcoderPath, workerLimit}) {
66532
+
66533
+ this._transcoderPath = transcoderPath || "https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/";
66534
+ this._transcoderBinary = null;
66535
+ this._transcoderPending = null;
66536
+ this._workerPool = new WorkerPool$1();
66537
+ this._workerSourceURL = '';
66538
+
66539
+ if (workerLimit) {
66540
+ this._workerPool.setWorkerLimit(workerLimit);
66541
+ }
66542
+
66543
+ const viewerCapabilities = viewer.capabilities;
66544
+
66545
+ this._workerConfig = {
66546
+ astcSupported: viewerCapabilities.astcSupported,
66547
+ etc1Supported: viewerCapabilities.etc1Supported,
66548
+ etc2Supported: viewerCapabilities.etc2Supported,
66549
+ dxtSupported: viewerCapabilities.dxtSupported,
66550
+ bptcSupported: viewerCapabilities.bptcSupported,
66551
+ pvrtcSupported: viewerCapabilities.pvrtcSupported
66552
+ };
66553
+
66554
+ this._supportedFileTypes = ["xkt2"];
66555
+ }
66556
+
66557
+ _init() {
66558
+ if (!this._transcoderPending) {
66559
+ const jsLoader = new FileLoader();
66560
+ jsLoader.setPath(this._transcoderPath);
66561
+ jsLoader.setWithCredentials(this.withCredentials);
66562
+ const jsContent = jsLoader.loadAsync('basis_transcoder.js');
66563
+ const binaryLoader = new FileLoader();
66564
+ binaryLoader.setPath(this._transcoderPath);
66565
+ binaryLoader.setResponseType('arraybuffer');
66566
+ binaryLoader.setWithCredentials(this.withCredentials);
66567
+ const binaryContent = binaryLoader.loadAsync('basis_transcoder.wasm');
66568
+ this._transcoderPending = Promise.all([jsContent, binaryContent])
66569
+ .then(([jsContent, binaryContent]) => {
66570
+ const fn = KTX2TextureTranscoder.BasisWorker.toString();
66571
+ const body = [
66572
+ '/* constants */',
66573
+ 'let _EngineFormat = ' + JSON.stringify(KTX2TextureTranscoder.EngineFormat),
66574
+ 'let _TranscoderFormat = ' + JSON.stringify(KTX2TextureTranscoder.TranscoderFormat),
66575
+ 'let _BasisFormat = ' + JSON.stringify(KTX2TextureTranscoder.BasisFormat),
66576
+ '/* basis_transcoder.js */',
66577
+ jsContent,
66578
+ '/* worker */',
66579
+ fn.substring(fn.indexOf('{') + 1, fn.lastIndexOf('}'))
66580
+ ].join('\n');
66581
+ this._workerSourceURL = URL.createObjectURL(new Blob([body]));
66582
+ this._transcoderBinary = binaryContent;
66583
+ this._workerPool.setWorkerCreator(() => {
66584
+ const worker = new Worker(this._workerSourceURL);
66585
+ const transcoderBinary = this._transcoderBinary.slice(0);
66586
+ worker.postMessage({
66587
+ type: 'init',
66588
+ config: this._workerConfig,
66589
+ transcoderBinary
66590
+ }, [transcoderBinary]);
66591
+ return worker;
66592
+ });
66593
+ });
66594
+ if (activeTranscoders > 0) {
66595
+ console.warn('KTX2TextureTranscoder: Multiple active KTX2TextureTranscoder may cause performance issues.' + ' Use a single KTX2TextureTranscoder instance, or call .dispose() on old instances.');
66596
+ }
66597
+ activeTranscoders++;
66598
+ }
66599
+ return this._transcoderPending;
66600
+ }
66601
+
66602
+ /**
66603
+ * Transcodes texture data from transcoded buffers into a {@link Texture2D}.
66604
+ *
66605
+ * @param {ArrayBuffer[]} buffers Transcoded texture data. Given as an array of buffers so that we can support multi-image textures, such as cube maps.
66606
+ * @param {*} config Transcoding options.
66607
+ * @param {Texture2D} texture The texture to load.
66608
+ * @returns {Promise} Resolves when the texture has loaded.
66609
+ */
66610
+ transcode(buffers, texture, config = {}) {
66611
+ return new Promise((resolve, reject) => {
66612
+ const taskConfig = config;
66613
+ this._init().then(() => {
66614
+ return this._workerPool.postMessage({
66615
+ type: 'transcode',
66616
+ buffers,
66617
+ taskConfig: taskConfig
66618
+ }, buffers);
66619
+ }).then((e) => {
66620
+ const transcodeResult = e.data;
66621
+ const {mipmaps, width, height, format, type, error, dfdTransferFn, dfdFlags} = transcodeResult;
66622
+ if (type === 'error') {
66623
+ return reject(error);
66624
+ }
66625
+ texture.setCompressedData({
66626
+ mipmaps,
66627
+ props: {
66628
+ format: format,
66629
+ minFilter: mipmaps.length === 1 ? LinearFilter : LinearMipmapLinearFilter,
66630
+ magFilter: mipmaps.length === 1 ? LinearFilter : LinearMipmapLinearFilter,
66631
+ encoding: dfdTransferFn === KTX2TransferSRGB ? sRGBEncoding : LinearEncoding,
66632
+ premultiplyAlpha: !!(dfdFlags & KTX2_ALPHA_PREMULTIPLIED)
66633
+ }
66634
+ });
66635
+ resolve();
66636
+ });
66637
+ });
66638
+ }
66639
+
66640
+ /**
66641
+ * Destroys this KTX2TextureTranscoder
66642
+ */
66643
+ destroy() {
66644
+ URL.revokeObjectURL(this._workerSourceURL);
66645
+ this._workerPool.destroy();
66646
+ activeTranscoders--;
66647
+ }
66648
+ }
66649
+
66650
+ /**
66651
+ * @private
66652
+ */
66653
+ KTX2TextureTranscoder.BasisFormat = {
66654
+ ETC1S: 0,
66655
+ UASTC_4x4: 1
66656
+ };
66657
+
66658
+ /**
66659
+ * @private
66660
+ */
66661
+ KTX2TextureTranscoder.TranscoderFormat = {
66662
+ ETC1: 0,
66663
+ ETC2: 1,
66664
+ BC1: 2,
66665
+ BC3: 3,
66666
+ BC4: 4,
66667
+ BC5: 5,
66668
+ BC7_M6_OPAQUE_ONLY: 6,
66669
+ BC7_M5: 7,
66670
+ PVRTC1_4_RGB: 8,
66671
+ PVRTC1_4_RGBA: 9,
66672
+ ASTC_4x4: 10,
66673
+ ATC_RGB: 11,
66674
+ ATC_RGBA_INTERPOLATED_ALPHA: 12,
66675
+ RGBA32: 13,
66676
+ RGB565: 14,
66677
+ BGR565: 15,
66678
+ RGBA4444: 16
66679
+ };
66680
+
66681
+ /**
66682
+ * @private
66683
+ */
66684
+ KTX2TextureTranscoder.EngineFormat = {
66685
+ RGBAFormat: RGBAFormat,
66686
+ RGBA_ASTC_4x4_Format: RGBA_ASTC_4x4_Format,
66687
+ RGBA_BPTC_Format: RGBA_BPTC_Format,
66688
+ RGBA_ETC2_EAC_Format: RGBA_ETC2_EAC_Format,
66689
+ RGBA_PVRTC_4BPPV1_Format: RGBA_PVRTC_4BPPV1_Format,
66690
+ RGBA_S3TC_DXT5_Format: RGBA_S3TC_DXT5_Format,
66691
+ RGB_ETC1_Format: RGB_ETC1_Format,
66692
+ RGB_ETC2_Format: RGB_ETC2_Format,
66693
+ RGB_PVRTC_4BPPV1_Format: RGB_PVRTC_4BPPV1_Format,
66694
+ RGB_S3TC_DXT1_Format: RGB_S3TC_DXT1_Format
66695
+ };
66696
+
66697
+ /* WEB WORKER */
66698
+
66699
+ /**
66700
+ * @private
66701
+ * @constructor
66702
+ */
66703
+ KTX2TextureTranscoder.BasisWorker = function () {
66704
+
66705
+ let config;
66706
+ let transcoderPending;
66707
+ let BasisModule;
66708
+
66709
+ const EngineFormat = _EngineFormat; // eslint-disable-line no-undef
66710
+ const TranscoderFormat = _TranscoderFormat; // eslint-disable-line no-undef
66711
+ const BasisFormat = _BasisFormat; // eslint-disable-line no-undef
66712
+
66713
+ self.addEventListener('message', function (e) {
66714
+ const message = e.data;
66715
+ switch (message.type) {
66716
+ case 'init':
66717
+ config = message.config;
66718
+ init(message.transcoderBinary);
66719
+ break;
66720
+ case 'transcode':
66721
+ transcoderPending.then(() => {
66722
+ try {
66723
+ const {
66724
+ width,
66725
+ height,
66726
+ hasAlpha,
66727
+ mipmaps,
66728
+ format,
66729
+ dfdTransferFn,
66730
+ dfdFlags
66731
+ } = transcode(message.buffers[0]);
66732
+ const buffers = [];
66733
+ for (let i = 0; i < mipmaps.length; ++i) {
66734
+ buffers.push(mipmaps[i].data.buffer);
66735
+ }
66736
+ self.postMessage({
66737
+ type: 'transcode',
66738
+ id: message.id,
66739
+ width,
66740
+ height,
66741
+ hasAlpha,
66742
+ mipmaps,
66743
+ format,
66744
+ dfdTransferFn,
66745
+ dfdFlags
66746
+ }, buffers);
66747
+ } catch (error) {
66748
+ console.error(`[KTX2TextureTranscoder.BasisWorker]: ${error}`);
66749
+ self.postMessage({type: 'error', id: message.id, error: error.message});
66750
+ }
66751
+ });
66752
+ break;
66753
+ }
66754
+ });
66755
+
66756
+ function init(wasmBinary) {
66757
+ transcoderPending = new Promise(resolve => {
66758
+ BasisModule = {
66759
+ wasmBinary,
66760
+ onRuntimeInitialized: resolve
66761
+ };
66762
+ BASIS(BasisModule); // eslint-disable-line no-undef
66763
+ }).then(() => {
66764
+ BasisModule.initializeBasis();
66765
+ if (BasisModule.KTX2File === undefined) {
66766
+ console.warn('KTX2TextureTranscoder: Please update Basis Universal transcoder.');
66767
+ }
66768
+ });
66769
+ }
66770
+
66771
+ function transcode(buffer) {
66772
+ const ktx2File = new BasisModule.KTX2File(new Uint8Array(buffer));
66773
+
66774
+ function cleanup() {
66775
+ ktx2File.close();
66776
+ ktx2File.delete();
66777
+ }
66778
+
66779
+ if (!ktx2File.isValid()) {
66780
+ cleanup();
66781
+ throw new Error('KTX2TextureTranscoder: Invalid or unsupported .ktx2 file');
66782
+ }
66783
+ const basisFormat = ktx2File.isUASTC() ? BasisFormat.UASTC_4x4 : BasisFormat.ETC1S;
66784
+ const width = ktx2File.getWidth();
66785
+ const height = ktx2File.getHeight();
66786
+ const levels = ktx2File.getLevels();
66787
+ const hasAlpha = ktx2File.getHasAlpha();
66788
+ const dfdTransferFn = ktx2File.getDFDTransferFunc();
66789
+ const dfdFlags = ktx2File.getDFDFlags();
66790
+ const {transcoderFormat, engineFormat} = getTranscoderFormat(basisFormat, width, height, hasAlpha);
66791
+ if (!width || !height || !levels) {
66792
+ cleanup();
66793
+ throw new Error('KTX2TextureTranscoder: Invalid texture');
66794
+ }
66795
+ if (!ktx2File.startTranscoding()) {
66796
+ cleanup();
66797
+ throw new Error('KTX2TextureTranscoder: .startTranscoding failed');
66798
+ }
66799
+ const mipmaps = [];
66800
+ for (let mip = 0; mip < levels; mip++) {
66801
+ const levelInfo = ktx2File.getImageLevelInfo(mip, 0, 0);
66802
+ const mipWidth = levelInfo.origWidth;
66803
+ const mipHeight = levelInfo.origHeight;
66804
+ const dst = new Uint8Array(ktx2File.getImageTranscodedSizeInBytes(mip, 0, 0, transcoderFormat));
66805
+ const status = ktx2File.transcodeImage(dst, mip, 0, 0, transcoderFormat, 0, -1, -1);
66806
+ if (!status) {
66807
+ cleanup();
66808
+ throw new Error('KTX2TextureTranscoder: .transcodeImage failed.');
66809
+ }
66810
+ mipmaps.push({data: dst, width: mipWidth, height: mipHeight});
66811
+ }
66812
+ cleanup();
66813
+ return {width, height, hasAlpha, mipmaps, format: engineFormat, dfdTransferFn, dfdFlags};
66814
+ }
66815
+
66816
+ // Optimal choice of a transcoder target format depends on the Basis format (ETC1S or UASTC),
66817
+ // device capabilities, and texture dimensions. The list below ranks the formats separately
66818
+ // for ETC1S and UASTC.
66819
+ //
66820
+ // In some cases, transcoding UASTC to RGBA32 might be preferred for higher quality (at
66821
+ // significant memory cost) compared to ETC1/2, BC1/3, and PVRTC. The transcoder currently
66822
+ // chooses RGBA32 only as a last resort and does not expose that option to the caller.
66823
+
66824
+ const FORMAT_OPTIONS = [{
66825
+ if: 'astcSupported',
66826
+ basisFormat: [BasisFormat.UASTC_4x4],
66827
+ transcoderFormat: [TranscoderFormat.ASTC_4x4, TranscoderFormat.ASTC_4x4],
66828
+ engineFormat: [EngineFormat.RGBA_ASTC_4x4_Format, EngineFormat.RGBA_ASTC_4x4_Format],
66829
+ priorityETC1S: Infinity,
66830
+ priorityUASTC: 1,
66831
+ needsPowerOfTwo: false
66832
+ }, {
66833
+ if: 'bptcSupported',
66834
+ basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4],
66835
+ transcoderFormat: [TranscoderFormat.BC7_M5, TranscoderFormat.BC7_M5],
66836
+ engineFormat: [EngineFormat.RGBA_BPTC_Format, EngineFormat.RGBA_BPTC_Format],
66837
+ priorityETC1S: 3,
66838
+ priorityUASTC: 2,
66839
+ needsPowerOfTwo: false
66840
+ }, {
66841
+ if: 'dxtSupported',
66842
+ basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4],
66843
+ transcoderFormat: [TranscoderFormat.BC1, TranscoderFormat.BC3],
66844
+ engineFormat: [EngineFormat.RGB_S3TC_DXT1_Format, EngineFormat.RGBA_S3TC_DXT5_Format],
66845
+ priorityETC1S: 4,
66846
+ priorityUASTC: 5,
66847
+ needsPowerOfTwo: false
66848
+ }, {
66849
+ if: 'etc2Supported',
66850
+ basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4],
66851
+ transcoderFormat: [TranscoderFormat.ETC1, TranscoderFormat.ETC2],
66852
+ engineFormat: [EngineFormat.RGB_ETC2_Format, EngineFormat.RGBA_ETC2_EAC_Format],
66853
+ priorityETC1S: 1,
66854
+ priorityUASTC: 3,
66855
+ needsPowerOfTwo: false
66856
+ }, {
66857
+ if: 'etc1Supported',
66858
+ basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4],
66859
+ transcoderFormat: [TranscoderFormat.ETC1],
66860
+ engineFormat: [EngineFormat.RGB_ETC1_Format],
66861
+ priorityETC1S: 2,
66862
+ priorityUASTC: 4,
66863
+ needsPowerOfTwo: false
66864
+ }, {
66865
+ if: 'pvrtcSupported',
66866
+ basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4],
66867
+ transcoderFormat: [TranscoderFormat.PVRTC1_4_RGB, TranscoderFormat.PVRTC1_4_RGBA],
66868
+ engineFormat: [EngineFormat.RGB_PVRTC_4BPPV1_Format, EngineFormat.RGBA_PVRTC_4BPPV1_Format],
66869
+ priorityETC1S: 5,
66870
+ priorityUASTC: 6,
66871
+ needsPowerOfTwo: true
66872
+ }];
66873
+ const ETC1S_OPTIONS = FORMAT_OPTIONS.sort(function (a, b) {
66874
+ return a.priorityETC1S - b.priorityETC1S;
66875
+ });
66876
+ const UASTC_OPTIONS = FORMAT_OPTIONS.sort(function (a, b) {
66877
+ return a.priorityUASTC - b.priorityUASTC;
66878
+ });
66879
+
66880
+ function getTranscoderFormat(basisFormat, width, height, hasAlpha) {
66881
+ let transcoderFormat;
66882
+ let engineFormat;
66883
+ const options = basisFormat === BasisFormat.ETC1S ? ETC1S_OPTIONS : UASTC_OPTIONS;
66884
+ for (let i = 0; i < options.length; i++) {
66885
+ const opt = options[i];
66886
+ if (!config[opt.if]) continue;
66887
+ if (!opt.basisFormat.includes(basisFormat)) continue;
66888
+ if (hasAlpha && opt.transcoderFormat.length < 2) continue;
66889
+ if (opt.needsPowerOfTwo && !(isPowerOfTwo(width) && isPowerOfTwo(height))) continue;
66890
+ transcoderFormat = opt.transcoderFormat[hasAlpha ? 1 : 0];
66891
+ engineFormat = opt.engineFormat[hasAlpha ? 1 : 0];
66892
+ return {
66893
+ transcoderFormat,
66894
+ engineFormat
66895
+ };
66896
+ }
66897
+ console.warn('KTX2TextureTranscoder: No suitable compressed texture format found. Decoding to RGBA32.');
66898
+ transcoderFormat = TranscoderFormat.RGBA32;
66899
+ engineFormat = EngineFormat.RGBAFormat;
66900
+ return {
66901
+ transcoderFormat,
66902
+ engineFormat
66903
+ };
66904
+ }
66905
+
66906
+ function isPowerOfTwo(value) {
66907
+ if (value <= 2) return true;
66908
+ return (value & value - 1) === 0 && value !== 0;
66909
+ }
66910
+ };
66911
+
66912
+ const cachedTranscoders = {};
66913
+
66914
+ /**
66915
+ * Returns a new {@link KTX2TextureTranscoder}.
66916
+ *
66917
+ * The ````transcoderPath```` config will be set to: "https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/"
66918
+ *
66919
+ * @private
66920
+ */
66921
+ function getKTX2TextureTranscoder(viewer) {
66922
+ const sceneId = viewer.scene.id;
66923
+ let transcoder = cachedTranscoders[sceneId];
66924
+ if (!transcoder) {
66925
+ transcoder = new KTX2TextureTranscoder({viewer});
66926
+ cachedTranscoders[sceneId] = transcoder;
66927
+ viewer.scene.on("destroyed", () => {
66928
+ delete cachedTranscoders[sceneId];
66929
+ transcoder.destroy();
66930
+ });
66931
+ }
66932
+ return transcoder;
66933
+ }
66934
+
65885
66935
  const tempVec3a$9 = math.vec3();
65886
66936
  const tempMat4$1 = math.mat4();
65887
66937
 
@@ -66957,7 +68007,7 @@ class VBOSceneModel extends Component {
66957
68007
 
66958
68008
  super(owner, cfg);
66959
68009
 
66960
- this._textureTranscoder = cfg.textureTranscoder;
68010
+ this._textureTranscoder = cfg.textureTranscoder || getKTX2TextureTranscoder(this.scene.viewer);
66961
68011
 
66962
68012
  this._maxGeometryBatchSize = cfg.maxGeometryBatchSize;
66963
68013
 
@@ -67933,7 +68983,7 @@ class VBOSceneModel extends Component {
67933
68983
  * @param {String} [cfg.src] Image file for the texture. Assumed to be transcoded if not having a recognized image file
67934
68984
  * extension (jpg, jpeg, png etc.). If transcoded, then assumes ````VBOSceneModel```` is configured with a {@link TextureTranscoder}.
67935
68985
  * @param {ArrayBuffer[]} [cfg.buffers] Transcoded texture data. Assumes ````VBOSceneModel```` is
67936
- * configured with a {@link TextureTranscoder}. Given as an array of buffers so we can potentially support multi-image textures, such as cube maps.
68986
+ * configured with a {@link TextureTranscoder}. This parameter is given as an array of buffers so we can potentially support multi-image textures, such as cube maps.
67937
68987
  * @param {HTMLImageElement} [cfg.image] HTML Image object to load into this texture. Overrides ````src```` and ````buffers````. Never transcoded.
67938
68988
  * @param {Number} [cfg.minFilter=LinearMipmapLinearFilter] How the texture is sampled when a texel covers less than one pixel.
67939
68989
  * Supported values are {@link LinearMipmapLinearFilter}, {@link LinearMipMapNearestFilter}, {@link NearestMipMapNearestFilter}, {@link NearestMipMapLinearFilter} and {@link LinearMipMapLinearFilter}.
@@ -67953,8 +69003,8 @@ class VBOSceneModel extends Component {
67953
69003
  this.error("Texture already created: " + textureId);
67954
69004
  return;
67955
69005
  }
67956
- if (!cfg.src && !cfg.image) {
67957
- this.error("Param expected: `src` or `image'");
69006
+ if (!cfg.src && !cfg.image && !cfg.buffers) {
69007
+ this.error("Param expected: `src`, `image' or 'buffers'");
67958
69008
  return null;
67959
69009
  }
67960
69010
  let minFilter = cfg.minFilter || LinearMipmapLinearFilter;
@@ -74055,7 +75105,7 @@ class WorkerThread {
74055
75105
 
74056
75106
  }
74057
75107
 
74058
- class WorkerPool$1 {
75108
+ class WorkerPool {
74059
75109
  constructor(props) {
74060
75110
  _defineProperty(this, "name", 'unnamed');
74061
75111
 
@@ -74263,7 +75313,7 @@ class WorkerFarm {
74263
75313
  let workerPool = this.workerPools.get(name);
74264
75314
 
74265
75315
  if (!workerPool) {
74266
- workerPool = new WorkerPool$1({
75316
+ workerPool = new WorkerPool({
74267
75317
  name,
74268
75318
  source,
74269
75319
  url
@@ -100442,7 +101492,7 @@ function inflate(deflatedData) {
100442
101492
 
100443
101493
  return {
100444
101494
  metadata: JSON.parse(pako.inflate(deflatedData.metadata, {to: 'string'})),
100445
- textureData: new Uint8ClampedArray(inflate(deflatedData.textureData)),
101495
+ textureData: new Uint8Array(inflate(deflatedData.textureData)),
100446
101496
  eachTextureDataPortion: new Uint32Array(inflate(deflatedData.eachTextureDataPortion)),
100447
101497
  eachTextureDimensions: new Uint16Array(inflate(deflatedData.eachTextureDimensions)),
100448
101498
  positions: new Uint16Array(inflate(deflatedData.positions)),
@@ -100482,7 +101532,7 @@ const decompressColor = (function () {
100482
101532
  };
100483
101533
  })();
100484
101534
 
100485
- const imagDataToImage = (function () {
101535
+ ((function () {
100486
101536
  const canvas = document.createElement('canvas');
100487
101537
  const context = canvas.getContext('2d');
100488
101538
  return function (imagedata) {
@@ -100491,14 +101541,14 @@ const imagDataToImage = (function () {
100491
101541
  context.putImageData(imagedata, 0, 0);
100492
101542
  return canvas.toDataURL();
100493
101543
  };
100494
- })();
101544
+ }))();
100495
101545
 
100496
101546
  function load(viewer, options, inflatedData, sceneModel) {
100497
101547
 
100498
101548
  const metadata = inflatedData.metadata;
100499
101549
  const textureData = inflatedData.textureData;
100500
101550
  const eachTextureDataPortion = inflatedData.eachTextureDataPortion;
100501
- const eachTextureDimensions = inflatedData.eachTextureDimensions;
101551
+ inflatedData.eachTextureDimensions;
100502
101552
  const positions = inflatedData.positions;
100503
101553
  const normals = inflatedData.normals;
100504
101554
  const colors = inflatedData.colors;
@@ -100559,20 +101609,13 @@ function load(viewer, options, inflatedData, sceneModel) {
100559
101609
  const textureDataPortionSize = textureDataPortionEnd - textureDataPortionStart;
100560
101610
  const textureDataPortionExists = (textureDataPortionSize > 0);
100561
101611
  if (textureDataPortionExists) {
100562
- const imageDataSubarray = textureData.subarray(textureDataPortionStart, textureDataPortionEnd);
100563
- const width = eachTextureDimensions[textureIndex * 2 + 0];
100564
- const height = eachTextureDimensions[textureIndex * 2 + 1];
100565
- const imageData = new ImageData(imageDataSubarray, width, height);
100566
-
100567
- //////////////////////////////////////////////////////////////
100568
- // TODO: This is super inefficient - replace with Basis:
100569
- //////////////////////////////////////////////////////////////
100570
101612
 
100571
- const image = imagDataToImage(imageData);
101613
+ const imageDataSubarray = new Uint8Array(textureData.subarray(textureDataPortionStart, textureDataPortionEnd));
101614
+ const arrayBuffer = imageDataSubarray.buffer;
100572
101615
 
100573
101616
  sceneModel.createTexture({
100574
101617
  id: `texture-${textureIndex}`,
100575
- src: image
101618
+ buffers: [arrayBuffer]
100576
101619
  });
100577
101620
  }
100578
101621
  }
@@ -100994,6 +102037,7 @@ parsers[ParserV10.version] = ParserV10;
100994
102037
  * * An *````.XKT````* file is a single BLOB containing a model, compressed using geometry quantization
100995
102038
  * and [pako](https://nodeca.github.io/pako/).
100996
102039
  * * Supports double-precision coordinates.
102040
+ * * Supports compressed textures.
100997
102041
  * * Set the position, scale and rotation of each model as you load it.
100998
102042
  * * Filter which IFC types get loaded.
100999
102043
  * * Configure initial default appearances for IFC types.
@@ -101112,17 +102156,26 @@ parsers[ParserV10.version] = ParserV10;
101112
102156
  * model.destroy();
101113
102157
  * ````
101114
102158
  *
101115
- * ## Loading XKT files containing KTX2 textures
102159
+ * ## Loading XKT files containing textures
101116
102160
  *
101117
- * An XKTLoaderPlugin that is configured with a {@link KTX2TextureTranscoder} will allow us to load XKT files that
101118
- * contain KTX2 textures. If we don't configure a KTX2TextureTranscoder, then the XKTLoaderPlugin will simply ignore
101119
- * the textures in the XKT.
102161
+ * XKTLoaderPlugin uses a {@link KTX2TextureTranscoder} to load textures in XKT files (XKT v10+). An XKTLoaderPlugin has its own
102162
+ * default KTX2TextureTranscoder, configured to load the Basis Codec from the CDN. If we wish, we can override that with our own
102163
+ * KTX2TextureTranscoder instance that's configured to load the Codec locally.
101120
102164
  *
101121
102165
  * In the example below, we'll create a {@link Viewer} and add an XKTLoaderPlugin
101122
- * configured with a KTX2TextureTranscoder. Then we'll use the XKTLoaderPlugin to load an
101123
- * XKT file that contains KTX2 textures, which the plugin will transcode using
102166
+ * configured with a KTX2TextureTranscoder that finds the Codec in our local file system. Then we'll use the
102167
+ * XKTLoaderPlugin to load an XKT file that contains KTX2 textures, which the plugin will transcode using
101124
102168
  * its KTX2TextureTranscoder.
101125
102169
  *
102170
+ * We'll configure our KTX2TextureTranscoder to load the Basis Codec from a local directory. If we were happy with loading the
102171
+ * Codec from our CDN (ie. our app will always have an Internet connection) then we could just leave out the
102172
+ * KTX2TextureTranscoder altogether, and let the XKTLoaderPlugin use its internal default KTX2TextureTranscoder, which is configured to
102173
+ * load the Codec from the CDN. We'll stick with loading our own Codec, in case we want to run our app without an Internet connection.
102174
+ *
102175
+ * <a href="https://xeokit.github.io/xeokit-sdk/examples/#loading_XKT_Textures_HousePlan"><img src="https://xeokit.github.io/xeokit-sdk/assets/images/xktWithTextures.png"></a>
102176
+ *
102177
+ * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_XKT_Textures_HousePlan)]
102178
+ *
101126
102179
  * ````javascript
101127
102180
  * const viewer = new Viewer({
101128
102181
  * canvasId: "myCanvas",
@@ -154208,1016 +155261,6 @@ class PerformanceModel extends VBOSceneModel {
154208
155261
  }
154209
155262
  }
154210
155263
 
154211
- class LoadingManager {
154212
-
154213
- constructor(onLoad, onProgress, onError) {
154214
-
154215
- this.isLoading = false;
154216
- this.itemsLoaded = 0;
154217
- this.itemsTotal = 0;
154218
- this.urlModifier = undefined;
154219
- this.handlers = [];
154220
-
154221
- this.onStart = undefined;
154222
- this.onLoad = onLoad;
154223
- this.onProgress = onProgress;
154224
- this.onError = onError;
154225
- }
154226
-
154227
- itemStart(url) {
154228
- this.itemsTotal++;
154229
- if (this.isLoading === false) {
154230
- if (this.onStart !== undefined) {
154231
- this.onStart(url, this.itemsLoaded, this.itemsTotal);
154232
- }
154233
- }
154234
- this.isLoading = true;
154235
- }
154236
-
154237
- itemEnd(url) {
154238
- this.itemsLoaded++;
154239
- if (this.onProgress !== undefined) {
154240
- this.onProgress(url, this.itemsLoaded, this.itemsTotal);
154241
- }
154242
- if (this.itemsLoaded === this.itemsTotal) {
154243
- this.isLoading = false;
154244
- if (this.onLoad !== undefined) {
154245
- this.onLoad();
154246
- }
154247
- }
154248
- }
154249
-
154250
- itemError(url) {
154251
- if (this.onError !== undefined) {
154252
- this.onError(url);
154253
- }
154254
- }
154255
-
154256
- resolveURL(url) {
154257
- if (this.urlModifier) {
154258
- return this.urlModifier(url);
154259
- }
154260
- return url;
154261
- }
154262
-
154263
- setURLModifier(transform) {
154264
- this.urlModifier = transform;
154265
- return this;
154266
- }
154267
-
154268
- addHandler(regex, loader) {
154269
- this.handlers.push(regex, loader);
154270
- return this;
154271
- }
154272
-
154273
- removeHandler(regex) {
154274
- const index = this.handlers.indexOf(regex);
154275
- if (index !== -1) {
154276
- this.handlers.splice(index, 2);
154277
- }
154278
- return this;
154279
- }
154280
-
154281
- getHandler(file) {
154282
- for (let i = 0, l = this.handlers.length; i < l; i += 2) {
154283
- const regex = this.handlers[i];
154284
- const loader = this.handlers[i + 1];
154285
- if (regex.global) regex.lastIndex = 0; // see #17920
154286
- if (regex.test(file)) {
154287
- return loader;
154288
- }
154289
- }
154290
- return null;
154291
- }
154292
- }
154293
-
154294
- const DefaultLoadingManager = new LoadingManager();
154295
-
154296
- class Loader {
154297
-
154298
- constructor(manager) {
154299
-
154300
- this.manager = (manager !== undefined) ? manager : DefaultLoadingManager;
154301
-
154302
- this.crossOrigin = 'anonymous';
154303
- this.withCredentials = false;
154304
- this.path = '';
154305
- this.resourcePath = '';
154306
- this.requestHeader = {};
154307
- }
154308
-
154309
- load( /* url, onLoad, onProgress, onError */) {
154310
- }
154311
-
154312
- loadAsync(url, onProgress) {
154313
- const scope = this;
154314
- return new Promise(function (resolve, reject) {
154315
- scope.load(url, resolve, onProgress, reject);
154316
- });
154317
- }
154318
-
154319
- parse( /* data */) {
154320
- }
154321
-
154322
- setCrossOrigin(crossOrigin) {
154323
- this.crossOrigin = crossOrigin;
154324
- return this;
154325
- }
154326
-
154327
- setWithCredentials(value) {
154328
- this.withCredentials = value;
154329
- return this;
154330
- }
154331
-
154332
- setPath(path) {
154333
- this.path = path;
154334
- return this;
154335
- }
154336
-
154337
- setResourcePath(resourcePath) {
154338
- this.resourcePath = resourcePath;
154339
- return this;
154340
- }
154341
-
154342
- setRequestHeader(requestHeader) {
154343
- this.requestHeader = requestHeader;
154344
- return this;
154345
- }
154346
- }
154347
-
154348
- /**
154349
- * @author Deepkolos / https://github.com/deepkolos
154350
- */
154351
-
154352
- class WorkerPool {
154353
-
154354
- constructor(pool = 4) {
154355
- this.pool = pool;
154356
- this.queue = [];
154357
- this.workers = [];
154358
- this.workersResolve = [];
154359
- this.workerStatus = 0;
154360
- }
154361
-
154362
- _initWorker(workerId) {
154363
- if (!this.workers[workerId]) {
154364
- const worker = this.workerCreator();
154365
- worker.addEventListener('message', this._onMessage.bind(this, workerId));
154366
- this.workers[workerId] = worker;
154367
- }
154368
- }
154369
-
154370
- _getIdleWorker() {
154371
- for (let i = 0; i < this.pool; i++)
154372
- if (!(this.workerStatus & (1 << i))) return i;
154373
- return -1;
154374
- }
154375
-
154376
- _onMessage(workerId, msg) {
154377
- const resolve = this.workersResolve[workerId];
154378
- resolve && resolve(msg);
154379
- if (this.queue.length) {
154380
- const {resolve, msg, transfer} = this.queue.shift();
154381
- this.workersResolve[workerId] = resolve;
154382
- this.workers[workerId].postMessage(msg, transfer);
154383
- } else {
154384
- this.workerStatus ^= 1 << workerId;
154385
- }
154386
- }
154387
-
154388
- setWorkerCreator(workerCreator) {
154389
- this.workerCreator = workerCreator;
154390
- }
154391
-
154392
- setWorkerLimit(pool) {
154393
- this.pool = pool;
154394
- }
154395
-
154396
- postMessage(msg, transfer) {
154397
- return new Promise((resolve) => {
154398
- const workerId = this._getIdleWorker();
154399
- if (workerId !== -1) {
154400
- this._initWorker(workerId);
154401
- this.workerStatus |= 1 << workerId;
154402
- this.workersResolve[workerId] = resolve;
154403
- this.workers[workerId].postMessage(msg, transfer);
154404
- } else {
154405
- this.queue.push({resolve, msg, transfer});
154406
- }
154407
- });
154408
- }
154409
-
154410
- destroy() {
154411
-
154412
- this.workers.forEach((worker) => worker.terminate());
154413
- this.workersResolve.length = 0;
154414
- this.workers.length = 0;
154415
- this.queue.length = 0;
154416
- this.workerStatus = 0;
154417
-
154418
- }
154419
-
154420
- }
154421
-
154422
- /**
154423
- * Transcodes texture data.
154424
- *
154425
- * A {@link SceneModel} configured with an appropriate TextureTranscoder will allow us to add textures from
154426
- * transcoded buffers or files. For a concrete example, see {@link VBOSceneModel}, which can be configured with
154427
- * a {@link KTX2TextureTranscoder}, which allows us to add textures from KTX2 buffers and files.
154428
- *
154429
- * @interface
154430
- */
154431
- class TextureTranscoder {
154432
-
154433
- /**
154434
- * Transcodes texture data from transcoded buffers into a {@link Texture2D}.
154435
- *
154436
- * @param {ArrayBuffer[]} buffers Transcoded texture data. Given as an array of buffers so that we can support
154437
- * multi-image textures, such as cube maps.
154438
- * @param {*} config Transcoding options.
154439
- * @param {Texture2D} texture The texture to load.
154440
- * @returns {Promise} Resolves when the texture has loaded.
154441
- */
154442
- transcode(buffers, texture, config = {}) {
154443
- }
154444
-
154445
- /**
154446
- * Destroys this transcoder.
154447
- */
154448
- destroy() {
154449
- }
154450
- }
154451
-
154452
- const Cache = {
154453
-
154454
- enabled: false,
154455
- files: {},
154456
-
154457
- add: function (key, file) {
154458
- if (this.enabled === false) {
154459
- return;
154460
- }
154461
- this.files[key] = file;
154462
- },
154463
-
154464
- get: function (key) {
154465
- if (this.enabled === false) {
154466
- return;
154467
- }
154468
- return this.files[key];
154469
- },
154470
-
154471
- remove: function (key) {
154472
- delete this.files[key];
154473
- },
154474
-
154475
- clear: function () {
154476
- this.files = {};
154477
- }
154478
- };
154479
-
154480
- const loading = {};
154481
-
154482
- class FileLoader extends Loader {
154483
-
154484
- constructor(manager) {
154485
- super(manager);
154486
- }
154487
-
154488
- load(url, onLoad, onProgress, onError) {
154489
- if (url === undefined) {
154490
- url = '';
154491
- }
154492
- if (this.path !== undefined) {
154493
- url = this.path + url;
154494
- }
154495
- url = this.manager.resolveURL(url);
154496
- const cached = Cache.get(url);
154497
- if (cached !== undefined) {
154498
- this.manager.itemStart(url);
154499
- setTimeout(() => {
154500
- if (onLoad) {
154501
- onLoad(cached);
154502
- }
154503
- this.manager.itemEnd(url);
154504
- }, 0);
154505
- return cached;
154506
- }
154507
- if (loading[url] !== undefined) {
154508
- loading[url].push({onLoad, onProgress, onError});
154509
- return;
154510
- }
154511
- loading[url] = [];
154512
- loading[url].push({onLoad, onProgress, onError});
154513
- const req = new Request(url, {
154514
- headers: new Headers(this.requestHeader),
154515
- credentials: this.withCredentials ? 'include' : 'same-origin'
154516
- });
154517
- const mimeType = this.mimeType;
154518
- const responseType = this.responseType;
154519
- fetch(req).then(response => {
154520
- if (response.status === 200 || response.status === 0) {
154521
- // Some browsers return HTTP Status 0 when using non-http protocol
154522
- // e.g. 'file://' or 'data://'. Handle as success.
154523
- if (response.status === 0) {
154524
- console.warn('FileLoader: HTTP Status 0 received.');
154525
- }
154526
- if (typeof ReadableStream === 'undefined' || response.body.getReader === undefined) {
154527
- return response;
154528
- }
154529
- const callbacks = loading[url];
154530
- const reader = response.body.getReader();
154531
- const contentLength = response.headers.get('Content-Length');
154532
- const total = contentLength ? parseInt(contentLength) : 0;
154533
- const lengthComputable = total !== 0;
154534
- let loaded = 0;
154535
- const stream = new ReadableStream({
154536
- start(controller) {
154537
- readData();
154538
-
154539
- function readData() {
154540
- reader.read().then(({done, value}) => {
154541
- if (done) {
154542
- controller.close();
154543
- } else {
154544
- loaded += value.byteLength;
154545
- const event = new ProgressEvent('progress', {lengthComputable, loaded, total});
154546
- for (let i = 0, il = callbacks.length; i < il; i++) {
154547
- const callback = callbacks[i];
154548
- if (callback.onProgress) {
154549
- callback.onProgress(event);
154550
- }
154551
- }
154552
- controller.enqueue(value);
154553
- readData();
154554
- }
154555
- });
154556
- }
154557
- }
154558
- });
154559
- return new Response(stream);
154560
- } else {
154561
- throw Error(`fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`);
154562
- }
154563
- }).then(response => {
154564
- switch (responseType) {
154565
- case 'arraybuffer':
154566
- return response.arrayBuffer();
154567
- case 'blob':
154568
- return response.blob();
154569
- case 'document':
154570
- return response.text()
154571
- .then(text => {
154572
- const parser = new DOMParser();
154573
- return parser.parseFromString(text, mimeType);
154574
- });
154575
- case 'json':
154576
- return response.json();
154577
- default:
154578
- if (mimeType === undefined) {
154579
- return response.text();
154580
- } else {
154581
- // sniff encoding
154582
- const re = /charset="?([^;"\s]*)"?/i;
154583
- const exec = re.exec(mimeType);
154584
- const label = exec && exec[1] ? exec[1].toLowerCase() : undefined;
154585
- const decoder = new TextDecoder(label);
154586
- return response.arrayBuffer().then(ab => decoder.decode(ab));
154587
- }
154588
- }
154589
- }).then(data => {
154590
- // Add to cache only on HTTP success, so that we do not cache
154591
- // error response bodies as proper responses to requests.
154592
- Cache.add(url, data);
154593
- const callbacks = loading[url];
154594
- delete loading[url];
154595
- for (let i = 0, il = callbacks.length; i < il; i++) {
154596
- const callback = callbacks[i];
154597
- if (callback.onLoad) {
154598
- callback.onLoad(data);
154599
- }
154600
- }
154601
- }).catch(err => {
154602
- // Abort errors and other errors are handled the same
154603
- const callbacks = loading[url];
154604
- if (callbacks === undefined) {
154605
- // When onLoad was called and url was deleted in `loading`
154606
- this.manager.itemError(url);
154607
- throw err;
154608
-
154609
- }
154610
- delete loading[url];
154611
- for (let i = 0, il = callbacks.length; i < il; i++) {
154612
- const callback = callbacks[i];
154613
- if (callback.onError) {
154614
- callback.onError(err);
154615
- }
154616
- }
154617
- this.manager.itemError(url);
154618
- }).finally(() => {
154619
- this.manager.itemEnd(url);
154620
- });
154621
- this.manager.itemStart(url);
154622
- }
154623
-
154624
- setResponseType(value) {
154625
- this.responseType = value;
154626
- return this;
154627
- }
154628
-
154629
- setMimeType(value) {
154630
- this.mimeType = value;
154631
- return this;
154632
- }
154633
- }
154634
-
154635
- const KTX2TransferSRGB = 2;
154636
- const KTX2_ALPHA_PREMULTIPLIED = 1;
154637
-
154638
- let activeTranscoders = 0;
154639
-
154640
- /**
154641
- * Transcodes texture data from KTX2.
154642
- *
154643
- * ## Overview
154644
- *
154645
- * * Uses the Basis Universal codec to transcode KTX2 texture assets.
154646
- * * An {@link XKTLoaderPlugin} that is configured with a KTX2TextureTranscoder will allow us to load KTX2 textures in
154647
- * XKT files. Textures in XKT are always KTX2. If we do not configure a KTX2TextureTranscoder, the XKTLoaderPlugin will
154648
- * simply ignore the textures in the XKT.
154649
- * * A {@link SceneModel} implementation (eg. {@link VBOSceneModel}) that is configured with a KTX2TextureTranscoder will
154650
- * allow us to load textures into it from KTX2 files or ArrayBuffers.
154651
- *
154652
- * ## What is KTX2?
154653
- *
154654
- * A KTX2 file stores GPU texture data in the Khronos Texture 2.0 (KTX2) container format. It contains image data for
154655
- * a texture asset compressed with Basis Universal (BasisU) supercompression that can be transcoded to different formats
154656
- * depending on the support provided by the target devices. KTX2 provides a lightweight format for distributing texture
154657
- * assets to GPUs. Due to BasisU compression, KTX2 files can store any image format supported by GPUs.
154658
- *
154659
- * ## Loading XKT files containing KTX2 textures
154660
- *
154661
- * An {@link XKTLoaderPlugin} that is configured with a KTX2TextureTranscoder will allow us to load XKT files that
154662
- * contain KTX2 textures. If we don't configure a KTX2TextureTranscoder, then the XKTLoaderPlugin will simply ignore
154663
- * the textures in the XKT.
154664
- *
154665
- * In the example below, we'll create a {@link Viewer} and add an {@link XKTLoaderPlugin}
154666
- * configured with a KTX2TextureTranscoder. Then we'll use the XKTLoaderPlugin to load an
154667
- * XKT file that contains KTX2 textures, which the plugin will transcode using
154668
- * its KTX2TextureTranscoder.
154669
- *
154670
- * ````javascript
154671
- * const viewer = new Viewer({
154672
- * canvasId: "myCanvas",
154673
- * transparent: true
154674
- * });
154675
- *
154676
- * viewer.camera.eye = [-2.56, 8.38, 8.27];
154677
- * viewer.camera.look = [13.44, 3.31, -14.83];
154678
- * viewer.camera.up = [0.10, 0.98, -0.14];
154679
- *
154680
- * const textureTranscoder = new KTX2TextureTranscoder({
154681
- * viewer,
154682
- * transcoderPath: "./../dist/basis/" // <------ Path to Basis Universal transcoder
154683
- * });
154684
- *
154685
- * const xktLoader = new XKTLoaderPlugin(viewer, {
154686
- * textureTranscoder // <<------------- Transcodes KTX2 textures in XKT files
154687
- * });
154688
- *
154689
- * const sceneModel = xktLoader.load({
154690
- * id: "myModel",
154691
- * src: "./HousePlan.xkt" // <<------ XKT file with KTX2 textures
154692
- * });
154693
- * ````
154694
- *
154695
- * ## Loading KTX2 files into a VBOSceneModel
154696
- *
154697
- * A {@link SceneModel} that is configured with a KTX2TextureTranscoder will
154698
- * allow us to load textures into it from KTX2-transcoded buffers or files.
154699
- *
154700
- * In the example below, we'll create a {@link Viewer}, containing a {@link VBOSceneModel} configured with a
154701
- * KTX2TextureTranscoder. We'll then programmatically create a simple object within the VBOSceneModel, consisting of
154702
- * a single mesh with a texture loaded from a KTX2 file, which our VBOSceneModel internally transcodes, using
154703
- * its KTX2TextureTranscoder. Note how we configure our KTX2TextureTranscoder with a path to the Basis Universal
154704
- * transcoder WASM module.
154705
- *
154706
- * ````javascript
154707
- * const viewer = new Viewer({
154708
- * canvasId: "myCanvas",
154709
- * transparent: true
154710
- * });
154711
- *
154712
- * viewer.scene.camera.eye = [-21.80, 4.01, 6.56];
154713
- * viewer.scene.camera.look = [0, -5.75, 0];
154714
- * viewer.scene.camera.up = [0.37, 0.91, -0.11];
154715
- *
154716
- * const textureTranscoder = new KTX2TextureTranscoder({
154717
- * viewer,
154718
- * transcoderPath: "./../dist/basis/" // <------ Path to BasisU transcoder module
154719
- * });
154720
- *
154721
- * const vboSceneModel = new VBOSceneModel(viewer.scene, {
154722
- * id: "myModel",
154723
- * textureTranscoder // <<-------------------- Configure model with our transcoder
154724
- * });
154725
- *
154726
- * vboSceneModel.createTexture({
154727
- * id: "myColorTexture",
154728
- * src: "../assets/textures/compressed/sample_uastc_zstd.ktx2" // <<----- KTX2 texture asset
154729
- * });
154730
- *
154731
- * vboSceneModel.createTexture({
154732
- * id: "myMetallicRoughnessTexture",
154733
- * src: "../assets/textures/alpha/crosshatchAlphaMap.jpg" // <<----- JPEG texture asset
154734
- * });
154735
- *
154736
- * vboSceneModel.createTextureSet({
154737
- * id: "myTextureSet",
154738
- * colorTextureId: "myColorTexture",
154739
- * metallicRoughnessTextureId: "myMetallicRoughnessTexture"
154740
- * });
154741
- *
154742
- * vboSceneModel.createMesh({
154743
- * id: "myMesh",
154744
- * textureSetId: "myTextureSet",
154745
- * primitive: "triangles",
154746
- * positions: [1, 1, 1, ...],
154747
- * normals: [0, 0, 1, 0, ...],
154748
- * uv: [1, 0, 0, ...],
154749
- * indices: [0, 1, 2, ...],
154750
- * });
154751
- *
154752
- * vboSceneModel.createEntity({
154753
- * id: "myEntity",
154754
- * meshIds: ["myMesh"]
154755
- * });
154756
- *
154757
- * vboSceneModel.finalize();
154758
- * ````
154759
- *
154760
- * ## Loading KTX2 ArrayBuffers into a VBOSceneModel
154761
- *
154762
- * A {@link SceneModel} that is configured with a KTX2TextureTranscoder will allow us to load textures into
154763
- * it from KTX2 ArrayBuffers.
154764
- *
154765
- * In the example below, we'll create a {@link Viewer}, containing a {@link VBOSceneModel} configured with a
154766
- * KTX2TextureTranscoder. We'll then programmatically create a simple object within the VBOSceneModel, consisting of
154767
- * a single mesh with a texture loaded from a KTX2 ArrayBuffer, which our VBOSceneModel internally transcodes, using
154768
- * its KTX2TextureTranscoder.
154769
- *
154770
- * ````javascript
154771
- * const viewer = new Viewer({
154772
- * canvasId: "myCanvas",
154773
- * transparent: true
154774
- * });
154775
- *
154776
- * viewer.scene.camera.eye = [-21.80, 4.01, 6.56];
154777
- * viewer.scene.camera.look = [0, -5.75, 0];
154778
- * viewer.scene.camera.up = [0.37, 0.91, -0.11];
154779
- *
154780
- * const textureTranscoder = new KTX2TextureTranscoder({
154781
- * viewer,
154782
- * transcoderPath: "./../dist/basis/" // <------ Path to BasisU transcoder module
154783
- * });
154784
- *
154785
- * const vboSceneModel = new VBOSceneModel(viewer.scene, {
154786
- * id: "myModel",
154787
- * textureTranscoder // <<-------------------- Configure model with our transcoder
154788
- * });
154789
- *
154790
- * utils.loadArraybuffer("../assets/textures/compressed/sample_uastc_zstd.ktx2",(arrayBuffer) => {
154791
- *
154792
- * vboSceneModel.createTexture({
154793
- * id: "myColorTexture",
154794
- * buffers: [arrayBuffer] // <<----- KTX2 texture asset
154795
- * });
154796
- *
154797
- * vboSceneModel.createTexture({
154798
- * id: "myMetallicRoughnessTexture",
154799
- * src: "../assets/textures/alpha/crosshatchAlphaMap.jpg" // <<----- JPEG texture asset
154800
- * });
154801
- *
154802
- * vboSceneModel.createTextureSet({
154803
- * id: "myTextureSet",
154804
- * colorTextureId: "myColorTexture",
154805
- * metallicRoughnessTextureId: "myMetallicRoughnessTexture"
154806
- * });
154807
- *
154808
- * vboSceneModel.createMesh({
154809
- * id: "myMesh",
154810
- * textureSetId: "myTextureSet",
154811
- * primitive: "triangles",
154812
- * positions: [1, 1, 1, ...],
154813
- * normals: [0, 0, 1, 0, ...],
154814
- * uv: [1, 0, 0, ...],
154815
- * indices: [0, 1, 2, ...],
154816
- * });
154817
- *
154818
- * vboSceneModel.createEntity({
154819
- * id: "myEntity",
154820
- * meshIds: ["myMesh"]
154821
- * });
154822
- *
154823
- * vboSceneModel.finalize();
154824
- * });
154825
- * ````
154826
- *
154827
- * @implements {TextureTranscoder}
154828
- */
154829
- class KTX2TextureTranscoder {
154830
-
154831
- /**
154832
- * Creates a new KTX2TextureTranscoder.
154833
- *
154834
- * @param {Viewer} viewer The Viewer that our KTX2TextureTranscoder will be used with. This KTX2TextureTranscoder
154835
- * must only be used to transcode textures for this Viewer. This is because the Viewer's capabilities will decide
154836
- * what target GPU formats this KTX2TextureTranscoder will transcode to.
154837
- * @param {String} transcoderPath Path to the Basis transcoder module that internally does the heavy lifting for our KTX2TextureTranscoder.
154838
- * @param {Number} [workerLimit] The maximum number of Workers to use for transcoding.
154839
- */
154840
- constructor({viewer, transcoderPath, workerLimit}) {
154841
-
154842
- this._transcoderPath = transcoderPath;
154843
- this._transcoderBinary = null;
154844
- this._transcoderPending = null;
154845
- this._workerPool = new WorkerPool();
154846
- this._workerSourceURL = '';
154847
-
154848
- if (workerLimit) {
154849
- this._workerPool.setWorkerLimit(workerLimit);
154850
- }
154851
-
154852
- const viewerCapabilities = viewer.capabilities;
154853
-
154854
- this._workerConfig = {
154855
- astcSupported: viewerCapabilities.astcSupported,
154856
- etc1Supported: viewerCapabilities.etc1Supported,
154857
- etc2Supported: viewerCapabilities.etc2Supported,
154858
- dxtSupported: viewerCapabilities.dxtSupported,
154859
- bptcSupported: viewerCapabilities.bptcSupported,
154860
- pvrtcSupported: viewerCapabilities.pvrtcSupported
154861
- };
154862
-
154863
- this._supportedFileTypes = ["xkt2"];
154864
- }
154865
-
154866
- _init() {
154867
- if (!this._transcoderPending) {
154868
- const jsLoader = new FileLoader();
154869
- jsLoader.setPath(this._transcoderPath);
154870
- jsLoader.setWithCredentials(this.withCredentials);
154871
- const jsContent = jsLoader.loadAsync('basis_transcoder.js');
154872
- const binaryLoader = new FileLoader();
154873
- binaryLoader.setPath(this._transcoderPath);
154874
- binaryLoader.setResponseType('arraybuffer');
154875
- binaryLoader.setWithCredentials(this.withCredentials);
154876
- const binaryContent = binaryLoader.loadAsync('basis_transcoder.wasm');
154877
- this._transcoderPending = Promise.all([jsContent, binaryContent])
154878
- .then(([jsContent, binaryContent]) => {
154879
- const fn = KTX2TextureTranscoder.BasisWorker.toString();
154880
- const body = [
154881
- '/* constants */',
154882
- 'let _EngineFormat = ' + JSON.stringify(KTX2TextureTranscoder.EngineFormat),
154883
- 'let _TranscoderFormat = ' + JSON.stringify(KTX2TextureTranscoder.TranscoderFormat),
154884
- 'let _BasisFormat = ' + JSON.stringify(KTX2TextureTranscoder.BasisFormat),
154885
- '/* basis_transcoder.js */',
154886
- jsContent,
154887
- '/* worker */',
154888
- fn.substring(fn.indexOf('{') + 1, fn.lastIndexOf('}'))
154889
- ].join('\n');
154890
- this._workerSourceURL = URL.createObjectURL(new Blob([body]));
154891
- this._transcoderBinary = binaryContent;
154892
- this._workerPool.setWorkerCreator(() => {
154893
- const worker = new Worker(this._workerSourceURL);
154894
- const transcoderBinary = this._transcoderBinary.slice(0);
154895
- worker.postMessage({
154896
- type: 'init',
154897
- config: this._workerConfig,
154898
- transcoderBinary
154899
- }, [transcoderBinary]);
154900
- return worker;
154901
- });
154902
- });
154903
- if (activeTranscoders > 0) {
154904
- console.warn('KTX2TextureTranscoder: Multiple active KTX2TextureTranscoder may cause performance issues.' + ' Use a single KTX2TextureTranscoder instance, or call .dispose() on old instances.');
154905
- }
154906
- activeTranscoders++;
154907
- }
154908
- return this._transcoderPending;
154909
- }
154910
-
154911
- /**
154912
- * Transcodes texture data from transcoded buffers into a {@link Texture2D}.
154913
- *
154914
- * @param {ArrayBuffer[]} buffers Transcoded texture data. Given as an array of buffers so that we can support multi-image textures, such as cube maps.
154915
- * @param {*} config Transcoding options.
154916
- * @param {Texture2D} texture The texture to load.
154917
- * @returns {Promise} Resolves when the texture has loaded.
154918
- */
154919
- transcode(buffers, texture, config = {}) {
154920
- return new Promise((resolve, reject) => {
154921
- const taskConfig = config;
154922
- this._init().then(() => {
154923
- return this._workerPool.postMessage({
154924
- type: 'transcode',
154925
- buffers,
154926
- taskConfig: taskConfig
154927
- }, buffers);
154928
- }).then((e) => {
154929
- const transcodeResult = e.data;
154930
- const {mipmaps, width, height, format, type, error, dfdTransferFn, dfdFlags} = transcodeResult;
154931
- if (type === 'error') {
154932
- return reject(error);
154933
- }
154934
- texture.setCompressedData({
154935
- mipmaps,
154936
- props: {
154937
- format: format,
154938
- minFilter: mipmaps.length === 1 ? LinearFilter : LinearMipmapLinearFilter,
154939
- magFilter: mipmaps.length === 1 ? LinearFilter : LinearMipmapLinearFilter,
154940
- encoding: dfdTransferFn === KTX2TransferSRGB ? sRGBEncoding : LinearEncoding,
154941
- premultiplyAlpha : !!(dfdFlags & KTX2_ALPHA_PREMULTIPLIED)
154942
- }
154943
- });
154944
- resolve();
154945
- });
154946
- });
154947
- }
154948
-
154949
- /**
154950
- * Destroys this KTX2TextureTranscoder
154951
- */
154952
- destroy() {
154953
- URL.revokeObjectURL(this._workerSourceURL);
154954
- this._workerPool.destroy();
154955
- activeTranscoders--;
154956
- }
154957
- }
154958
-
154959
- /**
154960
- * @private
154961
- */
154962
- KTX2TextureTranscoder.BasisFormat = {
154963
- ETC1S: 0,
154964
- UASTC_4x4: 1
154965
- };
154966
-
154967
- /**
154968
- * @private
154969
- */
154970
- KTX2TextureTranscoder.TranscoderFormat = {
154971
- ETC1: 0,
154972
- ETC2: 1,
154973
- BC1: 2,
154974
- BC3: 3,
154975
- BC4: 4,
154976
- BC5: 5,
154977
- BC7_M6_OPAQUE_ONLY: 6,
154978
- BC7_M5: 7,
154979
- PVRTC1_4_RGB: 8,
154980
- PVRTC1_4_RGBA: 9,
154981
- ASTC_4x4: 10,
154982
- ATC_RGB: 11,
154983
- ATC_RGBA_INTERPOLATED_ALPHA: 12,
154984
- RGBA32: 13,
154985
- RGB565: 14,
154986
- BGR565: 15,
154987
- RGBA4444: 16
154988
- };
154989
-
154990
- /**
154991
- * @private
154992
- */
154993
- KTX2TextureTranscoder.EngineFormat = {
154994
- RGBAFormat: RGBAFormat,
154995
- RGBA_ASTC_4x4_Format: RGBA_ASTC_4x4_Format,
154996
- RGBA_BPTC_Format: RGBA_BPTC_Format,
154997
- RGBA_ETC2_EAC_Format: RGBA_ETC2_EAC_Format,
154998
- RGBA_PVRTC_4BPPV1_Format: RGBA_PVRTC_4BPPV1_Format,
154999
- RGBA_S3TC_DXT5_Format: RGBA_S3TC_DXT5_Format,
155000
- RGB_ETC1_Format: RGB_ETC1_Format,
155001
- RGB_ETC2_Format: RGB_ETC2_Format,
155002
- RGB_PVRTC_4BPPV1_Format: RGB_PVRTC_4BPPV1_Format,
155003
- RGB_S3TC_DXT1_Format: RGB_S3TC_DXT1_Format
155004
- };
155005
-
155006
- /* WEB WORKER */
155007
-
155008
- /**
155009
- * @private
155010
- * @constructor
155011
- */
155012
- KTX2TextureTranscoder.BasisWorker = function () {
155013
-
155014
- let config;
155015
- let transcoderPending;
155016
- let BasisModule;
155017
-
155018
- const EngineFormat = _EngineFormat; // eslint-disable-line no-undef
155019
- const TranscoderFormat = _TranscoderFormat; // eslint-disable-line no-undef
155020
- const BasisFormat = _BasisFormat; // eslint-disable-line no-undef
155021
-
155022
- self.addEventListener('message', function (e) {
155023
- const message = e.data;
155024
- switch (message.type) {
155025
- case 'init':
155026
- config = message.config;
155027
- init(message.transcoderBinary);
155028
- break;
155029
- case 'transcode':
155030
- transcoderPending.then(() => {
155031
- try {
155032
- const {
155033
- width,
155034
- height,
155035
- hasAlpha,
155036
- mipmaps,
155037
- format,
155038
- dfdTransferFn,
155039
- dfdFlags
155040
- } = transcode(message.buffers[0]);
155041
- const buffers = [];
155042
- for (let i = 0; i < mipmaps.length; ++i) {
155043
- buffers.push(mipmaps[i].data.buffer);
155044
- }
155045
- self.postMessage({
155046
- type: 'transcode',
155047
- id: message.id,
155048
- width,
155049
- height,
155050
- hasAlpha,
155051
- mipmaps,
155052
- format,
155053
- dfdTransferFn,
155054
- dfdFlags
155055
- }, buffers);
155056
- } catch (error) {
155057
- console.error(`[KTX2TextureTranscoder.BasisWorker]: ${error}`);
155058
- self.postMessage({type: 'error', id: message.id, error: error.message});
155059
- }
155060
- });
155061
- break;
155062
- }
155063
- });
155064
-
155065
- function init(wasmBinary) {
155066
- transcoderPending = new Promise(resolve => {
155067
- BasisModule = {
155068
- wasmBinary,
155069
- onRuntimeInitialized: resolve
155070
- };
155071
- BASIS(BasisModule); // eslint-disable-line no-undef
155072
- }).then(() => {
155073
- BasisModule.initializeBasis();
155074
- if (BasisModule.KTX2File === undefined) {
155075
- console.warn('KTX2TextureTranscoder: Please update Basis Universal transcoder.');
155076
- }
155077
- });
155078
- }
155079
-
155080
- function transcode(buffer) {
155081
- const ktx2File = new BasisModule.KTX2File(new Uint8Array(buffer));
155082
-
155083
- function cleanup() {
155084
- ktx2File.close();
155085
- ktx2File.delete();
155086
- }
155087
-
155088
- if (!ktx2File.isValid()) {
155089
- cleanup();
155090
- throw new Error('KTX2TextureTranscoder: Invalid or unsupported .ktx2 file');
155091
- }
155092
- const basisFormat = ktx2File.isUASTC() ? BasisFormat.UASTC_4x4 : BasisFormat.ETC1S;
155093
- const width = ktx2File.getWidth();
155094
- const height = ktx2File.getHeight();
155095
- const levels = ktx2File.getLevels();
155096
- const hasAlpha = ktx2File.getHasAlpha();
155097
- const dfdTransferFn = ktx2File.getDFDTransferFunc();
155098
- const dfdFlags = ktx2File.getDFDFlags();
155099
- const {transcoderFormat, engineFormat} = getTranscoderFormat(basisFormat, width, height, hasAlpha);
155100
- if (!width || !height || !levels) {
155101
- cleanup();
155102
- throw new Error('KTX2TextureTranscoder: Invalid texture');
155103
- }
155104
- if (!ktx2File.startTranscoding()) {
155105
- cleanup();
155106
- throw new Error('KTX2TextureTranscoder: .startTranscoding failed');
155107
- }
155108
- const mipmaps = [];
155109
- for (let mip = 0; mip < levels; mip++) {
155110
- const levelInfo = ktx2File.getImageLevelInfo(mip, 0, 0);
155111
- const mipWidth = levelInfo.origWidth;
155112
- const mipHeight = levelInfo.origHeight;
155113
- const dst = new Uint8Array(ktx2File.getImageTranscodedSizeInBytes(mip, 0, 0, transcoderFormat));
155114
- const status = ktx2File.transcodeImage(dst, mip, 0, 0, transcoderFormat, 0, -1, -1);
155115
- if (!status) {
155116
- cleanup();
155117
- throw new Error('KTX2TextureTranscoder: .transcodeImage failed.');
155118
- }
155119
- mipmaps.push({data: dst, width: mipWidth, height: mipHeight});
155120
- }
155121
- cleanup();
155122
- return {width, height, hasAlpha, mipmaps, format: engineFormat, dfdTransferFn, dfdFlags};
155123
- }
155124
-
155125
- // Optimal choice of a transcoder target format depends on the Basis format (ETC1S or UASTC),
155126
- // device capabilities, and texture dimensions. The list below ranks the formats separately
155127
- // for ETC1S and UASTC.
155128
- //
155129
- // In some cases, transcoding UASTC to RGBA32 might be preferred for higher quality (at
155130
- // significant memory cost) compared to ETC1/2, BC1/3, and PVRTC. The transcoder currently
155131
- // chooses RGBA32 only as a last resort and does not expose that option to the caller.
155132
-
155133
- const FORMAT_OPTIONS = [{
155134
- if: 'astcSupported',
155135
- basisFormat: [BasisFormat.UASTC_4x4],
155136
- transcoderFormat: [TranscoderFormat.ASTC_4x4, TranscoderFormat.ASTC_4x4],
155137
- engineFormat: [EngineFormat.RGBA_ASTC_4x4_Format, EngineFormat.RGBA_ASTC_4x4_Format],
155138
- priorityETC1S: Infinity,
155139
- priorityUASTC: 1,
155140
- needsPowerOfTwo: false
155141
- }, {
155142
- if: 'bptcSupported',
155143
- basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4],
155144
- transcoderFormat: [TranscoderFormat.BC7_M5, TranscoderFormat.BC7_M5],
155145
- engineFormat: [EngineFormat.RGBA_BPTC_Format, EngineFormat.RGBA_BPTC_Format],
155146
- priorityETC1S: 3,
155147
- priorityUASTC: 2,
155148
- needsPowerOfTwo: false
155149
- }, {
155150
- if: 'dxtSupported',
155151
- basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4],
155152
- transcoderFormat: [TranscoderFormat.BC1, TranscoderFormat.BC3],
155153
- engineFormat: [EngineFormat.RGB_S3TC_DXT1_Format, EngineFormat.RGBA_S3TC_DXT5_Format],
155154
- priorityETC1S: 4,
155155
- priorityUASTC: 5,
155156
- needsPowerOfTwo: false
155157
- }, {
155158
- if: 'etc2Supported',
155159
- basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4],
155160
- transcoderFormat: [TranscoderFormat.ETC1, TranscoderFormat.ETC2],
155161
- engineFormat: [EngineFormat.RGB_ETC2_Format, EngineFormat.RGBA_ETC2_EAC_Format],
155162
- priorityETC1S: 1,
155163
- priorityUASTC: 3,
155164
- needsPowerOfTwo: false
155165
- }, {
155166
- if: 'etc1Supported',
155167
- basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4],
155168
- transcoderFormat: [TranscoderFormat.ETC1],
155169
- engineFormat: [EngineFormat.RGB_ETC1_Format],
155170
- priorityETC1S: 2,
155171
- priorityUASTC: 4,
155172
- needsPowerOfTwo: false
155173
- }, {
155174
- if: 'pvrtcSupported',
155175
- basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4],
155176
- transcoderFormat: [TranscoderFormat.PVRTC1_4_RGB, TranscoderFormat.PVRTC1_4_RGBA],
155177
- engineFormat: [EngineFormat.RGB_PVRTC_4BPPV1_Format, EngineFormat.RGBA_PVRTC_4BPPV1_Format],
155178
- priorityETC1S: 5,
155179
- priorityUASTC: 6,
155180
- needsPowerOfTwo: true
155181
- }];
155182
- const ETC1S_OPTIONS = FORMAT_OPTIONS.sort(function (a, b) {
155183
- return a.priorityETC1S - b.priorityETC1S;
155184
- });
155185
- const UASTC_OPTIONS = FORMAT_OPTIONS.sort(function (a, b) {
155186
- return a.priorityUASTC - b.priorityUASTC;
155187
- });
155188
-
155189
- function getTranscoderFormat(basisFormat, width, height, hasAlpha) {
155190
- let transcoderFormat;
155191
- let engineFormat;
155192
- const options = basisFormat === BasisFormat.ETC1S ? ETC1S_OPTIONS : UASTC_OPTIONS;
155193
- for (let i = 0; i < options.length; i++) {
155194
- const opt = options[i];
155195
- if (!config[opt.if]) continue;
155196
- if (!opt.basisFormat.includes(basisFormat)) continue;
155197
- if (hasAlpha && opt.transcoderFormat.length < 2) continue;
155198
- if (opt.needsPowerOfTwo && !(isPowerOfTwo(width) && isPowerOfTwo(height))) continue;
155199
- transcoderFormat = opt.transcoderFormat[hasAlpha ? 1 : 0];
155200
- engineFormat = opt.engineFormat[hasAlpha ? 1 : 0];
155201
- return {
155202
- transcoderFormat,
155203
- engineFormat
155204
- };
155205
- }
155206
- console.warn('KTX2TextureTranscoder: No suitable compressed texture format found. Decoding to RGBA32.');
155207
- transcoderFormat = TranscoderFormat.RGBA32;
155208
- engineFormat = EngineFormat.RGBAFormat;
155209
- return {
155210
- transcoderFormat,
155211
- engineFormat
155212
- };
155213
- }
155214
-
155215
- function isPowerOfTwo(value) {
155216
- if (value <= 2) return true;
155217
- return (value & value - 1) === 0 && value !== 0;
155218
- }
155219
- };
155220
-
155221
155264
  const screenPos = math.vec4();
155222
155265
  const viewPos = math.vec4();
155223
155266
 
@@ -161994,11 +162037,9 @@ class LASLoaderPlugin extends Plugin {
161994
162037
  try {
161995
162038
  parse$3(arrayBuffer, LASLoader, options).then((parsedData) => {
161996
162039
 
161997
- const loaderData = parsedData.loaderData;
161998
- const loaderDataHeader = loaderData.header;
161999
- const pointsFormatId = loaderDataHeader.pointsFormatId;
162000
-
162001
162040
  const attributes = parsedData.attributes;
162041
+ const loaderData = parsedData.loaderData;
162042
+ const pointsFormatId = loaderData.pointsFormatId !== undefined ? loaderData.pointsFormatId : -1;
162002
162043
 
162003
162044
  if (!attributes.POSITION) {
162004
162045
  sceneModel.finalize();
@@ -163536,4 +163577,4 @@ class CityJSONLoaderPlugin extends Plugin {
163536
163577
  }
163537
163578
  }
163538
163579
 
163539
- export { AlphaFormat, AmbientLight, AngleMeasurementsPlugin, AnnotationsPlugin, AxisGizmoPlugin, BCFViewpointsPlugin, BasicDepthPacking, ByteType, CameraMemento, CameraPath, CameraPathAnimation, CityJSONLoaderPlugin, ClampToEdgeWrapping, Component, Configs, ContextMenu, CubicBezierCurve, Curve, DefaultLoadingManager, DepthFormat, DepthStencilFormat, DirLight, DistanceMeasurementsPlugin, EdgeMaterial, EmphasisMaterial, FastNavPlugin, FloatType, Fresnel, GLTFDefaultDataSource, GLTFLoaderPlugin, HalfFloatType, ImagePlane, IntType, KTX2TextureTranscoder, LASLoaderPlugin, LambertMaterial, LightMap, LinearEncoding, LinearFilter, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, Loader, LoadingManager, LocaleService, LuminanceAlphaFormat, LuminanceFormat, Map$1 as Map, Marker, Mesh, MetallicMaterial, MirroredRepeatWrapping, ModelMemento, NavCubePlugin, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, Node$1 as Node, OBJLoaderPlugin, ObjectsMemento, Path, PerformanceModel, PhongMaterial, Plugin, PointLight, QuadraticBezierCurve, Queue, RGBADepthPacking, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBFormat, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, ReadableGeometry, RedFormat, RedIntegerFormat, ReflectionMap, RepeatWrapping, STLDefaultDataSource, STLLoaderPlugin, SceneModel, SectionPlane, SectionPlanesPlugin, ShortType, Skybox, SkyboxesPlugin, SpecularMaterial, SplineCurve, SpriteMarker, StoreyViewsPlugin, Texture, TextureTranscoder, TreeViewPlugin, UnsignedByteType, UnsignedInt248Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VBOGeometry, VBOSceneModel, ViewCullPlugin, Viewer, WebIFCLoaderPlugin, WorkerPool, XKTDefaultDataSource, XKTLoaderPlugin, XML3DLoaderPlugin, _SRGBAFormat, buildBoxGeometry, buildBoxLinesGeometry, buildCylinderGeometry, buildGridGeometry, buildPlaneGeometry, buildSphereGeometry, buildTorusGeometry, buildVectorTextGeometry, load3DSGeometry, loadOBJGeometry, math, sRGBEncoding, stats, utils };
163580
+ export { AlphaFormat, AmbientLight, AngleMeasurementsPlugin, AnnotationsPlugin, AxisGizmoPlugin, BCFViewpointsPlugin, BasicDepthPacking, ByteType, CameraMemento, CameraPath, CameraPathAnimation, CityJSONLoaderPlugin, ClampToEdgeWrapping, Component, Configs, ContextMenu, CubicBezierCurve, Curve, DefaultLoadingManager, DepthFormat, DepthStencilFormat, DirLight, DistanceMeasurementsPlugin, EdgeMaterial, EmphasisMaterial, FastNavPlugin, FloatType, Fresnel, GLTFDefaultDataSource, GLTFLoaderPlugin, HalfFloatType, ImagePlane, IntType, KTX2TextureTranscoder, LASLoaderPlugin, LambertMaterial, LightMap, LinearEncoding, LinearFilter, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, Loader, LoadingManager, LocaleService, LuminanceAlphaFormat, LuminanceFormat, Map$1 as Map, Marker, Mesh, MetallicMaterial, MirroredRepeatWrapping, ModelMemento, NavCubePlugin, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, Node$1 as Node, OBJLoaderPlugin, ObjectsMemento, Path, PerformanceModel, PhongMaterial, Plugin, PointLight, QuadraticBezierCurve, Queue, RGBADepthPacking, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBFormat, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, ReadableGeometry, RedFormat, RedIntegerFormat, ReflectionMap, RepeatWrapping, STLDefaultDataSource, STLLoaderPlugin, SceneModel, SectionPlane, SectionPlanesPlugin, ShortType, Skybox, SkyboxesPlugin, SpecularMaterial, SplineCurve, SpriteMarker, StoreyViewsPlugin, Texture, TextureTranscoder, TreeViewPlugin, UnsignedByteType, UnsignedInt248Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VBOGeometry, VBOSceneModel, ViewCullPlugin, Viewer, WebIFCLoaderPlugin, WorkerPool$1 as WorkerPool, XKTDefaultDataSource, XKTLoaderPlugin, XML3DLoaderPlugin, _SRGBAFormat, buildBoxGeometry, buildBoxLinesGeometry, buildCylinderGeometry, buildGridGeometry, buildPlaneGeometry, buildSphereGeometry, buildTorusGeometry, buildVectorTextGeometry, getKTX2TextureTranscoder, load3DSGeometry, loadOBJGeometry, math, sRGBEncoding, stats, utils };