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