diff --git a/webgl/gltf-demo/BasisTextureLoader.js b/webgl/gltf-demo/BasisTextureLoader.js new file mode 100644 index 0000000..2c8cfb9 --- /dev/null +++ b/webgl/gltf-demo/BasisTextureLoader.js @@ -0,0 +1,169 @@ +/** + * @author Don McCurdy / https://www.donmccurdy.com + * @author Austin Eng / ? + * @author Shrek Shao / https://github.com/shrekshao + */ + +/** + * An example three.js loader for Basis compressed textures. + */ +THREE.BasisTextureLoader = class BasisTextureLoader { + + constructor () { + + this.etcSupported = false; + this.dxtSupported = false; + this.pvrtcSupported = false; + + this.format = null; + + } + + detectSupport ( renderer ) { + + const context = renderer.context; + + this.etcSupported = context.getExtension('WEBGL_compressed_texture_etc1'); + this.dxtSupported = context.getExtension('WEBGL_compressed_texture_s3tc'); + this.pvrtcSupported = context.getExtension('WEBGL_compressed_texture_pvrtc') + || context.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc'); + + if ( ! this.etcSupported && ! this.dxtSupported && ! this.pvrtcSupported ) { + + throw new Error( 'THREE.BasisTextureLoader: No suitable compressed texture format found.' ); + + } + + this.format = this.etcSupported + ? BASIS_FORMAT.cTFETC1 + : ( this.dxtSupported + ? BASIS_FORMAT.cTFBC1 + : BASIS_FORMAT.cTFPVRTC1_4_OPAQUE_ONLY ); + + return this; + + } + + load ( url, onLoad, onProgress, onError ) { + + fetch( url ) + .then( ( res ) => res.arrayBuffer() ) + .then( (arrayBuffer) => this._createTexture( arrayBuffer ) ) + .then( onLoad ) + .catch( onError ); + + } + + _createTexture ( arrayBuffer ) { + + const BASIS_FORMAT = THREE.BasisTextureLoader.BASIS_FORMAT; + const DXT_FORMAT_MAP = THREE.BasisTextureLoader.DXT_FORMAT_MAP; + + const basisFile = new BasisFile( new Uint8Array( arrayBuffer ) ); + + const width = basisFile.getImageWidth( 0, 0 ); + const height = basisFile.getImageHeight( 0, 0 ); + const images = basisFile.getNumImages(); + const levels = basisFile.getNumLevels( 0 ); + + function cleanup () { + + basisFile.close(); + basisFile.delete(); + + } + + if ( ! width || ! height || ! images || ! levels ) { + + cleanup(); + throw new Error( 'THREE.BasisTextureLoader: Invalid .basis file' ); + + } + + if ( ! basisFile.startTranscoding() ) { + + cleanup(); + throw new Error( 'THREE.BasisTextureLoader: .startTranscoding failed' ); + + } + + const dst = new Uint8Array( basisFile.getImageTranscodedSizeInBytes( 0, 0, this.format ) ); + + const startTime = performance.now(); + + const status = basisFile.transcodeImage( + dst, + 0, + 0, + this.format, + this.etcSupported ? 0 : ( this.dxtSupported ? 1 : 0 ), + 0 + ); + + console.log( `THREE.BasisTextureLoader: Transcode time: ${performance.now() - startTime}ms`, dst ); + + cleanup(); + + if ( ! status ) { + + throw new Error( 'THREE.BasisTextureLoader: .transcodeImage failed.' ); + + } + + const mipmaps = [ { data: dst, width, height } ]; + + let texture; + + if ( this.etcSupported ) { + + texture = new THREE.CompressedTexture( mipmaps, width, height, THREE.RGB_ETC1_Format ); + + } else if ( this.dxtSupported ) { + + texture = new THREE.CompressedTexture( mipmaps, width, height, DXT_FORMAT_MAP[ this.format ], THREE.UnsignedByteType ); + + } else if ( this.pvrtcSupported ) { + + texture = new THREE.CompressedTexture( mipmaps, width, height, THREE.RGB_PVRTC_4BPPV1_Format ); + + } else { + + throw new Error( 'THREE.BasisTextureLoader: No supported format available.' ); + + } + + texture.minFilter = THREE.LinearMipMapLinearFilter; + texture.magFilter = THREE.LinearFilter; + texture.encoding = THREE.sRGBEncoding; + texture.generateMipmaps = false; + texture.flipY = false; + texture.needsUpdate = true; + + return texture; + + } +} + +const BASIS_FORMAT = { + cTFETC1: 0, + cTFBC1: 1, + cTFBC4: 2, + cTFPVRTC1_4_OPAQUE_ONLY: 3, + cTFBC7_M6_OPAQUE_ONLY: 4, + cTFETC2: 5, + cTFBC3: 6, + cTFBC5: 7, +}; + +// DXT formats, from: +// http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/ +const DXT_FORMAT_MAP = {}; +const COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0; +const COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1; +const COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2; +const COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3; +DXT_FORMAT_MAP[ BASIS_FORMAT.cTFBC1 ] = COMPRESSED_RGB_S3TC_DXT1_EXT; +DXT_FORMAT_MAP[ BASIS_FORMAT.cTFBC3 ] = COMPRESSED_RGBA_S3TC_DXT5_EXT; + +THREE.BasisTextureLoader.BASIS_FORMAT = BASIS_FORMAT; +THREE.BasisTextureLoader.DXT_FORMAT_MAP = DXT_FORMAT_MAP; diff --git a/webgl/gltf-demo/GLTFLoader.js b/webgl/gltf-demo/GLTFLoader.js index bb67be4..31bc8af 100644 --- a/webgl/gltf-demo/GLTFLoader.js +++ b/webgl/gltf-demo/GLTFLoader.js @@ -1,3 +1,8 @@ +/** + * Copyright 2019 the three.js authors + * SPDX-License-Identifier: MIT + */ + /** * @author Rich Tibbett / https://github.com/richtr * @author mrdoob / http://mrdoob.com/ @@ -6,6 +11,12 @@ * @author Don McCurdy / https://www.donmccurdy.com */ +/** + * A modified version of THREE.GLTFLoader, with support for the (hypothetical) + * GOOGLE_texture_basis extension. This extension is defined for the sake of + * example only – the glTF format will officially reference Basis files within + * a KTX2 wrapper. + */ THREE.GLTFLoader = ( function () { function GLTFLoader( manager ) { diff --git a/webgl/gltf-demo/index.html b/webgl/gltf-demo/index.html index 8cf04b2..c37a66c 100644 --- a/webgl/gltf-demo/index.html +++ b/webgl/gltf-demo/index.html @@ -3,220 +3,118 @@
+ -