babylon.sceneLoader.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  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. try {
  131. if ((<any>plugin).importMesh) {
  132. var syncedPlugin = <ISceneLoaderPlugin>plugin;
  133. if (!syncedPlugin.importMesh(meshesNames, scene, data, rootUrl, meshes, particleSystems, skeletons)) {
  134. if (onerror) {
  135. onerror(scene, 'Unable to import meshes from ' + rootUrl + sceneFilename);
  136. }
  137. scene._removePendingData(loadingToken);
  138. return;
  139. }
  140. if (onsuccess) {
  141. scene.importedMeshesFiles.push(rootUrl + sceneFilename);
  142. onsuccess(meshes, particleSystems, skeletons);
  143. scene._removePendingData(loadingToken);
  144. }
  145. } else {
  146. var asyncedPlugin = <ISceneLoaderPluginAsync>plugin;
  147. asyncedPlugin.importMeshAsync(meshesNames, scene, data, rootUrl, (meshes, particleSystems, skeletons) => {
  148. if (onsuccess) {
  149. scene.importedMeshesFiles.push(rootUrl + sceneFilename);
  150. onsuccess(meshes, particleSystems, skeletons);
  151. scene._removePendingData(loadingToken);
  152. }
  153. }, () => {
  154. if (onerror) {
  155. onerror(scene, 'Unable to import meshes from ' + rootUrl + sceneFilename);
  156. }
  157. scene._removePendingData(loadingToken);
  158. });
  159. }
  160. } catch (e) {
  161. if (onerror) {
  162. onerror(scene, 'Unable to import meshes from ' + rootUrl + sceneFilename, e);
  163. }
  164. scene._removePendingData(loadingToken);
  165. }
  166. };
  167. if (directLoad) {
  168. importMeshFromData(directLoad);
  169. return;
  170. }
  171. Tools.LoadFile(rootUrl + sceneFilename, data => {
  172. importMeshFromData(data);
  173. }, progressCallBack, database, useArrayBuffer);
  174. };
  175. if (scene.getEngine().enableOfflineSupport && !directLoad) {
  176. // Checking if a manifest file has been set for this scene and if offline mode has been requested
  177. var database = new Database(rootUrl + sceneFilename, manifestChecked);
  178. }
  179. else {
  180. // If the scene is a data stream or offline support is not enabled, it's a direct load
  181. manifestChecked(true);
  182. }
  183. }
  184. /**
  185. * Load a scene
  186. * @param rootUrl a string that defines the root url for scene and resources
  187. * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
  188. * @param engine is the instance of BABYLON.Engine to use to create the scene
  189. */
  190. public static Load(rootUrl: string, sceneFilename: any, engine: Engine, onsuccess?: (scene: Scene) => void, progressCallBack?: any, onerror?: (scene: Scene) => void): void {
  191. SceneLoader.Append(rootUrl, sceneFilename, new Scene(engine), onsuccess, progressCallBack, onerror);
  192. }
  193. /**
  194. * Append a scene
  195. * @param rootUrl a string that defines the root url for scene and resources
  196. * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
  197. * @param scene is the instance of BABYLON.Scene to append to
  198. */
  199. public static Append(rootUrl: string, sceneFilename: any, scene: Scene, onsuccess?: (scene: Scene) => void, progressCallBack?: any, onerror?: (scene: Scene) => void): void {
  200. if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
  201. Tools.Error("Wrong sceneFilename parameter");
  202. return;
  203. }
  204. var directLoad = SceneLoader._getDirectLoad(sceneFilename);
  205. var registeredPlugin = directLoad ? SceneLoader._getDefaultPlugin() : SceneLoader._getPluginForFilename(sceneFilename);
  206. var plugin = registeredPlugin.plugin;
  207. var useArrayBuffer = registeredPlugin.isBinary;
  208. var database;
  209. var loadingToken = {};
  210. scene._addPendingData(loadingToken);
  211. if (SceneLoader.ShowLoadingScreen) {
  212. scene.getEngine().displayLoadingUI();
  213. }
  214. var loadSceneFromData = data => {
  215. scene.database = database;
  216. if ((<any>plugin).load) {
  217. var syncedPlugin = <ISceneLoaderPlugin>plugin;
  218. if (!syncedPlugin.load(scene, data, rootUrl)) {
  219. if (onerror) {
  220. onerror(scene);
  221. }
  222. scene._removePendingData(loadingToken);
  223. scene.getEngine().hideLoadingUI();
  224. return;
  225. }
  226. if (onsuccess) {
  227. onsuccess(scene);
  228. }
  229. scene._removePendingData(loadingToken);
  230. } else {
  231. var asyncedPlugin = <ISceneLoaderPluginAsync>plugin;
  232. asyncedPlugin.loadAsync(scene, data, rootUrl, () => {
  233. if (onsuccess) {
  234. onsuccess(scene);
  235. }
  236. }, () => {
  237. if (onerror) {
  238. onerror(scene);
  239. }
  240. scene._removePendingData(loadingToken);
  241. scene.getEngine().hideLoadingUI();
  242. });
  243. }
  244. if (SceneLoader.ShowLoadingScreen) {
  245. scene.executeWhenReady(() => {
  246. scene.getEngine().hideLoadingUI();
  247. });
  248. }
  249. };
  250. var manifestChecked = success => {
  251. Tools.LoadFile(rootUrl + sceneFilename, loadSceneFromData, progressCallBack, database, useArrayBuffer);
  252. };
  253. if (directLoad) {
  254. loadSceneFromData(directLoad);
  255. return;
  256. }
  257. if (rootUrl.indexOf("file:") === -1) {
  258. if (scene.getEngine().enableOfflineSupport) {
  259. // Checking if a manifest file has been set for this scene and if offline mode has been requested
  260. database = new Database(rootUrl + sceneFilename, manifestChecked);
  261. }
  262. else {
  263. manifestChecked(true);
  264. }
  265. }
  266. // Loading file from disk via input file or drag'n'drop
  267. else {
  268. Tools.ReadFile(sceneFilename, loadSceneFromData, progressCallBack, useArrayBuffer);
  269. }
  270. }
  271. };
  272. }