@spiffcommerce/preview 3.6.2-rc.7 → 3.6.2-rc.8

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.
@@ -0,0 +1,825 @@
1
+ import { _ as __awaiter } from './_tslib.esm.js';
2
+ import { L as Logger, b as IsBase64DataUrl, E as Engine, c as Tools, S as Scene, R as RuntimeError, d as ErrorCodes } from './engine.esm.js';
3
+ import { O as Observable, E as EngineStore } from './webRequest.esm.js';
4
+ import { S as SceneLoaderFlags } from './sceneLoaderFlags.esm.js';
5
+
6
+ /**
7
+ * Mode that determines how to handle old animation groups before loading new ones.
8
+ */
9
+ var SceneLoaderAnimationGroupLoadingMode;
10
+ (function (SceneLoaderAnimationGroupLoadingMode) {
11
+ /**
12
+ * Reset all old animations to initial state then dispose them.
13
+ */
14
+ SceneLoaderAnimationGroupLoadingMode[SceneLoaderAnimationGroupLoadingMode["Clean"] = 0] = "Clean";
15
+ /**
16
+ * Stop all old animations.
17
+ */
18
+ SceneLoaderAnimationGroupLoadingMode[SceneLoaderAnimationGroupLoadingMode["Stop"] = 1] = "Stop";
19
+ /**
20
+ * Restart old animations from first frame.
21
+ */
22
+ SceneLoaderAnimationGroupLoadingMode[SceneLoaderAnimationGroupLoadingMode["Sync"] = 2] = "Sync";
23
+ /**
24
+ * Old animations remains untouched.
25
+ */
26
+ SceneLoaderAnimationGroupLoadingMode[SceneLoaderAnimationGroupLoadingMode["NoSync"] = 3] = "NoSync";
27
+ })(SceneLoaderAnimationGroupLoadingMode || (SceneLoaderAnimationGroupLoadingMode = {}));
28
+ /**
29
+ * Class used to load scene from various file formats using registered plugins
30
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/importers/loadingFileTypes
31
+ */
32
+ class SceneLoader {
33
+ /**
34
+ * Gets or sets a boolean indicating if entire scene must be loaded even if scene contains incremental data
35
+ */
36
+ static get ForceFullSceneLoadingForIncremental() {
37
+ return SceneLoaderFlags.ForceFullSceneLoadingForIncremental;
38
+ }
39
+ static set ForceFullSceneLoadingForIncremental(value) {
40
+ SceneLoaderFlags.ForceFullSceneLoadingForIncremental = value;
41
+ }
42
+ /**
43
+ * Gets or sets a boolean indicating if loading screen must be displayed while loading a scene
44
+ */
45
+ static get ShowLoadingScreen() {
46
+ return SceneLoaderFlags.ShowLoadingScreen;
47
+ }
48
+ static set ShowLoadingScreen(value) {
49
+ SceneLoaderFlags.ShowLoadingScreen = value;
50
+ }
51
+ /**
52
+ * Defines the current logging level (while loading the scene)
53
+ * @ignorenaming
54
+ */
55
+ // eslint-disable-next-line @typescript-eslint/naming-convention
56
+ static get loggingLevel() {
57
+ return SceneLoaderFlags.loggingLevel;
58
+ }
59
+ // eslint-disable-next-line @typescript-eslint/naming-convention
60
+ static set loggingLevel(value) {
61
+ SceneLoaderFlags.loggingLevel = value;
62
+ }
63
+ /**
64
+ * Gets or set a boolean indicating if matrix weights must be cleaned upon loading
65
+ */
66
+ static get CleanBoneMatrixWeights() {
67
+ return SceneLoaderFlags.CleanBoneMatrixWeights;
68
+ }
69
+ static set CleanBoneMatrixWeights(value) {
70
+ SceneLoaderFlags.CleanBoneMatrixWeights = value;
71
+ }
72
+ /**
73
+ * Gets the default plugin (used to load Babylon files)
74
+ * @returns the .babylon plugin
75
+ */
76
+ static GetDefaultPlugin() {
77
+ return SceneLoader._RegisteredPlugins[".babylon"];
78
+ }
79
+ static _GetPluginForExtension(extension) {
80
+ const registeredPlugin = SceneLoader._RegisteredPlugins[extension];
81
+ if (registeredPlugin) {
82
+ return registeredPlugin;
83
+ }
84
+ Logger.Warn("Unable to find a plugin to load " +
85
+ extension +
86
+ " files. Trying to use .babylon default plugin. To load from a specific filetype (eg. gltf) see: https://doc.babylonjs.com/features/featuresDeepDive/importers/loadingFileTypes");
87
+ return SceneLoader.GetDefaultPlugin();
88
+ }
89
+ static _GetPluginForDirectLoad(data) {
90
+ for (const extension in SceneLoader._RegisteredPlugins) {
91
+ const plugin = SceneLoader._RegisteredPlugins[extension].plugin;
92
+ if (plugin.canDirectLoad && plugin.canDirectLoad(data)) {
93
+ return SceneLoader._RegisteredPlugins[extension];
94
+ }
95
+ }
96
+ return SceneLoader.GetDefaultPlugin();
97
+ }
98
+ static _GetPluginForFilename(sceneFilename) {
99
+ const queryStringPosition = sceneFilename.indexOf("?");
100
+ if (queryStringPosition !== -1) {
101
+ sceneFilename = sceneFilename.substring(0, queryStringPosition);
102
+ }
103
+ const dotPosition = sceneFilename.lastIndexOf(".");
104
+ const extension = sceneFilename.substring(dotPosition, sceneFilename.length).toLowerCase();
105
+ return SceneLoader._GetPluginForExtension(extension);
106
+ }
107
+ static _GetDirectLoad(sceneFilename) {
108
+ if (sceneFilename.substr(0, 5) === "data:") {
109
+ return sceneFilename.substr(5);
110
+ }
111
+ return null;
112
+ }
113
+ static _FormatErrorMessage(fileInfo, message, exception) {
114
+ const fromLoad = fileInfo.rawData ? "binary data" : fileInfo.url;
115
+ let errorMessage = "Unable to load from " + fromLoad;
116
+ if (message) {
117
+ errorMessage += `: ${message}`;
118
+ }
119
+ else if (exception) {
120
+ errorMessage += `: ${exception}`;
121
+ }
122
+ return errorMessage;
123
+ }
124
+ static _LoadData(fileInfo, scene, onSuccess, onProgress, onError, onDispose, pluginExtension, name) {
125
+ const directLoad = SceneLoader._GetDirectLoad(fileInfo.url);
126
+ if (fileInfo.rawData && !pluginExtension) {
127
+ throw "When using ArrayBufferView to load data the file extension must be provided.";
128
+ }
129
+ const registeredPlugin = pluginExtension
130
+ ? SceneLoader._GetPluginForExtension(pluginExtension)
131
+ : directLoad
132
+ ? SceneLoader._GetPluginForDirectLoad(fileInfo.url)
133
+ : SceneLoader._GetPluginForFilename(fileInfo.url);
134
+ if (fileInfo.rawData && !registeredPlugin.isBinary) {
135
+ throw "Loading from ArrayBufferView can not be used with plugins that don't support binary loading.";
136
+ }
137
+ let plugin;
138
+ if (registeredPlugin.plugin.createPlugin !== undefined) {
139
+ plugin = registeredPlugin.plugin.createPlugin();
140
+ }
141
+ else {
142
+ plugin = registeredPlugin.plugin;
143
+ }
144
+ if (!plugin) {
145
+ throw "The loader plugin corresponding to the file type you are trying to load has not been found. If using es6, please import the plugin you wish to use before.";
146
+ }
147
+ SceneLoader.OnPluginActivatedObservable.notifyObservers(plugin);
148
+ // Check if we have a direct load url. If the plugin is registered to handle
149
+ // it or it's not a base64 data url, then pass it through the direct load path.
150
+ if (directLoad && ((plugin.canDirectLoad && plugin.canDirectLoad(fileInfo.url)) || !IsBase64DataUrl(fileInfo.url))) {
151
+ if (plugin.directLoad) {
152
+ const result = plugin.directLoad(scene, directLoad);
153
+ if (result.then) {
154
+ result
155
+ .then((data) => {
156
+ onSuccess(plugin, data);
157
+ })
158
+ .catch((error) => {
159
+ onError("Error in directLoad of _loadData: " + error, error);
160
+ });
161
+ }
162
+ else {
163
+ onSuccess(plugin, result);
164
+ }
165
+ }
166
+ else {
167
+ onSuccess(plugin, directLoad);
168
+ }
169
+ return plugin;
170
+ }
171
+ const useArrayBuffer = registeredPlugin.isBinary;
172
+ const dataCallback = (data, responseURL) => {
173
+ if (scene.isDisposed) {
174
+ onError("Scene has been disposed");
175
+ return;
176
+ }
177
+ onSuccess(plugin, data, responseURL);
178
+ };
179
+ let request = null;
180
+ let pluginDisposed = false;
181
+ const onDisposeObservable = plugin.onDisposeObservable;
182
+ if (onDisposeObservable) {
183
+ onDisposeObservable.add(() => {
184
+ pluginDisposed = true;
185
+ if (request) {
186
+ request.abort();
187
+ request = null;
188
+ }
189
+ onDispose();
190
+ });
191
+ }
192
+ const manifestChecked = () => {
193
+ if (pluginDisposed) {
194
+ return;
195
+ }
196
+ const errorCallback = (request, exception) => {
197
+ onError(request === null || request === void 0 ? void 0 : request.statusText, exception);
198
+ };
199
+ if (!plugin.loadFile && fileInfo.rawData) {
200
+ throw "Plugin does not support loading ArrayBufferView.";
201
+ }
202
+ request = plugin.loadFile
203
+ ? plugin.loadFile(scene, fileInfo.rawData || fileInfo.file || fileInfo.url, fileInfo.rootUrl, dataCallback, onProgress, useArrayBuffer, errorCallback, name)
204
+ : scene._loadFile(fileInfo.file || fileInfo.url, dataCallback, onProgress, true, useArrayBuffer, errorCallback);
205
+ };
206
+ const engine = scene.getEngine();
207
+ let canUseOfflineSupport = engine.enableOfflineSupport;
208
+ if (canUseOfflineSupport) {
209
+ // Also check for exceptions
210
+ let exceptionFound = false;
211
+ for (const regex of scene.disableOfflineSupportExceptionRules) {
212
+ if (regex.test(fileInfo.url)) {
213
+ exceptionFound = true;
214
+ break;
215
+ }
216
+ }
217
+ canUseOfflineSupport = !exceptionFound;
218
+ }
219
+ if (canUseOfflineSupport && Engine.OfflineProviderFactory) {
220
+ // Checking if a manifest file has been set for this scene and if offline mode has been requested
221
+ scene.offlineProvider = Engine.OfflineProviderFactory(fileInfo.url, manifestChecked, engine.disableManifestCheck);
222
+ }
223
+ else {
224
+ manifestChecked();
225
+ }
226
+ return plugin;
227
+ }
228
+ static _GetFileInfo(rootUrl, sceneFilename) {
229
+ let url;
230
+ let name;
231
+ let file = null;
232
+ let rawData = null;
233
+ if (!sceneFilename) {
234
+ url = rootUrl;
235
+ name = Tools.GetFilename(rootUrl);
236
+ rootUrl = Tools.GetFolderPath(rootUrl);
237
+ }
238
+ else if (sceneFilename.name) {
239
+ const sceneFile = sceneFilename;
240
+ url = `file:${sceneFile.name}`;
241
+ name = sceneFile.name;
242
+ file = sceneFile;
243
+ }
244
+ else if (ArrayBuffer.isView(sceneFilename)) {
245
+ url = "";
246
+ name = "arrayBuffer";
247
+ rawData = sceneFilename;
248
+ }
249
+ else if (typeof sceneFilename === "string" && sceneFilename.startsWith("data:")) {
250
+ url = sceneFilename;
251
+ name = "";
252
+ }
253
+ else {
254
+ const filename = sceneFilename;
255
+ if (filename.substr(0, 1) === "/") {
256
+ Tools.Error("Wrong sceneFilename parameter");
257
+ return null;
258
+ }
259
+ url = rootUrl + filename;
260
+ name = filename;
261
+ }
262
+ return {
263
+ url: url,
264
+ rootUrl: rootUrl,
265
+ name: name,
266
+ file: file,
267
+ rawData,
268
+ };
269
+ }
270
+ // Public functions
271
+ /**
272
+ * Gets a plugin that can load the given extension
273
+ * @param extension defines the extension to load
274
+ * @returns a plugin or null if none works
275
+ */
276
+ static GetPluginForExtension(extension) {
277
+ return SceneLoader._GetPluginForExtension(extension).plugin;
278
+ }
279
+ /**
280
+ * Gets a boolean indicating that the given extension can be loaded
281
+ * @param extension defines the extension to load
282
+ * @returns true if the extension is supported
283
+ */
284
+ static IsPluginForExtensionAvailable(extension) {
285
+ return !!SceneLoader._RegisteredPlugins[extension];
286
+ }
287
+ /**
288
+ * Adds a new plugin to the list of registered plugins
289
+ * @param plugin defines the plugin to add
290
+ */
291
+ static RegisterPlugin(plugin) {
292
+ if (typeof plugin.extensions === "string") {
293
+ const extension = plugin.extensions;
294
+ SceneLoader._RegisteredPlugins[extension.toLowerCase()] = {
295
+ plugin: plugin,
296
+ isBinary: false,
297
+ };
298
+ }
299
+ else {
300
+ const extensions = plugin.extensions;
301
+ Object.keys(extensions).forEach((extension) => {
302
+ SceneLoader._RegisteredPlugins[extension.toLowerCase()] = {
303
+ plugin: plugin,
304
+ isBinary: extensions[extension].isBinary,
305
+ };
306
+ });
307
+ }
308
+ }
309
+ /**
310
+ * Import meshes into a scene
311
+ * @param meshNames an array of mesh names, a single mesh name, or empty string for all meshes that filter what meshes are imported
312
+ * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
313
+ * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene or a File object (default: empty string)
314
+ * @param scene the instance of BABYLON.Scene to append to
315
+ * @param onSuccess a callback with a list of imported meshes, particleSystems, skeletons, and animationGroups when import succeeds
316
+ * @param onProgress a callback with a progress event for each file being loaded
317
+ * @param onError a callback with the scene, a message, and possibly an exception when import fails
318
+ * @param pluginExtension the extension used to determine the plugin
319
+ * @returns The loaded plugin
320
+ */
321
+ static ImportMesh(meshNames, rootUrl, sceneFilename = "", scene = EngineStore.LastCreatedScene, onSuccess = null, onProgress = null, onError = null, pluginExtension = null, name = "") {
322
+ if (!scene) {
323
+ Logger.Error("No scene available to import mesh to");
324
+ return null;
325
+ }
326
+ const fileInfo = SceneLoader._GetFileInfo(rootUrl, sceneFilename);
327
+ if (!fileInfo) {
328
+ return null;
329
+ }
330
+ const loadingToken = {};
331
+ scene.addPendingData(loadingToken);
332
+ const disposeHandler = () => {
333
+ scene.removePendingData(loadingToken);
334
+ };
335
+ const errorHandler = (message, exception) => {
336
+ const errorMessage = SceneLoader._FormatErrorMessage(fileInfo, message, exception);
337
+ if (onError) {
338
+ onError(scene, errorMessage, new RuntimeError(errorMessage, ErrorCodes.SceneLoaderError, exception));
339
+ }
340
+ else {
341
+ Logger.Error(errorMessage);
342
+ // should the exception be thrown?
343
+ }
344
+ disposeHandler();
345
+ };
346
+ const progressHandler = onProgress
347
+ ? (event) => {
348
+ try {
349
+ onProgress(event);
350
+ }
351
+ catch (e) {
352
+ errorHandler("Error in onProgress callback: " + e, e);
353
+ }
354
+ }
355
+ : undefined;
356
+ const successHandler = (meshes, particleSystems, skeletons, animationGroups, transformNodes, geometries, lights) => {
357
+ scene.importedMeshesFiles.push(fileInfo.url);
358
+ if (onSuccess) {
359
+ try {
360
+ onSuccess(meshes, particleSystems, skeletons, animationGroups, transformNodes, geometries, lights);
361
+ }
362
+ catch (e) {
363
+ errorHandler("Error in onSuccess callback: " + e, e);
364
+ }
365
+ }
366
+ scene.removePendingData(loadingToken);
367
+ };
368
+ return SceneLoader._LoadData(fileInfo, scene, (plugin, data, responseURL) => {
369
+ if (plugin.rewriteRootURL) {
370
+ fileInfo.rootUrl = plugin.rewriteRootURL(fileInfo.rootUrl, responseURL);
371
+ }
372
+ if (plugin.importMesh) {
373
+ const syncedPlugin = plugin;
374
+ const meshes = new Array();
375
+ const particleSystems = new Array();
376
+ const skeletons = new Array();
377
+ if (!syncedPlugin.importMesh(meshNames, scene, data, fileInfo.rootUrl, meshes, particleSystems, skeletons, errorHandler)) {
378
+ return;
379
+ }
380
+ scene.loadingPluginName = plugin.name;
381
+ successHandler(meshes, particleSystems, skeletons, [], [], [], []);
382
+ }
383
+ else {
384
+ const asyncedPlugin = plugin;
385
+ asyncedPlugin
386
+ .importMeshAsync(meshNames, scene, data, fileInfo.rootUrl, progressHandler, fileInfo.name)
387
+ .then((result) => {
388
+ scene.loadingPluginName = plugin.name;
389
+ successHandler(result.meshes, result.particleSystems, result.skeletons, result.animationGroups, result.transformNodes, result.geometries, result.lights);
390
+ })
391
+ .catch((error) => {
392
+ errorHandler(error.message, error);
393
+ });
394
+ }
395
+ }, progressHandler, errorHandler, disposeHandler, pluginExtension, name);
396
+ }
397
+ /**
398
+ * Import meshes into a scene
399
+ * @param meshNames an array of mesh names, a single mesh name, or empty string for all meshes that filter what meshes are imported
400
+ * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
401
+ * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene or a File object (default: empty string)
402
+ * @param scene the instance of BABYLON.Scene to append to
403
+ * @param onProgress a callback with a progress event for each file being loaded
404
+ * @param pluginExtension the extension used to determine the plugin
405
+ * @returns The loaded list of imported meshes, particle systems, skeletons, and animation groups
406
+ */
407
+ static ImportMeshAsync(meshNames, rootUrl, sceneFilename = "", scene = EngineStore.LastCreatedScene, onProgress = null, pluginExtension = null, name = "") {
408
+ return new Promise((resolve, reject) => {
409
+ SceneLoader.ImportMesh(meshNames, rootUrl, sceneFilename, scene, (meshes, particleSystems, skeletons, animationGroups, transformNodes, geometries, lights) => {
410
+ resolve({
411
+ meshes: meshes,
412
+ particleSystems: particleSystems,
413
+ skeletons: skeletons,
414
+ animationGroups: animationGroups,
415
+ transformNodes: transformNodes,
416
+ geometries: geometries,
417
+ lights: lights,
418
+ });
419
+ }, onProgress, (scene, message, exception) => {
420
+ reject(exception || new Error(message));
421
+ }, pluginExtension, name);
422
+ });
423
+ }
424
+ /**
425
+ * Load a scene
426
+ * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
427
+ * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene or a File object (default: empty string)
428
+ * @param engine is the instance of BABYLON.Engine to use to create the scene
429
+ * @param onSuccess a callback with the scene when import succeeds
430
+ * @param onProgress a callback with a progress event for each file being loaded
431
+ * @param onError a callback with the scene, a message, and possibly an exception when import fails
432
+ * @param pluginExtension the extension used to determine the plugin
433
+ * @returns The loaded plugin
434
+ */
435
+ static Load(rootUrl, sceneFilename = "", engine = EngineStore.LastCreatedEngine, onSuccess = null, onProgress = null, onError = null, pluginExtension = null, name = "") {
436
+ if (!engine) {
437
+ Tools.Error("No engine available");
438
+ return null;
439
+ }
440
+ return SceneLoader.Append(rootUrl, sceneFilename, new Scene(engine), onSuccess, onProgress, onError, pluginExtension, name);
441
+ }
442
+ /**
443
+ * Load a scene
444
+ * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
445
+ * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene or a File object (default: empty string)
446
+ * @param engine is the instance of BABYLON.Engine to use to create the scene
447
+ * @param onProgress a callback with a progress event for each file being loaded
448
+ * @param pluginExtension the extension used to determine the plugin
449
+ * @returns The loaded scene
450
+ */
451
+ static LoadAsync(rootUrl, sceneFilename = "", engine = EngineStore.LastCreatedEngine, onProgress = null, pluginExtension = null, name = "") {
452
+ return new Promise((resolve, reject) => {
453
+ SceneLoader.Load(rootUrl, sceneFilename, engine, (scene) => {
454
+ resolve(scene);
455
+ }, onProgress, (scene, message, exception) => {
456
+ reject(exception || new Error(message));
457
+ }, pluginExtension, name);
458
+ });
459
+ }
460
+ /**
461
+ * Append a scene
462
+ * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
463
+ * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene or a File object (default: empty string)
464
+ * @param scene is the instance of BABYLON.Scene to append to
465
+ * @param onSuccess a callback with the scene when import succeeds
466
+ * @param onProgress a callback with a progress event for each file being loaded
467
+ * @param onError a callback with the scene, a message, and possibly an exception when import fails
468
+ * @param pluginExtension the extension used to determine the plugin
469
+ * @returns The loaded plugin
470
+ */
471
+ static Append(rootUrl, sceneFilename = "", scene = EngineStore.LastCreatedScene, onSuccess = null, onProgress = null, onError = null, pluginExtension = null, name = "") {
472
+ if (!scene) {
473
+ Logger.Error("No scene available to append to");
474
+ return null;
475
+ }
476
+ const fileInfo = SceneLoader._GetFileInfo(rootUrl, sceneFilename);
477
+ if (!fileInfo) {
478
+ return null;
479
+ }
480
+ const loadingToken = {};
481
+ scene.addPendingData(loadingToken);
482
+ const disposeHandler = () => {
483
+ scene.removePendingData(loadingToken);
484
+ };
485
+ if (SceneLoader.ShowLoadingScreen && !this._ShowingLoadingScreen) {
486
+ this._ShowingLoadingScreen = true;
487
+ scene.getEngine().displayLoadingUI();
488
+ scene.executeWhenReady(() => {
489
+ scene.getEngine().hideLoadingUI();
490
+ this._ShowingLoadingScreen = false;
491
+ });
492
+ }
493
+ const errorHandler = (message, exception) => {
494
+ const errorMessage = SceneLoader._FormatErrorMessage(fileInfo, message, exception);
495
+ if (onError) {
496
+ onError(scene, errorMessage, new RuntimeError(errorMessage, ErrorCodes.SceneLoaderError, exception));
497
+ }
498
+ else {
499
+ Logger.Error(errorMessage);
500
+ // should the exception be thrown?
501
+ }
502
+ disposeHandler();
503
+ };
504
+ const progressHandler = onProgress
505
+ ? (event) => {
506
+ try {
507
+ onProgress(event);
508
+ }
509
+ catch (e) {
510
+ errorHandler("Error in onProgress callback", e);
511
+ }
512
+ }
513
+ : undefined;
514
+ const successHandler = () => {
515
+ if (onSuccess) {
516
+ try {
517
+ onSuccess(scene);
518
+ }
519
+ catch (e) {
520
+ errorHandler("Error in onSuccess callback", e);
521
+ }
522
+ }
523
+ scene.removePendingData(loadingToken);
524
+ };
525
+ return SceneLoader._LoadData(fileInfo, scene, (plugin, data) => {
526
+ if (plugin.load) {
527
+ const syncedPlugin = plugin;
528
+ if (!syncedPlugin.load(scene, data, fileInfo.rootUrl, errorHandler)) {
529
+ return;
530
+ }
531
+ scene.loadingPluginName = plugin.name;
532
+ successHandler();
533
+ }
534
+ else {
535
+ const asyncedPlugin = plugin;
536
+ asyncedPlugin
537
+ .loadAsync(scene, data, fileInfo.rootUrl, progressHandler, fileInfo.name)
538
+ .then(() => {
539
+ scene.loadingPluginName = plugin.name;
540
+ successHandler();
541
+ })
542
+ .catch((error) => {
543
+ errorHandler(error.message, error);
544
+ });
545
+ }
546
+ }, progressHandler, errorHandler, disposeHandler, pluginExtension, name);
547
+ }
548
+ /**
549
+ * Append a scene
550
+ * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
551
+ * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene or a File object (default: empty string)
552
+ * @param scene is the instance of BABYLON.Scene to append to
553
+ * @param onProgress a callback with a progress event for each file being loaded
554
+ * @param pluginExtension the extension used to determine the plugin
555
+ * @returns The given scene
556
+ */
557
+ static AppendAsync(rootUrl, sceneFilename = "", scene = EngineStore.LastCreatedScene, onProgress = null, pluginExtension = null, name = "") {
558
+ return new Promise((resolve, reject) => {
559
+ SceneLoader.Append(rootUrl, sceneFilename, scene, (scene) => {
560
+ resolve(scene);
561
+ }, onProgress, (scene, message, exception) => {
562
+ reject(exception || new Error(message));
563
+ }, pluginExtension, name);
564
+ });
565
+ }
566
+ /**
567
+ * Load a scene into an asset container
568
+ * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
569
+ * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene or a File object (default: empty string)
570
+ * @param scene is the instance of BABYLON.Scene to append to (default: last created scene)
571
+ * @param onSuccess a callback with the scene when import succeeds
572
+ * @param onProgress a callback with a progress event for each file being loaded
573
+ * @param onError a callback with the scene, a message, and possibly an exception when import fails
574
+ * @param pluginExtension the extension used to determine the plugin
575
+ * @returns The loaded plugin
576
+ */
577
+ static LoadAssetContainer(rootUrl, sceneFilename = "", scene = EngineStore.LastCreatedScene, onSuccess = null, onProgress = null, onError = null, pluginExtension = null, name = "") {
578
+ if (!scene) {
579
+ Logger.Error("No scene available to load asset container to");
580
+ return null;
581
+ }
582
+ const fileInfo = SceneLoader._GetFileInfo(rootUrl, sceneFilename);
583
+ if (!fileInfo) {
584
+ return null;
585
+ }
586
+ const loadingToken = {};
587
+ scene.addPendingData(loadingToken);
588
+ const disposeHandler = () => {
589
+ scene.removePendingData(loadingToken);
590
+ };
591
+ const errorHandler = (message, exception) => {
592
+ const errorMessage = SceneLoader._FormatErrorMessage(fileInfo, message, exception);
593
+ if (onError) {
594
+ onError(scene, errorMessage, new RuntimeError(errorMessage, ErrorCodes.SceneLoaderError, exception));
595
+ }
596
+ else {
597
+ Logger.Error(errorMessage);
598
+ // should the exception be thrown?
599
+ }
600
+ disposeHandler();
601
+ };
602
+ const progressHandler = onProgress
603
+ ? (event) => {
604
+ try {
605
+ onProgress(event);
606
+ }
607
+ catch (e) {
608
+ errorHandler("Error in onProgress callback", e);
609
+ }
610
+ }
611
+ : undefined;
612
+ const successHandler = (assets) => {
613
+ if (onSuccess) {
614
+ try {
615
+ onSuccess(assets);
616
+ }
617
+ catch (e) {
618
+ errorHandler("Error in onSuccess callback", e);
619
+ }
620
+ }
621
+ scene.removePendingData(loadingToken);
622
+ };
623
+ return SceneLoader._LoadData(fileInfo, scene, (plugin, data) => {
624
+ if (plugin.loadAssetContainer) {
625
+ const syncedPlugin = plugin;
626
+ const assetContainer = syncedPlugin.loadAssetContainer(scene, data, fileInfo.rootUrl, errorHandler);
627
+ if (!assetContainer) {
628
+ return;
629
+ }
630
+ scene.loadingPluginName = plugin.name;
631
+ successHandler(assetContainer);
632
+ }
633
+ else if (plugin.loadAssetContainerAsync) {
634
+ const asyncedPlugin = plugin;
635
+ asyncedPlugin
636
+ .loadAssetContainerAsync(scene, data, fileInfo.rootUrl, progressHandler, fileInfo.name)
637
+ .then((assetContainer) => {
638
+ scene.loadingPluginName = plugin.name;
639
+ successHandler(assetContainer);
640
+ })
641
+ .catch((error) => {
642
+ errorHandler(error.message, error);
643
+ });
644
+ }
645
+ else {
646
+ errorHandler("LoadAssetContainer is not supported by this plugin. Plugin did not provide a loadAssetContainer or loadAssetContainerAsync method.");
647
+ }
648
+ }, progressHandler, errorHandler, disposeHandler, pluginExtension, name);
649
+ }
650
+ /**
651
+ * Load a scene into an asset container
652
+ * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
653
+ * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene (default: empty string)
654
+ * @param scene is the instance of Scene to append to
655
+ * @param onProgress a callback with a progress event for each file being loaded
656
+ * @param pluginExtension the extension used to determine the plugin
657
+ * @returns The loaded asset container
658
+ */
659
+ static LoadAssetContainerAsync(rootUrl, sceneFilename = "", scene = EngineStore.LastCreatedScene, onProgress = null, pluginExtension = null) {
660
+ return new Promise((resolve, reject) => {
661
+ SceneLoader.LoadAssetContainer(rootUrl, sceneFilename, scene, (assetContainer) => {
662
+ resolve(assetContainer);
663
+ }, onProgress, (scene, message, exception) => {
664
+ reject(exception || new Error(message));
665
+ }, pluginExtension);
666
+ });
667
+ }
668
+ /**
669
+ * Import animations from a file into a scene
670
+ * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
671
+ * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene or a File object (default: empty string)
672
+ * @param scene is the instance of BABYLON.Scene to append to (default: last created scene)
673
+ * @param overwriteAnimations when true, animations are cleaned before importing new ones. Animations are appended otherwise
674
+ * @param animationGroupLoadingMode defines how to handle old animations groups before importing new ones
675
+ * @param targetConverter defines a function used to convert animation targets from loaded scene to current scene (default: search node by name)
676
+ * @param onSuccess a callback with the scene when import succeeds
677
+ * @param onProgress a callback with a progress event for each file being loaded
678
+ * @param onError a callback with the scene, a message, and possibly an exception when import fails
679
+ * @param pluginExtension the extension used to determine the plugin
680
+ */
681
+ static ImportAnimations(rootUrl, sceneFilename = "", scene = EngineStore.LastCreatedScene, overwriteAnimations = true, animationGroupLoadingMode = SceneLoaderAnimationGroupLoadingMode.Clean, targetConverter = null, onSuccess = null, onProgress = null, onError = null, pluginExtension = null) {
682
+ if (!scene) {
683
+ Logger.Error("No scene available to load animations to");
684
+ return;
685
+ }
686
+ if (overwriteAnimations) {
687
+ // Reset, stop and dispose all animations before loading new ones
688
+ for (const animatable of scene.animatables) {
689
+ animatable.reset();
690
+ }
691
+ scene.stopAllAnimations();
692
+ scene.animationGroups.slice().forEach((animationGroup) => {
693
+ animationGroup.dispose();
694
+ });
695
+ const nodes = scene.getNodes();
696
+ nodes.forEach((node) => {
697
+ if (node.animations) {
698
+ node.animations = [];
699
+ }
700
+ });
701
+ }
702
+ else {
703
+ switch (animationGroupLoadingMode) {
704
+ case SceneLoaderAnimationGroupLoadingMode.Clean:
705
+ scene.animationGroups.slice().forEach((animationGroup) => {
706
+ animationGroup.dispose();
707
+ });
708
+ break;
709
+ case SceneLoaderAnimationGroupLoadingMode.Stop:
710
+ scene.animationGroups.forEach((animationGroup) => {
711
+ animationGroup.stop();
712
+ });
713
+ break;
714
+ case SceneLoaderAnimationGroupLoadingMode.Sync:
715
+ scene.animationGroups.forEach((animationGroup) => {
716
+ animationGroup.reset();
717
+ animationGroup.restart();
718
+ });
719
+ break;
720
+ case SceneLoaderAnimationGroupLoadingMode.NoSync:
721
+ // nothing to do
722
+ break;
723
+ default:
724
+ Logger.Error("Unknown animation group loading mode value '" + animationGroupLoadingMode + "'");
725
+ return;
726
+ }
727
+ }
728
+ const startingIndexForNewAnimatables = scene.animatables.length;
729
+ const onAssetContainerLoaded = (container) => {
730
+ container.mergeAnimationsTo(scene, scene.animatables.slice(startingIndexForNewAnimatables), targetConverter);
731
+ container.dispose();
732
+ scene.onAnimationFileImportedObservable.notifyObservers(scene);
733
+ if (onSuccess) {
734
+ onSuccess(scene);
735
+ }
736
+ };
737
+ this.LoadAssetContainer(rootUrl, sceneFilename, scene, onAssetContainerLoaded, onProgress, onError, pluginExtension);
738
+ }
739
+ /**
740
+ * Import animations from a file into a scene
741
+ * @param rootUrl a string that defines the root url for the scene and resources or the concatenation of rootURL and filename (e.g. http://example.com/test.glb)
742
+ * @param sceneFilename a string that defines the name of the scene file or starts with "data:" following by the stringified version of the scene or a File object (default: empty string)
743
+ * @param scene is the instance of BABYLON.Scene to append to (default: last created scene)
744
+ * @param overwriteAnimations when true, animations are cleaned before importing new ones. Animations are appended otherwise
745
+ * @param animationGroupLoadingMode defines how to handle old animations groups before importing new ones
746
+ * @param targetConverter defines a function used to convert animation targets from loaded scene to current scene (default: search node by name)
747
+ * @param onSuccess a callback with the scene when import succeeds
748
+ * @param onProgress a callback with a progress event for each file being loaded
749
+ * @param onError a callback with the scene, a message, and possibly an exception when import fails
750
+ * @param pluginExtension the extension used to determine the plugin
751
+ * @returns the updated scene with imported animations
752
+ */
753
+ static ImportAnimationsAsync(rootUrl, sceneFilename = "", scene = EngineStore.LastCreatedScene, overwriteAnimations = true, animationGroupLoadingMode = SceneLoaderAnimationGroupLoadingMode.Clean, targetConverter = null,
754
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
755
+ onSuccess = null, onProgress = null,
756
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
757
+ onError = null, pluginExtension = null) {
758
+ return new Promise((resolve, reject) => {
759
+ SceneLoader.ImportAnimations(rootUrl, sceneFilename, scene, overwriteAnimations, animationGroupLoadingMode, targetConverter, (_scene) => {
760
+ resolve(_scene);
761
+ }, onProgress, (_scene, message, exception) => {
762
+ reject(exception || new Error(message));
763
+ }, pluginExtension);
764
+ });
765
+ }
766
+ }
767
+ /**
768
+ * No logging while loading
769
+ */
770
+ SceneLoader.NO_LOGGING = 0;
771
+ /**
772
+ * Minimal logging while loading
773
+ */
774
+ SceneLoader.MINIMAL_LOGGING = 1;
775
+ /**
776
+ * Summary logging while loading
777
+ */
778
+ SceneLoader.SUMMARY_LOGGING = 2;
779
+ /**
780
+ * Detailed logging while loading
781
+ */
782
+ SceneLoader.DETAILED_LOGGING = 3;
783
+ // Members
784
+ /**
785
+ * Event raised when a plugin is used to load a scene
786
+ */
787
+ SceneLoader.OnPluginActivatedObservable = new Observable();
788
+ SceneLoader._RegisteredPlugins = {};
789
+ SceneLoader._ShowingLoadingScreen = false;
790
+
791
+ /**
792
+ * A map of string to AssetContainer where the string represents
793
+ * a resource URL for a GLB file and the AssetContainer represents the loaded
794
+ * GL resources ready to use in a scene.
795
+ */
796
+ const assetCache = new Map();
797
+ /**
798
+ * This function wraps Babylon SceneLoader functionality and caches any
799
+ * existing loaded AssetContainers for future use. This ensures that we
800
+ * never have to hit browser cache and that all GL resources associated to a given URL
801
+ * are already loaded and ready to be applied to the scene.
802
+ * @param src The source to load from.
803
+ * @param scene The scene the container should be added to.
804
+ * @param progressHandler A handler to track progress of loading.
805
+ */
806
+ function getAssetContainer(src, scene, progressHandler) {
807
+ return __awaiter(this, void 0, void 0, function* () {
808
+ return new Promise((resolve, reject) => {
809
+ const existingContainer = assetCache.get(src);
810
+ if (existingContainer && existingContainer.scene.uid === scene.uid) {
811
+ return resolve(existingContainer);
812
+ }
813
+ else {
814
+ SceneLoader.LoadAssetContainerAsync(src, undefined, scene, progressHandler)
815
+ .then((newContainer) => {
816
+ assetCache.set(src, newContainer);
817
+ resolve(newContainer);
818
+ })
819
+ .catch(reject);
820
+ }
821
+ });
822
+ });
823
+ }
824
+
825
+ export { SceneLoader as S, assetCache as a, getAssetContainer as g };