babylon.sceneLoader.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. module BABYLON {
  2. export interface ISceneLoaderPlugin {
  3. extensions: string;
  4. importMesh: (meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => boolean;
  5. load: (scene: Scene, data: string, rootUrl: string) => boolean;
  6. }
  7. export interface ISceneLoaderPluginAsync {
  8. extensions: string;
  9. importMeshAsync: (meshesNames: any, scene: Scene, data: any, rootUrl: string, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onerror?: () => void) => void;
  10. loadAsync: (scene: Scene, data: string, rootUrl: string, onsuccess: () => void, onerror: () => void) => boolean;
  11. }
  12. export class SceneLoader {
  13. // Flags
  14. private static _ForceFullSceneLoadingForIncremental = false;
  15. private static _ShowLoadingScreen = true;
  16. public static get NO_LOGGING(): number {
  17. return 0;
  18. }
  19. public static get MINIMAL_LOGGING(): number {
  20. return 1;
  21. }
  22. public static get SUMMARY_LOGGING(): number {
  23. return 2;
  24. }
  25. public static get DETAILED_LOGGING(): number {
  26. return 3;
  27. }
  28. private static _loggingLevel = SceneLoader.NO_LOGGING;
  29. public static get ForceFullSceneLoadingForIncremental() {
  30. return SceneLoader._ForceFullSceneLoadingForIncremental;
  31. }
  32. public static set ForceFullSceneLoadingForIncremental(value: boolean) {
  33. SceneLoader._ForceFullSceneLoadingForIncremental = value;
  34. }
  35. public static get ShowLoadingScreen() {
  36. return SceneLoader._ShowLoadingScreen;
  37. }
  38. public static set ShowLoadingScreen(value: boolean) {
  39. SceneLoader._ShowLoadingScreen = value;
  40. }
  41. public static get loggingLevel() {
  42. return SceneLoader._loggingLevel;
  43. }
  44. public static set loggingLevel(value: number) {
  45. SceneLoader._loggingLevel = value;
  46. }
  47. // Members
  48. private static _registeredPlugins = new Array<ISceneLoaderPlugin | ISceneLoaderPluginAsync >();
  49. private static _getPluginForFilename(sceneFilename): ISceneLoaderPlugin | ISceneLoaderPluginAsync {
  50. var dotPosition = sceneFilename.lastIndexOf(".");
  51. var queryStringPosition = sceneFilename.indexOf("?");
  52. if (queryStringPosition === -1) {
  53. queryStringPosition = sceneFilename.length;
  54. }
  55. var extension = sceneFilename.substring(dotPosition, queryStringPosition).toLowerCase();
  56. for (var index = 0; index < this._registeredPlugins.length; index++) {
  57. var plugin = this._registeredPlugins[index];
  58. if (plugin.extensions.indexOf(extension) !== -1) {
  59. return plugin;
  60. }
  61. }
  62. return this._registeredPlugins[this._registeredPlugins.length - 1];
  63. }
  64. // Public functions
  65. public static GetPluginForExtension(extension: string): ISceneLoaderPlugin | ISceneLoaderPluginAsync {
  66. for (var index = 0; index < this._registeredPlugins.length; index++) {
  67. var plugin = this._registeredPlugins[index];
  68. if (plugin.extensions.indexOf(extension) !== -1) {
  69. return plugin;
  70. }
  71. }
  72. return null;
  73. }
  74. public static RegisterPlugin(plugin: ISceneLoaderPlugin): void {
  75. plugin.extensions = plugin.extensions.toLowerCase();
  76. SceneLoader._registeredPlugins.push(plugin);
  77. }
  78. public static ImportMesh(meshesNames: any, rootUrl: string, sceneFilename: string, scene: Scene, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, progressCallBack?: () => void, onerror?: (scene: Scene, message: string, exception?: any) => void): void {
  79. if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
  80. Tools.Error("Wrong sceneFilename parameter");
  81. return;
  82. }
  83. var loadingToken = {};
  84. scene._addPendingData(loadingToken);
  85. var manifestChecked = success => {
  86. scene.database = database;
  87. var plugin = SceneLoader._getPluginForFilename(sceneFilename);
  88. var importMeshFromData = data => {
  89. var meshes = [];
  90. var particleSystems = [];
  91. var skeletons = [];
  92. try {
  93. if ((<any>plugin).importMesh) {
  94. var syncedPlugin = <ISceneLoaderPlugin>plugin;
  95. if (!syncedPlugin.importMesh(meshesNames, scene, data, rootUrl, meshes, particleSystems, skeletons)) {
  96. if (onerror) {
  97. onerror(scene, 'Unable to import meshes from ' + rootUrl + sceneFilename);
  98. }
  99. scene._removePendingData(loadingToken);
  100. return;
  101. }
  102. if (onsuccess) {
  103. scene.importedMeshesFiles.push(rootUrl + sceneFilename);
  104. onsuccess(meshes, particleSystems, skeletons);
  105. scene._removePendingData(loadingToken);
  106. }
  107. } else {
  108. var asyncedPlugin = <ISceneLoaderPluginAsync>plugin;
  109. asyncedPlugin.importMeshAsync(meshesNames, scene, data, rootUrl, (meshes, particleSystems, skeletons) => {
  110. if (onsuccess) {
  111. scene.importedMeshesFiles.push(rootUrl + sceneFilename);
  112. onsuccess(meshes, particleSystems, skeletons);
  113. scene._removePendingData(loadingToken);
  114. }
  115. }, () => {
  116. if (onerror) {
  117. onerror(scene, 'Unable to import meshes from ' + rootUrl + sceneFilename);
  118. }
  119. scene._removePendingData(loadingToken);
  120. });
  121. }
  122. } catch (e) {
  123. if (onerror) {
  124. onerror(scene, 'Unable to import meshes from ' + rootUrl + sceneFilename + ' (Exception: ' + e + ')');
  125. }
  126. scene._removePendingData(loadingToken);
  127. }
  128. };
  129. if (sceneFilename.substr && sceneFilename.substr(0, 5) === "data:") {
  130. // Direct load
  131. importMeshFromData(sceneFilename.substr(5));
  132. return;
  133. }
  134. Tools.LoadFile(rootUrl + sceneFilename, data => {
  135. importMeshFromData(data);
  136. }, progressCallBack, database);
  137. };
  138. if (scene.getEngine().enableOfflineSupport && !(sceneFilename.substr && sceneFilename.substr(0, 5) === "data:")) {
  139. // Checking if a manifest file has been set for this scene and if offline mode has been requested
  140. var database = new Database(rootUrl + sceneFilename, manifestChecked);
  141. }
  142. else {
  143. // If the scene is a data stream or offline support is not enabled, it's a direct load
  144. manifestChecked(true);
  145. }
  146. }
  147. /**
  148. * Load a scene
  149. * @param rootUrl a string that defines the root url for scene and resources
  150. * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
  151. * @param engine is the instance of BABYLON.Engine to use to create the scene
  152. */
  153. public static Load(rootUrl: string, sceneFilename: any, engine: Engine, onsuccess?: (scene: Scene) => void, progressCallBack?: any, onerror?: (scene: Scene) => void): void {
  154. SceneLoader.Append(rootUrl, sceneFilename, new Scene(engine), onsuccess, progressCallBack, onerror);
  155. }
  156. /**
  157. * Append a scene
  158. * @param rootUrl a string that defines the root url for scene and resources
  159. * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
  160. * @param scene is the instance of BABYLON.Scene to append to
  161. */
  162. public static Append(rootUrl: string, sceneFilename: any, scene: Scene, onsuccess?: (scene: Scene) => void, progressCallBack?: any, onerror?: (scene: Scene) => void): void {
  163. if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
  164. Tools.Error("Wrong sceneFilename parameter");
  165. return;
  166. }
  167. var plugin = this._getPluginForFilename(sceneFilename.name || sceneFilename);
  168. var database;
  169. var loadingToken = {};
  170. scene._addPendingData(loadingToken);
  171. if (SceneLoader.ShowLoadingScreen) {
  172. scene.getEngine().displayLoadingUI();
  173. }
  174. var loadSceneFromData = data => {
  175. scene.database = database;
  176. if ((<any>plugin).load) {
  177. var syncedPlugin = <ISceneLoaderPlugin>plugin;
  178. if (!syncedPlugin.load(scene, data, rootUrl)) {
  179. if (onerror) {
  180. onerror(scene);
  181. }
  182. scene._removePendingData(loadingToken);
  183. scene.getEngine().hideLoadingUI();
  184. return;
  185. }
  186. if (onsuccess) {
  187. onsuccess(scene);
  188. }
  189. scene._removePendingData(loadingToken);
  190. } else {
  191. var asyncedPlugin = <ISceneLoaderPluginAsync>plugin;
  192. asyncedPlugin.loadAsync(scene, data, rootUrl, () => {
  193. if (onsuccess) {
  194. onsuccess(scene);
  195. }
  196. }, () => {
  197. if (onerror) {
  198. onerror(scene);
  199. }
  200. scene._removePendingData(loadingToken);
  201. scene.getEngine().hideLoadingUI();
  202. });
  203. }
  204. if (SceneLoader.ShowLoadingScreen) {
  205. scene.executeWhenReady(() => {
  206. scene.getEngine().hideLoadingUI();
  207. });
  208. }
  209. };
  210. var manifestChecked = success => {
  211. Tools.LoadFile(rootUrl + sceneFilename, loadSceneFromData, progressCallBack, database);
  212. };
  213. if (sceneFilename.substr && sceneFilename.substr(0, 5) === "data:") {
  214. // Direct load
  215. loadSceneFromData(sceneFilename.substr(5));
  216. return;
  217. }
  218. if (rootUrl.indexOf("file:") === -1) {
  219. if (scene.getEngine().enableOfflineSupport) {
  220. // Checking if a manifest file has been set for this scene and if offline mode has been requested
  221. database = new Database(rootUrl + sceneFilename, manifestChecked);
  222. }
  223. else {
  224. manifestChecked(true);
  225. }
  226. }
  227. // Loading file from disk via input file or drag'n'drop
  228. else {
  229. Tools.ReadFile(sceneFilename, loadSceneFromData, progressCallBack);
  230. }
  231. }
  232. };
  233. }