babylon.sceneLoader.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  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 registeredExtension = SceneLoader._registeredPlugins[extension];
  63. if (registeredExtension) {
  64. return registeredExtension;
  65. }
  66. return SceneLoader._getDefaultPlugin();
  67. }
  68. private static _getPluginForFilename(sceneFilename: string): IRegisteredPlugin {
  69. var dotPosition = sceneFilename.lastIndexOf(".");
  70. var queryStringPosition = sceneFilename.indexOf("?");
  71. if (queryStringPosition === -1) {
  72. queryStringPosition = sceneFilename.length;
  73. }
  74. var extension = sceneFilename.substring(dotPosition, queryStringPosition).toLowerCase();
  75. return SceneLoader._getPluginForExtension(extension);
  76. }
  77. // use babylon file loader directly if sceneFilename is prefixed with "data:"
  78. private static _getDirectLoad(sceneFilename: string): string {
  79. if (sceneFilename.substr && sceneFilename.substr(0, 5) === "data:") {
  80. return sceneFilename.substr(5);
  81. }
  82. return null;
  83. }
  84. // Public functions
  85. public static GetPluginForExtension(extension: string): ISceneLoaderPlugin | ISceneLoaderPluginAsync {
  86. return SceneLoader._getPluginForExtension(extension).plugin;
  87. }
  88. public static RegisterPlugin(plugin: ISceneLoaderPlugin | ISceneLoaderPluginAsync): void {
  89. if (typeof plugin.extensions === "string") {
  90. var extension = <string>plugin.extensions;
  91. SceneLoader._registeredPlugins[extension.toLowerCase()] = {
  92. plugin: plugin,
  93. isBinary: false
  94. };
  95. }
  96. else {
  97. var extensions = <ISceneLoaderPluginExtensions>plugin.extensions;
  98. Object.keys(extensions).forEach(extension => {
  99. SceneLoader._registeredPlugins[extension.toLowerCase()] = {
  100. plugin: plugin,
  101. isBinary: extensions[extension].isBinary
  102. };
  103. });
  104. }
  105. }
  106. 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 {
  107. if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
  108. Tools.Error("Wrong sceneFilename parameter");
  109. return;
  110. }
  111. if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
  112. Tools.Error("Wrong sceneFilename parameter");
  113. return;
  114. }
  115. var directLoad = SceneLoader._getDirectLoad(sceneFilename);
  116. var loadingToken = {};
  117. scene._addPendingData(loadingToken);
  118. var manifestChecked = success => {
  119. scene.database = database;
  120. var registeredExtension = directLoad ? SceneLoader._getDefaultPlugin() : SceneLoader._getPluginForFilename(sceneFilename);
  121. var plugin = registeredExtension.plugin;
  122. var useArrayBuffer = registeredExtension.isBinary;
  123. var importMeshFromData = data => {
  124. var meshes = [];
  125. var particleSystems = [];
  126. var skeletons = [];
  127. try {
  128. if ((<any>plugin).importMesh) {
  129. var syncedPlugin = <ISceneLoaderPlugin>plugin;
  130. if (!syncedPlugin.importMesh(meshesNames, scene, data, rootUrl, meshes, particleSystems, skeletons)) {
  131. if (onerror) {
  132. onerror(scene, 'Unable to import meshes from ' + rootUrl + sceneFilename);
  133. }
  134. scene._removePendingData(loadingToken);
  135. return;
  136. }
  137. if (onsuccess) {
  138. scene.importedMeshesFiles.push(rootUrl + sceneFilename);
  139. onsuccess(meshes, particleSystems, skeletons);
  140. scene._removePendingData(loadingToken);
  141. }
  142. } else {
  143. var asyncedPlugin = <ISceneLoaderPluginAsync>plugin;
  144. asyncedPlugin.importMeshAsync(meshesNames, scene, data, rootUrl, (meshes, particleSystems, skeletons) => {
  145. if (onsuccess) {
  146. scene.importedMeshesFiles.push(rootUrl + sceneFilename);
  147. onsuccess(meshes, particleSystems, skeletons);
  148. scene._removePendingData(loadingToken);
  149. }
  150. }, () => {
  151. if (onerror) {
  152. onerror(scene, 'Unable to import meshes from ' + rootUrl + sceneFilename);
  153. }
  154. scene._removePendingData(loadingToken);
  155. });
  156. }
  157. } catch (e) {
  158. if (onerror) {
  159. onerror(scene, 'Unable to import meshes from ' + rootUrl + sceneFilename, e);
  160. }
  161. scene._removePendingData(loadingToken);
  162. }
  163. };
  164. if (directLoad) {
  165. importMeshFromData(directLoad);
  166. return;
  167. }
  168. Tools.LoadFile(rootUrl + sceneFilename, data => {
  169. importMeshFromData(data);
  170. }, progressCallBack, database, useArrayBuffer);
  171. };
  172. if (scene.getEngine().enableOfflineSupport && !directLoad) {
  173. // Checking if a manifest file has been set for this scene and if offline mode has been requested
  174. var database = new Database(rootUrl + sceneFilename, manifestChecked);
  175. }
  176. else {
  177. // If the scene is a data stream or offline support is not enabled, it's a direct load
  178. manifestChecked(true);
  179. }
  180. }
  181. /**
  182. * Load a scene
  183. * @param rootUrl a string that defines the root url for scene and resources
  184. * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
  185. * @param engine is the instance of BABYLON.Engine to use to create the scene
  186. */
  187. public static Load(rootUrl: string, sceneFilename: any, engine: Engine, onsuccess?: (scene: Scene) => void, progressCallBack?: any, onerror?: (scene: Scene) => void): void {
  188. SceneLoader.Append(rootUrl, sceneFilename, new Scene(engine), onsuccess, progressCallBack, onerror);
  189. }
  190. /**
  191. * Append a scene
  192. * @param rootUrl a string that defines the root url for scene and resources
  193. * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
  194. * @param scene is the instance of BABYLON.Scene to append to
  195. */
  196. public static Append(rootUrl: string, sceneFilename: any, scene: Scene, onsuccess?: (scene: Scene) => void, progressCallBack?: any, onerror?: (scene: Scene) => void): void {
  197. if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
  198. Tools.Error("Wrong sceneFilename parameter");
  199. return;
  200. }
  201. var directLoad = SceneLoader._getDirectLoad(sceneFilename);
  202. var registeredExtension = directLoad ? SceneLoader._getDefaultPlugin() : SceneLoader._getPluginForFilename(sceneFilename);
  203. var plugin = registeredExtension.plugin;
  204. var useArrayBuffer = registeredExtension.isBinary;
  205. var database;
  206. var loadingToken = {};
  207. scene._addPendingData(loadingToken);
  208. if (SceneLoader.ShowLoadingScreen) {
  209. scene.getEngine().displayLoadingUI();
  210. }
  211. var loadSceneFromData = data => {
  212. scene.database = database;
  213. if ((<any>plugin).load) {
  214. var syncedPlugin = <ISceneLoaderPlugin>plugin;
  215. if (!syncedPlugin.load(scene, data, rootUrl)) {
  216. if (onerror) {
  217. onerror(scene);
  218. }
  219. scene._removePendingData(loadingToken);
  220. scene.getEngine().hideLoadingUI();
  221. return;
  222. }
  223. if (onsuccess) {
  224. onsuccess(scene);
  225. }
  226. scene._removePendingData(loadingToken);
  227. } else {
  228. var asyncedPlugin = <ISceneLoaderPluginAsync>plugin;
  229. asyncedPlugin.loadAsync(scene, data, rootUrl, () => {
  230. if (onsuccess) {
  231. onsuccess(scene);
  232. }
  233. }, () => {
  234. if (onerror) {
  235. onerror(scene);
  236. }
  237. scene._removePendingData(loadingToken);
  238. scene.getEngine().hideLoadingUI();
  239. });
  240. }
  241. if (SceneLoader.ShowLoadingScreen) {
  242. scene.executeWhenReady(() => {
  243. scene.getEngine().hideLoadingUI();
  244. });
  245. }
  246. };
  247. var manifestChecked = success => {
  248. Tools.LoadFile(rootUrl + sceneFilename, loadSceneFromData, progressCallBack, database, useArrayBuffer);
  249. };
  250. if (directLoad) {
  251. loadSceneFromData(directLoad);
  252. return;
  253. }
  254. if (rootUrl.indexOf("file:") === -1) {
  255. if (scene.getEngine().enableOfflineSupport) {
  256. // Checking if a manifest file has been set for this scene and if offline mode has been requested
  257. database = new Database(rootUrl + sceneFilename, manifestChecked);
  258. }
  259. else {
  260. manifestChecked(true);
  261. }
  262. }
  263. // Loading file from disk via input file or drag'n'drop
  264. else {
  265. Tools.ReadFile(sceneFilename, loadSceneFromData, progressCallBack, useArrayBuffer);
  266. }
  267. }
  268. };
  269. }