model-manager 0.0.3-1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (187) hide show
  1. package/administration/insert.js +179 -0
  2. package/administration/insert_one.js +33 -0
  3. package/administration/test_data.js +46 -0
  4. package/administration.html +149 -0
  5. package/assets/css/admin.css +247 -0
  6. package/assets/css/basic.css +474 -0
  7. package/assets/css/checkout.css +517 -0
  8. package/assets/css/dialog.css +158 -0
  9. package/assets/css/dialog_admin.css +73 -0
  10. package/assets/css/dialog_checkout.css +177 -0
  11. package/assets/css/info.css +10 -0
  12. package/assets/logo.png +0 -0
  13. package/assets/partnerart.png +0 -0
  14. package/assets/spinner.gif +0 -0
  15. package/assets/spinner_2.gif +0 -0
  16. package/assets/three/GLTFLoader.js +4448 -0
  17. package/assets/three/ModelLoader.js +58 -0
  18. package/assets/three/OrbitControls.js +1252 -0
  19. package/assets/three/three.js +36819 -0
  20. package/assets/three/three.module.js +50708 -0
  21. package/assets/white/add_white_24dp.svg +1 -0
  22. package/assets/white/admin/check.svg +1 -0
  23. package/assets/white/admin/person_add_FILL0_wght400_GRAD0_opsz48.svg +1 -0
  24. package/assets/white/admin/person_remove_FILL0_wght400_GRAD0_opsz48.svg +1 -0
  25. package/assets/white/admin.svg +1 -0
  26. package/assets/white/arrow_forward.svg +1 -0
  27. package/assets/white/brush_white_24dp.svg +1 -0
  28. package/assets/white/close_white_24dp.svg +1 -0
  29. package/assets/white/code_white_24dp.svg +1 -0
  30. package/assets/white/dashboard_white_24dp.svg +1 -0
  31. package/assets/white/done_white_24dp.svg +1 -0
  32. package/assets/white/emoji_people_white_24dp.svg +1 -0
  33. package/assets/white/filter_list_white_24dp.svg +1 -0
  34. package/assets/white/info_white_24dp.svg +1 -0
  35. package/assets/white/minimize_white_24dp.svg +1 -0
  36. package/assets/white/receipt_white_24dp.svg +1 -0
  37. package/assets/white/rocket_launch_white_24dp.svg +1 -0
  38. package/assets/white/search_black_24dp.svg +1 -0
  39. package/assets/white/search_white_24dp.svg +1 -0
  40. package/assets/white/settings_white_24dp.svg +1 -0
  41. package/assets/white/shopping_cart_white_24dp.svg +1 -0
  42. package/assets/white/store_white_24dp.svg +1 -0
  43. package/assets/white/timeline_white_24dp.svg +1 -0
  44. package/assets/white/view_in_ar_white_24dp.svg +1 -0
  45. package/checkout.html +132 -0
  46. package/checkout_admin.html +141 -0
  47. package/icon.png +0 -0
  48. package/imgs/armchair.png +0 -0
  49. package/imgs/arrow_tnt.png +0 -0
  50. package/imgs/bed_wnm.png +0 -0
  51. package/imgs/big_bed.png +0 -0
  52. package/imgs/birdscythe.png +0 -0
  53. package/imgs/blue_tnt.png +0 -0
  54. package/imgs/bull.png +0 -0
  55. package/imgs/carpet.png +0 -0
  56. package/imgs/chest.png +0 -0
  57. package/imgs/coin_stash.png +0 -0
  58. package/imgs/creeper_tnt.png +0 -0
  59. package/imgs/garbage_can.png +0 -0
  60. package/imgs/generator.png +0 -0
  61. package/imgs/golden_sword.png +0 -0
  62. package/imgs/highbed.png +0 -0
  63. package/imgs/jetpack1.png +0 -0
  64. package/imgs/jetpack2.png +0 -0
  65. package/imgs/jetpack3.png +0 -0
  66. package/imgs/jetpack4.png +0 -0
  67. package/imgs/jetpack5.png +0 -0
  68. package/imgs/jetpack6.png +0 -0
  69. package/imgs/karmincross.png +0 -0
  70. package/imgs/light_tnt.png +0 -0
  71. package/imgs/lucky_block.png +0 -0
  72. package/imgs/lucky_block_2.png +0 -0
  73. package/imgs/mega_tnt.png +0 -0
  74. package/imgs/modern_lamp.png +0 -0
  75. package/imgs/multiply_tnt.png +0 -0
  76. package/imgs/nuke.png +0 -0
  77. package/imgs/oak_tree.png +0 -0
  78. package/imgs/oak_tree_2.png +0 -0
  79. package/imgs/old_globe.png +0 -0
  80. package/imgs/scificannon_1.png +0 -0
  81. package/imgs/scificannon_10.png +0 -0
  82. package/imgs/scificannon_11.png +0 -0
  83. package/imgs/scificannon_12.png +0 -0
  84. package/imgs/scificannon_13.png +0 -0
  85. package/imgs/scificannon_14.png +0 -0
  86. package/imgs/scificannon_2.png +0 -0
  87. package/imgs/scificannon_3.png +0 -0
  88. package/imgs/scificannon_4.png +0 -0
  89. package/imgs/scificannon_5.png +0 -0
  90. package/imgs/scificannon_6.png +0 -0
  91. package/imgs/scificannon_7.png +0 -0
  92. package/imgs/scificannon_8.png +0 -0
  93. package/imgs/scificannon_9.png +0 -0
  94. package/imgs/simple_chair.png +0 -0
  95. package/imgs/small_car.png +0 -0
  96. package/imgs/small_modern_lamp.png +0 -0
  97. package/imgs/small_wardrobe.png +0 -0
  98. package/imgs/small_wooden_table.png +0 -0
  99. package/imgs/spike_sword.png +0 -0
  100. package/imgs/stone_holder.png +0 -0
  101. package/imgs/stone_sword.png +0 -0
  102. package/imgs/street_lamp.png +0 -0
  103. package/imgs/sword_1.png +0 -0
  104. package/imgs/sword_with_hole.png +0 -0
  105. package/imgs/testing.png +0 -0
  106. package/imgs/timer_tnt.png +0 -0
  107. package/imgs/tiny_tnt.png +0 -0
  108. package/imgs/tnt_cannon.png +0 -0
  109. package/imgs/wing_tnt.png +0 -0
  110. package/imgs/wooden_stool.png +0 -0
  111. package/imgs/wooden_wardrobe.png +0 -0
  112. package/index.html +179 -0
  113. package/index_admin.html +189 -0
  114. package/js/db/push_model.js +30 -0
  115. package/js/dialoges.js +23 -0
  116. package/js/item_functionality.js +7 -0
  117. package/js/load_admin.js +32 -0
  118. package/js/load_cart.js +76 -0
  119. package/js/load_items.js +467 -0
  120. package/js/update.js +35 -0
  121. package/login.html +287 -0
  122. package/main.js +306 -0
  123. package/models/armchair.gltf +1 -0
  124. package/models/arrow_tnt.gltf +1 -0
  125. package/models/bedwnm.gltf +1 -0
  126. package/models/big_bed.gltf +1 -0
  127. package/models/birdscythe.gltf +1 -0
  128. package/models/blue_tnt.gltf +1 -0
  129. package/models/bull.gltf +1 -0
  130. package/models/carpet.gltf +1 -0
  131. package/models/chest.gltf +1 -0
  132. package/models/coin_stash.gltf +1 -0
  133. package/models/creeper_tnt.gltf +1 -0
  134. package/models/garbage_can.gltf +1 -0
  135. package/models/generator.gltf +1 -0
  136. package/models/golden_sword.gltf +1 -0
  137. package/models/highbed.gltf +1 -0
  138. package/models/jetpack1.gltf +1 -0
  139. package/models/jetpack2.gltf +1 -0
  140. package/models/jetpack3.gltf +1 -0
  141. package/models/jetpack4.gltf +1 -0
  142. package/models/jetpack5.gltf +1 -0
  143. package/models/jetpack6.gltf +1 -0
  144. package/models/karmincross.gltf +1 -0
  145. package/models/light_tnt.gltf +1 -0
  146. package/models/lucky_block.gltf +1 -0
  147. package/models/lucky_block_2.gltf +1 -0
  148. package/models/mega_tnt.gltf +1 -0
  149. package/models/modern_lamp.gltf +1 -0
  150. package/models/multiply_tnt.gltf +1 -0
  151. package/models/nuke.gltf +1 -0
  152. package/models/oak_tree.gltf +1 -0
  153. package/models/oak_tree_2.gltf +1 -0
  154. package/models/old globe.gltf +1 -0
  155. package/models/scificannon_1.gltf +1 -0
  156. package/models/scificannon_10.gltf +1 -0
  157. package/models/scificannon_11.gltf +1 -0
  158. package/models/scificannon_12.gltf +1 -0
  159. package/models/scificannon_13.gltf +1 -0
  160. package/models/scificannon_14.gltf +1 -0
  161. package/models/scificannon_2.gltf +1 -0
  162. package/models/scificannon_3.gltf +1 -0
  163. package/models/scificannon_4.gltf +1 -0
  164. package/models/scificannon_5.gltf +1 -0
  165. package/models/scificannon_6.gltf +1 -0
  166. package/models/scificannon_7.gltf +1 -0
  167. package/models/scificannon_8.gltf +1 -0
  168. package/models/scificannon_9.gltf +1 -0
  169. package/models/simple_chair.gltf +1 -0
  170. package/models/small_car.gltf +1 -0
  171. package/models/small_modern_lamp.gltf +1 -0
  172. package/models/small_wardrobe.gltf +1 -0
  173. package/models/small_wooden_table.gltf +1 -0
  174. package/models/spike_sword.gltf +1 -0
  175. package/models/stone_holder.gltf +1 -0
  176. package/models/stone_sword.gltf +1 -0
  177. package/models/street_lamp.gltf +1 -0
  178. package/models/sword_1.gltf +1 -0
  179. package/models/sword_with_hole.gltf +1 -0
  180. package/models/timer_tnt.gltf +1 -0
  181. package/models/tiny_tnt.gltf +1 -0
  182. package/models/tnt_cannon.gltf +1 -0
  183. package/models/wing_tnt.gltf +1 -0
  184. package/models/wooden_stool.gltf +1 -0
  185. package/models/wooden_wardrobe.gltf +1 -0
  186. package/package.json +42 -0
  187. package/preload.js +26 -0
