@thanhthbm/scene-editor 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/README.md +169 -0
  2. package/dist/index.css +921 -0
  3. package/dist/index.js +14076 -0
  4. package/package.json +49 -0
  5. package/src/editor/css/main.css +1030 -0
  6. package/src/editor/js/Animation.js +618 -0
  7. package/src/editor/js/AnimationResizer.js +73 -0
  8. package/src/editor/js/Command.js +40 -0
  9. package/src/editor/js/Config.js +86 -0
  10. package/src/editor/js/Editor.js +1006 -0
  11. package/src/editor/js/EditorControls.js +489 -0
  12. package/src/editor/js/GLTFImportDialog.js +112 -0
  13. package/src/editor/js/History.js +321 -0
  14. package/src/editor/js/Loader.js +1162 -0
  15. package/src/editor/js/LoaderUtils.js +90 -0
  16. package/src/editor/js/Menubar.Add.js +559 -0
  17. package/src/editor/js/Menubar.Edit.js +155 -0
  18. package/src/editor/js/Menubar.File.js +585 -0
  19. package/src/editor/js/Menubar.Help.js +73 -0
  20. package/src/editor/js/Menubar.Render.js +858 -0
  21. package/src/editor/js/Menubar.Status.js +51 -0
  22. package/src/editor/js/Menubar.View.js +193 -0
  23. package/src/editor/js/Menubar.js +29 -0
  24. package/src/editor/js/Player.js +53 -0
  25. package/src/editor/js/Resizer.js +65 -0
  26. package/src/editor/js/Script.js +532 -0
  27. package/src/editor/js/Selector.js +129 -0
  28. package/src/editor/js/Sidebar.Geometry.BoxGeometry.js +121 -0
  29. package/src/editor/js/Sidebar.Geometry.BufferGeometry.js +124 -0
  30. package/src/editor/js/Sidebar.Geometry.CapsuleGeometry.js +109 -0
  31. package/src/editor/js/Sidebar.Geometry.CircleGeometry.js +97 -0
  32. package/src/editor/js/Sidebar.Geometry.CylinderGeometry.js +121 -0
  33. package/src/editor/js/Sidebar.Geometry.DodecahedronGeometry.js +73 -0
  34. package/src/editor/js/Sidebar.Geometry.ExtrudeGeometry.js +196 -0
  35. package/src/editor/js/Sidebar.Geometry.IcosahedronGeometry.js +73 -0
  36. package/src/editor/js/Sidebar.Geometry.LatheGeometry.js +98 -0
  37. package/src/editor/js/Sidebar.Geometry.Modifiers.js +73 -0
  38. package/src/editor/js/Sidebar.Geometry.OctahedronGeometry.js +74 -0
  39. package/src/editor/js/Sidebar.Geometry.PlaneGeometry.js +97 -0
  40. package/src/editor/js/Sidebar.Geometry.RingGeometry.js +121 -0
  41. package/src/editor/js/Sidebar.Geometry.ShapeGeometry.js +76 -0
  42. package/src/editor/js/Sidebar.Geometry.SphereGeometry.js +133 -0
  43. package/src/editor/js/Sidebar.Geometry.TetrahedronGeometry.js +74 -0
  44. package/src/editor/js/Sidebar.Geometry.TextGeometry.js +136 -0
  45. package/src/editor/js/Sidebar.Geometry.TorusGeometry.js +109 -0
  46. package/src/editor/js/Sidebar.Geometry.TorusKnotGeometry.js +121 -0
  47. package/src/editor/js/Sidebar.Geometry.TubeGeometry.js +135 -0
  48. package/src/editor/js/Sidebar.Geometry.js +471 -0
  49. package/src/editor/js/Sidebar.Material.BooleanProperty.js +60 -0
  50. package/src/editor/js/Sidebar.Material.ColorProperty.js +87 -0
  51. package/src/editor/js/Sidebar.Material.ConstantProperty.js +62 -0
  52. package/src/editor/js/Sidebar.Material.MapProperty.js +277 -0
  53. package/src/editor/js/Sidebar.Material.NumberProperty.js +60 -0
  54. package/src/editor/js/Sidebar.Material.Program.js +73 -0
  55. package/src/editor/js/Sidebar.Material.RangeValueProperty.js +63 -0
  56. package/src/editor/js/Sidebar.Material.js +751 -0
  57. package/src/editor/js/Sidebar.Object.js +892 -0
  58. package/src/editor/js/Sidebar.Project.App.js +218 -0
  59. package/src/editor/js/Sidebar.Project.Materials.js +82 -0
  60. package/src/editor/js/Sidebar.Project.Renderer.js +193 -0
  61. package/src/editor/js/Sidebar.Project.Resources.js +242 -0
  62. package/src/editor/js/Sidebar.Project.js +21 -0
  63. package/src/editor/js/Sidebar.Properties.js +73 -0
  64. package/src/editor/js/Sidebar.Scene.js +643 -0
  65. package/src/editor/js/Sidebar.Script.js +129 -0
  66. package/src/editor/js/Sidebar.Settings.History.js +146 -0
  67. package/src/editor/js/Sidebar.Settings.Shortcuts.js +198 -0
  68. package/src/editor/js/Sidebar.Settings.js +58 -0
  69. package/src/editor/js/Sidebar.js +41 -0
  70. package/src/editor/js/Storage.js +98 -0
  71. package/src/editor/js/Strings.js +2718 -0
  72. package/src/editor/js/TextureParametersDialog.js +293 -0
  73. package/src/editor/js/Toolbar.js +75 -0
  74. package/src/editor/js/Viewport.Controls.js +98 -0
  75. package/src/editor/js/Viewport.Info.js +144 -0
  76. package/src/editor/js/Viewport.Pathtracer.js +27 -0
  77. package/src/editor/js/Viewport.ViewHelper.js +41 -0
  78. package/src/editor/js/Viewport.XR.js +7 -0
  79. package/src/editor/js/Viewport.js +982 -0
  80. package/src/editor/js/commands/AddObjectCommand.js +68 -0
  81. package/src/editor/js/commands/AddScriptCommand.js +75 -0
  82. package/src/editor/js/commands/Commands.js +24 -0
  83. package/src/editor/js/commands/MoveObjectCommand.js +117 -0
  84. package/src/editor/js/commands/MultiCmdsCommand.js +85 -0
  85. package/src/editor/js/commands/RemoveObjectCommand.js +88 -0
  86. package/src/editor/js/commands/RemoveScriptCommand.js +81 -0
  87. package/src/editor/js/commands/SetColorCommand.js +73 -0
  88. package/src/editor/js/commands/SetGeometryCommand.js +86 -0
  89. package/src/editor/js/commands/SetGeometryValueCommand.js +70 -0
  90. package/src/editor/js/commands/SetMaterialColorCommand.js +87 -0
  91. package/src/editor/js/commands/SetMaterialCommand.js +80 -0
  92. package/src/editor/js/commands/SetMaterialMapCommand.js +144 -0
  93. package/src/editor/js/commands/SetMaterialRangeCommand.js +92 -0
  94. package/src/editor/js/commands/SetMaterialValueCommand.js +91 -0
  95. package/src/editor/js/commands/SetMaterialVectorCommand.js +88 -0
  96. package/src/editor/js/commands/SetPositionCommand.js +84 -0
  97. package/src/editor/js/commands/SetRotationCommand.js +84 -0
  98. package/src/editor/js/commands/SetScaleCommand.js +84 -0
  99. package/src/editor/js/commands/SetSceneCommand.js +104 -0
  100. package/src/editor/js/commands/SetScriptValueCommand.js +80 -0
  101. package/src/editor/js/commands/SetShadowValueCommand.js +73 -0
  102. package/src/editor/js/commands/SetTextureParametersCommand.js +143 -0
  103. package/src/editor/js/commands/SetUuidCommand.js +70 -0
  104. package/src/editor/js/commands/SetValueCommand.js +75 -0
  105. package/src/editor/js/libs/acorn/acorn.js +3236 -0
  106. package/src/editor/js/libs/acorn/acorn_loose.js +1299 -0
  107. package/src/editor/js/libs/acorn/walk.js +344 -0
  108. package/src/editor/js/libs/app/index.html +51 -0
  109. package/src/editor/js/libs/app.js +14 -0
  110. package/src/editor/js/libs/codemirror/addon/dialog.css +32 -0
  111. package/src/editor/js/libs/codemirror/addon/dialog.js +163 -0
  112. package/src/editor/js/libs/codemirror/addon/show-hint.css +36 -0
  113. package/src/editor/js/libs/codemirror/addon/show-hint.js +529 -0
  114. package/src/editor/js/libs/codemirror/addon/tern.css +87 -0
  115. package/src/editor/js/libs/codemirror/addon/tern.js +750 -0
  116. package/src/editor/js/libs/codemirror/codemirror.css +344 -0
  117. package/src/editor/js/libs/codemirror/codemirror.js +9849 -0
  118. package/src/editor/js/libs/codemirror/mode/glsl.js +233 -0
  119. package/src/editor/js/libs/codemirror/mode/javascript.js +959 -0
  120. package/src/editor/js/libs/codemirror/theme/monokai.css +41 -0
  121. package/src/editor/js/libs/esprima.js +6401 -0
  122. package/src/editor/js/libs/jsonlint.js +453 -0
  123. package/src/editor/js/libs/signals.min.js +14 -0
  124. package/src/editor/js/libs/tern-threejs/build-defs.js +233 -0
  125. package/src/editor/js/libs/ternjs/comment.js +87 -0
  126. package/src/editor/js/libs/ternjs/def.js +588 -0
  127. package/src/editor/js/libs/ternjs/doc_comment.js +401 -0
  128. package/src/editor/js/libs/ternjs/infer.js +1635 -0
  129. package/src/editor/js/libs/ternjs/polyfill.js +80 -0
  130. package/src/editor/js/libs/ternjs/signal.js +26 -0
  131. package/src/editor/js/libs/ternjs/tern.js +993 -0
  132. package/src/editor/js/libs/ui.js +1305 -0
  133. package/src/editor/js/libs/ui.three.js +946 -0
  134. package/src/events.js +273 -0
  135. package/src/index.js +284 -0
  136. package/src/presets/machines.js +239 -0
