modelLoader.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import { AbstractViewer } from "../viewer/viewer";
  2. import { ISceneLoaderPlugin, ISceneLoaderPluginAsync, Tools, SceneLoader, Tags } from "babylonjs";
  3. import { GLTFFileLoader } from "babylonjs-loaders";
  4. import { IModelConfiguration } from "../configuration/configuration";
  5. import { ViewerModel, ModelState } from "./viewerModel";
  6. /**
  7. * An instance of the class is in charge of loading the model correctly.
  8. * This class will continously be expended with tasks required from the specific loaders Babylon has.
  9. *
  10. * A Model loader is unique per (Abstract)Viewer. It is being generated by the viewer
  11. */
  12. export class ModelLoader {
  13. private _loadId: number;
  14. private _disposed = false;
  15. private _loaders: Array<ISceneLoaderPlugin | ISceneLoaderPluginAsync>;
  16. /**
  17. * Create a new Model loader
  18. * @param _viewer the viewer using this model loader
  19. */
  20. constructor(private _viewer: AbstractViewer) {
  21. this._loaders = [];
  22. this._loadId = 0;
  23. }
  24. /**
  25. * Load a model using predefined configuration
  26. * @param modelConfiguration the modelConfiguration to use to load the model
  27. */
  28. public load(modelConfiguration: IModelConfiguration): ViewerModel {
  29. const model = new ViewerModel(this._viewer, modelConfiguration);
  30. if (!modelConfiguration.url) {
  31. model.state = ModelState.ERROR;
  32. Tools.Error("No URL provided");
  33. return model;
  34. }
  35. let filename = Tools.GetFilename(modelConfiguration.url) || modelConfiguration.url;
  36. let base = modelConfiguration.root || Tools.GetFolderPath(modelConfiguration.url);
  37. let plugin = modelConfiguration.loader;
  38. model.loader = SceneLoader.ImportMesh(undefined, base, filename, this._viewer.scene, (meshes, particleSystems, skeletons, animationGroups) => {
  39. meshes.forEach(mesh => {
  40. Tags.AddTagsTo(mesh, "viewerMesh");
  41. });
  42. model.meshes = meshes;
  43. model.particleSystems = particleSystems;
  44. model.skeletons = skeletons;
  45. for (const animationGroup of animationGroups) {
  46. model.addAnimationGroup(animationGroup);
  47. }
  48. model.initAnimations();
  49. model.onLoadedObservable.notifyObserversWithPromise(model);
  50. }, (progressEvent) => {
  51. model.onLoadProgressObservable.notifyObserversWithPromise(progressEvent);
  52. }, (e, m, exception) => {
  53. model.state = ModelState.ERROR;
  54. Tools.Error("Load Error: There was an error loading the model. " + m);
  55. model.onLoadErrorObservable.notifyObserversWithPromise({ message: m, exception: exception });
  56. }, plugin)!;
  57. if (model.loader.name === "gltf") {
  58. let gltfLoader = (<GLTFFileLoader>model.loader);
  59. gltfLoader.animationStartMode = BABYLON.GLTFLoaderAnimationStartMode.NONE;
  60. }
  61. model.loadId = this._loadId++;
  62. this._loaders.push(model.loader);
  63. return model;
  64. }
  65. public cancelLoad(model: ViewerModel) {
  66. const loader = model.loader || this._loaders[model.loadId];
  67. // ATM only available in the GLTF Loader
  68. if (loader && loader.name === "gltf") {
  69. let gltfLoader = (<GLTFFileLoader>loader);
  70. gltfLoader.dispose();
  71. model.state = ModelState.CANCELED;
  72. } else {
  73. Tools.Warn("This type of loader cannot cancel the request");
  74. }
  75. }
  76. /**
  77. * dispose the model loader.
  78. * If loaders are registered and are in the middle of loading, they will be disposed and the request(s) will be cancelled.
  79. */
  80. public dispose() {
  81. this._loaders.forEach(loader => {
  82. if (loader.name === "gltf") {
  83. (<GLTFFileLoader>loader).dispose();
  84. }
  85. });
  86. this._loaders.length = 0;
  87. this._disposed = true;
  88. }
  89. }