@damienmortini/three 0.1.193 → 0.1.195

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.
@@ -1,790 +1,661 @@
1
- import {
2
- CompressedTexture,
3
- FileLoader,
4
- LinearFilter,
5
- LinearMipmapLinearFilter,
6
- Loader,
7
- RGBAFormat,
8
- RGBA_ASTC_4x4_Format,
9
- RGBA_BPTC_Format,
10
- RGBA_ETC2_EAC_Format,
11
- RGBA_PVRTC_4BPPV1_Format,
12
- RGBA_S3TC_DXT5_Format,
13
- RGB_ETC1_Format,
14
- RGB_ETC2_Format,
15
- RGB_PVRTC_4BPPV1_Format,
16
- RGB_S3TC_DXT1_Format,
17
- UnsignedByteType
18
- } from '../../../../three/src/Three.js';
19
-
20
- /**
21
- * Loader for Basis Universal GPU Texture Codec.
22
- *
23
- * Basis Universal is a "supercompressed" GPU texture and texture video
24
- * compression system that outputs a highly compressed intermediate file format
25
- * (.basis) that can be quickly transcoded to a wide variety of GPU texture
26
- * compression formats.
27
- *
28
- * This loader parallelizes the transcoding process across a configurable number
29
- * of web workers, before transferring the transcoded compressed texture back
30
- * to the main thread.
31
- */
32
-
33
- const _taskCache = new WeakMap();
34
-
1
+ import {
2
+ CompressedTexture,
3
+ FileLoader,
4
+ LinearFilter,
5
+ LinearMipmapLinearFilter,
6
+ Loader,
7
+ RGB_ETC1_Format,
8
+ RGB_ETC2_Format,
9
+ RGB_PVRTC_4BPPV1_Format,
10
+ RGB_S3TC_DXT1_Format,
11
+ RGBA_ASTC_4x4_Format,
12
+ RGBA_BPTC_Format,
13
+ RGBA_ETC2_EAC_Format,
14
+ RGBA_PVRTC_4BPPV1_Format,
15
+ RGBA_S3TC_DXT5_Format,
16
+ RGBAFormat,
17
+ UnsignedByteType,
18
+ } from '../../../../three/src/Three.js';
19
+
20
+ /**
21
+ * Loader for Basis Universal GPU Texture Codec.
22
+ *
23
+ * Basis Universal is a "supercompressed" GPU texture and texture video
24
+ * compression system that outputs a highly compressed intermediate file format
25
+ * (.basis) that can be quickly transcoded to a wide variety of GPU texture
26
+ * compression formats.
27
+ *
28
+ * This loader parallelizes the transcoding process across a configurable number
29
+ * of web workers, before transferring the transcoded compressed texture back
30
+ * to the main thread.
31
+ */
32
+
33
+ const _taskCache = new WeakMap();
34
+
35
35
  class BasisTextureLoader extends Loader {
36
-
37
- constructor( manager ) {
38
-
39
- super( manager );
40
-
41
- this.transcoderPath = '';
42
- this.transcoderBinary = null;
43
- this.transcoderPending = null;
44
-
45
- this.workerLimit = 4;
46
- this.workerPool = [];
47
- this.workerNextTaskID = 1;
48
- this.workerSourceURL = '';
49
- this.workerConfig = null;
50
-
51
- console.warn(
52
-
53
- 'THREE.BasisTextureLoader: This loader is deprecated, and will be removed in a future release. '
54
- + 'Instead, use Basis Universal compression in KTX2 (.ktx2) files with THREE.KTX2Loader.'
55
-
56
- );
57
-
58
- }
59
-
60
- setTranscoderPath( path ) {
61
-
62
- this.transcoderPath = path;
63
-
64
- return this;
65
-
66
- }
67
-
68
- setWorkerLimit( workerLimit ) {
69
-
70
- this.workerLimit = workerLimit;
71
-
72
- return this;
73
-
74
- }
75
-
76
- detectSupport( renderer ) {
77
-
78
- this.workerConfig = {
79
- astcSupported: renderer.extensions.has( 'WEBGL_compressed_texture_astc' ),
80
- etc1Supported: renderer.extensions.has( 'WEBGL_compressed_texture_etc1' ),
81
- etc2Supported: renderer.extensions.has( 'WEBGL_compressed_texture_etc' ),
82
- dxtSupported: renderer.extensions.has( 'WEBGL_compressed_texture_s3tc' ),
83
- bptcSupported: renderer.extensions.has( 'EXT_texture_compression_bptc' ),
84
- pvrtcSupported: renderer.extensions.has( 'WEBGL_compressed_texture_pvrtc' )
85
- || renderer.extensions.has( 'WEBKIT_WEBGL_compressed_texture_pvrtc' )
86
- };
87
-
88
- return this;
89
-
90
- }
91
-
92
- load( url, onLoad, onProgress, onError ) {
93
-
94
- const loader = new FileLoader( this.manager );
95
-
96
- loader.setResponseType( 'arraybuffer' );
97
- loader.setWithCredentials( this.withCredentials );
98
-
99
- const texture = new CompressedTexture();
100
-
101
- loader.load( url, ( buffer ) => {
102
-
103
- // Check for an existing task using this buffer. A transferred buffer cannot be transferred
104
- // again from this thread.
105
- if ( _taskCache.has( buffer ) ) {
106
-
107
- const cachedTask = _taskCache.get( buffer );
108
-
109
- return cachedTask.promise.then( onLoad ).catch( onError );
110
-
111
- }
112
-
113
- this._createTexture( [ buffer ] )
114
- .then( function ( _texture ) {
115
-
116
- texture.copy( _texture );
117
- texture.needsUpdate = true;
118
-
119
- if ( onLoad ) onLoad( texture );
120
-
121
- } )
122
- .catch( onError );
123
-
124
- }, onProgress, onError );
125
-
126
- return texture;
127
-
128
- }
129
-
130
- /** Low-level transcoding API, exposed for use by KTX2Loader. */
131
- parseInternalAsync( options ) {
132
-
133
- const { levels } = options;
134
-
135
- const buffers = new Set();
136
-
137
- for ( let i = 0; i < levels.length; i ++ ) {
138
-
139
- buffers.add( levels[ i ].data.buffer );
140
-
141
- }
142
-
143
- return this._createTexture( Array.from( buffers ), { ...options, lowLevel: true } );
144
-
145
- }
146
-
147
- /**
148
- * @param {ArrayBuffer[]} buffers
149
- * @param {object?} config
150
- * @return {Promise<CompressedTexture>}
151
- */
152
- _createTexture( buffers, config = {} ) {
153
-
154
- let worker;
155
- let taskID;
156
-
157
- const taskConfig = config;
158
- let taskCost = 0;
159
-
160
- for ( let i = 0; i < buffers.length; i ++ ) {
161
-
162
- taskCost += buffers[ i ].byteLength;
163
-
164
- }
165
-
166
- const texturePending = this._allocateWorker( taskCost )
167
- .then( ( _worker ) => {
168
-
169
- worker = _worker;
170
- taskID = this.workerNextTaskID ++;
171
-
172
- return new Promise( ( resolve, reject ) => {
173
-
174
- worker._callbacks[ taskID ] = { resolve, reject };
175
-
176
- worker.postMessage( { type: 'transcode', id: taskID, buffers: buffers, taskConfig: taskConfig }, buffers );
177
-
178
- } );
179
-
180
- } )
181
- .then( ( message ) => {
182
-
183
- const { mipmaps, width, height, format } = message;
184
-
185
- const texture = new CompressedTexture( mipmaps, width, height, format, UnsignedByteType );
186
- texture.minFilter = mipmaps.length === 1 ? LinearFilter : LinearMipmapLinearFilter;
187
- texture.magFilter = LinearFilter;
188
- texture.generateMipmaps = false;
189
- texture.needsUpdate = true;
190
-
191
- return texture;
192
-
193
- } );
194
-
195
- // Note: replaced '.finally()' with '.catch().then()' block - iOS 11 support (#19416)
196
- texturePending
197
- .catch( () => true )
198
- .then( () => {
199
-
200
- if ( worker && taskID ) {
201
-
202
- worker._taskLoad -= taskCost;
203
- delete worker._callbacks[ taskID ];
204
-
205
- }
206
-
207
- } );
208
-
209
- // Cache the task result.
210
- _taskCache.set( buffers[ 0 ], { promise: texturePending } );
211
-
212
- return texturePending;
213
-
214
- }
215
-
216
- _initTranscoder() {
217
-
218
- if ( ! this.transcoderPending ) {
219
-
220
- // Load transcoder wrapper.
221
- const jsLoader = new FileLoader( this.manager );
222
- jsLoader.setPath( this.transcoderPath );
223
- jsLoader.setWithCredentials( this.withCredentials );
224
- const jsContent = new Promise( ( resolve, reject ) => {
225
-
226
- jsLoader.load( 'basis_transcoder.js', resolve, undefined, reject );
227
-
228
- } );
229
-
230
- // Load transcoder WASM binary.
231
- const binaryLoader = new FileLoader( this.manager );
232
- binaryLoader.setPath( this.transcoderPath );
233
- binaryLoader.setResponseType( 'arraybuffer' );
234
- binaryLoader.setWithCredentials( this.withCredentials );
235
- const binaryContent = new Promise( ( resolve, reject ) => {
236
-
237
- binaryLoader.load( 'basis_transcoder.wasm', resolve, undefined, reject );
238
-
239
- } );
240
-
241
- this.transcoderPending = Promise.all( [ jsContent, binaryContent ] )
242
- .then( ( [ jsContent, binaryContent ] ) => {
243
-
244
- const fn = BasisTextureLoader.BasisWorker.toString();
245
-
246
- const body = [
247
- '/* constants */',
248
- 'let _EngineFormat = ' + JSON.stringify( BasisTextureLoader.EngineFormat ),
249
- 'let _TranscoderFormat = ' + JSON.stringify( BasisTextureLoader.TranscoderFormat ),
250
- 'let _BasisFormat = ' + JSON.stringify( BasisTextureLoader.BasisFormat ),
251
- '/* basis_transcoder.js */',
252
- jsContent,
253
- '/* worker */',
254
- fn.substring( fn.indexOf( '{' ) + 1, fn.lastIndexOf( '}' ) )
255
- ].join( '\n' );
256
-
257
- this.workerSourceURL = URL.createObjectURL( new Blob( [ body ] ) );
258
- this.transcoderBinary = binaryContent;
259
-
260
- } );
261
-
262
- }
263
-
264
- return this.transcoderPending;
265
-
266
- }
267
-
268
- _allocateWorker( taskCost ) {
269
-
270
- return this._initTranscoder().then( () => {
271
-
272
- if ( this.workerPool.length < this.workerLimit ) {
273
-
274
- const worker = new Worker( this.workerSourceURL );
275
-
276
- worker._callbacks = {};
277
- worker._taskLoad = 0;
278
-
279
- worker.postMessage( {
280
- type: 'init',
281
- config: this.workerConfig,
282
- transcoderBinary: this.transcoderBinary,
283
- } );
284
-
285
- worker.onmessage = function ( e ) {
286
-
287
- const message = e.data;
288
-
289
- switch ( message.type ) {
290
-
291
- case 'transcode':
292
- worker._callbacks[ message.id ].resolve( message );
293
- break;
294
-
295
- case 'error':
296
- worker._callbacks[ message.id ].reject( message );
297
- break;
298
-
299
- default:
300
- console.error( 'THREE.BasisTextureLoader: Unexpected message, "' + message.type + '"' );
301
-
302
- }
303
-
304
- };
305
-
306
- this.workerPool.push( worker );
307
-
308
- } else {
309
-
310
- this.workerPool.sort( function ( a, b ) {
311
-
312
- return a._taskLoad > b._taskLoad ? - 1 : 1;
313
-
314
- } );
315
-
316
- }
317
-
318
- const worker = this.workerPool[ this.workerPool.length - 1 ];
319
-
320
- worker._taskLoad += taskCost;
321
-
322
- return worker;
323
-
324
- } );
325
-
326
- }
327
-
328
- dispose() {
329
-
330
- for ( let i = 0; i < this.workerPool.length; i ++ ) {
331
-
332
- this.workerPool[ i ].terminate();
333
-
334
- }
335
-
336
- this.workerPool.length = 0;
337
-
338
- return this;
339
-
340
- }
341
-
342
- }
343
-
344
- /* CONSTANTS */
345
-
346
- BasisTextureLoader.BasisFormat = {
347
- ETC1S: 0,
348
- UASTC_4x4: 1,
349
- };
350
-
351
- BasisTextureLoader.TranscoderFormat = {
352
- ETC1: 0,
353
- ETC2: 1,
354
- BC1: 2,
355
- BC3: 3,
356
- BC4: 4,
357
- BC5: 5,
358
- BC7_M6_OPAQUE_ONLY: 6,
359
- BC7_M5: 7,
360
- PVRTC1_4_RGB: 8,
361
- PVRTC1_4_RGBA: 9,
362
- ASTC_4x4: 10,
363
- ATC_RGB: 11,
364
- ATC_RGBA_INTERPOLATED_ALPHA: 12,
365
- RGBA32: 13,
366
- RGB565: 14,
367
- BGR565: 15,
368
- RGBA4444: 16,
369
- };
370
-
371
- BasisTextureLoader.EngineFormat = {
372
- RGBAFormat: RGBAFormat,
373
- RGBA_ASTC_4x4_Format: RGBA_ASTC_4x4_Format,
374
- RGBA_BPTC_Format: RGBA_BPTC_Format,
375
- RGBA_ETC2_EAC_Format: RGBA_ETC2_EAC_Format,
376
- RGBA_PVRTC_4BPPV1_Format: RGBA_PVRTC_4BPPV1_Format,
377
- RGBA_S3TC_DXT5_Format: RGBA_S3TC_DXT5_Format,
378
- RGB_ETC1_Format: RGB_ETC1_Format,
379
- RGB_ETC2_Format: RGB_ETC2_Format,
380
- RGB_PVRTC_4BPPV1_Format: RGB_PVRTC_4BPPV1_Format,
381
- RGB_S3TC_DXT1_Format: RGB_S3TC_DXT1_Format,
382
- };
383
-
384
-
385
- /* WEB WORKER */
386
-
36
+ constructor(manager) {
37
+ super(manager);
38
+
39
+ this.transcoderPath = '';
40
+ this.transcoderBinary = null;
41
+ this.transcoderPending = null;
42
+
43
+ this.workerLimit = 4;
44
+ this.workerPool = [];
45
+ this.workerNextTaskID = 1;
46
+ this.workerSourceURL = '';
47
+ this.workerConfig = null;
48
+
49
+ console.warn(
50
+
51
+ 'THREE.BasisTextureLoader: This loader is deprecated, and will be removed in a future release. '
52
+ + 'Instead, use Basis Universal compression in KTX2 (.ktx2) files with THREE.KTX2Loader.',
53
+
54
+ );
55
+ }
56
+
57
+ setTranscoderPath(path) {
58
+ this.transcoderPath = path;
59
+
60
+ return this;
61
+ }
62
+
63
+ setWorkerLimit(workerLimit) {
64
+ this.workerLimit = workerLimit;
65
+
66
+ return this;
67
+ }
68
+
69
+ detectSupport(renderer) {
70
+ this.workerConfig = {
71
+ astcSupported: renderer.extensions.has('WEBGL_compressed_texture_astc'),
72
+ etc1Supported: renderer.extensions.has('WEBGL_compressed_texture_etc1'),
73
+ etc2Supported: renderer.extensions.has('WEBGL_compressed_texture_etc'),
74
+ dxtSupported: renderer.extensions.has('WEBGL_compressed_texture_s3tc'),
75
+ bptcSupported: renderer.extensions.has('EXT_texture_compression_bptc'),
76
+ pvrtcSupported: renderer.extensions.has('WEBGL_compressed_texture_pvrtc')
77
+ || renderer.extensions.has('WEBKIT_WEBGL_compressed_texture_pvrtc'),
78
+ };
79
+
80
+ return this;
81
+ }
82
+
83
+ load(url, onLoad, onProgress, onError) {
84
+ const loader = new FileLoader(this.manager);
85
+
86
+ loader.setResponseType('arraybuffer');
87
+ loader.setWithCredentials(this.withCredentials);
88
+
89
+ const texture = new CompressedTexture();
90
+
91
+ loader.load(url, (buffer) => {
92
+ // Check for an existing task using this buffer. A transferred buffer cannot be transferred
93
+ // again from this thread.
94
+ if (_taskCache.has(buffer)) {
95
+ const cachedTask = _taskCache.get(buffer);
96
+
97
+ return cachedTask.promise.then(onLoad).catch(onError);
98
+ }
99
+
100
+ this._createTexture([buffer])
101
+ .then(function (_texture) {
102
+ texture.copy(_texture);
103
+ texture.needsUpdate = true;
104
+
105
+ if (onLoad) onLoad(texture);
106
+ })
107
+ .catch(onError);
108
+ }, onProgress, onError);
109
+
110
+ return texture;
111
+ }
112
+
113
+ /** Low-level transcoding API, exposed for use by KTX2Loader. */
114
+ parseInternalAsync(options) {
115
+ const { levels } = options;
116
+
117
+ const buffers = new Set();
118
+
119
+ for (let i = 0; i < levels.length; i++) {
120
+ buffers.add(levels[i].data.buffer);
121
+ }
122
+
123
+ return this._createTexture(Array.from(buffers), { ...options, lowLevel: true });
124
+ }
125
+
126
+ /**
127
+ * @param {ArrayBuffer[]} buffers
128
+ * @param {object?} config
129
+ * @return {Promise<CompressedTexture>}
130
+ */
131
+ _createTexture(buffers, config = {}) {
132
+ let worker;
133
+ let taskID;
134
+
135
+ const taskConfig = config;
136
+ let taskCost = 0;
137
+
138
+ for (let i = 0; i < buffers.length; i++) {
139
+ taskCost += buffers[i].byteLength;
140
+ }
141
+
142
+ const texturePending = this._allocateWorker(taskCost)
143
+ .then((_worker) => {
144
+ worker = _worker;
145
+ taskID = this.workerNextTaskID++;
146
+
147
+ return new Promise((resolve, reject) => {
148
+ worker._callbacks[taskID] = { resolve, reject };
149
+
150
+ worker.postMessage({ type: 'transcode', id: taskID, buffers: buffers, taskConfig: taskConfig }, buffers);
151
+ });
152
+ })
153
+ .then((message) => {
154
+ const { mipmaps, width, height, format } = message;
155
+
156
+ const texture = new CompressedTexture(mipmaps, width, height, format, UnsignedByteType);
157
+ texture.minFilter = mipmaps.length === 1 ? LinearFilter : LinearMipmapLinearFilter;
158
+ texture.magFilter = LinearFilter;
159
+ texture.generateMipmaps = false;
160
+ texture.needsUpdate = true;
161
+
162
+ return texture;
163
+ });
164
+
165
+ // Note: replaced '.finally()' with '.catch().then()' block - iOS 11 support (#19416)
166
+ texturePending
167
+ .catch(() => true)
168
+ .then(() => {
169
+ if (worker && taskID) {
170
+ worker._taskLoad -= taskCost;
171
+ delete worker._callbacks[taskID];
172
+ }
173
+ });
174
+
175
+ // Cache the task result.
176
+ _taskCache.set(buffers[0], { promise: texturePending });
177
+
178
+ return texturePending;
179
+ }
180
+
181
+ _initTranscoder() {
182
+ if (!this.transcoderPending) {
183
+ // Load transcoder wrapper.
184
+ const jsLoader = new FileLoader(this.manager);
185
+ jsLoader.setPath(this.transcoderPath);
186
+ jsLoader.setWithCredentials(this.withCredentials);
187
+ const jsContent = new Promise((resolve, reject) => {
188
+ jsLoader.load('basis_transcoder.js', resolve, undefined, reject);
189
+ });
190
+
191
+ // Load transcoder WASM binary.
192
+ const binaryLoader = new FileLoader(this.manager);
193
+ binaryLoader.setPath(this.transcoderPath);
194
+ binaryLoader.setResponseType('arraybuffer');
195
+ binaryLoader.setWithCredentials(this.withCredentials);
196
+ const binaryContent = new Promise((resolve, reject) => {
197
+ binaryLoader.load('basis_transcoder.wasm', resolve, undefined, reject);
198
+ });
199
+
200
+ this.transcoderPending = Promise.all([jsContent, binaryContent])
201
+ .then(([jsContent, binaryContent]) => {
202
+ const fn = BasisTextureLoader.BasisWorker.toString();
203
+
204
+ const body = [
205
+ '/* constants */',
206
+ 'let _EngineFormat = ' + JSON.stringify(BasisTextureLoader.EngineFormat),
207
+ 'let _TranscoderFormat = ' + JSON.stringify(BasisTextureLoader.TranscoderFormat),
208
+ 'let _BasisFormat = ' + JSON.stringify(BasisTextureLoader.BasisFormat),
209
+ '/* basis_transcoder.js */',
210
+ jsContent,
211
+ '/* worker */',
212
+ fn.substring(fn.indexOf('{') + 1, fn.lastIndexOf('}')),
213
+ ].join('\n');
214
+
215
+ this.workerSourceURL = URL.createObjectURL(new Blob([body]));
216
+ this.transcoderBinary = binaryContent;
217
+ });
218
+ }
219
+
220
+ return this.transcoderPending;
221
+ }
222
+
223
+ _allocateWorker(taskCost) {
224
+ return this._initTranscoder().then(() => {
225
+ if (this.workerPool.length < this.workerLimit) {
226
+ const worker = new Worker(this.workerSourceURL);
227
+
228
+ worker._callbacks = {};
229
+ worker._taskLoad = 0;
230
+
231
+ worker.postMessage({
232
+ type: 'init',
233
+ config: this.workerConfig,
234
+ transcoderBinary: this.transcoderBinary,
235
+ });
236
+
237
+ worker.onmessage = function (e) {
238
+ const message = e.data;
239
+
240
+ switch (message.type) {
241
+ case 'transcode':
242
+ worker._callbacks[message.id].resolve(message);
243
+ break;
244
+
245
+ case 'error':
246
+ worker._callbacks[message.id].reject(message);
247
+ break;
248
+
249
+ default:
250
+ console.error('THREE.BasisTextureLoader: Unexpected message, "' + message.type + '"');
251
+ }
252
+ };
253
+
254
+ this.workerPool.push(worker);
255
+ }
256
+ else {
257
+ this.workerPool.sort(function (a, b) {
258
+ return a._taskLoad > b._taskLoad ? -1 : 1;
259
+ });
260
+ }
261
+
262
+ const worker = this.workerPool[this.workerPool.length - 1];
263
+
264
+ worker._taskLoad += taskCost;
265
+
266
+ return worker;
267
+ });
268
+ }
269
+
270
+ dispose() {
271
+ for (let i = 0; i < this.workerPool.length; i++) {
272
+ this.workerPool[i].terminate();
273
+ }
274
+
275
+ this.workerPool.length = 0;
276
+
277
+ return this;
278
+ }
279
+ }
280
+
281
+ /* CONSTANTS */
282
+
283
+ BasisTextureLoader.BasisFormat = {
284
+ ETC1S: 0,
285
+ UASTC_4x4: 1,
286
+ };
287
+
288
+ BasisTextureLoader.TranscoderFormat = {
289
+ ETC1: 0,
290
+ ETC2: 1,
291
+ BC1: 2,
292
+ BC3: 3,
293
+ BC4: 4,
294
+ BC5: 5,
295
+ BC7_M6_OPAQUE_ONLY: 6,
296
+ BC7_M5: 7,
297
+ PVRTC1_4_RGB: 8,
298
+ PVRTC1_4_RGBA: 9,
299
+ ASTC_4x4: 10,
300
+ ATC_RGB: 11,
301
+ ATC_RGBA_INTERPOLATED_ALPHA: 12,
302
+ RGBA32: 13,
303
+ RGB565: 14,
304
+ BGR565: 15,
305
+ RGBA4444: 16,
306
+ };
307
+
308
+ BasisTextureLoader.EngineFormat = {
309
+ RGBAFormat: RGBAFormat,
310
+ RGBA_ASTC_4x4_Format: RGBA_ASTC_4x4_Format,
311
+ RGBA_BPTC_Format: RGBA_BPTC_Format,
312
+ RGBA_ETC2_EAC_Format: RGBA_ETC2_EAC_Format,
313
+ RGBA_PVRTC_4BPPV1_Format: RGBA_PVRTC_4BPPV1_Format,
314
+ RGBA_S3TC_DXT5_Format: RGBA_S3TC_DXT5_Format,
315
+ RGB_ETC1_Format: RGB_ETC1_Format,
316
+ RGB_ETC2_Format: RGB_ETC2_Format,
317
+ RGB_PVRTC_4BPPV1_Format: RGB_PVRTC_4BPPV1_Format,
318
+ RGB_S3TC_DXT1_Format: RGB_S3TC_DXT1_Format,
319
+ };
320
+
321
+ /* WEB WORKER */
322
+
387
323
  BasisTextureLoader.BasisWorker = function () {
388
-
389
- let config;
390
- let transcoderPending;
391
- let BasisModule;
392
-
393
- const EngineFormat = _EngineFormat; // eslint-disable-line no-undef
394
- const TranscoderFormat = _TranscoderFormat; // eslint-disable-line no-undef
395
- const BasisFormat = _BasisFormat; // eslint-disable-line no-undef
396
-
397
- onmessage = function ( e ) {
398
-
399
- const message = e.data;
400
-
401
- switch ( message.type ) {
402
-
403
- case 'init':
404
- config = message.config;
405
- init( message.transcoderBinary );
406
- break;
407
-
408
- case 'transcode':
409
- transcoderPending.then( () => {
410
-
411
- try {
412
-
413
- const { width, height, hasAlpha, mipmaps, format } = message.taskConfig.lowLevel
414
- ? transcodeLowLevel( message.taskConfig )
415
- : transcode( message.buffers[ 0 ] );
416
-
417
- const buffers = [];
418
-
419
- for ( let i = 0; i < mipmaps.length; ++ i ) {
420
-
421
- buffers.push( mipmaps[ i ].data.buffer );
422
-
423
- }
424
-
425
- self.postMessage( { type: 'transcode', id: message.id, width, height, hasAlpha, mipmaps, format }, buffers );
426
-
427
- } catch ( error ) {
428
-
429
- console.error( error );
430
-
431
- self.postMessage( { type: 'error', id: message.id, error: error.message } );
432
-
433
- }
434
-
435
- } );
436
- break;
437
-
438
- }
439
-
440
- };
441
-
442
- function init( wasmBinary ) {
443
-
444
- transcoderPending = new Promise( ( resolve ) => {
445
-
446
- BasisModule = { wasmBinary, onRuntimeInitialized: resolve };
447
- BASIS( BasisModule ); // eslint-disable-line no-undef
448
-
449
- } ).then( () => {
450
-
451
- BasisModule.initializeBasis();
452
-
453
- } );
454
-
455
- }
456
-
457
- function transcodeLowLevel( taskConfig ) {
458
-
459
- const { basisFormat, width, height, hasAlpha } = taskConfig;
460
-
461
- const { transcoderFormat, engineFormat } = getTranscoderFormat( basisFormat, width, height, hasAlpha );
462
-
463
- const blockByteLength = BasisModule.getBytesPerBlockOrPixel( transcoderFormat );
464
-
465
- assert( BasisModule.isFormatSupported( transcoderFormat ), 'THREE.BasisTextureLoader: Unsupported format.' );
466
-
467
- const mipmaps = [];
468
-
469
- if ( basisFormat === BasisFormat.ETC1S ) {
470
-
471
- const transcoder = new BasisModule.LowLevelETC1SImageTranscoder();
472
-
473
- const { endpointCount, endpointsData, selectorCount, selectorsData, tablesData } = taskConfig.globalData;
474
-
475
- try {
476
-
477
- let ok;
478
-
479
- ok = transcoder.decodePalettes( endpointCount, endpointsData, selectorCount, selectorsData );
480
-
481
- assert( ok, 'THREE.BasisTextureLoader: decodePalettes() failed.' );
482
-
483
- ok = transcoder.decodeTables( tablesData );
484
-
485
- assert( ok, 'THREE.BasisTextureLoader: decodeTables() failed.' );
486
-
487
- for ( let i = 0; i < taskConfig.levels.length; i ++ ) {
488
-
489
- const level = taskConfig.levels[ i ];
490
- const imageDesc = taskConfig.globalData.imageDescs[ i ];
491
-
492
- const dstByteLength = getTranscodedImageByteLength( transcoderFormat, level.width, level.height );
493
- const dst = new Uint8Array( dstByteLength );
494
-
495
- ok = transcoder.transcodeImage(
496
- transcoderFormat,
497
- dst, dstByteLength / blockByteLength,
498
- level.data,
499
- getWidthInBlocks( transcoderFormat, level.width ),
500
- getHeightInBlocks( transcoderFormat, level.height ),
501
- level.width, level.height, level.index,
502
- imageDesc.rgbSliceByteOffset, imageDesc.rgbSliceByteLength,
503
- imageDesc.alphaSliceByteOffset, imageDesc.alphaSliceByteLength,
504
- imageDesc.imageFlags,
505
- hasAlpha,
506
- false,
507
- 0, 0
508
- );
509
-
510
- assert( ok, 'THREE.BasisTextureLoader: transcodeImage() failed for level ' + level.index + '.' );
511
-
512
- mipmaps.push( { data: dst, width: level.width, height: level.height } );
513
-
514
- }
515
-
516
- } finally {
517
-
518
- transcoder.delete();
519
-
520
- }
521
-
522
- } else {
523
-
524
- for ( let i = 0; i < taskConfig.levels.length; i ++ ) {
525
-
526
- const level = taskConfig.levels[ i ];
527
-
528
- const dstByteLength = getTranscodedImageByteLength( transcoderFormat, level.width, level.height );
529
- const dst = new Uint8Array( dstByteLength );
530
-
531
- const ok = BasisModule.transcodeUASTCImage(
532
- transcoderFormat,
533
- dst, dstByteLength / blockByteLength,
534
- level.data,
535
- getWidthInBlocks( transcoderFormat, level.width ),
536
- getHeightInBlocks( transcoderFormat, level.height ),
537
- level.width, level.height, level.index,
538
- 0,
539
- level.data.byteLength,
540
- 0,
541
- hasAlpha,
542
- false,
543
- 0, 0,
544
- - 1, - 1
545
- );
546
-
547
- assert( ok, 'THREE.BasisTextureLoader: transcodeUASTCImage() failed for level ' + level.index + '.' );
548
-
549
- mipmaps.push( { data: dst, width: level.width, height: level.height } );
550
-
551
- }
552
-
553
- }
554
-
555
- return { width, height, hasAlpha, mipmaps, format: engineFormat };
556
-
557
- }
558
-
559
- function transcode( buffer ) {
560
-
561
- const basisFile = new BasisModule.BasisFile( new Uint8Array( buffer ) );
562
-
563
- const basisFormat = basisFile.isUASTC() ? BasisFormat.UASTC_4x4 : BasisFormat.ETC1S;
564
- const width = basisFile.getImageWidth( 0, 0 );
565
- const height = basisFile.getImageHeight( 0, 0 );
566
- const levels = basisFile.getNumLevels( 0 );
567
- const hasAlpha = basisFile.getHasAlpha();
568
-
569
- function cleanup() {
570
-
571
- basisFile.close();
572
- basisFile.delete();
573
-
574
- }
575
-
576
- const { transcoderFormat, engineFormat } = getTranscoderFormat( basisFormat, width, height, hasAlpha );
577
-
578
- if ( ! width || ! height || ! levels ) {
579
-
580
- cleanup();
581
- throw new Error( 'THREE.BasisTextureLoader: Invalid texture' );
582
-
583
- }
584
-
585
- if ( ! basisFile.startTranscoding() ) {
586
-
587
- cleanup();
588
- throw new Error( 'THREE.BasisTextureLoader: .startTranscoding failed' );
589
-
590
- }
591
-
592
- const mipmaps = [];
593
-
594
- for ( let mip = 0; mip < levels; mip ++ ) {
595
-
596
- const mipWidth = basisFile.getImageWidth( 0, mip );
597
- const mipHeight = basisFile.getImageHeight( 0, mip );
598
- const dst = new Uint8Array( basisFile.getImageTranscodedSizeInBytes( 0, mip, transcoderFormat ) );
599
-
600
- const status = basisFile.transcodeImage(
601
- dst,
602
- 0,
603
- mip,
604
- transcoderFormat,
605
- 0,
606
- hasAlpha
607
- );
608
-
609
- if ( ! status ) {
610
-
611
- cleanup();
612
- throw new Error( 'THREE.BasisTextureLoader: .transcodeImage failed.' );
613
-
614
- }
615
-
616
- mipmaps.push( { data: dst, width: mipWidth, height: mipHeight } );
617
-
618
- }
619
-
620
- cleanup();
621
-
622
- return { width, height, hasAlpha, mipmaps, format: engineFormat };
623
-
624
- }
625
-
626
- //
627
-
628
- // Optimal choice of a transcoder target format depends on the Basis format (ETC1S or UASTC),
629
- // device capabilities, and texture dimensions. The list below ranks the formats separately
630
- // for ETC1S and UASTC.
631
- //
632
- // In some cases, transcoding UASTC to RGBA32 might be preferred for higher quality (at
633
- // significant memory cost) compared to ETC1/2, BC1/3, and PVRTC. The transcoder currently
634
- // chooses RGBA32 only as a last resort and does not expose that option to the caller.
635
- const FORMAT_OPTIONS = [
636
- {
637
- if: 'astcSupported',
638
- basisFormat: [ BasisFormat.UASTC_4x4 ],
639
- transcoderFormat: [ TranscoderFormat.ASTC_4x4, TranscoderFormat.ASTC_4x4 ],
640
- engineFormat: [ EngineFormat.RGBA_ASTC_4x4_Format, EngineFormat.RGBA_ASTC_4x4_Format ],
641
- priorityETC1S: Infinity,
642
- priorityUASTC: 1,
643
- needsPowerOfTwo: false,
644
- },
645
- {
646
- if: 'bptcSupported',
647
- basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],
648
- transcoderFormat: [ TranscoderFormat.BC7_M5, TranscoderFormat.BC7_M5 ],
649
- engineFormat: [ EngineFormat.RGBA_BPTC_Format, EngineFormat.RGBA_BPTC_Format ],
650
- priorityETC1S: 3,
651
- priorityUASTC: 2,
652
- needsPowerOfTwo: false,
653
- },
654
- {
655
- if: 'dxtSupported',
656
- basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],
657
- transcoderFormat: [ TranscoderFormat.BC1, TranscoderFormat.BC3 ],
658
- engineFormat: [ EngineFormat.RGB_S3TC_DXT1_Format, EngineFormat.RGBA_S3TC_DXT5_Format ],
659
- priorityETC1S: 4,
660
- priorityUASTC: 5,
661
- needsPowerOfTwo: false,
662
- },
663
- {
664
- if: 'etc2Supported',
665
- basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],
666
- transcoderFormat: [ TranscoderFormat.ETC1, TranscoderFormat.ETC2 ],
667
- engineFormat: [ EngineFormat.RGB_ETC2_Format, EngineFormat.RGBA_ETC2_EAC_Format ],
668
- priorityETC1S: 1,
669
- priorityUASTC: 3,
670
- needsPowerOfTwo: false,
671
- },
672
- {
673
- if: 'etc1Supported',
674
- basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],
675
- transcoderFormat: [ TranscoderFormat.ETC1, TranscoderFormat.ETC1 ],
676
- engineFormat: [ EngineFormat.RGB_ETC1_Format, EngineFormat.RGB_ETC1_Format ],
677
- priorityETC1S: 2,
678
- priorityUASTC: 4,
679
- needsPowerOfTwo: false,
680
- },
681
- {
682
- if: 'pvrtcSupported',
683
- basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],
684
- transcoderFormat: [ TranscoderFormat.PVRTC1_4_RGB, TranscoderFormat.PVRTC1_4_RGBA ],
685
- engineFormat: [ EngineFormat.RGB_PVRTC_4BPPV1_Format, EngineFormat.RGBA_PVRTC_4BPPV1_Format ],
686
- priorityETC1S: 5,
687
- priorityUASTC: 6,
688
- needsPowerOfTwo: true,
689
- },
690
- ];
691
-
692
- const ETC1S_OPTIONS = FORMAT_OPTIONS.sort( function ( a, b ) {
693
-
694
- return a.priorityETC1S - b.priorityETC1S;
695
-
696
- } );
697
- const UASTC_OPTIONS = FORMAT_OPTIONS.sort( function ( a, b ) {
698
-
699
- return a.priorityUASTC - b.priorityUASTC;
700
-
701
- } );
702
-
703
- function getTranscoderFormat( basisFormat, width, height, hasAlpha ) {
704
-
705
- let transcoderFormat;
706
- let engineFormat;
707
-
708
- const options = basisFormat === BasisFormat.ETC1S ? ETC1S_OPTIONS : UASTC_OPTIONS;
709
-
710
- for ( let i = 0; i < options.length; i ++ ) {
711
-
712
- const opt = options[ i ];
713
-
714
- if ( ! config[ opt.if ] ) continue;
715
- if ( ! opt.basisFormat.includes( basisFormat ) ) continue;
716
- if ( opt.needsPowerOfTwo && ! ( isPowerOfTwo( width ) && isPowerOfTwo( height ) ) ) continue;
717
-
718
- transcoderFormat = opt.transcoderFormat[ hasAlpha ? 1 : 0 ];
719
- engineFormat = opt.engineFormat[ hasAlpha ? 1 : 0 ];
720
-
721
- return { transcoderFormat, engineFormat };
722
-
723
- }
724
-
725
- console.warn( 'THREE.BasisTextureLoader: No suitable compressed texture format found. Decoding to RGBA32.' );
726
-
727
- transcoderFormat = TranscoderFormat.RGBA32;
728
- engineFormat = EngineFormat.RGBAFormat;
729
-
730
- return { transcoderFormat, engineFormat };
731
-
732
- }
733
-
734
- function assert( ok, message ) {
735
-
736
- if ( ! ok ) throw new Error( message );
737
-
738
- }
739
-
740
- function getWidthInBlocks( transcoderFormat, width ) {
741
-
742
- return Math.ceil( width / BasisModule.getFormatBlockWidth( transcoderFormat ) );
743
-
744
- }
745
-
746
- function getHeightInBlocks( transcoderFormat, height ) {
747
-
748
- return Math.ceil( height / BasisModule.getFormatBlockHeight( transcoderFormat ) );
749
-
750
- }
751
-
752
- function getTranscodedImageByteLength( transcoderFormat, width, height ) {
753
-
754
- const blockByteLength = BasisModule.getBytesPerBlockOrPixel( transcoderFormat );
755
-
756
- if ( BasisModule.formatIsUncompressed( transcoderFormat ) ) {
757
-
758
- return width * height * blockByteLength;
759
-
760
- }
761
-
762
- if ( transcoderFormat === TranscoderFormat.PVRTC1_4_RGB
763
- || transcoderFormat === TranscoderFormat.PVRTC1_4_RGBA ) {
764
-
765
- // GL requires extra padding for very small textures:
766
- // https://www.khronos.org/registry/OpenGL/extensions/IMG/IMG_texture_compression_pvrtc.txt
767
- const paddedWidth = ( width + 3 ) & ~ 3;
768
- const paddedHeight = ( height + 3 ) & ~ 3;
769
-
770
- return ( Math.max( 8, paddedWidth ) * Math.max( 8, paddedHeight ) * 4 + 7 ) / 8;
771
-
772
- }
773
-
774
- return ( getWidthInBlocks( transcoderFormat, width )
775
- * getHeightInBlocks( transcoderFormat, height )
776
- * blockByteLength );
777
-
778
- }
779
-
780
- function isPowerOfTwo( value ) {
781
-
782
- if ( value <= 2 ) return true;
783
-
784
- return ( value & ( value - 1 ) ) === 0 && value !== 0;
785
-
786
- }
787
-
788
- };
789
-
790
- export { BasisTextureLoader };
324
+ let config;
325
+ let transcoderPending;
326
+ let BasisModule;
327
+
328
+ const EngineFormat = _EngineFormat; // eslint-disable-line no-undef
329
+ const TranscoderFormat = _TranscoderFormat; // eslint-disable-line no-undef
330
+ const BasisFormat = _BasisFormat; // eslint-disable-line no-undef
331
+
332
+ onmessage = function (e) {
333
+ const message = e.data;
334
+
335
+ switch (message.type) {
336
+ case 'init':
337
+ config = message.config;
338
+ init(message.transcoderBinary);
339
+ break;
340
+
341
+ case 'transcode':
342
+ transcoderPending.then(() => {
343
+ try {
344
+ const { width, height, hasAlpha, mipmaps, format } = message.taskConfig.lowLevel
345
+ ? transcodeLowLevel(message.taskConfig)
346
+ : transcode(message.buffers[0]);
347
+
348
+ const buffers = [];
349
+
350
+ for (let i = 0; i < mipmaps.length; ++i) {
351
+ buffers.push(mipmaps[i].data.buffer);
352
+ }
353
+
354
+ self.postMessage({ type: 'transcode', id: message.id, width, height, hasAlpha, mipmaps, format }, buffers);
355
+ }
356
+ catch (error) {
357
+ console.error(error);
358
+
359
+ self.postMessage({ type: 'error', id: message.id, error: error.message });
360
+ }
361
+ });
362
+ break;
363
+ }
364
+ };
365
+
366
+ function init(wasmBinary) {
367
+ transcoderPending = new Promise((resolve) => {
368
+ BasisModule = { wasmBinary, onRuntimeInitialized: resolve };
369
+ BASIS(BasisModule); // eslint-disable-line no-undef
370
+ }).then(() => {
371
+ BasisModule.initializeBasis();
372
+ });
373
+ }
374
+
375
+ function transcodeLowLevel(taskConfig) {
376
+ const { basisFormat, width, height, hasAlpha } = taskConfig;
377
+
378
+ const { transcoderFormat, engineFormat } = getTranscoderFormat(basisFormat, width, height, hasAlpha);
379
+
380
+ const blockByteLength = BasisModule.getBytesPerBlockOrPixel(transcoderFormat);
381
+
382
+ assert(BasisModule.isFormatSupported(transcoderFormat), 'THREE.BasisTextureLoader: Unsupported format.');
383
+
384
+ const mipmaps = [];
385
+
386
+ if (basisFormat === BasisFormat.ETC1S) {
387
+ const transcoder = new BasisModule.LowLevelETC1SImageTranscoder();
388
+
389
+ const { endpointCount, endpointsData, selectorCount, selectorsData, tablesData } = taskConfig.globalData;
390
+
391
+ try {
392
+ let ok;
393
+
394
+ ok = transcoder.decodePalettes(endpointCount, endpointsData, selectorCount, selectorsData);
395
+
396
+ assert(ok, 'THREE.BasisTextureLoader: decodePalettes() failed.');
397
+
398
+ ok = transcoder.decodeTables(tablesData);
399
+
400
+ assert(ok, 'THREE.BasisTextureLoader: decodeTables() failed.');
401
+
402
+ for (let i = 0; i < taskConfig.levels.length; i++) {
403
+ const level = taskConfig.levels[i];
404
+ const imageDesc = taskConfig.globalData.imageDescs[i];
405
+
406
+ const dstByteLength = getTranscodedImageByteLength(transcoderFormat, level.width, level.height);
407
+ const dst = new Uint8Array(dstByteLength);
408
+
409
+ ok = transcoder.transcodeImage(
410
+ transcoderFormat,
411
+ dst, dstByteLength / blockByteLength,
412
+ level.data,
413
+ getWidthInBlocks(transcoderFormat, level.width),
414
+ getHeightInBlocks(transcoderFormat, level.height),
415
+ level.width, level.height, level.index,
416
+ imageDesc.rgbSliceByteOffset, imageDesc.rgbSliceByteLength,
417
+ imageDesc.alphaSliceByteOffset, imageDesc.alphaSliceByteLength,
418
+ imageDesc.imageFlags,
419
+ hasAlpha,
420
+ false,
421
+ 0, 0,
422
+ );
423
+
424
+ assert(ok, 'THREE.BasisTextureLoader: transcodeImage() failed for level ' + level.index + '.');
425
+
426
+ mipmaps.push({ data: dst, width: level.width, height: level.height });
427
+ }
428
+ }
429
+ finally {
430
+ transcoder.delete();
431
+ }
432
+ }
433
+ else {
434
+ for (let i = 0; i < taskConfig.levels.length; i++) {
435
+ const level = taskConfig.levels[i];
436
+
437
+ const dstByteLength = getTranscodedImageByteLength(transcoderFormat, level.width, level.height);
438
+ const dst = new Uint8Array(dstByteLength);
439
+
440
+ const ok = BasisModule.transcodeUASTCImage(
441
+ transcoderFormat,
442
+ dst, dstByteLength / blockByteLength,
443
+ level.data,
444
+ getWidthInBlocks(transcoderFormat, level.width),
445
+ getHeightInBlocks(transcoderFormat, level.height),
446
+ level.width, level.height, level.index,
447
+ 0,
448
+ level.data.byteLength,
449
+ 0,
450
+ hasAlpha,
451
+ false,
452
+ 0, 0,
453
+ -1, -1,
454
+ );
455
+
456
+ assert(ok, 'THREE.BasisTextureLoader: transcodeUASTCImage() failed for level ' + level.index + '.');
457
+
458
+ mipmaps.push({ data: dst, width: level.width, height: level.height });
459
+ }
460
+ }
461
+
462
+ return { width, height, hasAlpha, mipmaps, format: engineFormat };
463
+ }
464
+
465
+ function transcode(buffer) {
466
+ const basisFile = new BasisModule.BasisFile(new Uint8Array(buffer));
467
+
468
+ const basisFormat = basisFile.isUASTC() ? BasisFormat.UASTC_4x4 : BasisFormat.ETC1S;
469
+ const width = basisFile.getImageWidth(0, 0);
470
+ const height = basisFile.getImageHeight(0, 0);
471
+ const levels = basisFile.getNumLevels(0);
472
+ const hasAlpha = basisFile.getHasAlpha();
473
+
474
+ function cleanup() {
475
+ basisFile.close();
476
+ basisFile.delete();
477
+ }
478
+
479
+ const { transcoderFormat, engineFormat } = getTranscoderFormat(basisFormat, width, height, hasAlpha);
480
+
481
+ if (!width || !height || !levels) {
482
+ cleanup();
483
+ throw new Error('THREE.BasisTextureLoader: Invalid texture');
484
+ }
485
+
486
+ if (!basisFile.startTranscoding()) {
487
+ cleanup();
488
+ throw new Error('THREE.BasisTextureLoader: .startTranscoding failed');
489
+ }
490
+
491
+ const mipmaps = [];
492
+
493
+ for (let mip = 0; mip < levels; mip++) {
494
+ const mipWidth = basisFile.getImageWidth(0, mip);
495
+ const mipHeight = basisFile.getImageHeight(0, mip);
496
+ const dst = new Uint8Array(basisFile.getImageTranscodedSizeInBytes(0, mip, transcoderFormat));
497
+
498
+ const status = basisFile.transcodeImage(
499
+ dst,
500
+ 0,
501
+ mip,
502
+ transcoderFormat,
503
+ 0,
504
+ hasAlpha,
505
+ );
506
+
507
+ if (!status) {
508
+ cleanup();
509
+ throw new Error('THREE.BasisTextureLoader: .transcodeImage failed.');
510
+ }
511
+
512
+ mipmaps.push({ data: dst, width: mipWidth, height: mipHeight });
513
+ }
514
+
515
+ cleanup();
516
+
517
+ return { width, height, hasAlpha, mipmaps, format: engineFormat };
518
+ }
519
+
520
+ //
521
+
522
+ // Optimal choice of a transcoder target format depends on the Basis format (ETC1S or UASTC),
523
+ // device capabilities, and texture dimensions. The list below ranks the formats separately
524
+ // for ETC1S and UASTC.
525
+ //
526
+ // In some cases, transcoding UASTC to RGBA32 might be preferred for higher quality (at
527
+ // significant memory cost) compared to ETC1/2, BC1/3, and PVRTC. The transcoder currently
528
+ // chooses RGBA32 only as a last resort and does not expose that option to the caller.
529
+ const FORMAT_OPTIONS = [
530
+ {
531
+ if: 'astcSupported',
532
+ basisFormat: [BasisFormat.UASTC_4x4],
533
+ transcoderFormat: [TranscoderFormat.ASTC_4x4, TranscoderFormat.ASTC_4x4],
534
+ engineFormat: [EngineFormat.RGBA_ASTC_4x4_Format, EngineFormat.RGBA_ASTC_4x4_Format],
535
+ priorityETC1S: Infinity,
536
+ priorityUASTC: 1,
537
+ needsPowerOfTwo: false,
538
+ },
539
+ {
540
+ if: 'bptcSupported',
541
+ basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4],
542
+ transcoderFormat: [TranscoderFormat.BC7_M5, TranscoderFormat.BC7_M5],
543
+ engineFormat: [EngineFormat.RGBA_BPTC_Format, EngineFormat.RGBA_BPTC_Format],
544
+ priorityETC1S: 3,
545
+ priorityUASTC: 2,
546
+ needsPowerOfTwo: false,
547
+ },
548
+ {
549
+ if: 'dxtSupported',
550
+ basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4],
551
+ transcoderFormat: [TranscoderFormat.BC1, TranscoderFormat.BC3],
552
+ engineFormat: [EngineFormat.RGB_S3TC_DXT1_Format, EngineFormat.RGBA_S3TC_DXT5_Format],
553
+ priorityETC1S: 4,
554
+ priorityUASTC: 5,
555
+ needsPowerOfTwo: false,
556
+ },
557
+ {
558
+ if: 'etc2Supported',
559
+ basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4],
560
+ transcoderFormat: [TranscoderFormat.ETC1, TranscoderFormat.ETC2],
561
+ engineFormat: [EngineFormat.RGB_ETC2_Format, EngineFormat.RGBA_ETC2_EAC_Format],
562
+ priorityETC1S: 1,
563
+ priorityUASTC: 3,
564
+ needsPowerOfTwo: false,
565
+ },
566
+ {
567
+ if: 'etc1Supported',
568
+ basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4],
569
+ transcoderFormat: [TranscoderFormat.ETC1, TranscoderFormat.ETC1],
570
+ engineFormat: [EngineFormat.RGB_ETC1_Format, EngineFormat.RGB_ETC1_Format],
571
+ priorityETC1S: 2,
572
+ priorityUASTC: 4,
573
+ needsPowerOfTwo: false,
574
+ },
575
+ {
576
+ if: 'pvrtcSupported',
577
+ basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4],
578
+ transcoderFormat: [TranscoderFormat.PVRTC1_4_RGB, TranscoderFormat.PVRTC1_4_RGBA],
579
+ engineFormat: [EngineFormat.RGB_PVRTC_4BPPV1_Format, EngineFormat.RGBA_PVRTC_4BPPV1_Format],
580
+ priorityETC1S: 5,
581
+ priorityUASTC: 6,
582
+ needsPowerOfTwo: true,
583
+ },
584
+ ];
585
+
586
+ const ETC1S_OPTIONS = FORMAT_OPTIONS.sort(function (a, b) {
587
+ return a.priorityETC1S - b.priorityETC1S;
588
+ });
589
+ const UASTC_OPTIONS = FORMAT_OPTIONS.sort(function (a, b) {
590
+ return a.priorityUASTC - b.priorityUASTC;
591
+ });
592
+
593
+ function getTranscoderFormat(basisFormat, width, height, hasAlpha) {
594
+ let transcoderFormat;
595
+ let engineFormat;
596
+
597
+ const options = basisFormat === BasisFormat.ETC1S ? ETC1S_OPTIONS : UASTC_OPTIONS;
598
+
599
+ for (let i = 0; i < options.length; i++) {
600
+ const opt = options[i];
601
+
602
+ if (!config[opt.if]) continue;
603
+ if (!opt.basisFormat.includes(basisFormat)) continue;
604
+ if (opt.needsPowerOfTwo && !(isPowerOfTwo(width) && isPowerOfTwo(height))) continue;
605
+
606
+ transcoderFormat = opt.transcoderFormat[hasAlpha ? 1 : 0];
607
+ engineFormat = opt.engineFormat[hasAlpha ? 1 : 0];
608
+
609
+ return { transcoderFormat, engineFormat };
610
+ }
611
+
612
+ console.warn('THREE.BasisTextureLoader: No suitable compressed texture format found. Decoding to RGBA32.');
613
+
614
+ transcoderFormat = TranscoderFormat.RGBA32;
615
+ engineFormat = EngineFormat.RGBAFormat;
616
+
617
+ return { transcoderFormat, engineFormat };
618
+ }
619
+
620
+ function assert(ok, message) {
621
+ if (!ok) throw new Error(message);
622
+ }
623
+
624
+ function getWidthInBlocks(transcoderFormat, width) {
625
+ return Math.ceil(width / BasisModule.getFormatBlockWidth(transcoderFormat));
626
+ }
627
+
628
+ function getHeightInBlocks(transcoderFormat, height) {
629
+ return Math.ceil(height / BasisModule.getFormatBlockHeight(transcoderFormat));
630
+ }
631
+
632
+ function getTranscodedImageByteLength(transcoderFormat, width, height) {
633
+ const blockByteLength = BasisModule.getBytesPerBlockOrPixel(transcoderFormat);
634
+
635
+ if (BasisModule.formatIsUncompressed(transcoderFormat)) {
636
+ return width * height * blockByteLength;
637
+ }
638
+
639
+ if (transcoderFormat === TranscoderFormat.PVRTC1_4_RGB
640
+ || transcoderFormat === TranscoderFormat.PVRTC1_4_RGBA) {
641
+ // GL requires extra padding for very small textures:
642
+ // https://www.khronos.org/registry/OpenGL/extensions/IMG/IMG_texture_compression_pvrtc.txt
643
+ const paddedWidth = (width + 3) & ~3;
644
+ const paddedHeight = (height + 3) & ~3;
645
+
646
+ return (Math.max(8, paddedWidth) * Math.max(8, paddedHeight) * 4 + 7) / 8;
647
+ }
648
+
649
+ return (getWidthInBlocks(transcoderFormat, width)
650
+ * getHeightInBlocks(transcoderFormat, height)
651
+ * blockByteLength);
652
+ }
653
+
654
+ function isPowerOfTwo(value) {
655
+ if (value <= 2) return true;
656
+
657
+ return (value & (value - 1)) === 0 && value !== 0;
658
+ }
659
+ };
660
+
661
+ export { BasisTextureLoader };