babylon.sceneLoader.ts 14 KB

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