@@ -0,0 +1,4448 @@
1
+ import {
2
+ AnimationClip,
3
+ Bone,
4
+ Box3,
5
+ BufferAttribute,
6
+ BufferGeometry,
7
+ ClampToEdgeWrapping,
8
+ Color,
9
+ DirectionalLight,
10
+ DoubleSide,
11
+ FileLoader,
12
+ FrontSide,
13
+ Group,
14
+ ImageBitmapLoader,
15
+ InterleavedBuffer,
16
+ InterleavedBufferAttribute,
17
+ Interpolant,
18
+ InterpolateDiscrete,
19
+ InterpolateLinear,
20
+ Line,
21
+ LineBasicMaterial,
22
+ LineLoop,
23
+ LineSegments,
24
+ LinearFilter,
25
+ LinearMipmapLinearFilter,
26
+ LinearMipmapNearestFilter,
27
+ Loader,
28
+ LoaderUtils,
29
+ Material,
30
+ MathUtils,
31
+ Matrix4,
32
+ Mesh,
33
+ MeshBasicMaterial,
34
+ MeshPhysicalMaterial,
35
+ MeshStandardMaterial,
36
+ MirroredRepeatWrapping,
37
+ NearestFilter,
38
+ NearestMipmapLinearFilter,
39
+ NearestMipmapNearestFilter,
40
+ NumberKeyframeTrack,
41
+ Object3D,
42
+ OrthographicCamera,
43
+ PerspectiveCamera,
44
+ PointLight,
45
+ Points,
46
+ PointsMaterial,
47
+ PropertyBinding,
48
+ Quaternion,
49
+ QuaternionKeyframeTrack,
50
+ RepeatWrapping,
51
+ Skeleton,
52
+ SkinnedMesh,
53
+ Sphere,
54
+ SpotLight,
55
+ TangentSpaceNormalMap,
56
+ Texture,
57
+ TextureLoader,
58
+ TriangleFanDrawMode,
59
+ TriangleStripDrawMode,
60
+ Vector2,
61
+ Vector3,
62
+ VectorKeyframeTrack,
63
+ sRGBEncoding
64
+ } from './three.module.js';
65
+
66
+ class GLTFLoader extends Loader {
67
+
68
+ constructor( manager ) {
69
+
70
+ super( manager );
71
+
72
+ this.dracoLoader = null;
73
+ this.ktx2Loader = null;
74
+ this.meshoptDecoder = null;
75
+
76
+ this.pluginCallbacks = [];
77
+
78
+ this.register( function ( parser ) {
79
+
80
+ return new GLTFMaterialsClearcoatExtension( parser );
81
+
82
+ } );
83
+
84
+ this.register( function ( parser ) {
85
+
86
+ return new GLTFTextureBasisUExtension( parser );
87
+
88
+ } );
89
+
90
+ this.register( function ( parser ) {
91
+
92
+ return new GLTFTextureWebPExtension( parser );
93
+
94
+ } );
95
+
96
+ this.register( function ( parser ) {
97
+
98
+ return new GLTFMaterialsSheenExtension( parser );
99
+
100
+ } );
101
+
102
+ this.register( function ( parser ) {
103
+
104
+ return new GLTFMaterialsTransmissionExtension( parser );
105
+
106
+ } );
107
+
108
+ this.register( function ( parser ) {
109
+
110
+ return new GLTFMaterialsVolumeExtension( parser );
111
+
112
+ } );
113
+
114
+ this.register( function ( parser ) {
115
+
116
+ return new GLTFMaterialsIorExtension( parser );
117
+
118
+ } );
119
+
120
+ this.register( function ( parser ) {
121
+
122
+ return new GLTFMaterialsEmissiveStrengthExtension( parser );
123
+
124
+ } );
125
+
126
+ this.register( function ( parser ) {
127
+
128
+ return new GLTFMaterialsSpecularExtension( parser );
129
+
130
+ } );
131
+
132
+ this.register( function ( parser ) {
133
+
134
+ return new GLTFLightsExtension( parser );
135
+
136
+ } );
137
+
138
+ this.register( function ( parser ) {
139
+
140
+ return new GLTFMeshoptCompression( parser );
141
+
142
+ } );
143
+
144
+ }
145
+
146
+ load( url, onLoad, onProgress, onError ) {
147
+
148
+ const scope = this;
149
+
150
+ let resourcePath;
151
+
152
+ if ( this.resourcePath !== '' ) {
153
+
154
+ resourcePath = this.resourcePath;
155
+
156
+ } else if ( this.path !== '' ) {
157
+
158
+ resourcePath = this.path;
159
+
160
+ } else {
161
+
162
+ resourcePath = LoaderUtils.extractUrlBase( url );
163
+
164
+ }
165
+
166
+ // Tells the LoadingManager to track an extra item, which resolves after
167
+ // the model is fully loaded. This means the count of items loaded will
168
+ // be incorrect, but ensures manager.onLoad() does not fire early.
169
+ this.manager.itemStart( url );
170
+
171
+ const _onError = function ( e ) {
172
+
173
+ if ( onError ) {
174
+
175
+ onError( e );
176
+
177
+ } else {
178
+
179
+ console.error( e );
180
+
181
+ }
182
+
183
+ scope.manager.itemError( url );
184
+ scope.manager.itemEnd( url );
185
+
186
+ };
187
+
188
+ const loader = new FileLoader( this.manager );
189
+
190
+ loader.setPath( this.path );
191
+ loader.setResponseType( 'arraybuffer' );
192
+ loader.setRequestHeader( this.requestHeader );
193
+ loader.setWithCredentials( this.withCredentials );
194
+
195
+ loader.load( url, function ( data ) {
196
+
197
+ try {
198
+
199
+ scope.parse( data, resourcePath, function ( gltf ) {
200
+
201
+ onLoad( gltf );
202
+
203
+ scope.manager.itemEnd( url );
204
+
205
+ }, _onError );
206
+
207
+ } catch ( e ) {
208
+
209
+ _onError( e );
210
+
211
+ }
212
+
213
+ }, onProgress, _onError );
214
+
215
+ }
216
+
217
+ setDRACOLoader( dracoLoader ) {
218
+
219
+ this.dracoLoader = dracoLoader;
220
+ return this;
221
+
222
+ }
223
+
224
+ setDDSLoader() {
225
+
226
+ throw new Error(
227
+
228
+ 'THREE.GLTFLoader: "MSFT_texture_dds" no longer supported. Please update to "KHR_texture_basisu".'
229
+
230
+ );
231
+
232
+ }
233
+
234
+ setKTX2Loader( ktx2Loader ) {
235
+
236
+ this.ktx2Loader = ktx2Loader;
237
+ return this;
238
+
239
+ }
240
+
241
+ setMeshoptDecoder( meshoptDecoder ) {
242
+
243
+ this.meshoptDecoder = meshoptDecoder;
244
+ return this;
245
+
246
+ }
247
+
248
+ register( callback ) {
249
+
250
+ if ( this.pluginCallbacks.indexOf( callback ) === - 1 ) {
251
+
252
+ this.pluginCallbacks.push( callback );
253
+
254
+ }
255
+
256
+ return this;
257
+
258
+ }
259
+
260
+ unregister( callback ) {
261
+
262
+ if ( this.pluginCallbacks.indexOf( callback ) !== - 1 ) {
263
+
264
+ this.pluginCallbacks.splice( this.pluginCallbacks.indexOf( callback ), 1 );
265
+
266
+ }
267
+
268
+ return this;
269
+
270
+ }
271
+
272
+ parse( data, path, onLoad, onError ) {
273
+
274
+ let content;
275
+ const extensions = {};
276
+ const plugins = {};
277
+
278
+ if ( typeof data === 'string' ) {
279
+
280
+ content = data;
281
+
282
+ } else {
283
+
284
+ const magic = LoaderUtils.decodeText( new Uint8Array( data, 0, 4 ) );
285
+
286
+ if ( magic === BINARY_EXTENSION_HEADER_MAGIC ) {
287
+
288
+ try {
289
+
290
+ extensions[ EXTENSIONS.KHR_BINARY_GLTF ] = new GLTFBinaryExtension( data );
291
+
292
+ } catch ( error ) {
293
+
294
+ if ( onError ) onError( error );
295
+ return;
296
+
297
+ }
298
+
299
+ content = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].content;
300
+
301
+ } else {
302
+
303
+ content = LoaderUtils.decodeText( new Uint8Array( data ) );
304
+
305
+ }
306
+
307
+ }
308
+
309
+ const json = JSON.parse( content );
310
+
311
+ if ( json.asset === undefined || json.asset.version[ 0 ] < 2 ) {
312
+
313
+ if ( onError ) onError( new Error( 'THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported.' ) );
314
+ return;
315
+
316
+ }
317
+
318
+ const parser = new GLTFParser( json, {
319
+
320
+ path: path || this.resourcePath || '',
321
+ crossOrigin: this.crossOrigin,
322
+ requestHeader: this.requestHeader,
323
+ manager: this.manager,
324
+ ktx2Loader: this.ktx2Loader,
325
+ meshoptDecoder: this.meshoptDecoder
326
+
327
+ } );
328
+
329
+ parser.fileLoader.setRequestHeader( this.requestHeader );
330
+
331
+ for ( let i = 0; i < this.pluginCallbacks.length; i ++ ) {
332
+
333
+ const plugin = this.pluginCallbacks[ i ]( parser );
334
+ plugins[ plugin.name ] = plugin;
335
+
336
+ // Workaround to avoid determining as unknown extension
337
+ // in addUnknownExtensionsToUserData().
338
+ // Remove this workaround if we move all the existing
339
+ // extension handlers to plugin system
340
+ extensions[ plugin.name ] = true;
341
+
342
+ }
343
+
344
+ if ( json.extensionsUsed ) {
345
+
346
+ for ( let i = 0; i < json.extensionsUsed.length; ++ i ) {
347
+
348
+ const extensionName = json.extensionsUsed[ i ];
349
+ const extensionsRequired = json.extensionsRequired || [];
350
+
351
+ switch ( extensionName ) {
352
+
353
+ case EXTENSIONS.KHR_MATERIALS_UNLIT:
354
+ extensions[ extensionName ] = new GLTFMaterialsUnlitExtension();
355
+ break;
356
+
357
+ case EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS:
358
+ extensions[ extensionName ] = new GLTFMaterialsPbrSpecularGlossinessExtension();
359
+ break;
360
+
361
+ case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION:
362
+ extensions[ extensionName ] = new GLTFDracoMeshCompressionExtension( json, this.dracoLoader );
363
+ break;
364
+
365
+ case EXTENSIONS.KHR_TEXTURE_TRANSFORM:
366
+ extensions[ extensionName ] = new GLTFTextureTransformExtension();
367
+ break;
368
+
369
+ case EXTENSIONS.KHR_MESH_QUANTIZATION:
370
+ extensions[ extensionName ] = new GLTFMeshQuantizationExtension();
371
+ break;
372
+
373
+ default:
374
+
375
+ if ( extensionsRequired.indexOf( extensionName ) >= 0 && plugins[ extensionName ] === undefined ) {
376
+
377
+ console.warn( 'THREE.GLTFLoader: Unknown extension "' + extensionName + '".' );
378
+
379
+ }
380
+
381
+ }
382
+
383
+ }
384
+
385
+ }
386
+
387
+ parser.setExtensions( extensions );
388
+ parser.setPlugins( plugins );
389
+ parser.parse( onLoad, onError );
390
+
391
+ }
392
+
393
+ parseAsync( data, path ) {
394
+
395
+ const scope = this;
396
+
397
+ return new Promise( function ( resolve, reject ) {
398
+
399
+ scope.parse( data, path, resolve, reject );
400
+
401
+ } );
402
+
403
+ }
404
+
405
+ }
406
+
407
+ /* GLTFREGISTRY */
408
+
409
+ function GLTFRegistry() {
410
+
411
+ let objects = {};
412
+
413
+ return {
414
+
415
+ get: function ( key ) {
416
+
417
+ return objects[ key ];
418
+
419
+ },
420
+
421
+ add: function ( key, object ) {
422
+
423
+ objects[ key ] = object;
424
+
425
+ },
426
+
427
+ remove: function ( key ) {
428
+
429
+ delete objects[ key ];
430
+
431
+ },
432
+
433
+ removeAll: function () {
434
+
435
+ objects = {};
436
+
437
+ }
438
+
439
+ };
440
+
441
+ }
442
+
443
+ /*********************************/
444
+ /********** EXTENSIONS ***********/
445
+ /*********************************/
446
+
447
+ const EXTENSIONS = {
448
+ KHR_BINARY_GLTF: 'KHR_binary_glTF',
449
+ KHR_DRACO_MESH_COMPRESSION: 'KHR_draco_mesh_compression',
450
+ KHR_LIGHTS_PUNCTUAL: 'KHR_lights_punctual',
451
+ KHR_MATERIALS_CLEARCOAT: 'KHR_materials_clearcoat',
452
+ KHR_MATERIALS_IOR: 'KHR_materials_ior',
453
+ KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness',
454
+ KHR_MATERIALS_SHEEN: 'KHR_materials_sheen',
455
+ KHR_MATERIALS_SPECULAR: 'KHR_materials_specular',
456
+ KHR_MATERIALS_TRANSMISSION: 'KHR_materials_transmission',
457
+ KHR_MATERIALS_UNLIT: 'KHR_materials_unlit',
458
+ KHR_MATERIALS_VOLUME: 'KHR_materials_volume',
459
+ KHR_TEXTURE_BASISU: 'KHR_texture_basisu',
460
+ KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform',
461
+ KHR_MESH_QUANTIZATION: 'KHR_mesh_quantization',
462
+ KHR_MATERIALS_EMISSIVE_STRENGTH: 'KHR_materials_emissive_strength',
463
+ EXT_TEXTURE_WEBP: 'EXT_texture_webp',
464
+ EXT_MESHOPT_COMPRESSION: 'EXT_meshopt_compression'
465
+ };
466
+
467
+ /**
468
+ * Punctual Lights Extension
469
+ *
470
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual
471
+ */
472
+ class GLTFLightsExtension {
473
+
474
+ constructor( parser ) {
475
+
476
+ this.parser = parser;
477
+ this.name = EXTENSIONS.KHR_LIGHTS_PUNCTUAL;
478
+
479
+ // Object3D instance caches
480
+ this.cache = { refs: {}, uses: {} };
481
+
482
+ }
483
+
484
+ _markDefs() {
485
+
486
+ const parser = this.parser;
487
+ const nodeDefs = this.parser.json.nodes || [];
488
+
489
+ for ( let nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex ++ ) {
490
+
491
+ const nodeDef = nodeDefs[ nodeIndex ];
492
+
493
+ if ( nodeDef.extensions
494
+ && nodeDef.extensions[ this.name ]
495
+ && nodeDef.extensions[ this.name ].light !== undefined ) {
496
+
497
+ parser._addNodeRef( this.cache, nodeDef.extensions[ this.name ].light );
498
+
499
+ }
500
+
501
+ }
502
+
503
+ }
504
+
505
+ _loadLight( lightIndex ) {
506
+
507
+ const parser = this.parser;
508
+ const cacheKey = 'light:' + lightIndex;
509
+ let dependency = parser.cache.get( cacheKey );
510
+
511
+ if ( dependency ) return dependency;
512
+
513
+ const json = parser.json;
514
+ const extensions = ( json.extensions && json.extensions[ this.name ] ) || {};
515
+ const lightDefs = extensions.lights || [];
516
+ const lightDef = lightDefs[ lightIndex ];
517
+ let lightNode;
518
+
519
+ const color = new Color( 0xffffff );
520
+
521
+ if ( lightDef.color !== undefined ) color.fromArray( lightDef.color );
522
+
523
+ const range = lightDef.range !== undefined ? lightDef.range : 0;
524
+
525
+ switch ( lightDef.type ) {
526
+
527
+ case 'directional':
528
+ lightNode = new DirectionalLight( color );
529
+ lightNode.target.position.set( 0, 0, - 1 );
530
+ lightNode.add( lightNode.target );
531
+ break;
532
+
533
+ case 'point':
534
+ lightNode = new PointLight( color );
535
+ lightNode.distance = range;
536
+ break;
537
+
538
+ case 'spot':
539
+ lightNode = new SpotLight( color );
540
+ lightNode.distance = range;
541
+ // Handle spotlight properties.
542
+ lightDef.spot = lightDef.spot || {};
543
+ lightDef.spot.innerConeAngle = lightDef.spot.innerConeAngle !== undefined ? lightDef.spot.innerConeAngle : 0;
544
+ lightDef.spot.outerConeAngle = lightDef.spot.outerConeAngle !== undefined ? lightDef.spot.outerConeAngle : Math.PI / 4.0;
545
+ lightNode.angle = lightDef.spot.outerConeAngle;
546
+ lightNode.penumbra = 1.0 - lightDef.spot.innerConeAngle / lightDef.spot.outerConeAngle;
547
+ lightNode.target.position.set( 0, 0, - 1 );
548
+ lightNode.add( lightNode.target );
549
+ break;
550
+
551
+ default:
552
+ throw new Error( 'THREE.GLTFLoader: Unexpected light type: ' + lightDef.type );
553
+
554
+ }
555
+
556
+ // Some lights (e.g. spot) default to a position other than the origin. Reset the position
557
+ // here, because node-level parsing will only override position if explicitly specified.
558
+ lightNode.position.set( 0, 0, 0 );
559
+
560
+ lightNode.decay = 2;
561
+
562
+ if ( lightDef.intensity !== undefined ) lightNode.intensity = lightDef.intensity;
563
+
564
+ lightNode.name = parser.createUniqueName( lightDef.name || ( 'light_' + lightIndex ) );
565
+
566
+ dependency = Promise.resolve( lightNode );
567
+
568
+ parser.cache.add( cacheKey, dependency );
569
+
570
+ return dependency;
571
+
572
+ }
573
+
574
+ createNodeAttachment( nodeIndex ) {
575
+
576
+ const self = this;
577
+ const parser = this.parser;
578
+ const json = parser.json;
579
+ const nodeDef = json.nodes[ nodeIndex ];
580
+ const lightDef = ( nodeDef.extensions && nodeDef.extensions[ this.name ] ) || {};
581
+ const lightIndex = lightDef.light;
582
+
583
+ if ( lightIndex === undefined ) return null;
584
+
585
+ return this._loadLight( lightIndex ).then( function ( light ) {
586
+
587
+ return parser._getNodeRef( self.cache, lightIndex, light );
588
+
589
+ } );
590
+
591
+ }
592
+
593
+ }
594
+
595
+ /**
596
+ * Unlit Materials Extension
597
+ *
598
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit
599
+ */
600
+ class GLTFMaterialsUnlitExtension {
601
+
602
+ constructor() {
603
+
604
+ this.name = EXTENSIONS.KHR_MATERIALS_UNLIT;
605
+
606
+ }
607
+
608
+ getMaterialType() {
609
+
610
+ return MeshBasicMaterial;
611
+
612
+ }
613
+
614
+ extendParams( materialParams, materialDef, parser ) {
615
+
616
+ const pending = [];
617
+
618
+ materialParams.color = new Color( 1.0, 1.0, 1.0 );
619
+ materialParams.opacity = 1.0;
620
+
621
+ const metallicRoughness = materialDef.pbrMetallicRoughness;
622
+
623
+ if ( metallicRoughness ) {
624
+
625
+ if ( Array.isArray( metallicRoughness.baseColorFactor ) ) {
626
+
627
+ const array = metallicRoughness.baseColorFactor;
628
+
629
+ materialParams.color.fromArray( array );
630
+ materialParams.opacity = array[ 3 ];
631
+
632
+ }
633
+
634
+ if ( metallicRoughness.baseColorTexture !== undefined ) {
635
+
636
+ pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture, sRGBEncoding ) );
637
+
638
+ }
639
+
640
+ }
641
+
642
+ return Promise.all( pending );
643
+
644
+ }
645
+
646
+ }
647
+
648
+ /**
649
+ * Materials Emissive Strength Extension
650
+ *
651
+ * Specification: https://github.com/KhronosGroup/glTF/blob/5768b3ce0ef32bc39cdf1bef10b948586635ead3/extensions/2.0/Khronos/KHR_materials_emissive_strength/README.md
652
+ */
653
+ class GLTFMaterialsEmissiveStrengthExtension {
654
+
655
+ constructor( parser ) {
656
+
657
+ this.parser = parser;
658
+ this.name = EXTENSIONS.KHR_MATERIALS_EMISSIVE_STRENGTH;
659
+
660
+ }
661
+
662
+ extendMaterialParams( materialIndex, materialParams ) {
663
+
664
+ const parser = this.parser;
665
+ const materialDef = parser.json.materials[ materialIndex ];
666
+
667
+ if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
668
+
669
+ return Promise.resolve();
670
+
671
+ }
672
+
673
+ const emissiveStrength = materialDef.extensions[this.name].emissiveStrength;
674
+
675
+ if ( emissiveStrength !== undefined ) {
676
+
677
+ materialParams.emissiveIntensity = emissiveStrength;
678
+
679
+ }
680
+
681
+ return Promise.resolve();
682
+
683
+ }
684
+
685
+ }
686
+
687
+ /**
688
+ * Clearcoat Materials Extension
689
+ *
690
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_clearcoat
691
+ */
692
+ class GLTFMaterialsClearcoatExtension {
693
+
694
+ constructor( parser ) {
695
+
696
+ this.parser = parser;
697
+ this.name = EXTENSIONS.KHR_MATERIALS_CLEARCOAT;
698
+
699
+ }
700
+
701
+ getMaterialType( materialIndex ) {
702
+
703
+ const parser = this.parser;
704
+ const materialDef = parser.json.materials[ materialIndex ];
705
+
706
+ if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;
707
+
708
+ return MeshPhysicalMaterial;
709
+
710
+ }
711
+
712
+ extendMaterialParams( materialIndex, materialParams ) {
713
+
714
+ const parser = this.parser;
715
+ const materialDef = parser.json.materials[ materialIndex ];
716
+
717
+ if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
718
+
719
+ return Promise.resolve();
720
+
721
+ }
722
+
723
+ const pending = [];
724
+
725
+ const extension = materialDef.extensions[ this.name ];
726
+
727
+ if ( extension.clearcoatFactor !== undefined ) {
728
+
729
+ materialParams.clearcoat = extension.clearcoatFactor;
730
+
731
+ }
732
+
733
+ if ( extension.clearcoatTexture !== undefined ) {
734
+
735
+ pending.push( parser.assignTexture( materialParams, 'clearcoatMap', extension.clearcoatTexture ) );
736
+
737
+ }
738
+
739
+ if ( extension.clearcoatRoughnessFactor !== undefined ) {
740
+
741
+ materialParams.clearcoatRoughness = extension.clearcoatRoughnessFactor;
742
+
743
+ }
744
+
745
+ if ( extension.clearcoatRoughnessTexture !== undefined ) {
746
+
747
+ pending.push( parser.assignTexture( materialParams, 'clearcoatRoughnessMap', extension.clearcoatRoughnessTexture ) );
748
+
749
+ }
750
+
751
+ if ( extension.clearcoatNormalTexture !== undefined ) {
752
+
753
+ pending.push( parser.assignTexture( materialParams, 'clearcoatNormalMap', extension.clearcoatNormalTexture ) );
754
+
755
+ if ( extension.clearcoatNormalTexture.scale !== undefined ) {
756
+
757
+ const scale = extension.clearcoatNormalTexture.scale;
758
+
759
+ materialParams.clearcoatNormalScale = new Vector2( scale, scale );
760
+
761
+ }
762
+
763
+ }
764
+
765
+ return Promise.all( pending );
766
+
767
+ }
768
+
769
+ }
770
+
771
+ /**
772
+ * Sheen Materials Extension
773
+ *
774
+ * Specification: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_sheen
775
+ */
776
+ class GLTFMaterialsSheenExtension {
777
+
778
+ constructor( parser ) {
779
+
780
+ this.parser = parser;
781
+ this.name = EXTENSIONS.KHR_MATERIALS_SHEEN;
782
+
783
+ }
784
+
785
+ getMaterialType( materialIndex ) {
786
+
787
+ const parser = this.parser;
788
+ const materialDef = parser.json.materials[ materialIndex ];
789
+
790
+ if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;
791
+
792
+ return MeshPhysicalMaterial;
793
+
794
+ }
795
+
796
+ extendMaterialParams( materialIndex, materialParams ) {
797
+
798
+ const parser = this.parser;
799
+ const materialDef = parser.json.materials[ materialIndex ];
800
+
801
+ if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
802
+
803
+ return Promise.resolve();
804
+
805
+ }
806
+
807
+ const pending = [];
808
+
809
+ materialParams.sheenColor = new Color( 0, 0, 0 );
810
+ materialParams.sheenRoughness = 0;
811
+ materialParams.sheen = 1;
812
+
813
+ const extension = materialDef.extensions[ this.name ];
814
+
815
+ if ( extension.sheenColorFactor !== undefined ) {
816
+
817
+ materialParams.sheenColor.fromArray( extension.sheenColorFactor );
818
+
819
+ }
820
+
821
+ if ( extension.sheenRoughnessFactor !== undefined ) {
822
+
823
+ materialParams.sheenRoughness = extension.sheenRoughnessFactor;
824
+
825
+ }
826
+
827
+ if ( extension.sheenColorTexture !== undefined ) {
828
+
829
+ pending.push( parser.assignTexture( materialParams, 'sheenColorMap', extension.sheenColorTexture, sRGBEncoding ) );
830
+
831
+ }
832
+
833
+ if ( extension.sheenRoughnessTexture !== undefined ) {
834
+
835
+ pending.push( parser.assignTexture( materialParams, 'sheenRoughnessMap', extension.sheenRoughnessTexture ) );
836
+
837
+ }
838
+
839
+ return Promise.all( pending );
840
+
841
+ }
842
+
843
+ }
844
+
845
+ /**
846
+ * Transmission Materials Extension
847
+ *
848
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_transmission
849
+ * Draft: https://github.com/KhronosGroup/glTF/pull/1698
850
+ */
851
+ class GLTFMaterialsTransmissionExtension {
852
+
853
+ constructor( parser ) {
854
+
855
+ this.parser = parser;
856
+ this.name = EXTENSIONS.KHR_MATERIALS_TRANSMISSION;
857
+
858
+ }
859
+
860
+ getMaterialType( materialIndex ) {
861
+
862
+ const parser = this.parser;
863
+ const materialDef = parser.json.materials[ materialIndex ];
864
+
865
+ if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;
866
+
867
+ return MeshPhysicalMaterial;
868
+
869
+ }
870
+
871
+ extendMaterialParams( materialIndex, materialParams ) {
872
+
873
+ const parser = this.parser;
874
+ const materialDef = parser.json.materials[ materialIndex ];
875
+
876
+ if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
877
+
878
+ return Promise.resolve();
879
+
880
+ }
881
+
882
+ const pending = [];
883
+
884
+ const extension = materialDef.extensions[ this.name ];
885
+
886
+ if ( extension.transmissionFactor !== undefined ) {
887
+
888
+ materialParams.transmission = extension.transmissionFactor;
889
+
890
+ }
891
+
892
+ if ( extension.transmissionTexture !== undefined ) {
893
+
894
+ pending.push( parser.assignTexture( materialParams, 'transmissionMap', extension.transmissionTexture ) );
895
+
896
+ }
897
+
898
+ return Promise.all( pending );
899
+
900
+ }
901
+
902
+ }
903
+
904
+ /**
905
+ * Materials Volume Extension
906
+ *
907
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_volume
908
+ */
909
+ class GLTFMaterialsVolumeExtension {
910
+
911
+ constructor( parser ) {
912
+
913
+ this.parser = parser;
914
+ this.name = EXTENSIONS.KHR_MATERIALS_VOLUME;
915
+
916
+ }
917
+
918
+ getMaterialType( materialIndex ) {
919
+
920
+ const parser = this.parser;
921
+ const materialDef = parser.json.materials[ materialIndex ];
922
+
923
+ if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;
924
+
925
+ return MeshPhysicalMaterial;
926
+
927
+ }
928
+
929
+ extendMaterialParams( materialIndex, materialParams ) {
930
+
931
+ const parser = this.parser;
932
+ const materialDef = parser.json.materials[ materialIndex ];
933
+
934
+ if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
935
+
936
+ return Promise.resolve();
937
+
938
+ }
939
+
940
+ const pending = [];
941
+
942
+ const extension = materialDef.extensions[ this.name ];
943
+
944
+ materialParams.thickness = extension.thicknessFactor !== undefined ? extension.thicknessFactor : 0;
945
+
946
+ if ( extension.thicknessTexture !== undefined ) {
947
+
948
+ pending.push( parser.assignTexture( materialParams, 'thicknessMap', extension.thicknessTexture ) );
949
+
950
+ }
951
+
952
+ materialParams.attenuationDistance = extension.attenuationDistance || 0;
953
+
954
+ const colorArray = extension.attenuationColor || [ 1, 1, 1 ];
955
+ materialParams.attenuationColor = new Color( colorArray[ 0 ], colorArray[ 1 ], colorArray[ 2 ] );
956
+
957
+ return Promise.all( pending );
958
+
959
+ }
960
+
961
+ }
962
+
963
+ /**
964
+ * Materials ior Extension
965
+ *
966
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_ior
967
+ */
968
+ class GLTFMaterialsIorExtension {
969
+
970
+ constructor( parser ) {
971
+
972
+ this.parser = parser;
973
+ this.name = EXTENSIONS.KHR_MATERIALS_IOR;
974
+
975
+ }
976
+
977
+ getMaterialType( materialIndex ) {
978
+
979
+ const parser = this.parser;
980
+ const materialDef = parser.json.materials[ materialIndex ];
981
+
982
+ if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;
983
+
984
+ return MeshPhysicalMaterial;
985
+
986
+ }
987
+
988
+ extendMaterialParams( materialIndex, materialParams ) {
989
+
990
+ const parser = this.parser;
991
+ const materialDef = parser.json.materials[ materialIndex ];
992
+
993
+ if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
994
+
995
+ return Promise.resolve();
996
+
997
+ }
998
+
999
+ const extension = materialDef.extensions[ this.name ];
1000
+
1001
+ materialParams.ior = extension.ior !== undefined ? extension.ior : 1.5;
1002
+
1003
+ return Promise.resolve();
1004
+
1005
+ }
1006
+
1007
+ }
1008
+
1009
+ /**
1010
+ * Materials specular Extension
1011
+ *
1012
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_specular
1013
+ */
1014
+ class GLTFMaterialsSpecularExtension {
1015
+
1016
+ constructor( parser ) {
1017
+
1018
+ this.parser = parser;
1019
+ this.name = EXTENSIONS.KHR_MATERIALS_SPECULAR;
1020
+
1021
+ }
1022
+
1023
+ getMaterialType( materialIndex ) {
1024
+
1025
+ const parser = this.parser;
1026
+ const materialDef = parser.json.materials[ materialIndex ];
1027
+
1028
+ if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;
1029
+
1030
+ return MeshPhysicalMaterial;
1031
+
1032
+ }
1033
+
1034
+ extendMaterialParams( materialIndex, materialParams ) {
1035
+
1036
+ const parser = this.parser;
1037
+ const materialDef = parser.json.materials[ materialIndex ];
1038
+
1039
+ if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
1040
+
1041
+ return Promise.resolve();
1042
+
1043
+ }
1044
+
1045
+ const pending = [];
1046
+
1047
+ const extension = materialDef.extensions[ this.name ];
1048
+
1049
+ materialParams.specularIntensity = extension.specularFactor !== undefined ? extension.specularFactor : 1.0;
1050
+
1051
+ if ( extension.specularTexture !== undefined ) {
1052
+
1053
+ pending.push( parser.assignTexture( materialParams, 'specularIntensityMap', extension.specularTexture ) );
1054
+
1055
+ }
1056
+
1057
+ const colorArray = extension.specularColorFactor || [ 1, 1, 1 ];
1058
+ materialParams.specularColor = new Color( colorArray[ 0 ], colorArray[ 1 ], colorArray[ 2 ] );
1059
+
1060
+ if ( extension.specularColorTexture !== undefined ) {
1061
+
1062
+ pending.push( parser.assignTexture( materialParams, 'specularColorMap', extension.specularColorTexture, sRGBEncoding ) );
1063
+
1064
+ }
1065
+
1066
+ return Promise.all( pending );
1067
+
1068
+ }
1069
+
1070
+ }
1071
+
1072
+ /**
1073
+ * BasisU Texture Extension
1074
+ *
1075
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_texture_basisu
1076
+ */
1077
+ class GLTFTextureBasisUExtension {
1078
+
1079
+ constructor( parser ) {
1080
+
1081
+ this.parser = parser;
1082
+ this.name = EXTENSIONS.KHR_TEXTURE_BASISU;
1083
+
1084
+ }
1085
+
1086
+ loadTexture( textureIndex ) {
1087
+
1088
+ const parser = this.parser;
1089
+ const json = parser.json;
1090
+
1091
+ const textureDef = json.textures[ textureIndex ];
1092
+
1093
+ if ( ! textureDef.extensions || ! textureDef.extensions[ this.name ] ) {
1094
+
1095
+ return null;
1096
+
1097
+ }
1098
+
1099
+ const extension = textureDef.extensions[ this.name ];
1100
+ const loader = parser.options.ktx2Loader;
1101
+
1102
+ if ( ! loader ) {
1103
+
1104
+ if ( json.extensionsRequired && json.extensionsRequired.indexOf( this.name ) >= 0 ) {
1105
+
1106
+ throw new Error( 'THREE.GLTFLoader: setKTX2Loader must be called before loading KTX2 textures' );
1107
+
1108
+ } else {
1109
+
1110
+ // Assumes that the extension is optional and that a fallback texture is present
1111
+ return null;
1112
+
1113
+ }
1114
+
1115
+ }
1116
+
1117
+ return parser.loadTextureImage( textureIndex, extension.source, loader );
1118
+
1119
+ }
1120
+
1121
+ }
1122
+
1123
+ /**
1124
+ * WebP Texture Extension
1125
+ *
1126
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_texture_webp
1127
+ */
1128
+ class GLTFTextureWebPExtension {
1129
+
1130
+ constructor( parser ) {
1131
+
1132
+ this.parser = parser;
1133
+ this.name = EXTENSIONS.EXT_TEXTURE_WEBP;
1134
+ this.isSupported = null;
1135
+
1136
+ }
1137
+
1138
+ loadTexture( textureIndex ) {
1139
+
1140
+ const name = this.name;
1141
+ const parser = this.parser;
1142
+ const json = parser.json;
1143
+
1144
+ const textureDef = json.textures[ textureIndex ];
1145
+
1146
+ if ( ! textureDef.extensions || ! textureDef.extensions[ name ] ) {
1147
+
1148
+ return null;
1149
+
1150
+ }
1151
+
1152
+ const extension = textureDef.extensions[ name ];
1153
+ const source = json.images[ extension.source ];
1154
+
1155
+ let loader = parser.textureLoader;
1156
+ if ( source.uri ) {
1157
+
1158
+ const handler = parser.options.manager.getHandler( source.uri );
1159
+ if ( handler !== null ) loader = handler;
1160
+
1161
+ }
1162
+
1163
+ return this.detectSupport().then( function ( isSupported ) {
1164
+
1165
+ if ( isSupported ) return parser.loadTextureImage( textureIndex, extension.source, loader );
1166
+
1167
+ if ( json.extensionsRequired && json.extensionsRequired.indexOf( name ) >= 0 ) {
1168
+
1169
+ throw new Error( 'THREE.GLTFLoader: WebP required by asset but unsupported.' );
1170
+
1171
+ }
1172
+
1173
+ // Fall back to PNG or JPEG.
1174
+ return parser.loadTexture( textureIndex );
1175
+
1176
+ } );
1177
+
1178
+ }
1179
+
1180
+ detectSupport() {
1181
+
1182
+ if ( ! this.isSupported ) {
1183
+
1184
+ this.isSupported = new Promise( function ( resolve ) {
1185
+
1186
+ const image = new Image();
1187
+
1188
+ // Lossy test image. Support for lossy images doesn't guarantee support for all
1189
+ // WebP images, unfortunately.
1190
+ image.src = 'data:image/webp;base64,UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA';
1191
+
1192
+ image.onload = image.onerror = function () {
1193
+
1194
+ resolve( image.height === 1 );
1195
+
1196
+ };
1197
+
1198
+ } );
1199
+
1200
+ }
1201
+
1202
+ return this.isSupported;
1203
+
1204
+ }
1205
+
1206
+ }
1207
+
1208
+ /**
1209
+ * meshopt BufferView Compression Extension
1210
+ *
1211
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_meshopt_compression
1212
+ */
1213
+ class GLTFMeshoptCompression {
1214
+
1215
+ constructor( parser ) {
1216
+
1217
+ this.name = EXTENSIONS.EXT_MESHOPT_COMPRESSION;
1218
+ this.parser = parser;
1219
+
1220
+ }
1221
+
1222
+ loadBufferView( index ) {
1223
+
1224
+ const json = this.parser.json;
1225
+ const bufferView = json.bufferViews[ index ];
1226
+
1227
+ if ( bufferView.extensions && bufferView.extensions[ this.name ] ) {
1228
+
1229
+ const extensionDef = bufferView.extensions[ this.name ];
1230
+
1231
+ const buffer = this.parser.getDependency( 'buffer', extensionDef.buffer );
1232
+ const decoder = this.parser.options.meshoptDecoder;
1233
+
1234
+ if ( ! decoder || ! decoder.supported ) {
1235
+
1236
+ if ( json.extensionsRequired && json.extensionsRequired.indexOf( this.name ) >= 0 ) {
1237
+
1238
+ throw new Error( 'THREE.GLTFLoader: setMeshoptDecoder must be called before loading compressed files' );
1239
+
1240
+ } else {
1241
+
1242
+ // Assumes that the extension is optional and that fallback buffer data is present
1243
+ return null;
1244
+
1245
+ }
1246
+
1247
+ }
1248
+
1249
+ return Promise.all( [ buffer, decoder.ready ] ).then( function ( res ) {
1250
+
1251
+ const byteOffset = extensionDef.byteOffset || 0;
1252
+ const byteLength = extensionDef.byteLength || 0;
1253
+
1254
+ const count = extensionDef.count;
1255
+ const stride = extensionDef.byteStride;
1256
+
1257
+ const result = new ArrayBuffer( count * stride );
1258
+ const source = new Uint8Array( res[ 0 ], byteOffset, byteLength );
1259
+
1260
+ decoder.decodeGltfBuffer( new Uint8Array( result ), count, stride, source, extensionDef.mode, extensionDef.filter );
1261
+ return result;
1262
+
1263
+ } );
1264
+
1265
+ } else {
1266
+
1267
+ return null;
1268
+
1269
+ }
1270
+
1271
+ }
1272
+
1273
+ }
1274
+
1275
+ /* BINARY EXTENSION */
1276
+ const BINARY_EXTENSION_HEADER_MAGIC = 'glTF';
1277
+ const BINARY_EXTENSION_HEADER_LENGTH = 12;
1278
+ const BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4E4F534A, BIN: 0x004E4942 };
1279
+
1280
+ class GLTFBinaryExtension {
1281
+
1282
+ constructor( data ) {
1283
+
1284
+ this.name = EXTENSIONS.KHR_BINARY_GLTF;
1285
+ this.content = null;
1286
+ this.body = null;
1287
+
1288
+ const headerView = new DataView( data, 0, BINARY_EXTENSION_HEADER_LENGTH );
1289
+
1290
+ this.header = {
1291
+ magic: LoaderUtils.decodeText( new Uint8Array( data.slice( 0, 4 ) ) ),
1292
+ version: headerView.getUint32( 4, true ),
1293
+ length: headerView.getUint32( 8, true )
1294
+ };
1295
+
1296
+ if ( this.header.magic !== BINARY_EXTENSION_HEADER_MAGIC ) {
1297
+
1298
+ throw new Error( 'THREE.GLTFLoader: Unsupported glTF-Binary header.' );
1299
+
1300
+ } else if ( this.header.version < 2.0 ) {
1301
+
1302
+ throw new Error( 'THREE.GLTFLoader: Legacy binary file detected.' );
1303
+
1304
+ }
1305
+
1306
+ const chunkContentsLength = this.header.length - BINARY_EXTENSION_HEADER_LENGTH;
1307
+ const chunkView = new DataView( data, BINARY_EXTENSION_HEADER_LENGTH );
1308
+ let chunkIndex = 0;
1309
+
1310
+ while ( chunkIndex < chunkContentsLength ) {
1311
+
1312
+ const chunkLength = chunkView.getUint32( chunkIndex, true );
1313
+ chunkIndex += 4;
1314
+
1315
+ const chunkType = chunkView.getUint32( chunkIndex, true );
1316
+ chunkIndex += 4;
1317
+
1318
+ if ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON ) {
1319
+
1320
+ const contentArray = new Uint8Array( data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength );
1321
+ this.content = LoaderUtils.decodeText( contentArray );
1322
+
1323
+ } else if ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN ) {
1324
+
1325
+ const byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex;
1326
+ this.body = data.slice( byteOffset, byteOffset + chunkLength );
1327
+
1328
+ }
1329
+
1330
+ // Clients must ignore chunks with unknown types.
1331
+
1332
+ chunkIndex += chunkLength;
1333
+
1334
+ }
1335
+
1336
+ if ( this.content === null ) {
1337
+
1338
+ throw new Error( 'THREE.GLTFLoader: JSON content not found.' );
1339
+
1340
+ }
1341
+
1342
+ }
1343
+
1344
+ }
1345
+
1346
+ /**
1347
+ * DRACO Mesh Compression Extension
1348
+ *
1349
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression
1350
+ */
1351
+ class GLTFDracoMeshCompressionExtension {
1352
+
1353
+ constructor( json, dracoLoader ) {
1354
+
1355
+ if ( ! dracoLoader ) {
1356
+
1357
+ throw new Error( 'THREE.GLTFLoader: No DRACOLoader instance provided.' );
1358
+
1359
+ }
1360
+
1361
+ this.name = EXTENSIONS.KHR_DRACO_MESH_COMPRESSION;
1362
+ this.json = json;
1363
+ this.dracoLoader = dracoLoader;
1364
+ this.dracoLoader.preload();
1365
+
1366
+ }
1367
+
1368
+ decodePrimitive( primitive, parser ) {
1369
+
1370
+ const json = this.json;
1371
+ const dracoLoader = this.dracoLoader;
1372
+ const bufferViewIndex = primitive.extensions[ this.name ].bufferView;
1373
+ const gltfAttributeMap = primitive.extensions[ this.name ].attributes;
1374
+ const threeAttributeMap = {};
1375
+ const attributeNormalizedMap = {};
1376
+ const attributeTypeMap = {};
1377
+
1378
+ for ( const attributeName in gltfAttributeMap ) {
1379
+
1380
+ const threeAttributeName = ATTRIBUTES[ attributeName ] || attributeName.toLowerCase();
1381
+
1382
+ threeAttributeMap[ threeAttributeName ] = gltfAttributeMap[ attributeName ];
1383
+
1384
+ }
1385
+
1386
+ for ( const attributeName in primitive.attributes ) {
1387
+
1388
+ const threeAttributeName = ATTRIBUTES[ attributeName ] || attributeName.toLowerCase();
1389
+
1390
+ if ( gltfAttributeMap[ attributeName ] !== undefined ) {
1391
+
1392
+ const accessorDef = json.accessors[ primitive.attributes[ attributeName ] ];
1393
+ const componentType = WEBGL_COMPONENT_TYPES[ accessorDef.componentType ];
1394
+
1395
+ attributeTypeMap[ threeAttributeName ] = componentType;
1396
+ attributeNormalizedMap[ threeAttributeName ] = accessorDef.normalized === true;
1397
+
1398
+ }
1399
+
1400
+ }
1401
+
1402
+ return parser.getDependency( 'bufferView', bufferViewIndex ).then( function ( bufferView ) {
1403
+
1404
+ return new Promise( function ( resolve ) {
1405
+
1406
+ dracoLoader.decodeDracoFile( bufferView, function ( geometry ) {
1407
+
1408
+ for ( const attributeName in geometry.attributes ) {
1409
+
1410
+ const attribute = geometry.attributes[ attributeName ];
1411
+ const normalized = attributeNormalizedMap[ attributeName ];
1412
+
1413
+ if ( normalized !== undefined ) attribute.normalized = normalized;
1414
+
1415
+ }
1416
+
1417
+ resolve( geometry );
1418
+
1419
+ }, threeAttributeMap, attributeTypeMap );
1420
+
1421
+ } );
1422
+
1423
+ } );
1424
+
1425
+ }
1426
+
1427
+ }
1428
+
1429
+ /**
1430
+ * Texture Transform Extension
1431
+ *
1432
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_texture_transform
1433
+ */
1434
+ class GLTFTextureTransformExtension {
1435
+
1436
+ constructor() {
1437
+
1438
+ this.name = EXTENSIONS.KHR_TEXTURE_TRANSFORM;
1439
+
1440
+ }
1441
+
1442
+ extendTexture( texture, transform ) {
1443
+
1444
+ if ( transform.texCoord !== undefined ) {
1445
+
1446
+ console.warn( 'THREE.GLTFLoader: Custom UV sets in "' + this.name + '" extension not yet supported.' );
1447
+
1448
+ }
1449
+
1450
+ if ( transform.offset === undefined && transform.rotation === undefined && transform.scale === undefined ) {
1451
+
1452
+ // See https://github.com/mrdoob/three.js/issues/21819.
1453
+ return texture;
1454
+
1455
+ }
1456
+
1457
+ texture = texture.clone();
1458
+
1459
+ if ( transform.offset !== undefined ) {
1460
+
1461
+ texture.offset.fromArray( transform.offset );
1462
+
1463
+ }
1464
+
1465
+ if ( transform.rotation !== undefined ) {
1466
+
1467
+ texture.rotation = transform.rotation;
1468
+
1469
+ }
1470
+
1471
+ if ( transform.scale !== undefined ) {
1472
+
1473
+ texture.repeat.fromArray( transform.scale );
1474
+
1475
+ }
1476
+
1477
+ texture.needsUpdate = true;
1478
+
1479
+ return texture;
1480
+
1481
+ }
1482
+
1483
+ }
1484
+
1485
+ /**
1486
+ * Specular-Glossiness Extension
1487
+ *
1488
+ * Specification: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Archived/KHR_materials_pbrSpecularGlossiness
1489
+ */
1490
+
1491
+ /**
1492
+ * A sub class of StandardMaterial with some of the functionality
1493
+ * changed via the `onBeforeCompile` callback
1494
+ * @pailhead
1495
+ */
1496
+ class GLTFMeshStandardSGMaterial extends MeshStandardMaterial {
1497
+
1498
+ constructor( params ) {
1499
+
1500
+ super();
1501
+
1502
+ this.isGLTFSpecularGlossinessMaterial = true;
1503
+
1504
+ //various chunks that need replacing
1505
+ const specularMapParsFragmentChunk = [
1506
+ '#ifdef USE_SPECULARMAP',
1507
+ ' uniform sampler2D specularMap;',
1508
+ '#endif'
1509
+ ].join( '\n' );
1510
+
1511
+ const glossinessMapParsFragmentChunk = [
1512
+ '#ifdef USE_GLOSSINESSMAP',
1513
+ ' uniform sampler2D glossinessMap;',
1514
+ '#endif'
1515
+ ].join( '\n' );
1516
+
1517
+ const specularMapFragmentChunk = [
1518
+ 'vec3 specularFactor = specular;',
1519
+ '#ifdef USE_SPECULARMAP',
1520
+ ' vec4 texelSpecular = texture2D( specularMap, vUv );',
1521
+ ' // reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture',
1522
+ ' specularFactor *= texelSpecular.rgb;',
1523
+ '#endif'
1524
+ ].join( '\n' );
1525
+
1526
+ const glossinessMapFragmentChunk = [
1527
+ 'float glossinessFactor = glossiness;',
1528
+ '#ifdef USE_GLOSSINESSMAP',
1529
+ ' vec4 texelGlossiness = texture2D( glossinessMap, vUv );',
1530
+ ' // reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture',
1531
+ ' glossinessFactor *= texelGlossiness.a;',
1532
+ '#endif'
1533
+ ].join( '\n' );
1534
+
1535
+ const lightPhysicalFragmentChunk = [
1536
+ 'PhysicalMaterial material;',
1537
+ 'material.diffuseColor = diffuseColor.rgb * ( 1. - max( specularFactor.r, max( specularFactor.g, specularFactor.b ) ) );',
1538
+ 'vec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );',
1539
+ 'float geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );',
1540
+ 'material.roughness = max( 1.0 - glossinessFactor, 0.0525 ); // 0.0525 corresponds to the base mip of a 256 cubemap.',
1541
+ 'material.roughness += geometryRoughness;',
1542
+ 'material.roughness = min( material.roughness, 1.0 );',
1543
+ 'material.specularColor = specularFactor;',
1544
+ ].join( '\n' );
1545
+
1546
+ const uniforms = {
1547
+ specular: { value: new Color().setHex( 0xffffff ) },
1548
+ glossiness: { value: 1 },
1549
+ specularMap: { value: null },
1550
+ glossinessMap: { value: null }
1551
+ };
1552
+
1553
+ this._extraUniforms = uniforms;
1554
+
1555
+ this.onBeforeCompile = function ( shader ) {
1556
+
1557
+ for ( const uniformName in uniforms ) {
1558
+
1559
+ shader.uniforms[ uniformName ] = uniforms[ uniformName ];
1560
+
1561
+ }
1562
+
1563
+ shader.fragmentShader = shader.fragmentShader
1564
+ .replace( 'uniform float roughness;', 'uniform vec3 specular;' )
1565
+ .replace( 'uniform float metalness;', 'uniform float glossiness;' )
1566
+ .replace( '#include <roughnessmap_pars_fragment>', specularMapParsFragmentChunk )
1567
+ .replace( '#include <metalnessmap_pars_fragment>', glossinessMapParsFragmentChunk )
1568
+ .replace( '#include <roughnessmap_fragment>', specularMapFragmentChunk )
1569
+ .replace( '#include <metalnessmap_fragment>', glossinessMapFragmentChunk )
1570
+ .replace( '#include <lights_physical_fragment>', lightPhysicalFragmentChunk );
1571
+
1572
+ };
1573
+
1574
+ Object.defineProperties( this, {
1575
+
1576
+ specular: {
1577
+ get: function () {
1578
+
1579
+ return uniforms.specular.value;
1580
+
1581
+ },
1582
+ set: function ( v ) {
1583
+
1584
+ uniforms.specular.value = v;
1585
+
1586
+ }
1587
+ },
1588
+
1589
+ specularMap: {
1590
+ get: function () {
1591
+
1592
+ return uniforms.specularMap.value;
1593
+
1594
+ },
1595
+ set: function ( v ) {
1596
+
1597
+ uniforms.specularMap.value = v;
1598
+
1599
+ if ( v ) {
1600
+
1601
+ this.defines.USE_SPECULARMAP = ''; // USE_UV is set by the renderer for specular maps
1602
+
1603
+ } else {
1604
+
1605
+ delete this.defines.USE_SPECULARMAP;
1606
+
1607
+ }
1608
+
1609
+ }
1610
+ },
1611
+
1612
+ glossiness: {
1613
+ get: function () {
1614
+
1615
+ return uniforms.glossiness.value;
1616
+
1617
+ },
1618
+ set: function ( v ) {
1619
+
1620
+ uniforms.glossiness.value = v;
1621
+
1622
+ }
1623
+ },
1624
+
1625
+ glossinessMap: {
1626
+ get: function () {
1627
+
1628
+ return uniforms.glossinessMap.value;
1629
+
1630
+ },
1631
+ set: function ( v ) {
1632
+
1633
+ uniforms.glossinessMap.value = v;
1634
+
1635
+ if ( v ) {
1636
+
1637
+ this.defines.USE_GLOSSINESSMAP = '';
1638
+ this.defines.USE_UV = '';
1639
+
1640
+ } else {
1641
+
1642
+ delete this.defines.USE_GLOSSINESSMAP;
1643
+ delete this.defines.USE_UV;
1644
+
1645
+ }
1646
+
1647
+ }
1648
+ }
1649
+
1650
+ } );
1651
+
1652
+ delete this.metalness;
1653
+ delete this.roughness;
1654
+ delete this.metalnessMap;
1655
+ delete this.roughnessMap;
1656
+
1657
+ this.setValues( params );
1658
+
1659
+ }
1660
+
1661
+ copy( source ) {
1662
+
1663
+ super.copy( source );
1664
+
1665
+ this.specularMap = source.specularMap;
1666
+ this.specular.copy( source.specular );
1667
+ this.glossinessMap = source.glossinessMap;
1668
+ this.glossiness = source.glossiness;
1669
+ delete this.metalness;
1670
+ delete this.roughness;
1671
+ delete this.metalnessMap;
1672
+ delete this.roughnessMap;
1673
+ return this;
1674
+
1675
+ }
1676
+
1677
+ }
1678
+
1679
+
1680
+ class GLTFMaterialsPbrSpecularGlossinessExtension {
1681
+
1682
+ constructor() {
1683
+
1684
+ this.name = EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS;
1685
+
1686
+ this.specularGlossinessParams = [
1687
+ 'color',
1688
+ 'map',
1689
+ 'lightMap',
1690
+ 'lightMapIntensity',
1691
+ 'aoMap',
1692
+ 'aoMapIntensity',
1693
+ 'emissive',
1694
+ 'emissiveIntensity',
1695
+ 'emissiveMap',
1696
+ 'bumpMap',
1697
+ 'bumpScale',
1698
+ 'normalMap',
1699
+ 'normalMapType',
1700
+ 'displacementMap',
1701
+ 'displacementScale',
1702
+ 'displacementBias',
1703
+ 'specularMap',
1704
+ 'specular',
1705
+ 'glossinessMap',
1706
+ 'glossiness',
1707
+ 'alphaMap',
1708
+ 'envMap',
1709
+ 'envMapIntensity'
1710
+ ];
1711
+
1712
+ }
1713
+
1714
+ getMaterialType() {
1715
+
1716
+ return GLTFMeshStandardSGMaterial;
1717
+
1718
+ }
1719
+
1720
+ extendParams( materialParams, materialDef, parser ) {
1721
+
1722
+ const pbrSpecularGlossiness = materialDef.extensions[ this.name ];
1723
+
1724
+ materialParams.color = new Color( 1.0, 1.0, 1.0 );
1725
+ materialParams.opacity = 1.0;
1726
+
1727
+ const pending = [];
1728
+
1729
+ if ( Array.isArray( pbrSpecularGlossiness.diffuseFactor ) ) {
1730
+
1731
+ const array = pbrSpecularGlossiness.diffuseFactor;
1732
+
1733
+ materialParams.color.fromArray( array );
1734
+ materialParams.opacity = array[ 3 ];
1735
+
1736
+ }
1737
+
1738
+ if ( pbrSpecularGlossiness.diffuseTexture !== undefined ) {
1739
+
1740
+ pending.push( parser.assignTexture( materialParams, 'map', pbrSpecularGlossiness.diffuseTexture, sRGBEncoding ) );
1741
+
1742
+ }
1743
+
1744
+ materialParams.emissive = new Color( 0.0, 0.0, 0.0 );
1745
+ materialParams.glossiness = pbrSpecularGlossiness.glossinessFactor !== undefined ? pbrSpecularGlossiness.glossinessFactor : 1.0;
1746
+ materialParams.specular = new Color( 1.0, 1.0, 1.0 );
1747
+
1748
+ if ( Array.isArray( pbrSpecularGlossiness.specularFactor ) ) {
1749
+
1750
+ materialParams.specular.fromArray( pbrSpecularGlossiness.specularFactor );
1751
+
1752
+ }
1753
+
1754
+ if ( pbrSpecularGlossiness.specularGlossinessTexture !== undefined ) {
1755
+
1756
+ const specGlossMapDef = pbrSpecularGlossiness.specularGlossinessTexture;
1757
+ pending.push( parser.assignTexture( materialParams, 'glossinessMap', specGlossMapDef ) );
1758
+ pending.push( parser.assignTexture( materialParams, 'specularMap', specGlossMapDef, sRGBEncoding ) );
1759
+
1760
+ }
1761
+
1762
+ return Promise.all( pending );
1763
+
1764
+ }
1765
+
1766
+ createMaterial( materialParams ) {
1767
+
1768
+ const material = new GLTFMeshStandardSGMaterial( materialParams );
1769
+ material.fog = true;
1770
+
1771
+ material.color = materialParams.color;
1772
+
1773
+ material.map = materialParams.map === undefined ? null : materialParams.map;
1774
+
1775
+ material.lightMap = null;
1776
+ material.lightMapIntensity = 1.0;
1777
+
1778
+ material.aoMap = materialParams.aoMap === undefined ? null : materialParams.aoMap;
1779
+ material.aoMapIntensity = 1.0;
1780
+
1781
+ material.emissive = materialParams.emissive;
1782
+ material.emissiveIntensity = materialParams.emissiveIntensity === undefined ? 1.0 : materialParams.emissiveIntensity;
1783
+ material.emissiveMap = materialParams.emissiveMap === undefined ? null : materialParams.emissiveMap;
1784
+
1785
+ material.bumpMap = materialParams.bumpMap === undefined ? null : materialParams.bumpMap;
1786
+ material.bumpScale = 1;
1787
+
1788
+ material.normalMap = materialParams.normalMap === undefined ? null : materialParams.normalMap;
1789
+ material.normalMapType = TangentSpaceNormalMap;
1790
+
1791
+ if ( materialParams.normalScale ) material.normalScale = materialParams.normalScale;
1792
+
1793
+ material.displacementMap = null;
1794
+ material.displacementScale = 1;
1795
+ material.displacementBias = 0;
1796
+
1797
+ material.specularMap = materialParams.specularMap === undefined ? null : materialParams.specularMap;
1798
+ material.specular = materialParams.specular;
1799
+
1800
+ material.glossinessMap = materialParams.glossinessMap === undefined ? null : materialParams.glossinessMap;
1801
+ material.glossiness = materialParams.glossiness;
1802
+
1803
+ material.alphaMap = null;
1804
+
1805
+ material.envMap = materialParams.envMap === undefined ? null : materialParams.envMap;
1806
+ material.envMapIntensity = 1.0;
1807
+
1808
+ return material;
1809
+
1810
+ }
1811
+
1812
+ }
1813
+
1814
+ /**
1815
+ * Mesh Quantization Extension
1816
+ *
1817
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_mesh_quantization
1818
+ */
1819
+ class GLTFMeshQuantizationExtension {
1820
+
1821
+ constructor() {
1822
+
1823
+ this.name = EXTENSIONS.KHR_MESH_QUANTIZATION;
1824
+
1825
+ }
1826
+
1827
+ }
1828
+
1829
+ /*********************************/
1830
+ /********** INTERPOLATION ********/
1831
+ /*********************************/
1832
+
1833
+ // Spline Interpolation
1834
+ // Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#appendix-c-spline-interpolation
1835
+ class GLTFCubicSplineInterpolant extends Interpolant {
1836
+
1837
+ constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
1838
+
1839
+ super( parameterPositions, sampleValues, sampleSize, resultBuffer );
1840
+
1841
+ }
1842
+
1843
+ copySampleValue_( index ) {
1844
+
1845
+ // Copies a sample value to the result buffer. See description of glTF
1846
+ // CUBICSPLINE values layout in interpolate_() function below.
1847
+
1848
+ const result = this.resultBuffer,
1849
+ values = this.sampleValues,
1850
+ valueSize = this.valueSize,
1851
+ offset = index * valueSize * 3 + valueSize;
1852
+
1853
+ for ( let i = 0; i !== valueSize; i ++ ) {
1854
+
1855
+ result[ i ] = values[ offset + i ];
1856
+
1857
+ }
1858
+
1859
+ return result;
1860
+
1861
+ }
1862
+
1863
+ }
1864
+
1865
+ GLTFCubicSplineInterpolant.prototype.beforeStart_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_;
1866
+
1867
+ GLTFCubicSplineInterpolant.prototype.afterEnd_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_;
1868
+
1869
+ GLTFCubicSplineInterpolant.prototype.interpolate_ = function ( i1, t0, t, t1 ) {
1870
+
1871
+ const result = this.resultBuffer;
1872
+ const values = this.sampleValues;
1873
+ const stride = this.valueSize;
1874
+
1875
+ const stride2 = stride * 2;
1876
+ const stride3 = stride * 3;
1877
+
1878
+ const td = t1 - t0;
1879
+
1880
+ const p = ( t - t0 ) / td;
1881
+ const pp = p * p;
1882
+ const ppp = pp * p;
1883
+
1884
+ const offset1 = i1 * stride3;
1885
+ const offset0 = offset1 - stride3;
1886
+
1887
+ const s2 = - 2 * ppp + 3 * pp;
1888
+ const s3 = ppp - pp;
1889
+ const s0 = 1 - s2;
1890
+ const s1 = s3 - pp + p;
1891
+
1892
+ // Layout of keyframe output values for CUBICSPLINE animations:
1893
+ // [ inTangent_1, splineVertex_1, outTangent_1, inTangent_2, splineVertex_2, ... ]
1894
+ for ( let i = 0; i !== stride; i ++ ) {
1895
+
1896
+ const p0 = values[ offset0 + i + stride ]; // splineVertex_k
1897
+ const m0 = values[ offset0 + i + stride2 ] * td; // outTangent_k * (t_k+1 - t_k)
1898
+ const p1 = values[ offset1 + i + stride ]; // splineVertex_k+1
1899
+ const m1 = values[ offset1 + i ] * td; // inTangent_k+1 * (t_k+1 - t_k)
1900
+
1901
+ result[ i ] = s0 * p0 + s1 * m0 + s2 * p1 + s3 * m1;
1902
+
1903
+ }
1904
+
1905
+ return result;
1906
+
1907
+ };
1908
+
1909
+ const _q = new Quaternion();
1910
+
1911
+ class GLTFCubicSplineQuaternionInterpolant extends GLTFCubicSplineInterpolant {
1912
+
1913
+ interpolate_( i1, t0, t, t1 ) {
1914
+
1915
+ const result = super.interpolate_( i1, t0, t, t1 );
1916
+
1917
+ _q.fromArray( result ).normalize().toArray( result );
1918
+
1919
+ return result;
1920
+
1921
+ }
1922
+
1923
+ }
1924
+
1925
+
1926
+ /*********************************/
1927
+ /********** INTERNALS ************/
1928
+ /*********************************/
1929
+
1930
+ /* CONSTANTS */
1931
+
1932
+ const WEBGL_CONSTANTS = {
1933
+ FLOAT: 5126,
1934
+ //FLOAT_MAT2: 35674,
1935
+ FLOAT_MAT3: 35675,
1936
+ FLOAT_MAT4: 35676,
1937
+ FLOAT_VEC2: 35664,
1938
+ FLOAT_VEC3: 35665,
1939
+ FLOAT_VEC4: 35666,
1940
+ LINEAR: 9729,
1941
+ REPEAT: 10497,
1942
+ SAMPLER_2D: 35678,
1943
+ POINTS: 0,
1944
+ LINES: 1,
1945
+ LINE_LOOP: 2,
1946
+ LINE_STRIP: 3,
1947
+ TRIANGLES: 4,
1948
+ TRIANGLE_STRIP: 5,
1949
+ TRIANGLE_FAN: 6,
1950
+ UNSIGNED_BYTE: 5121,
1951
+ UNSIGNED_SHORT: 5123
1952
+ };
1953
+
1954
+ const WEBGL_COMPONENT_TYPES = {
1955
+ 5120: Int8Array,
1956
+ 5121: Uint8Array,
1957
+ 5122: Int16Array,
1958
+ 5123: Uint16Array,
1959
+ 5125: Uint32Array,
1960
+ 5126: Float32Array
1961
+ };
1962
+
1963
+ const WEBGL_FILTERS = {
1964
+ 9728: NearestFilter,
1965
+ 9729: LinearFilter,
1966
+ 9984: NearestMipmapNearestFilter,
1967
+ 9985: LinearMipmapNearestFilter,
1968
+ 9986: NearestMipmapLinearFilter,
1969
+ 9987: LinearMipmapLinearFilter
1970
+ };
1971
+
1972
+ const WEBGL_WRAPPINGS = {
1973
+ 33071: ClampToEdgeWrapping,
1974
+ 33648: MirroredRepeatWrapping,
1975
+ 10497: RepeatWrapping
1976
+ };
1977
+
1978
+ const WEBGL_TYPE_SIZES = {
1979
+ 'SCALAR': 1,
1980
+ 'VEC2': 2,
1981
+ 'VEC3': 3,
1982
+ 'VEC4': 4,
1983
+ 'MAT2': 4,
1984
+ 'MAT3': 9,
1985
+ 'MAT4': 16
1986
+ };
1987
+
1988
+ const ATTRIBUTES = {
1989
+ POSITION: 'position',
1990
+ NORMAL: 'normal',
1991
+ TANGENT: 'tangent',
1992
+ TEXCOORD_0: 'uv',
1993
+ TEXCOORD_1: 'uv2',
1994
+ COLOR_0: 'color',
1995
+ WEIGHTS_0: 'skinWeight',
1996
+ JOINTS_0: 'skinIndex',
1997
+ };
1998
+
1999
+ const PATH_PROPERTIES = {
2000
+ scale: 'scale',
2001
+ translation: 'position',
2002
+ rotation: 'quaternion',
2003
+ weights: 'morphTargetInfluences'
2004
+ };
2005
+
2006
+ const INTERPOLATION = {
2007
+ CUBICSPLINE: undefined, // We use a custom interpolant (GLTFCubicSplineInterpolation) for CUBICSPLINE tracks. Each
2008
+ // keyframe track will be initialized with a default interpolation type, then modified.
2009
+ LINEAR: InterpolateLinear,
2010
+ STEP: InterpolateDiscrete
2011
+ };
2012
+
2013
+ const ALPHA_MODES = {
2014
+ OPAQUE: 'OPAQUE',
2015
+ MASK: 'MASK',
2016
+ BLEND: 'BLEND'
2017
+ };
2018
+
2019
+ /**
2020
+ * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#default-material
2021
+ */
2022
+ function createDefaultMaterial( cache ) {
2023
+
2024
+ if ( cache[ 'DefaultMaterial' ] === undefined ) {
2025
+
2026
+ cache[ 'DefaultMaterial' ] = new MeshStandardMaterial( {
2027
+ color: 0xFFFFFF,
2028
+ emissive: 0x000000,
2029
+ metalness: 1,
2030
+ roughness: 1,
2031
+ transparent: false,
2032
+ depthTest: true,
2033
+ side: FrontSide
2034
+ } );
2035
+
2036
+ }
2037
+
2038
+ return cache[ 'DefaultMaterial' ];
2039
+
2040
+ }
2041
+
2042
+ function addUnknownExtensionsToUserData( knownExtensions, object, objectDef ) {
2043
+
2044
+ // Add unknown glTF extensions to an object's userData.
2045
+
2046
+ for ( const name in objectDef.extensions ) {
2047
+
2048
+ if ( knownExtensions[ name ] === undefined ) {
2049
+
2050
+ object.userData.gltfExtensions = object.userData.gltfExtensions || {};
2051
+ object.userData.gltfExtensions[ name ] = objectDef.extensions[ name ];
2052
+
2053
+ }
2054
+
2055
+ }
2056
+
2057
+ }
2058
+
2059
+ /**
2060
+ * @param {Object3D|Material|BufferGeometry} object
2061
+ * @param {GLTF.definition} gltfDef
2062
+ */
2063
+ function assignExtrasToUserData( object, gltfDef ) {
2064
+
2065
+ if ( gltfDef.extras !== undefined ) {
2066
+
2067
+ if ( typeof gltfDef.extras === 'object' ) {
2068
+
2069
+ Object.assign( object.userData, gltfDef.extras );
2070
+
2071
+ } else {
2072
+
2073
+ console.warn( 'THREE.GLTFLoader: Ignoring primitive type .extras, ' + gltfDef.extras );
2074
+
2075
+ }
2076
+
2077
+ }
2078
+
2079
+ }
2080
+
2081
+ /**
2082
+ * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets
2083
+ *
2084
+ * @param {BufferGeometry} geometry
2085
+ * @param {Array<GLTF.Target>} targets
2086
+ * @param {GLTFParser} parser
2087
+ * @return {Promise<BufferGeometry>}
2088
+ */
2089
+ function addMorphTargets( geometry, targets, parser ) {
2090
+
2091
+ let hasMorphPosition = false;
2092
+ let hasMorphNormal = false;
2093
+ let hasMorphColor = false;
2094
+
2095
+ for ( let i = 0, il = targets.length; i < il; i ++ ) {
2096
+
2097
+ const target = targets[ i ];
2098
+
2099
+ if ( target.POSITION !== undefined ) hasMorphPosition = true;
2100
+ if ( target.NORMAL !== undefined ) hasMorphNormal = true;
2101
+ if ( target.COLOR_0 !== undefined ) hasMorphColor = true;
2102
+
2103
+ if ( hasMorphPosition && hasMorphNormal && hasMorphColor ) break;
2104
+
2105
+ }
2106
+
2107
+ if ( ! hasMorphPosition && ! hasMorphNormal && ! hasMorphColor ) return Promise.resolve( geometry );
2108
+
2109
+ const pendingPositionAccessors = [];
2110
+ const pendingNormalAccessors = [];
2111
+ const pendingColorAccessors = [];
2112
+
2113
+ for ( let i = 0, il = targets.length; i < il; i ++ ) {
2114
+
2115
+ const target = targets[ i ];
2116
+
2117
+ if ( hasMorphPosition ) {
2118
+
2119
+ const pendingAccessor = target.POSITION !== undefined
2120
+ ? parser.getDependency( 'accessor', target.POSITION )
2121
+ : geometry.attributes.position;
2122
+
2123
+ pendingPositionAccessors.push( pendingAccessor );
2124
+
2125
+ }
2126
+
2127
+ if ( hasMorphNormal ) {
2128
+
2129
+ const pendingAccessor = target.NORMAL !== undefined
2130
+ ? parser.getDependency( 'accessor', target.NORMAL )
2131
+ : geometry.attributes.normal;
2132
+
2133
+ pendingNormalAccessors.push( pendingAccessor );
2134
+
2135
+ }
2136
+
2137
+ if ( hasMorphColor ) {
2138
+
2139
+ const pendingAccessor = target.COLOR_0 !== undefined
2140
+ ? parser.getDependency( 'accessor', target.COLOR_0 )
2141
+ : geometry.attributes.color;
2142
+
2143
+ pendingColorAccessors.push( pendingAccessor );
2144
+
2145
+ }
2146
+
2147
+ }
2148
+
2149
+ return Promise.all( [
2150
+ Promise.all( pendingPositionAccessors ),
2151
+ Promise.all( pendingNormalAccessors ),
2152
+ Promise.all( pendingColorAccessors )
2153
+ ] ).then( function ( accessors ) {
2154
+
2155
+ const morphPositions = accessors[ 0 ];
2156
+ const morphNormals = accessors[ 1 ];
2157
+ const morphColors = accessors[ 2 ];
2158
+
2159
+ if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions;
2160
+ if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;
2161
+ if ( hasMorphColor ) geometry.morphAttributes.color = morphColors;
2162
+ geometry.morphTargetsRelative = true;
2163
+
2164
+ return geometry;
2165
+
2166
+ } );
2167
+
2168
+ }
2169
+
2170
+ /**
2171
+ * @param {Mesh} mesh
2172
+ * @param {GLTF.Mesh} meshDef
2173
+ */
2174
+ function updateMorphTargets( mesh, meshDef ) {
2175
+
2176
+ mesh.updateMorphTargets();
2177
+
2178
+ if ( meshDef.weights !== undefined ) {
2179
+
2180
+ for ( let i = 0, il = meshDef.weights.length; i < il; i ++ ) {
2181
+
2182
+ mesh.morphTargetInfluences[ i ] = meshDef.weights[ i ];
2183
+
2184
+ }
2185
+
2186
+ }
2187
+
2188
+ // .extras has user-defined data, so check that .extras.targetNames is an array.
2189
+ if ( meshDef.extras && Array.isArray( meshDef.extras.targetNames ) ) {
2190
+
2191
+ const targetNames = meshDef.extras.targetNames;
2192
+
2193
+ if ( mesh.morphTargetInfluences.length === targetNames.length ) {
2194
+
2195
+ mesh.morphTargetDictionary = {};
2196
+
2197
+ for ( let i = 0, il = targetNames.length; i < il; i ++ ) {
2198
+
2199
+ mesh.morphTargetDictionary[ targetNames[ i ] ] = i;
2200
+
2201
+ }
2202
+
2203
+ } else {
2204
+
2205
+ console.warn( 'THREE.GLTFLoader: Invalid extras.targetNames length. Ignoring names.' );
2206
+
2207
+ }
2208
+
2209
+ }
2210
+
2211
+ }
2212
+
2213
+ function createPrimitiveKey( primitiveDef ) {
2214
+
2215
+ const dracoExtension = primitiveDef.extensions && primitiveDef.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ];
2216
+ let geometryKey;
2217
+
2218
+ if ( dracoExtension ) {
2219
+
2220
+ geometryKey = 'draco:' + dracoExtension.bufferView
2221
+ + ':' + dracoExtension.indices
2222
+ + ':' + createAttributesKey( dracoExtension.attributes );
2223
+
2224
+ } else {
2225
+
2226
+ geometryKey = primitiveDef.indices + ':' + createAttributesKey( primitiveDef.attributes ) + ':' + primitiveDef.mode;
2227
+
2228
+ }
2229
+
2230
+ return geometryKey;
2231
+
2232
+ }
2233
+
2234
+ function createAttributesKey( attributes ) {
2235
+
2236
+ let attributesKey = '';
2237
+
2238
+ const keys = Object.keys( attributes ).sort();
2239
+
2240
+ for ( let i = 0, il = keys.length; i < il; i ++ ) {
2241
+
2242
+ attributesKey += keys[ i ] + ':' + attributes[ keys[ i ] ] + ';';
2243
+
2244
+ }
2245
+
2246
+ return attributesKey;
2247
+
2248
+ }
2249
+
2250
+ function getNormalizedComponentScale( constructor ) {
2251
+
2252
+ // Reference:
2253
+ // https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_mesh_quantization#encoding-quantized-data
2254
+
2255
+ switch ( constructor ) {
2256
+
2257
+ case Int8Array:
2258
+ return 1 / 127;
2259
+
2260
+ case Uint8Array:
2261
+ return 1 / 255;
2262
+
2263
+ case Int16Array:
2264
+ return 1 / 32767;
2265
+
2266
+ case Uint16Array:
2267
+ return 1 / 65535;
2268
+
2269
+ default:
2270
+ throw new Error( 'THREE.GLTFLoader: Unsupported normalized accessor component type.' );
2271
+
2272
+ }
2273
+
2274
+ }
2275
+
2276
+ function getImageURIMimeType( uri ) {
2277
+
2278
+ if ( uri.search( /\.jpe?g($|\?)/i ) > 0 || uri.search( /^data\:image\/jpeg/ ) === 0 ) return 'image/jpeg';
2279
+ if ( uri.search( /\.webp($|\?)/i ) > 0 || uri.search( /^data\:image\/webp/ ) === 0 ) return 'image/webp';
2280
+
2281
+ return 'image/png';
2282
+
2283
+ }
2284
+
2285
+ /* GLTF PARSER */
2286
+
2287
+ class GLTFParser {
2288
+
2289
+ constructor( json = {}, options = {} ) {
2290
+
2291
+ this.json = json;
2292
+ this.extensions = {};
2293
+ this.plugins = {};
2294
+ this.options = options;
2295
+
2296
+ // loader object cache
2297
+ this.cache = new GLTFRegistry();
2298
+
2299
+ // associations between Three.js objects and glTF elements
2300
+ this.associations = new Map();
2301
+
2302
+ // BufferGeometry caching
2303
+ this.primitiveCache = {};
2304
+
2305
+ // Object3D instance caches
2306
+ this.meshCache = { refs: {}, uses: {} };
2307
+ this.cameraCache = { refs: {}, uses: {} };
2308
+ this.lightCache = { refs: {}, uses: {} };
2309
+
2310
+ this.sourceCache = {};
2311
+ this.textureCache = {};
2312
+
2313
+ // Track node names, to ensure no duplicates
2314
+ this.nodeNamesUsed = {};
2315
+
2316
+ // Use an ImageBitmapLoader if imageBitmaps are supported. Moves much of the
2317
+ // expensive work of uploading a texture to the GPU off the main thread.
2318
+ if ( typeof createImageBitmap !== 'undefined' && /^((?!chrome|android).)*safari/i.test( navigator.userAgent ) === false ) {
2319
+
2320
+ this.textureLoader = new ImageBitmapLoader( this.options.manager );
2321
+
2322
+ } else {
2323
+
2324
+ this.textureLoader = new TextureLoader( this.options.manager );
2325
+
2326
+ }
2327
+
2328
+ this.textureLoader.setCrossOrigin( this.options.crossOrigin );
2329
+ this.textureLoader.setRequestHeader( this.options.requestHeader );
2330
+
2331
+ this.fileLoader = new FileLoader( this.options.manager );
2332
+ this.fileLoader.setResponseType( 'arraybuffer' );
2333
+
2334
+ if ( this.options.crossOrigin === 'use-credentials' ) {
2335
+
2336
+ this.fileLoader.setWithCredentials( true );
2337
+
2338
+ }
2339
+
2340
+ }
2341
+
2342
+ setExtensions( extensions ) {
2343
+
2344
+ this.extensions = extensions;
2345
+
2346
+ }
2347
+
2348
+ setPlugins( plugins ) {
2349
+
2350
+ this.plugins = plugins;
2351
+
2352
+ }
2353
+
2354
+ parse( onLoad, onError ) {
2355
+
2356
+ const parser = this;
2357
+ const json = this.json;
2358
+ const extensions = this.extensions;
2359
+
2360
+ // Clear the loader cache
2361
+ this.cache.removeAll();
2362
+
2363
+ // Mark the special nodes/meshes in json for efficient parse
2364
+ this._invokeAll( function ( ext ) {
2365
+
2366
+ return ext._markDefs && ext._markDefs();
2367
+
2368
+ } );
2369
+
2370
+ Promise.all( this._invokeAll( function ( ext ) {
2371
+
2372
+ return ext.beforeRoot && ext.beforeRoot();
2373
+
2374
+ } ) ).then( function () {
2375
+
2376
+ return Promise.all( [
2377
+
2378
+ parser.getDependencies( 'scene' ),
2379
+ parser.getDependencies( 'animation' ),
2380
+ parser.getDependencies( 'camera' ),
2381
+
2382
+ ] );
2383
+
2384
+ } ).then( function ( dependencies ) {
2385
+
2386
+ const result = {
2387
+ scene: dependencies[ 0 ][ json.scene || 0 ],
2388
+ scenes: dependencies[ 0 ],
2389
+ animations: dependencies[ 1 ],
2390
+ cameras: dependencies[ 2 ],
2391
+ asset: json.asset,
2392
+ parser: parser,
2393
+ userData: {}
2394
+ };
2395
+
2396
+ addUnknownExtensionsToUserData( extensions, result, json );
2397
+
2398
+ assignExtrasToUserData( result, json );
2399
+
2400
+ Promise.all( parser._invokeAll( function ( ext ) {
2401
+
2402
+ return ext.afterRoot && ext.afterRoot( result );
2403
+
2404
+ } ) ).then( function () {
2405
+
2406
+ onLoad( result );
2407
+
2408
+ } );
2409
+
2410
+ } ).catch( onError );
2411
+
2412
+ }
2413
+
2414
+ /**
2415
+ * Marks the special nodes/meshes in json for efficient parse.
2416
+ */
2417
+ _markDefs() {
2418
+
2419
+ const nodeDefs = this.json.nodes || [];
2420
+ const skinDefs = this.json.skins || [];
2421
+ const meshDefs = this.json.meshes || [];
2422
+
2423
+ // Nothing in the node definition indicates whether it is a Bone or an
2424
+ // Object3D. Use the skins' joint references to mark bones.
2425
+ for ( let skinIndex = 0, skinLength = skinDefs.length; skinIndex < skinLength; skinIndex ++ ) {
2426
+
2427
+ const joints = skinDefs[ skinIndex ].joints;
2428
+
2429
+ for ( let i = 0, il = joints.length; i < il; i ++ ) {
2430
+
2431
+ nodeDefs[ joints[ i ] ].isBone = true;
2432
+
2433
+ }
2434
+
2435
+ }
2436
+
2437
+ // Iterate over all nodes, marking references to shared resources,
2438
+ // as well as skeleton joints.
2439
+ for ( let nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex ++ ) {
2440
+
2441
+ const nodeDef = nodeDefs[ nodeIndex ];
2442
+
2443
+ if ( nodeDef.mesh !== undefined ) {
2444
+
2445
+ this._addNodeRef( this.meshCache, nodeDef.mesh );
2446
+
2447
+ // Nothing in the mesh definition indicates whether it is
2448
+ // a SkinnedMesh or Mesh. Use the node's mesh reference
2449
+ // to mark SkinnedMesh if node has skin.
2450
+ if ( nodeDef.skin !== undefined ) {
2451
+
2452
+ meshDefs[ nodeDef.mesh ].isSkinnedMesh = true;
2453
+
2454
+ }
2455
+
2456
+ }
2457
+
2458
+ if ( nodeDef.camera !== undefined ) {
2459
+
2460
+ this._addNodeRef( this.cameraCache, nodeDef.camera );
2461
+
2462
+ }
2463
+
2464
+ }
2465
+
2466
+ }
2467
+
2468
+ /**
2469
+ * Counts references to shared node / Object3D resources. These resources
2470
+ * can be reused, or "instantiated", at multiple nodes in the scene
2471
+ * hierarchy. Mesh, Camera, and Light instances are instantiated and must
2472
+ * be marked. Non-scenegraph resources (like Materials, Geometries, and
2473
+ * Textures) can be reused directly and are not marked here.
2474
+ *
2475
+ * Example: CesiumMilkTruck sample model reuses "Wheel" meshes.
2476
+ */
2477
+ _addNodeRef( cache, index ) {
2478
+
2479
+ if ( index === undefined ) return;
2480
+
2481
+ if ( cache.refs[ index ] === undefined ) {
2482
+
2483
+ cache.refs[ index ] = cache.uses[ index ] = 0;
2484
+
2485
+ }
2486
+
2487
+ cache.refs[ index ] ++;
2488
+
2489
+ }
2490
+
2491
+ /** Returns a reference to a shared resource, cloning it if necessary. */
2492
+ _getNodeRef( cache, index, object ) {
2493
+
2494
+ if ( cache.refs[ index ] <= 1 ) return object;
2495
+
2496
+ const ref = object.clone();
2497
+
2498
+ // Propagates mappings to the cloned object, prevents mappings on the
2499
+ // original object from being lost.
2500
+ const updateMappings = ( original, clone ) => {
2501
+
2502
+ const mappings = this.associations.get( original );
2503
+ if ( mappings != null ) {
2504
+
2505
+ this.associations.set( clone, mappings );
2506
+
2507
+ }
2508
+
2509
+ for ( const [ i, child ] of original.children.entries() ) {
2510
+
2511
+ updateMappings( child, clone.children[ i ] );
2512
+
2513
+ }
2514
+
2515
+ };
2516
+
2517
+ updateMappings( object, ref );
2518
+
2519
+ ref.name += '_instance_' + ( cache.uses[ index ] ++ );
2520
+
2521
+ return ref;
2522
+
2523
+ }
2524
+
2525
+ _invokeOne( func ) {
2526
+
2527
+ const extensions = Object.values( this.plugins );
2528
+ extensions.push( this );
2529
+
2530
+ for ( let i = 0; i < extensions.length; i ++ ) {
2531
+
2532
+ const result = func( extensions[ i ] );
2533
+
2534
+ if ( result ) return result;
2535
+
2536
+ }
2537
+
2538
+ return null;
2539
+
2540
+ }
2541
+
2542
+ _invokeAll( func ) {
2543
+
2544
+ const extensions = Object.values( this.plugins );
2545
+ extensions.unshift( this );
2546
+
2547
+ const pending = [];
2548
+
2549
+ for ( let i = 0; i < extensions.length; i ++ ) {
2550
+
2551
+ const result = func( extensions[ i ] );
2552
+
2553
+ if ( result ) pending.push( result );
2554
+
2555
+ }
2556
+
2557
+ return pending;
2558
+
2559
+ }
2560
+
2561
+ /**
2562
+ * Requests the specified dependency asynchronously, with caching.
2563
+ * @param {string} type
2564
+ * @param {number} index
2565
+ * @return {Promise<Object3D|Material|THREE.Texture|AnimationClip|ArrayBuffer|Object>}
2566
+ */
2567
+ getDependency( type, index ) {
2568
+
2569
+ const cacheKey = type + ':' + index;
2570
+ let dependency = this.cache.get( cacheKey );
2571
+
2572
+ if ( ! dependency ) {
2573
+
2574
+ switch ( type ) {
2575
+
2576
+ case 'scene':
2577
+ dependency = this.loadScene( index );
2578
+ break;
2579
+
2580
+ case 'node':
2581
+ dependency = this.loadNode( index );
2582
+ break;
2583
+
2584
+ case 'mesh':
2585
+ dependency = this._invokeOne( function ( ext ) {
2586
+
2587
+ return ext.loadMesh && ext.loadMesh( index );
2588
+
2589
+ } );
2590
+ break;
2591
+
2592
+ case 'accessor':
2593
+ dependency = this.loadAccessor( index );
2594
+ break;
2595
+
2596
+ case 'bufferView':
2597
+ dependency = this._invokeOne( function ( ext ) {
2598
+
2599
+ return ext.loadBufferView && ext.loadBufferView( index );
2600
+
2601
+ } );
2602
+ break;
2603
+
2604
+ case 'buffer':
2605
+ dependency = this.loadBuffer( index );
2606
+ break;
2607
+
2608
+ case 'material':
2609
+ dependency = this._invokeOne( function ( ext ) {
2610
+
2611
+ return ext.loadMaterial && ext.loadMaterial( index );
2612
+
2613
+ } );
2614
+ break;
2615
+
2616
+ case 'texture':
2617
+ dependency = this._invokeOne( function ( ext ) {
2618
+
2619
+ return ext.loadTexture && ext.loadTexture( index );
2620
+
2621
+ } );
2622
+ break;
2623
+
2624
+ case 'skin':
2625
+ dependency = this.loadSkin( index );
2626
+ break;
2627
+
2628
+ case 'animation':
2629
+ dependency = this._invokeOne( function ( ext ) {
2630
+
2631
+ return ext.loadAnimation && ext.loadAnimation( index );
2632
+
2633
+ } );
2634
+ break;
2635
+
2636
+ case 'camera':
2637
+ dependency = this.loadCamera( index );
2638
+ break;
2639
+
2640
+ default:
2641
+ throw new Error( 'Unknown type: ' + type );
2642
+
2643
+ }
2644
+
2645
+ this.cache.add( cacheKey, dependency );
2646
+
2647
+ }
2648
+
2649
+ return dependency;
2650
+
2651
+ }
2652
+
2653
+ /**
2654
+ * Requests all dependencies of the specified type asynchronously, with caching.
2655
+ * @param {string} type
2656
+ * @return {Promise<Array<Object>>}
2657
+ */
2658
+ getDependencies( type ) {
2659
+
2660
+ let dependencies = this.cache.get( type );
2661
+
2662
+ if ( ! dependencies ) {
2663
+
2664
+ const parser = this;
2665
+ const defs = this.json[ type + ( type === 'mesh' ? 'es' : 's' ) ] || [];
2666
+
2667
+ dependencies = Promise.all( defs.map( function ( def, index ) {
2668
+
2669
+ return parser.getDependency( type, index );
2670
+
2671
+ } ) );
2672
+
2673
+ this.cache.add( type, dependencies );
2674
+
2675
+ }
2676
+
2677
+ return dependencies;
2678
+
2679
+ }
2680
+
2681
+ /**
2682
+ * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views
2683
+ * @param {number} bufferIndex
2684
+ * @return {Promise<ArrayBuffer>}
2685
+ */
2686
+ loadBuffer( bufferIndex ) {
2687
+
2688
+ const bufferDef = this.json.buffers[ bufferIndex ];
2689
+ const loader = this.fileLoader;
2690
+
2691
+ if ( bufferDef.type && bufferDef.type !== 'arraybuffer' ) {
2692
+
2693
+ throw new Error( 'THREE.GLTFLoader: ' + bufferDef.type + ' buffer type is not supported.' );
2694
+
2695
+ }
2696
+
2697
+ // If present, GLB container is required to be the first buffer.
2698
+ if ( bufferDef.uri === undefined && bufferIndex === 0 ) {
2699
+
2700
+ return Promise.resolve( this.extensions[ EXTENSIONS.KHR_BINARY_GLTF ].body );
2701
+
2702
+ }
2703
+
2704
+ const options = this.options;
2705
+
2706
+ return new Promise( function ( resolve, reject ) {
2707
+
2708
+ loader.load( LoaderUtils.resolveURL( bufferDef.uri, options.path ), resolve, undefined, function () {
2709
+
2710
+ reject( new Error( 'THREE.GLTFLoader: Failed to load buffer "' + bufferDef.uri + '".' ) );
2711
+
2712
+ } );
2713
+
2714
+ } );
2715
+
2716
+ }
2717
+
2718
+ /**
2719
+ * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views
2720
+ * @param {number} bufferViewIndex
2721
+ * @return {Promise<ArrayBuffer>}
2722
+ */
2723
+ loadBufferView( bufferViewIndex ) {
2724
+
2725
+ const bufferViewDef = this.json.bufferViews[ bufferViewIndex ];
2726
+
2727
+ return this.getDependency( 'buffer', bufferViewDef.buffer ).then( function ( buffer ) {
2728
+
2729
+ const byteLength = bufferViewDef.byteLength || 0;
2730
+ const byteOffset = bufferViewDef.byteOffset || 0;
2731
+ return buffer.slice( byteOffset, byteOffset + byteLength );
2732
+
2733
+ } );
2734
+
2735
+ }
2736
+
2737
+ /**
2738
+ * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#accessors
2739
+ * @param {number} accessorIndex
2740
+ * @return {Promise<BufferAttribute|InterleavedBufferAttribute>}
2741
+ */
2742
+ loadAccessor( accessorIndex ) {
2743
+
2744
+ const parser = this;
2745
+ const json = this.json;
2746
+
2747
+ const accessorDef = this.json.accessors[ accessorIndex ];
2748
+
2749
+ if ( accessorDef.bufferView === undefined && accessorDef.sparse === undefined ) {
2750
+
2751
+ // Ignore empty accessors, which may be used to declare runtime
2752
+ // information about attributes coming from another source (e.g. Draco
2753
+ // compression extension).
2754
+ return Promise.resolve( null );
2755
+
2756
+ }
2757
+
2758
+ const pendingBufferViews = [];
2759
+
2760
+ if ( accessorDef.bufferView !== undefined ) {
2761
+
2762
+ pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.bufferView ) );
2763
+
2764
+ } else {
2765
+
2766
+ pendingBufferViews.push( null );
2767
+
2768
+ }
2769
+
2770
+ if ( accessorDef.sparse !== undefined ) {
2771
+
2772
+ pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.sparse.indices.bufferView ) );
2773
+ pendingBufferViews.push( this.getDependency( 'bufferView', accessorDef.sparse.values.bufferView ) );
2774
+
2775
+ }
2776
+
2777
+ return Promise.all( pendingBufferViews ).then( function ( bufferViews ) {
2778
+
2779
+ const bufferView = bufferViews[ 0 ];
2780
+
2781
+ const itemSize = WEBGL_TYPE_SIZES[ accessorDef.type ];
2782
+ const TypedArray = WEBGL_COMPONENT_TYPES[ accessorDef.componentType ];
2783
+
2784
+ // For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12.
2785
+ const elementBytes = TypedArray.BYTES_PER_ELEMENT;
2786
+ const itemBytes = elementBytes * itemSize;
2787
+ const byteOffset = accessorDef.byteOffset || 0;
2788
+ const byteStride = accessorDef.bufferView !== undefined ? json.bufferViews[ accessorDef.bufferView ].byteStride : undefined;
2789
+ const normalized = accessorDef.normalized === true;
2790
+ let array, bufferAttribute;
2791
+
2792
+ // The buffer is not interleaved if the stride is the item size in bytes.
2793
+ if ( byteStride && byteStride !== itemBytes ) {
2794
+
2795
+ // Each "slice" of the buffer, as defined by 'count' elements of 'byteStride' bytes, gets its own InterleavedBuffer
2796
+ // This makes sure that IBA.count reflects accessor.count properly
2797
+ const ibSlice = Math.floor( byteOffset / byteStride );
2798
+ const ibCacheKey = 'InterleavedBuffer:' + accessorDef.bufferView + ':' + accessorDef.componentType + ':' + ibSlice + ':' + accessorDef.count;
2799
+ let ib = parser.cache.get( ibCacheKey );
2800
+
2801
+ if ( ! ib ) {
2802
+
2803
+ array = new TypedArray( bufferView, ibSlice * byteStride, accessorDef.count * byteStride / elementBytes );
2804
+
2805
+ // Integer parameters to IB/IBA are in array elements, not bytes.
2806
+ ib = new InterleavedBuffer( array, byteStride / elementBytes );
2807
+
2808
+ parser.cache.add( ibCacheKey, ib );
2809
+
2810
+ }
2811
+
2812
+ bufferAttribute = new InterleavedBufferAttribute( ib, itemSize, ( byteOffset % byteStride ) / elementBytes, normalized );
2813
+
2814
+ } else {
2815
+
2816
+ if ( bufferView === null ) {
2817
+
2818
+ array = new TypedArray( accessorDef.count * itemSize );
2819
+
2820
+ } else {
2821
+
2822
+ array = new TypedArray( bufferView, byteOffset, accessorDef.count * itemSize );
2823
+
2824
+ }
2825
+
2826
+ bufferAttribute = new BufferAttribute( array, itemSize, normalized );
2827
+
2828
+ }
2829
+
2830
+ // https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#sparse-accessors
2831
+ if ( accessorDef.sparse !== undefined ) {
2832
+
2833
+ const itemSizeIndices = WEBGL_TYPE_SIZES.SCALAR;
2834
+ const TypedArrayIndices = WEBGL_COMPONENT_TYPES[ accessorDef.sparse.indices.componentType ];
2835
+
2836
+ const byteOffsetIndices = accessorDef.sparse.indices.byteOffset || 0;
2837
+ const byteOffsetValues = accessorDef.sparse.values.byteOffset || 0;
2838
+
2839
+ const sparseIndices = new TypedArrayIndices( bufferViews[ 1 ], byteOffsetIndices, accessorDef.sparse.count * itemSizeIndices );
2840
+ const sparseValues = new TypedArray( bufferViews[ 2 ], byteOffsetValues, accessorDef.sparse.count * itemSize );
2841
+
2842
+ if ( bufferView !== null ) {
2843
+
2844
+ // Avoid modifying the original ArrayBuffer, if the bufferView wasn't initialized with zeroes.
2845
+ bufferAttribute = new BufferAttribute( bufferAttribute.array.slice(), bufferAttribute.itemSize, bufferAttribute.normalized );
2846
+
2847
+ }
2848
+
2849
+ for ( let i = 0, il = sparseIndices.length; i < il; i ++ ) {
2850
+
2851
+ const index = sparseIndices[ i ];
2852
+
2853
+ bufferAttribute.setX( index, sparseValues[ i * itemSize ] );
2854
+ if ( itemSize >= 2 ) bufferAttribute.setY( index, sparseValues[ i * itemSize + 1 ] );
2855
+ if ( itemSize >= 3 ) bufferAttribute.setZ( index, sparseValues[ i * itemSize + 2 ] );
2856
+ if ( itemSize >= 4 ) bufferAttribute.setW( index, sparseValues[ i * itemSize + 3 ] );
2857
+ if ( itemSize >= 5 ) throw new Error( 'THREE.GLTFLoader: Unsupported itemSize in sparse BufferAttribute.' );
2858
+
2859
+ }
2860
+
2861
+ }
2862
+
2863
+ return bufferAttribute;
2864
+
2865
+ } );
2866
+
2867
+ }
2868
+
2869
+ /**
2870
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#textures
2871
+ * @param {number} textureIndex
2872
+ * @return {Promise<THREE.Texture>}
2873
+ */
2874
+ loadTexture( textureIndex ) {
2875
+
2876
+ const json = this.json;
2877
+ const options = this.options;
2878
+ const textureDef = json.textures[ textureIndex ];
2879
+ const sourceIndex = textureDef.source;
2880
+ const sourceDef = json.images[ sourceIndex ];
2881
+
2882
+ let loader = this.textureLoader;
2883
+
2884
+ if ( sourceDef.uri ) {
2885
+
2886
+ const handler = options.manager.getHandler( sourceDef.uri );
2887
+ if ( handler !== null ) loader = handler;
2888
+
2889
+ }
2890
+
2891
+ return this.loadTextureImage( textureIndex, sourceIndex, loader );
2892
+
2893
+ }
2894
+
2895
+ loadTextureImage( textureIndex, sourceIndex, loader ) {
2896
+
2897
+ const parser = this;
2898
+ const json = this.json;
2899
+
2900
+ const textureDef = json.textures[ textureIndex ];
2901
+ const sourceDef = json.images[ sourceIndex ];
2902
+
2903
+ const cacheKey = ( sourceDef.uri || sourceDef.bufferView ) + ':' + textureDef.sampler;
2904
+
2905
+ if ( this.textureCache[ cacheKey ] ) {
2906
+
2907
+ // See https://github.com/mrdoob/three.js/issues/21559.
2908
+ return this.textureCache[ cacheKey ];
2909
+
2910
+ }
2911
+
2912
+ const promise = this.loadImageSource( sourceIndex, loader ).then( function ( texture ) {
2913
+
2914
+ texture.flipY = false;
2915
+
2916
+ if ( textureDef.name ) texture.name = textureDef.name;
2917
+
2918
+ const samplers = json.samplers || {};
2919
+ const sampler = samplers[ textureDef.sampler ] || {};
2920
+
2921
+ texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ] || LinearFilter;
2922
+ texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || LinearMipmapLinearFilter;
2923
+ texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ] || RepeatWrapping;
2924
+ texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ] || RepeatWrapping;
2925
+
2926
+ parser.associations.set( texture, { textures: textureIndex } );
2927
+
2928
+ return texture;
2929
+
2930
+ } ).catch( function () {
2931
+
2932
+ return null;
2933
+
2934
+ } );
2935
+
2936
+ this.textureCache[ cacheKey ] = promise;
2937
+
2938
+ return promise;
2939
+
2940
+ }
2941
+
2942
+ loadImageSource( sourceIndex, loader ) {
2943
+
2944
+ const parser = this;
2945
+ const json = this.json;
2946
+ const options = this.options;
2947
+
2948
+ if ( this.sourceCache[ sourceIndex ] !== undefined ) {
2949
+
2950
+ return this.sourceCache[ sourceIndex ].then( ( texture ) => texture.clone() );
2951
+
2952
+ }
2953
+
2954
+ const sourceDef = json.images[ sourceIndex ];
2955
+
2956
+ const URL = self.URL || self.webkitURL;
2957
+
2958
+ let sourceURI = sourceDef.uri || '';
2959
+ let isObjectURL = false;
2960
+
2961
+ if ( sourceDef.bufferView !== undefined ) {
2962
+
2963
+ // Load binary image data from bufferView, if provided.
2964
+
2965
+ sourceURI = parser.getDependency( 'bufferView', sourceDef.bufferView ).then( function ( bufferView ) {
2966
+
2967
+ isObjectURL = true;
2968
+ const blob = new Blob( [ bufferView ], { type: sourceDef.mimeType } );
2969
+ sourceURI = URL.createObjectURL( blob );
2970
+ return sourceURI;
2971
+
2972
+ } );
2973
+
2974
+ } else if ( sourceDef.uri === undefined ) {
2975
+
2976
+ throw new Error( 'THREE.GLTFLoader: Image ' + sourceIndex + ' is missing URI and bufferView' );
2977
+
2978
+ }
2979
+
2980
+ const promise = Promise.resolve( sourceURI ).then( function ( sourceURI ) {
2981
+
2982
+ return new Promise( function ( resolve, reject ) {
2983
+
2984
+ let onLoad = resolve;
2985
+
2986
+ if ( loader.isImageBitmapLoader === true ) {
2987
+
2988
+ onLoad = function ( imageBitmap ) {
2989
+
2990
+ const texture = new Texture( imageBitmap );
2991
+ texture.needsUpdate = true;
2992
+
2993
+ resolve( texture );
2994
+
2995
+ };
2996
+
2997
+ }
2998
+
2999
+ loader.load( LoaderUtils.resolveURL( sourceURI, options.path ), onLoad, undefined, reject );
3000
+
3001
+ } );
3002
+
3003
+ } ).then( function ( texture ) {
3004
+
3005
+ // Clean up resources and configure Texture.
3006
+
3007
+ if ( isObjectURL === true ) {
3008
+
3009
+ URL.revokeObjectURL( sourceURI );
3010
+
3011
+ }
3012
+
3013
+ texture.userData.mimeType = sourceDef.mimeType || getImageURIMimeType( sourceDef.uri );
3014
+
3015
+ return texture;
3016
+
3017
+ } ).catch( function ( error ) {
3018
+
3019
+ console.error( 'THREE.GLTFLoader: Couldn\'t load texture', sourceURI );
3020
+ throw error;
3021
+
3022
+ } );
3023
+
3024
+ this.sourceCache[ sourceIndex ] = promise;
3025
+ return promise;
3026
+
3027
+ }
3028
+
3029
+ /**
3030
+ * Asynchronously assigns a texture to the given material parameters.
3031
+ * @param {Object} materialParams
3032
+ * @param {string} mapName
3033
+ * @param {Object} mapDef
3034
+ * @return {Promise<Texture>}
3035
+ */
3036
+ assignTexture( materialParams, mapName, mapDef, encoding ) {
3037
+
3038
+ const parser = this;
3039
+
3040
+ return this.getDependency( 'texture', mapDef.index ).then( function ( texture ) {
3041
+
3042
+ // Materials sample aoMap from UV set 1 and other maps from UV set 0 - this can't be configured
3043
+ // However, we will copy UV set 0 to UV set 1 on demand for aoMap
3044
+ if ( mapDef.texCoord !== undefined && mapDef.texCoord != 0 && ! ( mapName === 'aoMap' && mapDef.texCoord == 1 ) ) {
3045
+
3046
+ console.warn( 'THREE.GLTFLoader: Custom UV set ' + mapDef.texCoord + ' for texture ' + mapName + ' not yet supported.' );
3047
+
3048
+ }
3049
+
3050
+ if ( parser.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] ) {
3051
+
3052
+ const transform = mapDef.extensions !== undefined ? mapDef.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] : undefined;
3053
+
3054
+ if ( transform ) {
3055
+
3056
+ const gltfReference = parser.associations.get( texture );
3057
+ texture = parser.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ].extendTexture( texture, transform );
3058
+ parser.associations.set( texture, gltfReference );
3059
+
3060
+ }
3061
+
3062
+ }
3063
+
3064
+ if ( encoding !== undefined ) {
3065
+
3066
+ texture.encoding = encoding;
3067
+
3068
+ }
3069
+
3070
+ materialParams[ mapName ] = texture;
3071
+
3072
+ return texture;
3073
+
3074
+ } );
3075
+
3076
+ }
3077
+
3078
+ /**
3079
+ * Assigns final material to a Mesh, Line, or Points instance. The instance
3080
+ * already has a material (generated from the glTF material options alone)
3081
+ * but reuse of the same glTF material may require multiple threejs materials
3082
+ * to accommodate different primitive types, defines, etc. New materials will
3083
+ * be created if necessary, and reused from a cache.
3084
+ * @param {Object3D} mesh Mesh, Line, or Points instance.
3085
+ */
3086
+ assignFinalMaterial( mesh ) {
3087
+
3088
+ const geometry = mesh.geometry;
3089
+ let material = mesh.material;
3090
+
3091
+ const useDerivativeTangents = geometry.attributes.tangent === undefined;
3092
+ const useVertexColors = geometry.attributes.color !== undefined;
3093
+ const useFlatShading = geometry.attributes.normal === undefined;
3094
+
3095
+ if ( mesh.isPoints ) {
3096
+
3097
+ const cacheKey = 'PointsMaterial:' + material.uuid;
3098
+
3099
+ let pointsMaterial = this.cache.get( cacheKey );
3100
+
3101
+ if ( ! pointsMaterial ) {
3102
+
3103
+ pointsMaterial = new PointsMaterial();
3104
+ Material.prototype.copy.call( pointsMaterial, material );
3105
+ pointsMaterial.color.copy( material.color );
3106
+ pointsMaterial.map = material.map;
3107
+ pointsMaterial.sizeAttenuation = false; // glTF spec says points should be 1px
3108
+
3109
+ this.cache.add( cacheKey, pointsMaterial );
3110
+
3111
+ }
3112
+
3113
+ material = pointsMaterial;
3114
+
3115
+ } else if ( mesh.isLine ) {
3116
+
3117
+ const cacheKey = 'LineBasicMaterial:' + material.uuid;
3118
+
3119
+ let lineMaterial = this.cache.get( cacheKey );
3120
+
3121
+ if ( ! lineMaterial ) {
3122
+
3123
+ lineMaterial = new LineBasicMaterial();
3124
+ Material.prototype.copy.call( lineMaterial, material );
3125
+ lineMaterial.color.copy( material.color );
3126
+
3127
+ this.cache.add( cacheKey, lineMaterial );
3128
+
3129
+ }
3130
+
3131
+ material = lineMaterial;
3132
+
3133
+ }
3134
+
3135
+ // Clone the material if it will be modified
3136
+ if ( useDerivativeTangents || useVertexColors || useFlatShading ) {
3137
+
3138
+ let cacheKey = 'ClonedMaterial:' + material.uuid + ':';
3139
+
3140
+ if ( material.isGLTFSpecularGlossinessMaterial ) cacheKey += 'specular-glossiness:';
3141
+ if ( useDerivativeTangents ) cacheKey += 'derivative-tangents:';
3142
+ if ( useVertexColors ) cacheKey += 'vertex-colors:';
3143
+ if ( useFlatShading ) cacheKey += 'flat-shading:';
3144
+
3145
+ let cachedMaterial = this.cache.get( cacheKey );
3146
+
3147
+ if ( ! cachedMaterial ) {
3148
+
3149
+ cachedMaterial = material.clone();
3150
+
3151
+ if ( useVertexColors ) cachedMaterial.vertexColors = true;
3152
+ if ( useFlatShading ) cachedMaterial.flatShading = true;
3153
+
3154
+ if ( useDerivativeTangents ) {
3155
+
3156
+ // https://github.com/mrdoob/three.js/issues/11438#issuecomment-507003995
3157
+ if ( cachedMaterial.normalScale ) cachedMaterial.normalScale.y *= - 1;
3158
+ if ( cachedMaterial.clearcoatNormalScale ) cachedMaterial.clearcoatNormalScale.y *= - 1;
3159
+
3160
+ }
3161
+
3162
+ this.cache.add( cacheKey, cachedMaterial );
3163
+
3164
+ this.associations.set( cachedMaterial, this.associations.get( material ) );
3165
+
3166
+ }
3167
+
3168
+ material = cachedMaterial;
3169
+
3170
+ }
3171
+
3172
+ // workarounds for mesh and geometry
3173
+
3174
+ if ( material.aoMap && geometry.attributes.uv2 === undefined && geometry.attributes.uv !== undefined ) {
3175
+
3176
+ geometry.setAttribute( 'uv2', geometry.attributes.uv );
3177
+
3178
+ }
3179
+
3180
+ mesh.material = material;
3181
+
3182
+ }
3183
+
3184
+ getMaterialType( /* materialIndex */ ) {
3185
+
3186
+ return MeshStandardMaterial;
3187
+
3188
+ }
3189
+
3190
+ /**
3191
+ * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#materials
3192
+ * @param {number} materialIndex
3193
+ * @return {Promise<Material>}
3194
+ */
3195
+ loadMaterial( materialIndex ) {
3196
+
3197
+ const parser = this;
3198
+ const json = this.json;
3199
+ const extensions = this.extensions;
3200
+ const materialDef = json.materials[ materialIndex ];
3201
+
3202
+ let materialType;
3203
+ const materialParams = {};
3204
+ const materialExtensions = materialDef.extensions || {};
3205
+
3206
+ const pending = [];
3207
+
3208
+ if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ] ) {
3209
+
3210
+ const sgExtension = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ];
3211
+ materialType = sgExtension.getMaterialType();
3212
+ pending.push( sgExtension.extendParams( materialParams, materialDef, parser ) );
3213
+
3214
+ } else if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ] ) {
3215
+
3216
+ const kmuExtension = extensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ];
3217
+ materialType = kmuExtension.getMaterialType();
3218
+ pending.push( kmuExtension.extendParams( materialParams, materialDef, parser ) );
3219
+
3220
+ } else {
3221
+
3222
+ // Specification:
3223
+ // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material
3224
+
3225
+ const metallicRoughness = materialDef.pbrMetallicRoughness || {};
3226
+
3227
+ materialParams.color = new Color( 1.0, 1.0, 1.0 );
3228
+ materialParams.opacity = 1.0;
3229
+
3230
+ if ( Array.isArray( metallicRoughness.baseColorFactor ) ) {
3231
+
3232
+ const array = metallicRoughness.baseColorFactor;
3233
+
3234
+ materialParams.color.fromArray( array );
3235
+ materialParams.opacity = array[ 3 ];
3236
+
3237
+ }
3238
+
3239
+ if ( metallicRoughness.baseColorTexture !== undefined ) {
3240
+
3241
+ pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture, sRGBEncoding ) );
3242
+
3243
+ }
3244
+
3245
+ materialParams.metalness = metallicRoughness.metallicFactor !== undefined ? metallicRoughness.metallicFactor : 1.0;
3246
+ materialParams.roughness = metallicRoughness.roughnessFactor !== undefined ? metallicRoughness.roughnessFactor : 1.0;
3247
+
3248
+ if ( metallicRoughness.metallicRoughnessTexture !== undefined ) {
3249
+
3250
+ pending.push( parser.assignTexture( materialParams, 'metalnessMap', metallicRoughness.metallicRoughnessTexture ) );
3251
+ pending.push( parser.assignTexture( materialParams, 'roughnessMap', metallicRoughness.metallicRoughnessTexture ) );
3252
+
3253
+ }
3254
+
3255
+ materialType = this._invokeOne( function ( ext ) {
3256
+
3257
+ return ext.getMaterialType && ext.getMaterialType( materialIndex );
3258
+
3259
+ } );
3260
+
3261
+ pending.push( Promise.all( this._invokeAll( function ( ext ) {
3262
+
3263
+ return ext.extendMaterialParams && ext.extendMaterialParams( materialIndex, materialParams );
3264
+
3265
+ } ) ) );
3266
+
3267
+ }
3268
+
3269
+ if ( materialDef.doubleSided === true ) {
3270
+
3271
+ materialParams.side = DoubleSide;
3272
+
3273
+ }
3274
+
3275
+ const alphaMode = materialDef.alphaMode || ALPHA_MODES.OPAQUE;
3276
+
3277
+ if ( alphaMode === ALPHA_MODES.BLEND ) {
3278
+
3279
+ materialParams.transparent = true;
3280
+
3281
+ // See: https://github.com/mrdoob/three.js/issues/17706
3282
+ materialParams.depthWrite = false;
3283
+
3284
+ } else {
3285
+
3286
+ materialParams.transparent = false;
3287
+
3288
+ if ( alphaMode === ALPHA_MODES.MASK ) {
3289
+
3290
+ materialParams.alphaTest = materialDef.alphaCutoff !== undefined ? materialDef.alphaCutoff : 0.5;
3291
+
3292
+ }
3293
+
3294
+ }
3295
+
3296
+ if ( materialDef.normalTexture !== undefined && materialType !== MeshBasicMaterial ) {
3297
+
3298
+ pending.push( parser.assignTexture( materialParams, 'normalMap', materialDef.normalTexture ) );
3299
+
3300
+ materialParams.normalScale = new Vector2( 1, 1 );
3301
+
3302
+ if ( materialDef.normalTexture.scale !== undefined ) {
3303
+
3304
+ const scale = materialDef.normalTexture.scale;
3305
+
3306
+ materialParams.normalScale.set( scale, scale );
3307
+
3308
+ }
3309
+
3310
+ }
3311
+
3312
+ if ( materialDef.occlusionTexture !== undefined && materialType !== MeshBasicMaterial ) {
3313
+
3314
+ pending.push( parser.assignTexture( materialParams, 'aoMap', materialDef.occlusionTexture ) );
3315
+
3316
+ if ( materialDef.occlusionTexture.strength !== undefined ) {
3317
+
3318
+ materialParams.aoMapIntensity = materialDef.occlusionTexture.strength;
3319
+
3320
+ }
3321
+
3322
+ }
3323
+
3324
+ if ( materialDef.emissiveFactor !== undefined && materialType !== MeshBasicMaterial ) {
3325
+
3326
+ materialParams.emissive = new Color().fromArray( materialDef.emissiveFactor );
3327
+
3328
+ }
3329
+
3330
+ if ( materialDef.emissiveTexture !== undefined && materialType !== MeshBasicMaterial ) {
3331
+
3332
+ pending.push( parser.assignTexture( materialParams, 'emissiveMap', materialDef.emissiveTexture, sRGBEncoding ) );
3333
+
3334
+ }
3335
+
3336
+ return Promise.all( pending ).then( function () {
3337
+
3338
+ let material;
3339
+
3340
+ if ( materialType === GLTFMeshStandardSGMaterial ) {
3341
+
3342
+ material = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].createMaterial( materialParams );
3343
+
3344
+ } else {
3345
+
3346
+ material = new materialType( materialParams );
3347
+
3348
+ }
3349
+
3350
+ if ( materialDef.name ) material.name = materialDef.name;
3351
+
3352
+ assignExtrasToUserData( material, materialDef );
3353
+
3354
+ parser.associations.set( material, { materials: materialIndex } );
3355
+
3356
+ if ( materialDef.extensions ) addUnknownExtensionsToUserData( extensions, material, materialDef );
3357
+
3358
+ return material;
3359
+
3360
+ } );
3361
+
3362
+ }
3363
+
3364
+ /** When Object3D instances are targeted by animation, they need unique names. */
3365
+ createUniqueName( originalName ) {
3366
+
3367
+ const sanitizedName = PropertyBinding.sanitizeNodeName( originalName || '' );
3368
+
3369
+ let name = sanitizedName;
3370
+
3371
+ for ( let i = 1; this.nodeNamesUsed[ name ]; ++ i ) {
3372
+
3373
+ name = sanitizedName + '_' + i;
3374
+
3375
+ }
3376
+
3377
+ this.nodeNamesUsed[ name ] = true;
3378
+
3379
+ return name;
3380
+
3381
+ }
3382
+
3383
+ /**
3384
+ * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#geometry
3385
+ *
3386
+ * Creates BufferGeometries from primitives.
3387
+ *
3388
+ * @param {Array<GLTF.Primitive>} primitives
3389
+ * @return {Promise<Array<BufferGeometry>>}
3390
+ */
3391
+ loadGeometries( primitives ) {
3392
+
3393
+ const parser = this;
3394
+ const extensions = this.extensions;
3395
+ const cache = this.primitiveCache;
3396
+
3397
+ function createDracoPrimitive( primitive ) {
3398
+
3399
+ return extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ]
3400
+ .decodePrimitive( primitive, parser )
3401
+ .then( function ( geometry ) {
3402
+
3403
+ return addPrimitiveAttributes( geometry, primitive, parser );
3404
+
3405
+ } );
3406
+
3407
+ }
3408
+
3409
+ const pending = [];
3410
+
3411
+ for ( let i = 0, il = primitives.length; i < il; i ++ ) {
3412
+
3413
+ const primitive = primitives[ i ];
3414
+ const cacheKey = createPrimitiveKey( primitive );
3415
+
3416
+ // See if we've already created this geometry
3417
+ const cached = cache[ cacheKey ];
3418
+
3419
+ if ( cached ) {
3420
+
3421
+ // Use the cached geometry if it exists
3422
+ pending.push( cached.promise );
3423
+
3424
+ } else {
3425
+
3426
+ let geometryPromise;
3427
+
3428
+ if ( primitive.extensions && primitive.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ] ) {
3429
+
3430
+ // Use DRACO geometry if available
3431
+ geometryPromise = createDracoPrimitive( primitive );
3432
+
3433
+ } else {
3434
+
3435
+ // Otherwise create a new geometry
3436
+ geometryPromise = addPrimitiveAttributes( new BufferGeometry(), primitive, parser );
3437
+
3438
+ }
3439
+
3440
+ // Cache this geometry
3441
+ cache[ cacheKey ] = { primitive: primitive, promise: geometryPromise };
3442
+
3443
+ pending.push( geometryPromise );
3444
+
3445
+ }
3446
+
3447
+ }
3448
+
3449
+ return Promise.all( pending );
3450
+
3451
+ }
3452
+
3453
+ /**
3454
+ * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#meshes
3455
+ * @param {number} meshIndex
3456
+ * @return {Promise<Group|Mesh|SkinnedMesh>}
3457
+ */
3458
+ loadMesh( meshIndex ) {
3459
+
3460
+ const parser = this;
3461
+ const json = this.json;
3462
+ const extensions = this.extensions;
3463
+
3464
+ const meshDef = json.meshes[ meshIndex ];
3465
+ const primitives = meshDef.primitives;
3466
+
3467
+ const pending = [];
3468
+
3469
+ for ( let i = 0, il = primitives.length; i < il; i ++ ) {
3470
+
3471
+ const material = primitives[ i ].material === undefined
3472
+ ? createDefaultMaterial( this.cache )
3473
+ : this.getDependency( 'material', primitives[ i ].material );
3474
+
3475
+ pending.push( material );
3476
+
3477
+ }
3478
+
3479
+ pending.push( parser.loadGeometries( primitives ) );
3480
+
3481
+ return Promise.all( pending ).then( function ( results ) {
3482
+
3483
+ const materials = results.slice( 0, results.length - 1 );
3484
+ const geometries = results[ results.length - 1 ];
3485
+
3486
+ const meshes = [];
3487
+
3488
+ for ( let i = 0, il = geometries.length; i < il; i ++ ) {
3489
+
3490
+ const geometry = geometries[ i ];
3491
+ const primitive = primitives[ i ];
3492
+
3493
+ // 1. create Mesh
3494
+
3495
+ let mesh;
3496
+
3497
+ const material = materials[ i ];
3498
+
3499
+ if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES ||
3500
+ primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ||
3501
+ primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ||
3502
+ primitive.mode === undefined ) {
3503
+
3504
+ // .isSkinnedMesh isn't in glTF spec. See ._markDefs()
3505
+ mesh = meshDef.isSkinnedMesh === true
3506
+ ? new SkinnedMesh( geometry, material )
3507
+ : new Mesh( geometry, material );
3508
+
3509
+ if ( mesh.isSkinnedMesh === true && ! mesh.geometry.attributes.skinWeight.normalized ) {
3510
+
3511
+ // we normalize floating point skin weight array to fix malformed assets (see #15319)
3512
+ // it's important to skip this for non-float32 data since normalizeSkinWeights assumes non-normalized inputs
3513
+ mesh.normalizeSkinWeights();
3514
+
3515
+ }
3516
+
3517
+ if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ) {
3518
+
3519
+ mesh.geometry = toTrianglesDrawMode( mesh.geometry, TriangleStripDrawMode );
3520
+
3521
+ } else if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ) {
3522
+
3523
+ mesh.geometry = toTrianglesDrawMode( mesh.geometry, TriangleFanDrawMode );
3524
+
3525
+ }
3526
+
3527
+ } else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) {
3528
+
3529
+ mesh = new LineSegments( geometry, material );
3530
+
3531
+ } else if ( primitive.mode === WEBGL_CONSTANTS.LINE_STRIP ) {
3532
+
3533
+ mesh = new Line( geometry, material );
3534
+
3535
+ } else if ( primitive.mode === WEBGL_CONSTANTS.LINE_LOOP ) {
3536
+
3537
+ mesh = new LineLoop( geometry, material );
3538
+
3539
+ } else if ( primitive.mode === WEBGL_CONSTANTS.POINTS ) {
3540
+
3541
+ mesh = new Points( geometry, material );
3542
+
3543
+ } else {
3544
+
3545
+ throw new Error( 'THREE.GLTFLoader: Primitive mode unsupported: ' + primitive.mode );
3546
+
3547
+ }
3548
+
3549
+ if ( Object.keys( mesh.geometry.morphAttributes ).length > 0 ) {
3550
+
3551
+ updateMorphTargets( mesh, meshDef );
3552
+
3553
+ }
3554
+
3555
+ mesh.name = parser.createUniqueName( meshDef.name || ( 'mesh_' + meshIndex ) );
3556
+
3557
+ assignExtrasToUserData( mesh, meshDef );
3558
+
3559
+ if ( primitive.extensions ) addUnknownExtensionsToUserData( extensions, mesh, primitive );
3560
+
3561
+ parser.assignFinalMaterial( mesh );
3562
+
3563
+ meshes.push( mesh );
3564
+
3565
+ }
3566
+
3567
+ for ( let i = 0, il = meshes.length; i < il; i ++ ) {
3568
+
3569
+ parser.associations.set( meshes[ i ], {
3570
+ meshes: meshIndex,
3571
+ primitives: i
3572
+ } );
3573
+
3574
+ }
3575
+
3576
+ if ( meshes.length === 1 ) {
3577
+
3578
+ return meshes[ 0 ];
3579
+
3580
+ }
3581
+
3582
+ const group = new Group();
3583
+
3584
+ parser.associations.set( group, { meshes: meshIndex } );
3585
+
3586
+ for ( let i = 0, il = meshes.length; i < il; i ++ ) {
3587
+
3588
+ group.add( meshes[ i ] );
3589
+
3590
+ }
3591
+
3592
+ return group;
3593
+
3594
+ } );
3595
+
3596
+ }
3597
+
3598
+ /**
3599
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#cameras
3600
+ * @param {number} cameraIndex
3601
+ * @return {Promise<THREE.Camera>}
3602
+ */
3603
+ loadCamera( cameraIndex ) {
3604
+
3605
+ let camera;
3606
+ const cameraDef = this.json.cameras[ cameraIndex ];
3607
+ const params = cameraDef[ cameraDef.type ];
3608
+
3609
+ if ( ! params ) {
3610
+
3611
+ console.warn( 'THREE.GLTFLoader: Missing camera parameters.' );
3612
+ return;
3613
+
3614
+ }
3615
+
3616
+ if ( cameraDef.type === 'perspective' ) {
3617
+
3618
+ camera = new PerspectiveCamera( MathUtils.radToDeg( params.yfov ), params.aspectRatio || 1, params.znear || 1, params.zfar || 2e6 );
3619
+
3620
+ } else if ( cameraDef.type === 'orthographic' ) {
3621
+
3622
+ camera = new OrthographicCamera( - params.xmag, params.xmag, params.ymag, - params.ymag, params.znear, params.zfar );
3623
+
3624
+ }
3625
+
3626
+ if ( cameraDef.name ) camera.name = this.createUniqueName( cameraDef.name );
3627
+
3628
+ assignExtrasToUserData( camera, cameraDef );
3629
+
3630
+ return Promise.resolve( camera );
3631
+
3632
+ }
3633
+
3634
+ /**
3635
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins
3636
+ * @param {number} skinIndex
3637
+ * @return {Promise<Object>}
3638
+ */
3639
+ loadSkin( skinIndex ) {
3640
+
3641
+ const skinDef = this.json.skins[ skinIndex ];
3642
+
3643
+ const skinEntry = { joints: skinDef.joints };
3644
+
3645
+ if ( skinDef.inverseBindMatrices === undefined ) {
3646
+
3647
+ return Promise.resolve( skinEntry );
3648
+
3649
+ }
3650
+
3651
+ return this.getDependency( 'accessor', skinDef.inverseBindMatrices ).then( function ( accessor ) {
3652
+
3653
+ skinEntry.inverseBindMatrices = accessor;
3654
+
3655
+ return skinEntry;
3656
+
3657
+ } );
3658
+
3659
+ }
3660
+
3661
+ /**
3662
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#animations
3663
+ * @param {number} animationIndex
3664
+ * @return {Promise<AnimationClip>}
3665
+ */
3666
+ loadAnimation( animationIndex ) {
3667
+
3668
+ const json = this.json;
3669
+
3670
+ const animationDef = json.animations[ animationIndex ];
3671
+
3672
+ const pendingNodes = [];
3673
+ const pendingInputAccessors = [];
3674
+ const pendingOutputAccessors = [];
3675
+ const pendingSamplers = [];
3676
+ const pendingTargets = [];
3677
+
3678
+ for ( let i = 0, il = animationDef.channels.length; i < il; i ++ ) {
3679
+
3680
+ const channel = animationDef.channels[ i ];
3681
+ const sampler = animationDef.samplers[ channel.sampler ];
3682
+ const target = channel.target;
3683
+ const name = target.node !== undefined ? target.node : target.id; // NOTE: target.id is deprecated.
3684
+ const input = animationDef.parameters !== undefined ? animationDef.parameters[ sampler.input ] : sampler.input;
3685
+ const output = animationDef.parameters !== undefined ? animationDef.parameters[ sampler.output ] : sampler.output;
3686
+
3687
+ pendingNodes.push( this.getDependency( 'node', name ) );
3688
+ pendingInputAccessors.push( this.getDependency( 'accessor', input ) );
3689
+ pendingOutputAccessors.push( this.getDependency( 'accessor', output ) );
3690
+ pendingSamplers.push( sampler );
3691
+ pendingTargets.push( target );
3692
+
3693
+ }
3694
+
3695
+ return Promise.all( [
3696
+
3697
+ Promise.all( pendingNodes ),
3698
+ Promise.all( pendingInputAccessors ),
3699
+ Promise.all( pendingOutputAccessors ),
3700
+ Promise.all( pendingSamplers ),
3701
+ Promise.all( pendingTargets )
3702
+
3703
+ ] ).then( function ( dependencies ) {
3704
+
3705
+ const nodes = dependencies[ 0 ];
3706
+ const inputAccessors = dependencies[ 1 ];
3707
+ const outputAccessors = dependencies[ 2 ];
3708
+ const samplers = dependencies[ 3 ];
3709
+ const targets = dependencies[ 4 ];
3710
+
3711
+ const tracks = [];
3712
+
3713
+ for ( let i = 0, il = nodes.length; i < il; i ++ ) {
3714
+
3715
+ const node = nodes[ i ];
3716
+ const inputAccessor = inputAccessors[ i ];
3717
+ const outputAccessor = outputAccessors[ i ];
3718
+ const sampler = samplers[ i ];
3719
+ const target = targets[ i ];
3720
+
3721
+ if ( node === undefined ) continue;
3722
+
3723
+ node.updateMatrix();
3724
+ node.matrixAutoUpdate = true;
3725
+
3726
+ let TypedKeyframeTrack;
3727
+
3728
+ switch ( PATH_PROPERTIES[ target.path ] ) {
3729
+
3730
+ case PATH_PROPERTIES.weights:
3731
+
3732
+ TypedKeyframeTrack = NumberKeyframeTrack;
3733
+ break;
3734
+
3735
+ case PATH_PROPERTIES.rotation:
3736
+
3737
+ TypedKeyframeTrack = QuaternionKeyframeTrack;
3738
+ break;
3739
+
3740
+ case PATH_PROPERTIES.position:
3741
+ case PATH_PROPERTIES.scale:
3742
+ default:
3743
+
3744
+ TypedKeyframeTrack = VectorKeyframeTrack;
3745
+ break;
3746
+
3747
+ }
3748
+
3749
+ const targetName = node.name ? node.name : node.uuid;
3750
+
3751
+ const interpolation = sampler.interpolation !== undefined ? INTERPOLATION[ sampler.interpolation ] : InterpolateLinear;
3752
+
3753
+ const targetNames = [];
3754
+
3755
+ if ( PATH_PROPERTIES[ target.path ] === PATH_PROPERTIES.weights ) {
3756
+
3757
+ node.traverse( function ( object ) {
3758
+
3759
+ if ( object.morphTargetInfluences ) {
3760
+
3761
+ targetNames.push( object.name ? object.name : object.uuid );
3762
+
3763
+ }
3764
+
3765
+ } );
3766
+
3767
+ } else {
3768
+
3769
+ targetNames.push( targetName );
3770
+
3771
+ }
3772
+
3773
+ let outputArray = outputAccessor.array;
3774
+
3775
+ if ( outputAccessor.normalized ) {
3776
+
3777
+ const scale = getNormalizedComponentScale( outputArray.constructor );
3778
+ const scaled = new Float32Array( outputArray.length );
3779
+
3780
+ for ( let j = 0, jl = outputArray.length; j < jl; j ++ ) {
3781
+
3782
+ scaled[ j ] = outputArray[ j ] * scale;
3783
+
3784
+ }
3785
+
3786
+ outputArray = scaled;
3787
+
3788
+ }
3789
+
3790
+ for ( let j = 0, jl = targetNames.length; j < jl; j ++ ) {
3791
+
3792
+ const track = new TypedKeyframeTrack(
3793
+ targetNames[ j ] + '.' + PATH_PROPERTIES[ target.path ],
3794
+ inputAccessor.array,
3795
+ outputArray,
3796
+ interpolation
3797
+ );
3798
+
3799
+ // Override interpolation with custom factory method.
3800
+ if ( sampler.interpolation === 'CUBICSPLINE' ) {
3801
+
3802
+ track.createInterpolant = function InterpolantFactoryMethodGLTFCubicSpline( result ) {
3803
+
3804
+ // A CUBICSPLINE keyframe in glTF has three output values for each input value,
3805
+ // representing inTangent, splineVertex, and outTangent. As a result, track.getValueSize()
3806
+ // must be divided by three to get the interpolant's sampleSize argument.
3807
+
3808
+ const interpolantType = ( this instanceof QuaternionKeyframeTrack ) ? GLTFCubicSplineQuaternionInterpolant : GLTFCubicSplineInterpolant;
3809
+
3810
+ return new interpolantType( this.times, this.values, this.getValueSize() / 3, result );
3811
+
3812
+ };
3813
+
3814
+ // Mark as CUBICSPLINE. `track.getInterpolation()` doesn't support custom interpolants.
3815
+ track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline = true;
3816
+
3817
+ }
3818
+
3819
+ tracks.push( track );
3820
+
3821
+ }
3822
+
3823
+ }
3824
+
3825
+ const name = animationDef.name ? animationDef.name : 'animation_' + animationIndex;
3826
+
3827
+ return new AnimationClip( name, undefined, tracks );
3828
+
3829
+ } );
3830
+
3831
+ }
3832
+
3833
+ createNodeMesh( nodeIndex ) {
3834
+
3835
+ const json = this.json;
3836
+ const parser = this;
3837
+ const nodeDef = json.nodes[ nodeIndex ];
3838
+
3839
+ if ( nodeDef.mesh === undefined ) return null;
3840
+
3841
+ return parser.getDependency( 'mesh', nodeDef.mesh ).then( function ( mesh ) {
3842
+
3843
+ const node = parser._getNodeRef( parser.meshCache, nodeDef.mesh, mesh );
3844
+
3845
+ // if weights are provided on the node, override weights on the mesh.
3846
+ if ( nodeDef.weights !== undefined ) {
3847
+
3848
+ node.traverse( function ( o ) {
3849
+
3850
+ if ( ! o.isMesh ) return;
3851
+
3852
+ for ( let i = 0, il = nodeDef.weights.length; i < il; i ++ ) {
3853
+
3854
+ o.morphTargetInfluences[ i ] = nodeDef.weights[ i ];
3855
+
3856
+ }
3857
+
3858
+ } );
3859
+
3860
+ }
3861
+
3862
+ return node;
3863
+
3864
+ } );
3865
+
3866
+ }
3867
+
3868
+ /**
3869
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#nodes-and-hierarchy
3870
+ * @param {number} nodeIndex
3871
+ * @return {Promise<Object3D>}
3872
+ */
3873
+ loadNode( nodeIndex ) {
3874
+
3875
+ const json = this.json;
3876
+ const extensions = this.extensions;
3877
+ const parser = this;
3878
+
3879
+ const nodeDef = json.nodes[ nodeIndex ];
3880
+
3881
+ // reserve node's name before its dependencies, so the root has the intended name.
3882
+ const nodeName = nodeDef.name ? parser.createUniqueName( nodeDef.name ) : '';
3883
+
3884
+ return ( function () {
3885
+
3886
+ const pending = [];
3887
+
3888
+ const meshPromise = parser._invokeOne( function ( ext ) {
3889
+
3890
+ return ext.createNodeMesh && ext.createNodeMesh( nodeIndex );
3891
+
3892
+ } );
3893
+
3894
+ if ( meshPromise ) {
3895
+
3896
+ pending.push( meshPromise );
3897
+
3898
+ }
3899
+
3900
+ if ( nodeDef.camera !== undefined ) {
3901
+
3902
+ pending.push( parser.getDependency( 'camera', nodeDef.camera ).then( function ( camera ) {
3903
+
3904
+ return parser._getNodeRef( parser.cameraCache, nodeDef.camera, camera );
3905
+
3906
+ } ) );
3907
+
3908
+ }
3909
+
3910
+ parser._invokeAll( function ( ext ) {
3911
+
3912
+ return ext.createNodeAttachment && ext.createNodeAttachment( nodeIndex );
3913
+
3914
+ } ).forEach( function ( promise ) {
3915
+
3916
+ pending.push( promise );
3917
+
3918
+ } );
3919
+
3920
+ return Promise.all( pending );
3921
+
3922
+ }() ).then( function ( objects ) {
3923
+
3924
+ let node;
3925
+
3926
+ // .isBone isn't in glTF spec. See ._markDefs
3927
+ if ( nodeDef.isBone === true ) {
3928
+
3929
+ node = new Bone();
3930
+
3931
+ } else if ( objects.length > 1 ) {
3932
+
3933
+ node = new Group();
3934
+
3935
+ } else if ( objects.length === 1 ) {
3936
+
3937
+ node = objects[ 0 ];
3938
+
3939
+ } else {
3940
+
3941
+ node = new Object3D();
3942
+
3943
+ }
3944
+
3945
+ if ( node !== objects[ 0 ] ) {
3946
+
3947
+ for ( let i = 0, il = objects.length; i < il; i ++ ) {
3948
+
3949
+ node.add( objects[ i ] );
3950
+
3951
+ }
3952
+
3953
+ }
3954
+
3955
+ if ( nodeDef.name ) {
3956
+
3957
+ node.userData.name = nodeDef.name;
3958
+ node.name = nodeName;
3959
+
3960
+ }
3961
+
3962
+ assignExtrasToUserData( node, nodeDef );
3963
+
3964
+ if ( nodeDef.extensions ) addUnknownExtensionsToUserData( extensions, node, nodeDef );
3965
+
3966
+ if ( nodeDef.matrix !== undefined ) {
3967
+
3968
+ const matrix = new Matrix4();
3969
+ matrix.fromArray( nodeDef.matrix );
3970
+ node.applyMatrix4( matrix );
3971
+
3972
+ } else {
3973
+
3974
+ if ( nodeDef.translation !== undefined ) {
3975
+
3976
+ node.position.fromArray( nodeDef.translation );
3977
+
3978
+ }
3979
+
3980
+ if ( nodeDef.rotation !== undefined ) {
3981
+
3982
+ node.quaternion.fromArray( nodeDef.rotation );
3983
+
3984
+ }
3985
+
3986
+ if ( nodeDef.scale !== undefined ) {
3987
+
3988
+ node.scale.fromArray( nodeDef.scale );
3989
+
3990
+ }
3991
+
3992
+ }
3993
+
3994
+ if ( ! parser.associations.has( node ) ) {
3995
+
3996
+ parser.associations.set( node, {} );
3997
+
3998
+ }
3999
+
4000
+ parser.associations.get( node ).nodes = nodeIndex;
4001
+
4002
+ return node;
4003
+
4004
+ } );
4005
+
4006
+ }
4007
+
4008
+ /**
4009
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#scenes
4010
+ * @param {number} sceneIndex
4011
+ * @return {Promise<Group>}
4012
+ */
4013
+ loadScene( sceneIndex ) {
4014
+
4015
+ const json = this.json;
4016
+ const extensions = this.extensions;
4017
+ const sceneDef = this.json.scenes[ sceneIndex ];
4018
+ const parser = this;
4019
+
4020
+ // Loader returns Group, not Scene.
4021
+ // See: https://github.com/mrdoob/three.js/issues/18342#issuecomment-578981172
4022
+ const scene = new Group();
4023
+ if ( sceneDef.name ) scene.name = parser.createUniqueName( sceneDef.name );
4024
+
4025
+ assignExtrasToUserData( scene, sceneDef );
4026
+
4027
+ if ( sceneDef.extensions ) addUnknownExtensionsToUserData( extensions, scene, sceneDef );
4028
+
4029
+ const nodeIds = sceneDef.nodes || [];
4030
+
4031
+ const pending = [];
4032
+
4033
+ for ( let i = 0, il = nodeIds.length; i < il; i ++ ) {
4034
+
4035
+ pending.push( buildNodeHierarchy( nodeIds[ i ], scene, json, parser ) );
4036
+
4037
+ }
4038
+
4039
+ return Promise.all( pending ).then( function () {
4040
+
4041
+ // Removes dangling associations, associations that reference a node that
4042
+ // didn't make it into the scene.
4043
+ const reduceAssociations = ( node ) => {
4044
+
4045
+ const reducedAssociations = new Map();
4046
+
4047
+ for ( const [ key, value ] of parser.associations ) {
4048
+
4049
+ if ( key instanceof Material || key instanceof Texture ) {
4050
+
4051
+ reducedAssociations.set( key, value );
4052
+
4053
+ }
4054
+
4055
+ }
4056
+
4057
+ node.traverse( ( node ) => {
4058
+
4059
+ const mappings = parser.associations.get( node );
4060
+
4061
+ if ( mappings != null ) {
4062
+
4063
+ reducedAssociations.set( node, mappings );
4064
+
4065
+ }
4066
+
4067
+ } );
4068
+
4069
+ return reducedAssociations;
4070
+
4071
+ };
4072
+
4073
+ parser.associations = reduceAssociations( scene );
4074
+
4075
+ return scene;
4076
+
4077
+ } );
4078
+
4079
+ }
4080
+
4081
+ }
4082
+
4083
+ function buildNodeHierarchy( nodeId, parentObject, json, parser ) {
4084
+
4085
+ const nodeDef = json.nodes[ nodeId ];
4086
+
4087
+ return parser.getDependency( 'node', nodeId ).then( function ( node ) {
4088
+
4089
+ if ( nodeDef.skin === undefined ) return node;
4090
+
4091
+ // build skeleton here as well
4092
+
4093
+ let skinEntry;
4094
+
4095
+ return parser.getDependency( 'skin', nodeDef.skin ).then( function ( skin ) {
4096
+
4097
+ skinEntry = skin;
4098
+
4099
+ const pendingJoints = [];
4100
+
4101
+ for ( let i = 0, il = skinEntry.joints.length; i < il; i ++ ) {
4102
+
4103
+ pendingJoints.push( parser.getDependency( 'node', skinEntry.joints[ i ] ) );
4104
+
4105
+ }
4106
+
4107
+ return Promise.all( pendingJoints );
4108
+
4109
+ } ).then( function ( jointNodes ) {
4110
+
4111
+ node.traverse( function ( mesh ) {
4112
+
4113
+ if ( ! mesh.isMesh ) return;
4114
+
4115
+ const bones = [];
4116
+ const boneInverses = [];
4117
+
4118
+ for ( let j = 0, jl = jointNodes.length; j < jl; j ++ ) {
4119
+
4120
+ const jointNode = jointNodes[ j ];
4121
+
4122
+ if ( jointNode ) {
4123
+
4124
+ bones.push( jointNode );
4125
+
4126
+ const mat = new Matrix4();
4127
+
4128
+ if ( skinEntry.inverseBindMatrices !== undefined ) {
4129
+
4130
+ mat.fromArray( skinEntry.inverseBindMatrices.array, j * 16 );
4131
+
4132
+ }
4133
+
4134
+ boneInverses.push( mat );
4135
+
4136
+ } else {
4137
+
4138
+ console.warn( 'THREE.GLTFLoader: Joint "%s" could not be found.', skinEntry.joints[ j ] );
4139
+
4140
+ }
4141
+
4142
+ }
4143
+
4144
+ mesh.bind( new Skeleton( bones, boneInverses ), mesh.matrixWorld );
4145
+
4146
+ } );
4147
+
4148
+ return node;
4149
+
4150
+ } );
4151
+
4152
+ } ).then( function ( node ) {
4153
+
4154
+ // build node hierachy
4155
+
4156
+ parentObject.add( node );
4157
+
4158
+ const pending = [];
4159
+
4160
+ if ( nodeDef.children ) {
4161
+
4162
+ const children = nodeDef.children;
4163
+
4164
+ for ( let i = 0, il = children.length; i < il; i ++ ) {
4165
+
4166
+ const child = children[ i ];
4167
+ pending.push( buildNodeHierarchy( child, node, json, parser ) );
4168
+
4169
+ }
4170
+
4171
+ }
4172
+
4173
+ return Promise.all( pending );
4174
+
4175
+ } );
4176
+
4177
+ }
4178
+
4179
+ /**
4180
+ * @param {BufferGeometry} geometry
4181
+ * @param {GLTF.Primitive} primitiveDef
4182
+ * @param {GLTFParser} parser
4183
+ */
4184
+ function computeBounds( geometry, primitiveDef, parser ) {
4185
+
4186
+ const attributes = primitiveDef.attributes;
4187
+
4188
+ const box = new Box3();
4189
+
4190
+ if ( attributes.POSITION !== undefined ) {
4191
+
4192
+ const accessor = parser.json.accessors[ attributes.POSITION ];
4193
+
4194
+ const min = accessor.min;
4195
+ const max = accessor.max;
4196
+
4197
+ // glTF requires 'min' and 'max', but VRM (which extends glTF) currently ignores that requirement.
4198
+
4199
+ if ( min !== undefined && max !== undefined ) {
4200
+
4201
+ box.set(
4202
+ new Vector3( min[ 0 ], min[ 1 ], min[ 2 ] ),
4203
+ new Vector3( max[ 0 ], max[ 1 ], max[ 2 ] )
4204
+ );
4205
+
4206
+ if ( accessor.normalized ) {
4207
+
4208
+ const boxScale = getNormalizedComponentScale( WEBGL_COMPONENT_TYPES[ accessor.componentType ] );
4209
+ box.min.multiplyScalar( boxScale );
4210
+ box.max.multiplyScalar( boxScale );
4211
+
4212
+ }
4213
+
4214
+ } else {
4215
+
4216
+ console.warn( 'THREE.GLTFLoader: Missing min/max properties for accessor POSITION.' );
4217
+
4218
+ return;
4219
+
4220
+ }
4221
+
4222
+ } else {
4223
+
4224
+ return;
4225
+
4226
+ }
4227
+
4228
+ const targets = primitiveDef.targets;
4229
+
4230
+ if ( targets !== undefined ) {
4231
+
4232
+ const maxDisplacement = new Vector3();
4233
+ const vector = new Vector3();
4234
+
4235
+ for ( let i = 0, il = targets.length; i < il; i ++ ) {
4236
+
4237
+ const target = targets[ i ];
4238
+
4239
+ if ( target.POSITION !== undefined ) {
4240
+
4241
+ const accessor = parser.json.accessors[ target.POSITION ];
4242
+ const min = accessor.min;
4243
+ const max = accessor.max;
4244
+
4245
+ // glTF requires 'min' and 'max', but VRM (which extends glTF) currently ignores that requirement.
4246
+
4247
+ if ( min !== undefined && max !== undefined ) {
4248
+
4249
+ // we need to get max of absolute components because target weight is [-1,1]
4250
+ vector.setX( Math.max( Math.abs( min[ 0 ] ), Math.abs( max[ 0 ] ) ) );
4251
+ vector.setY( Math.max( Math.abs( min[ 1 ] ), Math.abs( max[ 1 ] ) ) );
4252
+ vector.setZ( Math.max( Math.abs( min[ 2 ] ), Math.abs( max[ 2 ] ) ) );
4253
+
4254
+
4255
+ if ( accessor.normalized ) {
4256
+
4257
+ const boxScale = getNormalizedComponentScale( WEBGL_COMPONENT_TYPES[ accessor.componentType ] );
4258
+ vector.multiplyScalar( boxScale );
4259
+
4260
+ }
4261
+
4262
+ // Note: this assumes that the sum of all weights is at most 1. This isn't quite correct - it's more conservative
4263
+ // to assume that each target can have a max weight of 1. However, for some use cases - notably, when morph targets
4264
+ // are used to implement key-frame animations and as such only two are active at a time - this results in very large
4265
+ // boxes. So for now we make a box that's sometimes a touch too small but is hopefully mostly of reasonable size.
4266
+ maxDisplacement.max( vector );
4267
+
4268
+ } else {
4269
+
4270
+ console.warn( 'THREE.GLTFLoader: Missing min/max properties for accessor POSITION.' );
4271
+
4272
+ }
4273
+
4274
+ }
4275
+
4276
+ }
4277
+
4278
+ // As per comment above this box isn't conservative, but has a reasonable size for a very large number of morph targets.
4279
+ box.expandByVector( maxDisplacement );
4280
+
4281
+ }
4282
+
4283
+ geometry.boundingBox = box;
4284
+
4285
+ const sphere = new Sphere();
4286
+
4287
+ box.getCenter( sphere.center );
4288
+ sphere.radius = box.min.distanceTo( box.max ) / 2;
4289
+
4290
+ geometry.boundingSphere = sphere;
4291
+
4292
+ }
4293
+
4294
+ /**
4295
+ * @param {BufferGeometry} geometry
4296
+ * @param {GLTF.Primitive} primitiveDef
4297
+ * @param {GLTFParser} parser
4298
+ * @return {Promise<BufferGeometry>}
4299
+ */
4300
+ function addPrimitiveAttributes( geometry, primitiveDef, parser ) {
4301
+
4302
+ const attributes = primitiveDef.attributes;
4303
+
4304
+ const pending = [];
4305
+
4306
+ function assignAttributeAccessor( accessorIndex, attributeName ) {
4307
+
4308
+ return parser.getDependency( 'accessor', accessorIndex )
4309
+ .then( function ( accessor ) {
4310
+
4311
+ geometry.setAttribute( attributeName, accessor );
4312
+
4313
+ } );
4314
+
4315
+ }
4316
+
4317
+ for ( const gltfAttributeName in attributes ) {
4318
+
4319
+ const threeAttributeName = ATTRIBUTES[ gltfAttributeName ] || gltfAttributeName.toLowerCase();
4320
+
4321
+ // Skip attributes already provided by e.g. Draco extension.
4322
+ if ( threeAttributeName in geometry.attributes ) continue;
4323
+
4324
+ pending.push( assignAttributeAccessor( attributes[ gltfAttributeName ], threeAttributeName ) );
4325
+
4326
+ }
4327
+
4328
+ if ( primitiveDef.indices !== undefined && ! geometry.index ) {
4329
+
4330
+ const accessor = parser.getDependency( 'accessor', primitiveDef.indices ).then( function ( accessor ) {
4331
+
4332
+ geometry.setIndex( accessor );
4333
+
4334
+ } );
4335
+
4336
+ pending.push( accessor );
4337
+
4338
+ }
4339
+
4340
+ assignExtrasToUserData( geometry, primitiveDef );
4341
+
4342
+ computeBounds( geometry, primitiveDef, parser );
4343
+
4344
+ return Promise.all( pending ).then( function () {
4345
+
4346
+ return primitiveDef.targets !== undefined
4347
+ ? addMorphTargets( geometry, primitiveDef.targets, parser )
4348
+ : geometry;
4349
+
4350
+ } );
4351
+
4352
+ }
4353
+
4354
+ /**
4355
+ * @param {BufferGeometry} geometry
4356
+ * @param {Number} drawMode
4357
+ * @return {BufferGeometry}
4358
+ */
4359
+ function toTrianglesDrawMode( geometry, drawMode ) {
4360
+
4361
+ let index = geometry.getIndex();
4362
+
4363
+ // generate index if not present
4364
+
4365
+ if ( index === null ) {
4366
+
4367
+ const indices = [];
4368
+
4369
+ const position = geometry.getAttribute( 'position' );
4370
+
4371
+ if ( position !== undefined ) {
4372
+
4373
+ for ( let i = 0; i < position.count; i ++ ) {
4374
+
4375
+ indices.push( i );
4376
+
4377
+ }
4378
+
4379
+ geometry.setIndex( indices );
4380
+ index = geometry.getIndex();
4381
+
4382
+ } else {
4383
+
4384
+ console.error( 'THREE.GLTFLoader.toTrianglesDrawMode(): Undefined position attribute. Processing not possible.' );
4385
+ return geometry;
4386
+
4387
+ }
4388
+
4389
+ }
4390
+
4391
+ //
4392
+
4393
+ const numberOfTriangles = index.count - 2;
4394
+ const newIndices = [];
4395
+
4396
+ if ( drawMode === TriangleFanDrawMode ) {
4397
+
4398
+ // gl.TRIANGLE_FAN
4399
+
4400
+ for ( let i = 1; i <= numberOfTriangles; i ++ ) {
4401
+
4402
+ newIndices.push( index.getX( 0 ) );
4403
+ newIndices.push( index.getX( i ) );
4404
+ newIndices.push( index.getX( i + 1 ) );
4405
+
4406
+ }
4407
+
4408
+ } else {
4409
+
4410
+ // gl.TRIANGLE_STRIP
4411
+
4412
+ for ( let i = 0; i < numberOfTriangles; i ++ ) {
4413
+
4414
+ if ( i % 2 === 0 ) {
4415
+
4416
+ newIndices.push( index.getX( i ) );
4417
+ newIndices.push( index.getX( i + 1 ) );
4418
+ newIndices.push( index.getX( i + 2 ) );
4419
+
4420
+
4421
+ } else {
4422
+
4423
+ newIndices.push( index.getX( i + 2 ) );
4424
+ newIndices.push( index.getX( i + 1 ) );
4425
+ newIndices.push( index.getX( i ) );
4426
+
4427
+ }
4428
+
4429
+ }
4430
+
4431
+ }
4432
+
4433
+ if ( ( newIndices.length / 3 ) !== numberOfTriangles ) {
4434
+
4435
+ console.error( 'THREE.GLTFLoader.toTrianglesDrawMode(): Unable to generate correct amount of triangles.' );
4436
+
4437
+ }
4438
+
4439
+ // build final geometry
4440
+
4441
+ const newGeometry = geometry.clone();
4442
+ newGeometry.setIndex( newIndices );
4443
+
4444
+ return newGeometry;
4445
+
4446
+ }
4447
+
4448
+ export { GLTFLoader };