@@ -0,0 +1,1162 @@
1
+ import * as THREE from 'three';
2
+
3
+ import { TGALoader } from 'three/addons/loaders/TGALoader.js';
4
+
5
+ import { AddObjectCommand } from './commands/AddObjectCommand.js';
6
+ import { SetSceneCommand } from './commands/SetSceneCommand.js';
7
+
8
+ import { LoaderUtils } from './LoaderUtils.js';
9
+
10
+ import { GLTFImportDialog } from './GLTFImportDialog.js';
11
+
12
+ import { unzipSync, strFromU8 } from 'three/addons/libs/fflate.module.js';
13
+
14
+ function Loader( editor ) {
15
+
16
+ const scope = this;
17
+
18
+ this.texturePath = '';
19
+
20
+ this.loadItemList = function ( items ) {
21
+
22
+ LoaderUtils.getFilesFromItemList( items, function ( files, filesMap ) {
23
+
24
+ scope.loadFiles( files, filesMap );
25
+
26
+ } );
27
+
28
+ };
29
+
30
+ this.loadFiles = function ( files, filesMap ) {
31
+
32
+ if ( files.length > 0 ) {
33
+
34
+ filesMap = filesMap || LoaderUtils.createFilesMap( files );
35
+
36
+ const normalizeLookupPath = function ( path ) {
37
+
38
+ let normalized = String( path || '' ).replace( /\\/g, '/' );
39
+ const queryIndex = normalized.indexOf( '?' );
40
+ if ( queryIndex !== - 1 ) normalized = normalized.slice( 0, queryIndex );
41
+ const hashIndex = normalized.indexOf( '#' );
42
+ if ( hashIndex !== - 1 ) normalized = normalized.slice( 0, hashIndex );
43
+
44
+ while ( normalized.startsWith( './' ) ) normalized = normalized.slice( 2 );
45
+ while ( normalized.startsWith( '../' ) ) normalized = normalized.slice( 3 );
46
+ while ( normalized.startsWith( '/' ) ) normalized = normalized.slice( 1 );
47
+
48
+ try {
49
+
50
+ normalized = decodeURIComponent( normalized );
51
+
52
+ } catch ( e ) { /* malformed URI — keep as-is */ }
53
+
54
+ normalized = normalized.normalize( 'NFC' );
55
+
56
+ return normalized;
57
+
58
+ };
59
+
60
+ const createFileFinder = function ( map ) {
61
+
62
+ const suffixMap = {};
63
+ const warnedAmbiguous = new Set();
64
+
65
+ const addCandidate = function ( suffix, candidate ) {
66
+
67
+ if ( ! suffixMap[ suffix ] ) suffixMap[ suffix ] = [];
68
+ suffixMap[ suffix ].push( candidate );
69
+
70
+ };
71
+
72
+ for ( const rawKey in map ) {
73
+
74
+ const key = normalizeLookupPath( rawKey );
75
+ const file = map[ rawKey ];
76
+ if ( key === '' || ! file ) continue;
77
+
78
+ const parts = key.split( '/' );
79
+
80
+ for ( let i = 0; i < parts.length; i ++ ) {
81
+
82
+ const suffix = parts.slice( i ).join( '/' );
83
+ if ( suffix !== '' ) addCandidate( suffix, { key, file } );
84
+
85
+ }
86
+
87
+ }
88
+
89
+ for ( const suffix in suffixMap ) {
90
+
91
+ suffixMap[ suffix ].sort( function ( a, b ) {
92
+
93
+ if ( a.key.length !== b.key.length ) return a.key.length - b.key.length;
94
+ if ( a.key < b.key ) return - 1;
95
+ if ( a.key > b.key ) return 1;
96
+ return 0;
97
+
98
+ } );
99
+
100
+ }
101
+
102
+ return function findFile( url ) {
103
+
104
+ const lookup = normalizeLookupPath( url );
105
+ if ( lookup === '' ) return null;
106
+
107
+ const candidates = suffixMap[ lookup ];
108
+ if ( ! candidates || candidates.length === 0 ) return null;
109
+ if ( candidates.length === 1 ) return candidates[ 0 ];
110
+
111
+ for ( let i = 0; i < candidates.length; i ++ ) {
112
+
113
+ if ( candidates[ i ].key === lookup ) return candidates[ i ];
114
+
115
+ }
116
+
117
+ if ( ! warnedAmbiguous.has( lookup ) ) {
118
+
119
+ console.warn( 'Loader: Ambiguous file reference "' + lookup + '". Using "' + candidates[ 0 ].key + '".' );
120
+ warnedAmbiguous.add( lookup );
121
+
122
+ }
123
+
124
+ return candidates[ 0 ];
125
+
126
+ };
127
+
128
+ };
129
+
130
+ const findFile = createFileFinder( filesMap );
131
+
132
+ const manager = new THREE.LoadingManager();
133
+ manager.setURLModifier( function ( url ) {
134
+
135
+ const resolved = findFile( url );
136
+
137
+ if ( resolved ) {
138
+
139
+ console.log( 'Loading', url );
140
+
141
+ return URL.createObjectURL( resolved.file );
142
+
143
+ }
144
+
145
+ return url;
146
+
147
+ } );
148
+
149
+ manager.addHandler( /\.tga$/i, new TGALoader() );
150
+
151
+ for ( let i = 0; i < files.length; i ++ ) {
152
+
153
+ scope.loadFile( files[ i ], manager );
154
+
155
+ }
156
+
157
+ }
158
+
159
+ };
160
+
161
+ this.loadFile = function ( file, manager ) {
162
+
163
+ const filename = file.name;
164
+ const extension = filename.split( '.' ).pop().toLowerCase();
165
+
166
+ const reader = new FileReader();
167
+ reader.addEventListener( 'progress', function ( event ) {
168
+
169
+ const size = '(' + editor.utils.formatNumber( Math.floor( event.total / 1000 ) ) + ' KB)';
170
+ const progress = Math.floor( ( event.loaded / event.total ) * 100 ) + '%';
171
+
172
+ console.log( 'Loading', filename, size, progress );
173
+
174
+ } );
175
+
176
+ switch ( extension ) {
177
+
178
+ case '3dm':
179
+
180
+ {
181
+
182
+ reader.addEventListener( 'load', async function ( event ) {
183
+
184
+ const contents = event.target.result;
185
+
186
+ const { Rhino3dmLoader } = await import( 'three/addons/loaders/3DMLoader.js' );
187
+
188
+ const loader = new Rhino3dmLoader();
189
+ loader.setLibraryPath( '../examples/jsm/libs/rhino3dm/' );
190
+ loader.parse( contents, function ( object ) {
191
+
192
+ object.name = filename;
193
+
194
+ editor.execute( new AddObjectCommand( editor, object ) );
195
+
196
+ }, function ( error ) {
197
+
198
+ console.error( error );
199
+
200
+ } );
201
+
202
+ }, false );
203
+ reader.readAsArrayBuffer( file );
204
+
205
+ break;
206
+
207
+ }
208
+
209
+ case '3ds':
210
+
211
+ {
212
+
213
+ reader.addEventListener( 'load', async function ( event ) {
214
+
215
+ const { TDSLoader } = await import( 'three/addons/loaders/TDSLoader.js' );
216
+
217
+ const loader = new TDSLoader();
218
+ const object = loader.parse( event.target.result );
219
+
220
+ editor.execute( new AddObjectCommand( editor, object ) );
221
+
222
+ }, false );
223
+ reader.readAsArrayBuffer( file );
224
+
225
+ break;
226
+
227
+ }
228
+
229
+ case '3mf':
230
+
231
+ {
232
+
233
+ reader.addEventListener( 'load', async function ( event ) {
234
+
235
+ const { ThreeMFLoader } = await import( 'three/addons/loaders/3MFLoader.js' );
236
+
237
+ const loader = new ThreeMFLoader();
238
+ const object = loader.parse( event.target.result );
239
+
240
+ editor.execute( new AddObjectCommand( editor, object ) );
241
+
242
+ }, false );
243
+ reader.readAsArrayBuffer( file );
244
+
245
+ break;
246
+
247
+ }
248
+
249
+ case 'amf':
250
+
251
+ {
252
+
253
+ reader.addEventListener( 'load', async function ( event ) {
254
+
255
+ const { AMFLoader } = await import( 'three/addons/loaders/AMFLoader.js' );
256
+
257
+ const loader = new AMFLoader();
258
+ const amfobject = loader.parse( event.target.result );
259
+
260
+ editor.execute( new AddObjectCommand( editor, amfobject ) );
261
+
262
+ }, false );
263
+ reader.readAsArrayBuffer( file );
264
+
265
+ break;
266
+
267
+ }
268
+
269
+ case 'dae':
270
+
271
+ {
272
+
273
+ reader.addEventListener( 'load', async function ( event ) {
274
+
275
+ const contents = event.target.result;
276
+
277
+ const { ColladaLoader } = await import( 'three/addons/loaders/ColladaLoader.js' );
278
+
279
+ const loader = new ColladaLoader( manager );
280
+ const collada = loader.parse( contents );
281
+
282
+ collada.scene.name = filename;
283
+
284
+ editor.execute( new AddObjectCommand( editor, collada.scene ) );
285
+
286
+ }, false );
287
+ reader.readAsText( file );
288
+
289
+ break;
290
+
291
+ }
292
+
293
+ case 'drc':
294
+
295
+ {
296
+
297
+ reader.addEventListener( 'load', async function ( event ) {
298
+
299
+ const contents = event.target.result;
300
+
301
+ const { DRACOLoader } = await import( 'three/addons/loaders/DRACOLoader.js' );
302
+
303
+ const loader = new DRACOLoader();
304
+ loader.setDecoderPath( '../examples/jsm/libs/draco/' );
305
+ loader.parse( contents, function ( geometry ) {
306
+
307
+ let object;
308
+
309
+ if ( geometry.index !== null ) {
310
+
311
+ const material = new THREE.MeshStandardMaterial();
312
+
313
+ object = new THREE.Mesh( geometry, material );
314
+ object.name = filename;
315
+
316
+ } else {
317
+
318
+ const material = new THREE.PointsMaterial( { size: 0.01 } );
319
+ material.vertexColors = geometry.hasAttribute( 'color' );
320
+
321
+ object = new THREE.Points( geometry, material );
322
+ object.name = filename;
323
+
324
+ }
325
+
326
+ loader.dispose();
327
+ editor.execute( new AddObjectCommand( editor, object ) );
328
+
329
+ } );
330
+
331
+ }, false );
332
+ reader.readAsArrayBuffer( file );
333
+
334
+ break;
335
+
336
+ }
337
+
338
+ case 'fbx':
339
+
340
+ {
341
+
342
+ reader.addEventListener( 'load', async function ( event ) {
343
+
344
+ const contents = event.target.result;
345
+
346
+ const { FBXLoader } = await import( 'three/addons/loaders/FBXLoader.js' );
347
+
348
+ const loader = new FBXLoader( manager );
349
+ const object = loader.parse( contents );
350
+
351
+ editor.execute( new AddObjectCommand( editor, object ) );
352
+
353
+ }, false );
354
+ reader.readAsArrayBuffer( file );
355
+
356
+ break;
357
+
358
+ }
359
+
360
+ case 'glb':
361
+
362
+ {
363
+
364
+ reader.addEventListener( 'load', async function ( event ) {
365
+
366
+ const contents = event.target.result;
367
+
368
+ try {
369
+
370
+ const dialog = new GLTFImportDialog( editor.strings );
371
+ const options = await dialog.show();
372
+
373
+ const loader = await createGLTFLoader();
374
+
375
+ loader.parse( contents, '', function ( result ) {
376
+
377
+ const scene = result.scene;
378
+ scene.name = filename;
379
+
380
+ scene.animations.push( ...result.animations );
381
+
382
+ if ( options.asScene ) {
383
+
384
+ editor.execute( new SetSceneCommand( editor, scene ) );
385
+
386
+ } else {
387
+
388
+ editor.execute( new AddObjectCommand( editor, scene ) );
389
+
390
+ }
391
+
392
+ loader.dracoLoader.dispose();
393
+ loader.ktx2Loader.dispose();
394
+
395
+ } );
396
+
397
+ } catch ( e ) {
398
+
399
+ // Import cancelled
400
+
401
+ }
402
+
403
+ }, false );
404
+ reader.readAsArrayBuffer( file );
405
+
406
+ break;
407
+
408
+ }
409
+
410
+ case 'gltf':
411
+
412
+ {
413
+
414
+ reader.addEventListener( 'load', async function ( event ) {
415
+
416
+ const contents = event.target.result;
417
+
418
+ try {
419
+
420
+ const dialog = new GLTFImportDialog( editor.strings );
421
+ const options = await dialog.show();
422
+
423
+ const loader = await createGLTFLoader( manager );
424
+
425
+ loader.parse( contents, '', function ( result ) {
426
+
427
+ const scene = result.scene;
428
+ scene.name = filename;
429
+
430
+ scene.animations.push( ...result.animations );
431
+
432
+ if ( options.asScene ) {
433
+
434
+ editor.execute( new SetSceneCommand( editor, scene ) );
435
+
436
+ } else {
437
+
438
+ editor.execute( new AddObjectCommand( editor, scene ) );
439
+
440
+ }
441
+
442
+ loader.dracoLoader.dispose();
443
+ loader.ktx2Loader.dispose();
444
+
445
+ } );
446
+
447
+ } catch ( e ) {
448
+
449
+ // Import cancelled
450
+
451
+ }
452
+
453
+ }, false );
454
+ reader.readAsArrayBuffer( file );
455
+
456
+ break;
457
+
458
+ }
459
+
460
+ case 'js':
461
+ case 'json':
462
+
463
+ {
464
+
465
+ reader.addEventListener( 'load', function ( event ) {
466
+
467
+ const contents = event.target.result;
468
+
469
+ // >= 3.0
470
+
471
+ let data;
472
+
473
+ try {
474
+
475
+ data = JSON.parse( contents );
476
+
477
+ } catch ( error ) {
478
+
479
+ alert( error );
480
+ return;
481
+
482
+ }
483
+
484
+ handleJSON( data );
485
+
486
+ }, false );
487
+ reader.readAsText( file );
488
+
489
+ break;
490
+
491
+ }
492
+
493
+ case 'kmz':
494
+
495
+ {
496
+
497
+ reader.addEventListener( 'load', async function ( event ) {
498
+
499
+ const { KMZLoader } = await import( 'three/addons/loaders/KMZLoader.js' );
500
+
501
+ const loader = new KMZLoader();
502
+ const collada = loader.parse( event.target.result );
503
+
504
+ collada.scene.name = filename;
505
+
506
+ editor.execute( new AddObjectCommand( editor, collada.scene ) );
507
+
508
+ }, false );
509
+ reader.readAsArrayBuffer( file );
510
+
511
+ break;
512
+
513
+ }
514
+
515
+ case 'ldr':
516
+ case 'mpd':
517
+
518
+ {
519
+
520
+ reader.addEventListener( 'load', async function ( event ) {
521
+
522
+ const { LDrawLoader } = await import( 'three/addons/loaders/LDrawLoader.js' );
523
+
524
+ const loader = new LDrawLoader();
525
+ loader.setPath( '../../examples/models/ldraw/officialLibrary/' );
526
+ loader.parse( event.target.result, function ( group ) {
527
+
528
+ group.name = filename;
529
+ // Convert from LDraw coordinates: rotate 180 degrees around OX
530
+ group.rotation.x = Math.PI;
531
+
532
+ editor.execute( new AddObjectCommand( editor, group ) );
533
+
534
+ } );
535
+
536
+ }, false );
537
+ reader.readAsText( file );
538
+
539
+ break;
540
+
541
+ }
542
+
543
+ case 'md2':
544
+
545
+ {
546
+
547
+ reader.addEventListener( 'load', async function ( event ) {
548
+
549
+ const contents = event.target.result;
550
+
551
+ const { MD2Loader } = await import( 'three/addons/loaders/MD2Loader.js' );
552
+
553
+ const geometry = new MD2Loader().parse( contents );
554
+ const material = new THREE.MeshStandardMaterial();
555
+
556
+ const mesh = new THREE.Mesh( geometry, material );
557
+ mesh.mixer = new THREE.AnimationMixer( mesh );
558
+ mesh.name = filename;
559
+
560
+ mesh.animations.push( ...geometry.animations );
561
+ editor.execute( new AddObjectCommand( editor, mesh ) );
562
+
563
+ }, false );
564
+ reader.readAsArrayBuffer( file );
565
+
566
+ break;
567
+
568
+ }
569
+
570
+ case 'obj':
571
+
572
+ {
573
+
574
+ reader.addEventListener( 'load', async function ( event ) {
575
+
576
+ const contents = event.target.result;
577
+
578
+ const { OBJLoader } = await import( 'three/addons/loaders/OBJLoader.js' );
579
+
580
+ const object = new OBJLoader().parse( contents );
581
+ object.name = filename;
582
+
583
+ editor.execute( new AddObjectCommand( editor, object ) );
584
+
585
+ }, false );
586
+ reader.readAsText( file );
587
+
588
+ break;
589
+
590
+ }
591
+
592
+ case 'pcd':
593
+
594
+ {
595
+
596
+ reader.addEventListener( 'load', async function ( event ) {
597
+
598
+ const contents = event.target.result;
599
+
600
+ const { PCDLoader } = await import( 'three/addons/loaders/PCDLoader.js' );
601
+
602
+ const points = new PCDLoader().parse( contents );
603
+ points.name = filename;
604
+
605
+ editor.execute( new AddObjectCommand( editor, points ) );
606
+
607
+ }, false );
608
+ reader.readAsArrayBuffer( file );
609
+
610
+ break;
611
+
612
+ }
613
+
614
+ case 'ply':
615
+
616
+ {
617
+
618
+ reader.addEventListener( 'load', async function ( event ) {
619
+
620
+ const contents = event.target.result;
621
+
622
+ const { PLYLoader } = await import( 'three/addons/loaders/PLYLoader.js' );
623
+
624
+ const geometry = new PLYLoader().parse( contents );
625
+ let object;
626
+
627
+ if ( geometry.index !== null ) {
628
+
629
+ const material = new THREE.MeshStandardMaterial();
630
+
631
+ object = new THREE.Mesh( geometry, material );
632
+ object.name = filename;
633
+
634
+ } else {
635
+
636
+ const material = new THREE.PointsMaterial( { size: 0.01 } );
637
+ material.vertexColors = geometry.hasAttribute( 'color' );
638
+
639
+ object = new THREE.Points( geometry, material );
640
+ object.name = filename;
641
+
642
+ }
643
+
644
+ editor.execute( new AddObjectCommand( editor, object ) );
645
+
646
+ }, false );
647
+ reader.readAsArrayBuffer( file );
648
+
649
+ break;
650
+
651
+ }
652
+
653
+ case 'stl':
654
+
655
+ {
656
+
657
+ reader.addEventListener( 'load', async function ( event ) {
658
+
659
+ const contents = event.target.result;
660
+
661
+ const { STLLoader } = await import( 'three/addons/loaders/STLLoader.js' );
662
+
663
+ const geometry = new STLLoader().parse( contents );
664
+ const material = new THREE.MeshStandardMaterial();
665
+
666
+ const mesh = new THREE.Mesh( geometry, material );
667
+ mesh.name = filename;
668
+
669
+ editor.execute( new AddObjectCommand( editor, mesh ) );
670
+
671
+ }, false );
672
+
673
+ if ( reader.readAsBinaryString !== undefined ) {
674
+
675
+ reader.readAsBinaryString( file );
676
+
677
+ } else {
678
+
679
+ reader.readAsArrayBuffer( file );
680
+
681
+ }
682
+
683
+ break;
684
+
685
+ }
686
+
687
+ case 'svg':
688
+
689
+ {
690
+
691
+ reader.addEventListener( 'load', async function ( event ) {
692
+
693
+ const contents = event.target.result;
694
+
695
+ const { SVGLoader } = await import( 'three/addons/loaders/SVGLoader.js' );
696
+
697
+ const loader = new SVGLoader();
698
+ const paths = loader.parse( contents ).paths;
699
+
700
+ //
701
+
702
+ const group = new THREE.Group();
703
+ group.name = filename;
704
+ group.scale.multiplyScalar( 0.1 );
705
+ group.scale.y *= - 1;
706
+
707
+ let renderOrder = 0;
708
+
709
+ for ( let i = 0; i < paths.length; i ++ ) {
710
+
711
+ const path = paths[ i ];
712
+
713
+ // fill
714
+
715
+ const fillMaterial = SVGLoader.createFillMaterial( path );
716
+
717
+ if ( fillMaterial ) {
718
+
719
+ const shapes = path.toShapes();
720
+
721
+ for ( let j = 0; j < shapes.length; j ++ ) {
722
+
723
+ const shape = shapes[ j ];
724
+
725
+ const geometry = new THREE.ShapeGeometry( shape );
726
+ const mesh = new THREE.Mesh( geometry, fillMaterial );
727
+ mesh.renderOrder = renderOrder ++;
728
+
729
+ group.add( mesh );
730
+
731
+ }
732
+
733
+ }
734
+
735
+ // stroke
736
+
737
+ const strokeMaterial = SVGLoader.createStrokeMaterial( path );
738
+
739
+ if ( strokeMaterial ) {
740
+
741
+ for ( const subPath of path.subPaths ) {
742
+
743
+ const geometry = SVGLoader.pointsToStroke( subPath.getPoints(), path.userData.style );
744
+
745
+ if ( geometry ) {
746
+
747
+ const mesh = new THREE.Mesh( geometry, strokeMaterial );
748
+ mesh.renderOrder = renderOrder ++;
749
+
750
+ group.add( mesh );
751
+
752
+ }
753
+
754
+ }
755
+
756
+ }
757
+
758
+ }
759
+
760
+ editor.execute( new AddObjectCommand( editor, group ) );
761
+
762
+ }, false );
763
+ reader.readAsText( file );
764
+
765
+ break;
766
+
767
+ }
768
+
769
+ case 'usd':
770
+ case 'usda':
771
+ case 'usdc':
772
+ case 'usdz':
773
+
774
+ {
775
+
776
+ reader.addEventListener( 'load', async function ( event ) {
777
+
778
+ const contents = event.target.result;
779
+
780
+ const { USDLoader } = await import( 'three/addons/loaders/USDLoader.js' );
781
+
782
+ const loader = new USDLoader( manager );
783
+ loader.parse( contents, '', function ( group ) {
784
+
785
+ group.name = filename;
786
+ editor.execute( new AddObjectCommand( editor, group ) );
787
+
788
+ } );
789
+
790
+ }, false );
791
+ reader.readAsArrayBuffer( file );
792
+
793
+ break;
794
+
795
+ }
796
+
797
+ case 'vox':
798
+
799
+ {
800
+
801
+ reader.addEventListener( 'load', async function ( event ) {
802
+
803
+ const contents = event.target.result;
804
+
805
+ const { VOXLoader } = await import( 'three/addons/loaders/VOXLoader.js' );
806
+
807
+ const { scene } = new VOXLoader().parse( contents );
808
+
809
+ scene.name = filename;
810
+
811
+ editor.execute( new AddObjectCommand( editor, scene ) );
812
+
813
+ }, false );
814
+ reader.readAsArrayBuffer( file );
815
+
816
+ break;
817
+
818
+ }
819
+
820
+ case 'wrl':
821
+
822
+ {
823
+
824
+ reader.addEventListener( 'load', async function ( event ) {
825
+
826
+ const contents = event.target.result;
827
+
828
+ const { VRMLLoader } = await import( 'three/addons/loaders/VRMLLoader.js' );
829
+
830
+ const result = new VRMLLoader().parse( contents );
831
+
832
+ editor.execute( new AddObjectCommand( editor, result ) );
833
+
834
+ }, false );
835
+ reader.readAsText( file );
836
+
837
+ break;
838
+
839
+ }
840
+
841
+ case 'xyz':
842
+
843
+ {
844
+
845
+ reader.addEventListener( 'load', async function ( event ) {
846
+
847
+ const contents = event.target.result;
848
+
849
+ const { XYZLoader } = await import( 'three/addons/loaders/XYZLoader.js' );
850
+
851
+ const geometry = new XYZLoader().parse( contents );
852
+
853
+ const material = new THREE.PointsMaterial();
854
+ material.vertexColors = geometry.hasAttribute( 'color' );
855
+
856
+ const points = new THREE.Points( geometry, material );
857
+ points.name = filename;
858
+
859
+ editor.execute( new AddObjectCommand( editor, points ) );
860
+
861
+ }, false );
862
+ reader.readAsText( file );
863
+
864
+ break;
865
+
866
+ }
867
+
868
+ case 'zip':
869
+
870
+ {
871
+
872
+ reader.addEventListener( 'load', function ( event ) {
873
+
874
+ handleZIP( event.target.result );
875
+
876
+ }, false );
877
+ reader.readAsArrayBuffer( file );
878
+
879
+ break;
880
+
881
+ }
882
+
883
+ case 'bmp':
884
+ case 'gif':
885
+ case 'jpg':
886
+ case 'jpeg':
887
+ case 'png':
888
+ case 'tga':
889
+
890
+ break; // Image files are handled as textures by other loaders
891
+
892
+ default:
893
+
894
+ console.error( 'Unsupported file format (' + extension + ').' );
895
+
896
+ break;
897
+
898
+ }
899
+
900
+ };
901
+
902
+ function handleJSON( data ) {
903
+
904
+ if ( data.metadata === undefined ) { // 2.0
905
+
906
+ data.metadata = { type: 'Geometry' };
907
+
908
+ }
909
+
910
+ if ( data.metadata.type === undefined ) { // 3.0
911
+
912
+ data.metadata.type = 'Geometry';
913
+
914
+ }
915
+
916
+ if ( data.metadata.formatVersion !== undefined ) {
917
+
918
+ data.metadata.version = data.metadata.formatVersion;
919
+
920
+ }
921
+
922
+ switch ( data.metadata.type.toLowerCase() ) {
923
+
924
+ case 'buffergeometry':
925
+
926
+ {
927
+
928
+ const loader = new THREE.BufferGeometryLoader();
929
+ const result = loader.parse( data );
930
+
931
+ const mesh = new THREE.Mesh( result );
932
+
933
+ editor.execute( new AddObjectCommand( editor, mesh ) );
934
+
935
+ break;
936
+
937
+ }
938
+
939
+ case 'geometry':
940
+
941
+ console.error( 'Loader: "Geometry" is no longer supported.' );
942
+
943
+ break;
944
+
945
+ case 'object':
946
+
947
+ {
948
+
949
+ const loader = new THREE.ObjectLoader();
950
+ loader.setResourcePath( scope.texturePath );
951
+
952
+ loader.parse( data, function ( result ) {
953
+
954
+ editor.execute( new AddObjectCommand( editor, result ) );
955
+
956
+ } );
957
+
958
+ break;
959
+
960
+ }
961
+
962
+ case 'app':
963
+
964
+ editor.fromJSON( data );
965
+
966
+ break;
967
+
968
+ }
969
+
970
+ }
971
+
972
+ async function handleZIP( contents ) {
973
+
974
+ const zip = unzipSync( new Uint8Array( contents ) );
975
+
976
+ // Build a lookup map with NFC-normalized keys to handle
977
+ // unicode normalization differences (e.g. NFD vs NFC)
978
+
979
+ const zipLookup = {};
980
+
981
+ for ( const path in zip ) {
982
+
983
+ zipLookup[ path.normalize( 'NFC' ) ] = zip[ path ];
984
+
985
+ }
986
+
987
+ const manager = new THREE.LoadingManager();
988
+ manager.setURLModifier( function ( url ) {
989
+
990
+ const normalized = decodeURIComponent( url ).normalize( 'NFC' );
991
+ const file = zipLookup[ normalized ];
992
+
993
+ if ( file ) {
994
+
995
+ console.log( 'Loading', url );
996
+
997
+ const blob = new Blob( [ file.buffer ], { type: 'application/octet-stream' } );
998
+ return URL.createObjectURL( blob );
999
+
1000
+ }
1001
+
1002
+ return url;
1003
+
1004
+ } );
1005
+
1006
+ // Poly
1007
+
1008
+ if ( zip[ 'model.obj' ] && zip[ 'materials.mtl' ] ) {
1009
+
1010
+ const { MTLLoader } = await import( 'three/addons/loaders/MTLLoader.js' );
1011
+ const { OBJLoader } = await import( 'three/addons/loaders/OBJLoader.js' );
1012
+
1013
+ const materials = new MTLLoader( manager ).parse( strFromU8( zip[ 'materials.mtl' ] ) );
1014
+ const object = new OBJLoader().setMaterials( materials ).parse( strFromU8( zip[ 'model.obj' ] ) );
1015
+
1016
+ editor.execute( new AddObjectCommand( editor, object ) );
1017
+ return;
1018
+
1019
+ }
1020
+
1021
+ //
1022
+
1023
+ for ( const path in zip ) {
1024
+
1025
+ const file = zip[ path ];
1026
+
1027
+ const extension = path.split( '.' ).pop().toLowerCase();
1028
+
1029
+ switch ( extension ) {
1030
+
1031
+ case 'fbx':
1032
+
1033
+ {
1034
+
1035
+ const { FBXLoader } = await import( 'three/addons/loaders/FBXLoader.js' );
1036
+
1037
+ const loader = new FBXLoader( manager );
1038
+ const object = loader.parse( file.buffer );
1039
+
1040
+ editor.execute( new AddObjectCommand( editor, object ) );
1041
+
1042
+ break;
1043
+
1044
+ }
1045
+
1046
+ case 'glb':
1047
+
1048
+ {
1049
+
1050
+ try {
1051
+
1052
+ const dialog = new GLTFImportDialog( editor.strings );
1053
+ const options = await dialog.show();
1054
+
1055
+ const loader = await createGLTFLoader();
1056
+
1057
+ loader.parse( file.buffer, '', function ( result ) {
1058
+
1059
+ const scene = result.scene;
1060
+
1061
+ scene.animations.push( ...result.animations );
1062
+
1063
+ if ( options.asScene ) {
1064
+
1065
+ editor.execute( new SetSceneCommand( editor, scene ) );
1066
+
1067
+ } else {
1068
+
1069
+ editor.execute( new AddObjectCommand( editor, scene ) );
1070
+
1071
+ }
1072
+
1073
+ loader.dracoLoader.dispose();
1074
+ loader.ktx2Loader.dispose();
1075
+
1076
+ } );
1077
+
1078
+ } catch ( e ) {
1079
+
1080
+ // Import cancelled
1081
+
1082
+ }
1083
+
1084
+ break;
1085
+
1086
+ }
1087
+
1088
+ case 'gltf':
1089
+
1090
+ {
1091
+
1092
+ try {
1093
+
1094
+ const dialog = new GLTFImportDialog( editor.strings );
1095
+ const options = await dialog.show();
1096
+
1097
+ const loader = await createGLTFLoader( manager );
1098
+
1099
+ loader.parse( strFromU8( file ), '', function ( result ) {
1100
+
1101
+ const scene = result.scene;
1102
+
1103
+ scene.animations.push( ...result.animations );
1104
+
1105
+ if ( options.asScene ) {
1106
+
1107
+ editor.execute( new SetSceneCommand( editor, scene ) );
1108
+
1109
+ } else {
1110
+
1111
+ editor.execute( new AddObjectCommand( editor, scene ) );
1112
+
1113
+ }
1114
+
1115
+ loader.dracoLoader.dispose();
1116
+ loader.ktx2Loader.dispose();
1117
+
1118
+ } );
1119
+
1120
+ } catch ( e ) {
1121
+
1122
+ // Import cancelled
1123
+
1124
+ }
1125
+
1126
+ break;
1127
+
1128
+ }
1129
+
1130
+ }
1131
+
1132
+ }
1133
+
1134
+ }
1135
+
1136
+ async function createGLTFLoader( manager ) {
1137
+
1138
+ const { GLTFLoader } = await import( 'three/addons/loaders/GLTFLoader.js' );
1139
+ const { DRACOLoader } = await import( 'three/addons/loaders/DRACOLoader.js' );
1140
+ const { KTX2Loader } = await import( 'three/addons/loaders/KTX2Loader.js' );
1141
+ const { MeshoptDecoder } = await import( 'three/addons/libs/meshopt_decoder.module.js' );
1142
+
1143
+ const dracoLoader = new DRACOLoader();
1144
+ dracoLoader.setDecoderPath( '../examples/jsm/libs/draco/gltf/' );
1145
+
1146
+ const ktx2Loader = new KTX2Loader( manager );
1147
+ ktx2Loader.setTranscoderPath( '../examples/jsm/libs/basis/' );
1148
+
1149
+ editor.signals.rendererDetectKTX2Support.dispatch( ktx2Loader );
1150
+
1151
+ const loader = new GLTFLoader( manager );
1152
+ loader.setDRACOLoader( dracoLoader );
1153
+ loader.setKTX2Loader( ktx2Loader );
1154
+ loader.setMeshoptDecoder( MeshoptDecoder );
1155
+
1156
+ return loader;
1157
+
1158
+ }
1159
+
1160
+ }
1161
+
1162
+ export { Loader };