@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.
- package/dist/xeokit-sdk.cjs.js +1137 -1094
- package/dist/xeokit-sdk.es.js +1135 -1094
- package/dist/xeokit-sdk.min.cjs.js +1 -1
- package/dist/xeokit-sdk.min.es.js +1 -1
- package/package.json +1 -1
package/dist/xeokit-sdk.es.js
CHANGED
|
@@ -15295,7 +15295,7 @@ class RenderBufferManager {
|
|
|
15295
15295
|
/**
|
|
15296
15296
|
* @private
|
|
15297
15297
|
*/
|
|
15298
|
-
function getExtension
|
|
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
|
|
15364
|
+
astcSupported: !!getExtension(gl, 'WEBGL_compressed_texture_astc'),
|
|
15365
15365
|
etc1Supported: true, // WebGL2
|
|
15366
|
-
etc2Supported: !!getExtension
|
|
15367
|
-
dxtSupported: !!getExtension
|
|
15368
|
-
bptcSupported: !!getExtension
|
|
15369
|
-
pvrtcSupported: !!(getExtension
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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,
|
|
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
|
|
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
|
-
|
|
64785
|
-
|
|
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
|
-
|
|
64796
|
-
|
|
64797
|
-
|
|
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
|
-
|
|
64801
|
-
|
|
64802
|
-
|
|
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
|
-
|
|
64806
|
-
|
|
64807
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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}.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
102159
|
+
* ## Loading XKT files containing textures
|
|
101116
102160
|
*
|
|
101117
|
-
*
|
|
101118
|
-
*
|
|
101119
|
-
*
|
|
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
|
|
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 };
|