assetsManager.js 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008
  1. import { SceneLoader, SceneLoaderAnimationGroupLoadingMode } from "../Loading/sceneLoader.js";
  2. import { Tools } from "./tools.js";
  3. import { Observable } from "./observable.js";
  4. import { Texture } from "../Materials/Textures/texture.js";
  5. import { CubeTexture } from "../Materials/Textures/cubeTexture.js";
  6. import { HDRCubeTexture } from "../Materials/Textures/hdrCubeTexture.js";
  7. import { EquiRectangularCubeTexture } from "../Materials/Textures/equiRectangularCubeTexture.js";
  8. import { Logger } from "../Misc/logger.js";
  9. import { EngineStore } from "../Engines/engineStore.js";
  10. /**
  11. * Defines the list of states available for a task inside a AssetsManager
  12. */
  13. export var AssetTaskState;
  14. (function (AssetTaskState) {
  15. /**
  16. * Initialization
  17. */
  18. AssetTaskState[AssetTaskState["INIT"] = 0] = "INIT";
  19. /**
  20. * Running
  21. */
  22. AssetTaskState[AssetTaskState["RUNNING"] = 1] = "RUNNING";
  23. /**
  24. * Done
  25. */
  26. AssetTaskState[AssetTaskState["DONE"] = 2] = "DONE";
  27. /**
  28. * Error
  29. */
  30. AssetTaskState[AssetTaskState["ERROR"] = 3] = "ERROR";
  31. })(AssetTaskState || (AssetTaskState = {}));
  32. /**
  33. * Define an abstract asset task used with a AssetsManager class to load assets into a scene
  34. */
  35. export class AbstractAssetTask {
  36. /**
  37. * Creates a new AssetsManager
  38. * @param name defines the name of the task
  39. */
  40. constructor(
  41. /**
  42. * Task name
  43. */ name) {
  44. this.name = name;
  45. this._isCompleted = false;
  46. this._taskState = AssetTaskState.INIT;
  47. }
  48. /**
  49. * Get if the task is completed
  50. */
  51. get isCompleted() {
  52. return this._isCompleted;
  53. }
  54. /**
  55. * Gets the current state of the task
  56. */
  57. get taskState() {
  58. return this._taskState;
  59. }
  60. /**
  61. * Gets the current error object (if task is in error)
  62. */
  63. get errorObject() {
  64. return this._errorObject;
  65. }
  66. /**
  67. * Internal only
  68. * @internal
  69. */
  70. _setErrorObject(message, exception) {
  71. if (this._errorObject) {
  72. return;
  73. }
  74. this._errorObject = {
  75. message: message,
  76. exception: exception,
  77. };
  78. }
  79. /**
  80. * Execute the current task
  81. * @param scene defines the scene where you want your assets to be loaded
  82. * @param onSuccess is a callback called when the task is successfully executed
  83. * @param onError is a callback called if an error occurs
  84. */
  85. run(scene, onSuccess, onError) {
  86. this._taskState = AssetTaskState.RUNNING;
  87. this.runTask(scene, () => {
  88. this._onDoneCallback(onSuccess, onError);
  89. }, (msg, exception) => {
  90. this._onErrorCallback(onError, msg, exception);
  91. });
  92. }
  93. /**
  94. * Execute the current task
  95. * @param scene defines the scene where you want your assets to be loaded
  96. * @param onSuccess is a callback called when the task is successfully executed
  97. * @param onError is a callback called if an error occurs
  98. */
  99. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  100. runTask(scene, onSuccess, onError) {
  101. throw new Error("runTask is not implemented");
  102. }
  103. /**
  104. * Reset will set the task state back to INIT, so the next load call of the assets manager will execute this task again.
  105. * This can be used with failed tasks that have the reason for failure fixed.
  106. */
  107. reset() {
  108. this._taskState = AssetTaskState.INIT;
  109. }
  110. _onErrorCallback(onError, message, exception) {
  111. this._taskState = AssetTaskState.ERROR;
  112. this._errorObject = {
  113. message: message,
  114. exception: exception,
  115. };
  116. if (this.onError) {
  117. this.onError(this, message, exception);
  118. }
  119. onError();
  120. }
  121. _onDoneCallback(onSuccess, onError) {
  122. try {
  123. this._taskState = AssetTaskState.DONE;
  124. this._isCompleted = true;
  125. if (this.onSuccess) {
  126. this.onSuccess(this);
  127. }
  128. onSuccess();
  129. }
  130. catch (e) {
  131. this._onErrorCallback(onError, "Task is done, error executing success callback(s)", e);
  132. }
  133. }
  134. }
  135. /**
  136. * Class used to share progress information about assets loading
  137. */
  138. export class AssetsProgressEvent {
  139. /**
  140. * Creates a AssetsProgressEvent
  141. * @param remainingCount defines the number of remaining tasks to process
  142. * @param totalCount defines the total number of tasks
  143. * @param task defines the task that was just processed
  144. */
  145. constructor(remainingCount, totalCount, task) {
  146. this.remainingCount = remainingCount;
  147. this.totalCount = totalCount;
  148. this.task = task;
  149. }
  150. }
  151. /**
  152. * Define a task used by AssetsManager to load assets into a container
  153. */
  154. export class ContainerAssetTask extends AbstractAssetTask {
  155. /**
  156. * Creates a new ContainerAssetTask
  157. * @param name defines the name of the task
  158. * @param meshesNames defines the list of mesh's names you want to load
  159. * @param rootUrl defines the root url to use as a base to load your meshes and associated resources
  160. * @param sceneFilename defines the filename or File of the scene to load from
  161. * @param extension defines the extension to use to load the scene (if not defined, ".babylon" will be used)
  162. */
  163. constructor(
  164. /**
  165. * Defines the name of the task
  166. */
  167. name,
  168. /**
  169. * Defines the list of mesh's names you want to load
  170. */
  171. meshesNames,
  172. /**
  173. * Defines the root url to use as a base to load your meshes and associated resources
  174. */
  175. rootUrl,
  176. /**
  177. * Defines the filename or File of the scene to load from
  178. */
  179. sceneFilename,
  180. /**
  181. * Defines the extension to use to load the scene (if not defined, ".babylon" will be used)
  182. */
  183. extension) {
  184. super(name);
  185. this.name = name;
  186. this.meshesNames = meshesNames;
  187. this.rootUrl = rootUrl;
  188. this.sceneFilename = sceneFilename;
  189. this.extension = extension;
  190. }
  191. /**
  192. * Execute the current task
  193. * @param scene defines the scene where you want your assets to be loaded
  194. * @param onSuccess is a callback called when the task is successfully executed
  195. * @param onError is a callback called if an error occurs
  196. */
  197. runTask(scene, onSuccess, onError) {
  198. SceneLoader.LoadAssetContainer(this.rootUrl, this.sceneFilename, scene, (container) => {
  199. this.loadedContainer = container;
  200. this.loadedMeshes = container.meshes;
  201. this.loadedTransformNodes = container.transformNodes;
  202. this.loadedParticleSystems = container.particleSystems;
  203. this.loadedSkeletons = container.skeletons;
  204. this.loadedAnimationGroups = container.animationGroups;
  205. onSuccess();
  206. }, null, (scene, message, exception) => {
  207. onError(message, exception);
  208. }, this.extension);
  209. }
  210. }
  211. /**
  212. * Define a task used by AssetsManager to load meshes
  213. */
  214. export class MeshAssetTask extends AbstractAssetTask {
  215. /**
  216. * Creates a new MeshAssetTask
  217. * @param name defines the name of the task
  218. * @param meshesNames defines the list of mesh's names you want to load
  219. * @param rootUrl defines the root url to use as a base to load your meshes and associated resources
  220. * @param sceneFilename defines the filename or File of the scene to load from
  221. * @param extension defines the extension to use to load the scene (if not defined, ".babylon" will be used)
  222. */
  223. constructor(
  224. /**
  225. * Defines the name of the task
  226. */
  227. name,
  228. /**
  229. * Defines the list of mesh's names you want to load
  230. */
  231. meshesNames,
  232. /**
  233. * Defines the root url to use as a base to load your meshes and associated resources
  234. */
  235. rootUrl,
  236. /**
  237. * Defines the filename or File of the scene to load from
  238. */
  239. sceneFilename,
  240. /**
  241. * Defines the extension to use to load the scene (if not defined, ".babylon" will be used)
  242. */
  243. extension) {
  244. super(name);
  245. this.name = name;
  246. this.meshesNames = meshesNames;
  247. this.rootUrl = rootUrl;
  248. this.sceneFilename = sceneFilename;
  249. this.extension = extension;
  250. }
  251. /**
  252. * Execute the current task
  253. * @param scene defines the scene where you want your assets to be loaded
  254. * @param onSuccess is a callback called when the task is successfully executed
  255. * @param onError is a callback called if an error occurs
  256. */
  257. runTask(scene, onSuccess, onError) {
  258. SceneLoader.ImportMesh(this.meshesNames, this.rootUrl, this.sceneFilename, scene, (meshes, particleSystems, skeletons, animationGroups, transformNodes) => {
  259. this.loadedMeshes = meshes;
  260. this.loadedTransformNodes = transformNodes;
  261. this.loadedParticleSystems = particleSystems;
  262. this.loadedSkeletons = skeletons;
  263. this.loadedAnimationGroups = animationGroups;
  264. onSuccess();
  265. }, null, (scene, message, exception) => {
  266. onError(message, exception);
  267. }, this.extension);
  268. }
  269. }
  270. /**
  271. * Define a task used by AssetsManager to load animations
  272. */
  273. export class AnimationAssetTask extends AbstractAssetTask {
  274. /**
  275. * Creates a new AnimationAssetTask
  276. * @param name defines the name of the task
  277. * @param rootUrl defines the root url to use as a base to load your meshes and associated resources
  278. * @param filename defines the filename or File of the scene to load from
  279. * @param targetConverter defines a function used to convert animation targets from loaded scene to current scene (default: search node by name)
  280. * @param extension defines the extension to use to load the scene (if not defined, ".babylon" will be used)
  281. */
  282. constructor(
  283. /**
  284. * Defines the name of the task
  285. */
  286. name,
  287. /**
  288. * Defines the root url to use as a base to load your meshes and associated resources
  289. */
  290. rootUrl,
  291. /**
  292. * Defines the filename to load from
  293. */
  294. filename,
  295. /**
  296. * Defines a function used to convert animation targets from loaded scene to current scene (default: search node by name)
  297. */
  298. targetConverter,
  299. /**
  300. * Defines the extension to use to load the scene (if not defined, ".babylon" will be used)
  301. */
  302. extension) {
  303. super(name);
  304. this.name = name;
  305. this.rootUrl = rootUrl;
  306. this.filename = filename;
  307. this.targetConverter = targetConverter;
  308. this.extension = extension;
  309. }
  310. /**
  311. * Execute the current task
  312. * @param scene defines the scene where you want your assets to be loaded
  313. * @param onSuccess is a callback called when the task is successfully executed
  314. * @param onError is a callback called if an error occurs
  315. */
  316. runTask(scene, onSuccess, onError) {
  317. const startingIndexForNewAnimatables = scene.animatables.length;
  318. const startingIndexForNewAnimationGroups = scene.animationGroups.length;
  319. this.loadedAnimatables = [];
  320. this.loadedAnimationGroups = [];
  321. SceneLoader.ImportAnimations(this.rootUrl, this.filename, scene, false, SceneLoaderAnimationGroupLoadingMode.NoSync, this.targetConverter, () => {
  322. this.loadedAnimatables = scene.animatables.slice(startingIndexForNewAnimatables);
  323. this.loadedAnimationGroups = scene.animationGroups.slice(startingIndexForNewAnimationGroups);
  324. onSuccess();
  325. }, null, (scene, message, exception) => {
  326. onError(message, exception);
  327. }, this.extension);
  328. }
  329. }
  330. /**
  331. * Define a task used by AssetsManager to load text content
  332. */
  333. export class TextFileAssetTask extends AbstractAssetTask {
  334. /**
  335. * Creates a new TextFileAssetTask object
  336. * @param name defines the name of the task
  337. * @param url defines the location of the file to load
  338. */
  339. constructor(
  340. /**
  341. * Defines the name of the task
  342. */
  343. name,
  344. /**
  345. * Defines the location of the file to load
  346. */
  347. url) {
  348. super(name);
  349. this.name = name;
  350. this.url = url;
  351. }
  352. /**
  353. * Execute the current task
  354. * @param scene defines the scene where you want your assets to be loaded
  355. * @param onSuccess is a callback called when the task is successfully executed
  356. * @param onError is a callback called if an error occurs
  357. */
  358. runTask(scene, onSuccess, onError) {
  359. scene._loadFile(this.url, (data) => {
  360. this.text = data;
  361. onSuccess();
  362. }, undefined, false, false, (request, exception) => {
  363. if (request) {
  364. onError(request.status + " " + request.statusText, exception);
  365. }
  366. });
  367. }
  368. }
  369. /**
  370. * Define a task used by AssetsManager to load binary data
  371. */
  372. export class BinaryFileAssetTask extends AbstractAssetTask {
  373. /**
  374. * Creates a new BinaryFileAssetTask object
  375. * @param name defines the name of the new task
  376. * @param url defines the location of the file to load
  377. */
  378. constructor(
  379. /**
  380. * Defines the name of the task
  381. */
  382. name,
  383. /**
  384. * Defines the location of the file to load
  385. */
  386. url) {
  387. super(name);
  388. this.name = name;
  389. this.url = url;
  390. }
  391. /**
  392. * Execute the current task
  393. * @param scene defines the scene where you want your assets to be loaded
  394. * @param onSuccess is a callback called when the task is successfully executed
  395. * @param onError is a callback called if an error occurs
  396. */
  397. runTask(scene, onSuccess, onError) {
  398. scene._loadFile(this.url, (data) => {
  399. this.data = data;
  400. onSuccess();
  401. }, undefined, true, true, (request, exception) => {
  402. if (request) {
  403. onError(request.status + " " + request.statusText, exception);
  404. }
  405. });
  406. }
  407. }
  408. /**
  409. * Define a task used by AssetsManager to load images
  410. */
  411. export class ImageAssetTask extends AbstractAssetTask {
  412. /**
  413. * Creates a new ImageAssetTask
  414. * @param name defines the name of the task
  415. * @param url defines the location of the image to load
  416. */
  417. constructor(
  418. /**
  419. * Defines the name of the task
  420. */
  421. name,
  422. /**
  423. * Defines the location of the image to load
  424. */
  425. url) {
  426. super(name);
  427. this.name = name;
  428. this.url = url;
  429. }
  430. /**
  431. * Execute the current task
  432. * @param scene defines the scene where you want your assets to be loaded
  433. * @param onSuccess is a callback called when the task is successfully executed
  434. * @param onError is a callback called if an error occurs
  435. */
  436. runTask(scene, onSuccess, onError) {
  437. const img = new Image();
  438. Tools.SetCorsBehavior(this.url, img);
  439. img.onload = () => {
  440. this.image = img;
  441. onSuccess();
  442. };
  443. img.onerror = (err) => {
  444. onError("Error loading image", err);
  445. };
  446. img.src = this.url;
  447. }
  448. }
  449. /**
  450. * Define a task used by AssetsManager to load 2D textures
  451. */
  452. export class TextureAssetTask extends AbstractAssetTask {
  453. /**
  454. * Creates a new TextureAssetTask object
  455. * @param name defines the name of the task
  456. * @param url defines the location of the file to load
  457. * @param noMipmap defines if mipmap should not be generated (default is false)
  458. * @param invertY defines if texture must be inverted on Y axis (default is true)
  459. * @param samplingMode defines the sampling mode to use (default is Texture.TRILINEAR_SAMPLINGMODE)
  460. */
  461. constructor(
  462. /**
  463. * Defines the name of the task
  464. */
  465. name,
  466. /**
  467. * Defines the location of the file to load
  468. */
  469. url,
  470. /**
  471. * Defines if mipmap should not be generated (default is false)
  472. */
  473. noMipmap,
  474. /**
  475. * Defines if texture must be inverted on Y axis (default is true)
  476. */
  477. invertY = true,
  478. /**
  479. * Defines the sampling mode to use (default is Texture.TRILINEAR_SAMPLINGMODE)
  480. */
  481. samplingMode = Texture.TRILINEAR_SAMPLINGMODE) {
  482. super(name);
  483. this.name = name;
  484. this.url = url;
  485. this.noMipmap = noMipmap;
  486. this.invertY = invertY;
  487. this.samplingMode = samplingMode;
  488. }
  489. /**
  490. * Execute the current task
  491. * @param scene defines the scene where you want your assets to be loaded
  492. * @param onSuccess is a callback called when the task is successfully executed
  493. * @param onError is a callback called if an error occurs
  494. */
  495. runTask(scene, onSuccess, onError) {
  496. const onload = () => {
  497. onSuccess();
  498. };
  499. const onerror = (message, exception) => {
  500. onError(message, exception);
  501. };
  502. this.texture = new Texture(this.url, scene, this.noMipmap, this.invertY, this.samplingMode, onload, onerror);
  503. }
  504. }
  505. /**
  506. * Define a task used by AssetsManager to load cube textures
  507. */
  508. export class CubeTextureAssetTask extends AbstractAssetTask {
  509. /**
  510. * Creates a new CubeTextureAssetTask
  511. * @param name defines the name of the task
  512. * @param url defines the location of the files to load (You have to specify the folder where the files are + filename with no extension)
  513. * @param extensions defines the extensions to use to load files (["_px", "_py", "_pz", "_nx", "_ny", "_nz"] by default)
  514. * @param noMipmap defines if mipmaps should not be generated (default is false)
  515. * @param files defines the explicit list of files (undefined by default)
  516. * @param prefiltered
  517. */
  518. constructor(
  519. /**
  520. * Defines the name of the task
  521. */
  522. name,
  523. /**
  524. * Defines the location of the files to load (You have to specify the folder where the files are + filename with no extension)
  525. */
  526. url,
  527. /**
  528. * Defines the extensions to use to load files (["_px", "_py", "_pz", "_nx", "_ny", "_nz"] by default)
  529. */
  530. extensions,
  531. /**
  532. * Defines if mipmaps should not be generated (default is false)
  533. */
  534. noMipmap,
  535. /**
  536. * Defines the explicit list of files (undefined by default)
  537. */
  538. files,
  539. /**
  540. * Defines the prefiltered texture option (default is false)
  541. */
  542. prefiltered) {
  543. super(name);
  544. this.name = name;
  545. this.url = url;
  546. this.extensions = extensions;
  547. this.noMipmap = noMipmap;
  548. this.files = files;
  549. this.prefiltered = prefiltered;
  550. }
  551. /**
  552. * Execute the current task
  553. * @param scene defines the scene where you want your assets to be loaded
  554. * @param onSuccess is a callback called when the task is successfully executed
  555. * @param onError is a callback called if an error occurs
  556. */
  557. runTask(scene, onSuccess, onError) {
  558. const onload = () => {
  559. onSuccess();
  560. };
  561. const onerror = (message, exception) => {
  562. onError(message, exception);
  563. };
  564. this.texture = new CubeTexture(this.url, scene, this.extensions, this.noMipmap, this.files, onload, onerror, undefined, this.prefiltered);
  565. }
  566. }
  567. /**
  568. * Define a task used by AssetsManager to load HDR cube textures
  569. */
  570. export class HDRCubeTextureAssetTask extends AbstractAssetTask {
  571. /**
  572. * Creates a new HDRCubeTextureAssetTask object
  573. * @param name defines the name of the task
  574. * @param url defines the location of the file to load
  575. * @param size defines the desired size (the more it increases the longer the generation will be) If the size is omitted this implies you are using a preprocessed cubemap.
  576. * @param noMipmap defines if mipmaps should not be generated (default is false)
  577. * @param generateHarmonics specifies whether you want to extract the polynomial harmonics during the generation process (default is true)
  578. * @param gammaSpace specifies if the texture will be use in gamma or linear space (the PBR material requires those texture in linear space, but the standard material would require them in Gamma space) (default is false)
  579. * @param reserved Internal use only
  580. */
  581. constructor(
  582. /**
  583. * Defines the name of the task
  584. */
  585. name,
  586. /**
  587. * Defines the location of the file to load
  588. */
  589. url,
  590. /**
  591. * Defines the desired size (the more it increases the longer the generation will be)
  592. */
  593. size,
  594. /**
  595. * Defines if mipmaps should not be generated (default is false)
  596. */
  597. noMipmap = false,
  598. /**
  599. * Specifies whether you want to extract the polynomial harmonics during the generation process (default is true)
  600. */
  601. generateHarmonics = true,
  602. /**
  603. * Specifies if the texture will be use in gamma or linear space (the PBR material requires those texture in linear space, but the standard material would require them in Gamma space) (default is false)
  604. */
  605. gammaSpace = false,
  606. /**
  607. * Internal Use Only
  608. */
  609. reserved = false) {
  610. super(name);
  611. this.name = name;
  612. this.url = url;
  613. this.size = size;
  614. this.noMipmap = noMipmap;
  615. this.generateHarmonics = generateHarmonics;
  616. this.gammaSpace = gammaSpace;
  617. this.reserved = reserved;
  618. }
  619. /**
  620. * Execute the current task
  621. * @param scene defines the scene where you want your assets to be loaded
  622. * @param onSuccess is a callback called when the task is successfully executed
  623. * @param onError is a callback called if an error occurs
  624. */
  625. runTask(scene, onSuccess, onError) {
  626. const onload = () => {
  627. onSuccess();
  628. };
  629. const onerror = (message, exception) => {
  630. onError(message, exception);
  631. };
  632. this.texture = new HDRCubeTexture(this.url, scene, this.size, this.noMipmap, this.generateHarmonics, this.gammaSpace, this.reserved, onload, onerror);
  633. }
  634. }
  635. /**
  636. * Define a task used by AssetsManager to load Equirectangular cube textures
  637. */
  638. export class EquiRectangularCubeTextureAssetTask extends AbstractAssetTask {
  639. /**
  640. * Creates a new EquiRectangularCubeTextureAssetTask object
  641. * @param name defines the name of the task
  642. * @param url defines the location of the file to load
  643. * @param size defines the desired size (the more it increases the longer the generation will be)
  644. * If the size is omitted this implies you are using a preprocessed cubemap.
  645. * @param noMipmap defines if mipmaps should not be generated (default is false)
  646. * @param gammaSpace specifies if the texture will be used in gamma or linear space
  647. * (the PBR material requires those texture in linear space, but the standard material would require them in Gamma space)
  648. * (default is true)
  649. */
  650. constructor(
  651. /**
  652. * Defines the name of the task
  653. */
  654. name,
  655. /**
  656. * Defines the location of the file to load
  657. */
  658. url,
  659. /**
  660. * Defines the desired size (the more it increases the longer the generation will be)
  661. */
  662. size,
  663. /**
  664. * Defines if mipmaps should not be generated (default is false)
  665. */
  666. noMipmap = false,
  667. /**
  668. * Specifies if the texture will be use in gamma or linear space (the PBR material requires those texture in linear space,
  669. * but the standard material would require them in Gamma space) (default is true)
  670. */
  671. gammaSpace = true) {
  672. super(name);
  673. this.name = name;
  674. this.url = url;
  675. this.size = size;
  676. this.noMipmap = noMipmap;
  677. this.gammaSpace = gammaSpace;
  678. }
  679. /**
  680. * Execute the current task
  681. * @param scene defines the scene where you want your assets to be loaded
  682. * @param onSuccess is a callback called when the task is successfully executed
  683. * @param onError is a callback called if an error occurs
  684. */
  685. runTask(scene, onSuccess, onError) {
  686. const onload = () => {
  687. onSuccess();
  688. };
  689. const onerror = (message, exception) => {
  690. onError(message, exception);
  691. };
  692. this.texture = new EquiRectangularCubeTexture(this.url, scene, this.size, this.noMipmap, this.gammaSpace, onload, onerror);
  693. }
  694. }
  695. /**
  696. * This class can be used to easily import assets into a scene
  697. * @see https://doc.babylonjs.com/features/featuresDeepDive/importers/assetManager
  698. */
  699. export class AssetsManager {
  700. /**
  701. * Creates a new AssetsManager
  702. * @param scene defines the scene to work on
  703. */
  704. constructor(scene) {
  705. this._isLoading = false;
  706. this._tasks = new Array();
  707. this._waitingTasksCount = 0;
  708. this._totalTasksCount = 0;
  709. /**
  710. * Observable called when all tasks are processed
  711. */
  712. this.onTaskSuccessObservable = new Observable();
  713. /**
  714. * Observable called when a task had an error
  715. */
  716. this.onTaskErrorObservable = new Observable();
  717. /**
  718. * Observable called when all tasks were executed
  719. */
  720. this.onTasksDoneObservable = new Observable();
  721. /**
  722. * Observable called when a task is done (whatever the result is)
  723. */
  724. this.onProgressObservable = new Observable();
  725. /**
  726. * Gets or sets a boolean defining if the AssetsManager should use the default loading screen
  727. * @see https://doc.babylonjs.com/features/featuresDeepDive/scene/customLoadingScreen
  728. */
  729. this.useDefaultLoadingScreen = true;
  730. /**
  731. * Gets or sets a boolean defining if the AssetsManager should automatically hide the loading screen
  732. * when all assets have been downloaded.
  733. * If set to false, you need to manually call in hideLoadingUI() once your scene is ready.
  734. */
  735. this.autoHideLoadingUI = true;
  736. this._scene = scene || EngineStore.LastCreatedScene;
  737. }
  738. /**
  739. * Add a ContainerAssetTask to the list of active tasks
  740. * @param taskName defines the name of the new task
  741. * @param meshesNames defines the name of meshes to load
  742. * @param rootUrl defines the root url to use to locate files
  743. * @param sceneFilename defines the filename of the scene file or the File itself
  744. * @param extension defines the extension to use to load the file
  745. * @returns a new ContainerAssetTask object
  746. */
  747. addContainerTask(taskName, meshesNames, rootUrl, sceneFilename, extension) {
  748. const task = new ContainerAssetTask(taskName, meshesNames, rootUrl, sceneFilename, extension);
  749. this._tasks.push(task);
  750. return task;
  751. }
  752. /**
  753. * Add a MeshAssetTask to the list of active tasks
  754. * @param taskName defines the name of the new task
  755. * @param meshesNames defines the name of meshes to load
  756. * @param rootUrl defines the root url to use to locate files
  757. * @param sceneFilename defines the filename of the scene file or the File itself
  758. * @param extension defines the extension to use to load the file
  759. * @returns a new MeshAssetTask object
  760. */
  761. addMeshTask(taskName, meshesNames, rootUrl, sceneFilename, extension) {
  762. const task = new MeshAssetTask(taskName, meshesNames, rootUrl, sceneFilename, extension);
  763. this._tasks.push(task);
  764. return task;
  765. }
  766. /**
  767. * Add a TextFileAssetTask to the list of active tasks
  768. * @param taskName defines the name of the new task
  769. * @param url defines the url of the file to load
  770. * @returns a new TextFileAssetTask object
  771. */
  772. addTextFileTask(taskName, url) {
  773. const task = new TextFileAssetTask(taskName, url);
  774. this._tasks.push(task);
  775. return task;
  776. }
  777. /**
  778. * Add a BinaryFileAssetTask to the list of active tasks
  779. * @param taskName defines the name of the new task
  780. * @param url defines the url of the file to load
  781. * @returns a new BinaryFileAssetTask object
  782. */
  783. addBinaryFileTask(taskName, url) {
  784. const task = new BinaryFileAssetTask(taskName, url);
  785. this._tasks.push(task);
  786. return task;
  787. }
  788. /**
  789. * Add a ImageAssetTask to the list of active tasks
  790. * @param taskName defines the name of the new task
  791. * @param url defines the url of the file to load
  792. * @returns a new ImageAssetTask object
  793. */
  794. addImageTask(taskName, url) {
  795. const task = new ImageAssetTask(taskName, url);
  796. this._tasks.push(task);
  797. return task;
  798. }
  799. /**
  800. * Add a TextureAssetTask to the list of active tasks
  801. * @param taskName defines the name of the new task
  802. * @param url defines the url of the file to load
  803. * @param noMipmap defines if the texture must not receive mipmaps (false by default)
  804. * @param invertY defines if you want to invert Y axis of the loaded texture (true by default)
  805. * @param samplingMode defines the sampling mode to use (Texture.TRILINEAR_SAMPLINGMODE by default)
  806. * @returns a new TextureAssetTask object
  807. */
  808. addTextureTask(taskName, url, noMipmap, invertY, samplingMode = Texture.TRILINEAR_SAMPLINGMODE) {
  809. const task = new TextureAssetTask(taskName, url, noMipmap, invertY, samplingMode);
  810. this._tasks.push(task);
  811. return task;
  812. }
  813. /**
  814. * Add a CubeTextureAssetTask to the list of active tasks
  815. * @param taskName defines the name of the new task
  816. * @param url defines the url of the file to load
  817. * @param extensions defines the extension to use to load the cube map (can be null)
  818. * @param noMipmap defines if the texture must not receive mipmaps (false by default)
  819. * @param files defines the list of files to load (can be null)
  820. * @param prefiltered defines the prefiltered texture option (default is false)
  821. * @returns a new CubeTextureAssetTask object
  822. */
  823. addCubeTextureTask(taskName, url, extensions, noMipmap, files, prefiltered) {
  824. const task = new CubeTextureAssetTask(taskName, url, extensions, noMipmap, files, prefiltered);
  825. this._tasks.push(task);
  826. return task;
  827. }
  828. /**
  829. *
  830. * Add a HDRCubeTextureAssetTask to the list of active tasks
  831. * @param taskName defines the name of the new task
  832. * @param url defines the url of the file to load
  833. * @param size defines the size you want for the cubemap (can be null)
  834. * @param noMipmap defines if the texture must not receive mipmaps (false by default)
  835. * @param generateHarmonics defines if you want to automatically generate (true by default)
  836. * @param gammaSpace specifies if the texture will be use in gamma or linear space (the PBR material requires those texture in linear space, but the standard material would require them in Gamma space) (default is false)
  837. * @param reserved Internal use only
  838. * @returns a new HDRCubeTextureAssetTask object
  839. */
  840. addHDRCubeTextureTask(taskName, url, size, noMipmap = false, generateHarmonics = true, gammaSpace = false, reserved = false) {
  841. const task = new HDRCubeTextureAssetTask(taskName, url, size, noMipmap, generateHarmonics, gammaSpace, reserved);
  842. this._tasks.push(task);
  843. return task;
  844. }
  845. /**
  846. *
  847. * Add a EquiRectangularCubeTextureAssetTask to the list of active tasks
  848. * @param taskName defines the name of the new task
  849. * @param url defines the url of the file to load
  850. * @param size defines the size you want for the cubemap (can be null)
  851. * @param noMipmap defines if the texture must not receive mipmaps (false by default)
  852. * @param gammaSpace Specifies if the texture will be used in gamma or linear space
  853. * (the PBR material requires those textures in linear space, but the standard material would require them in Gamma space)
  854. * @returns a new EquiRectangularCubeTextureAssetTask object
  855. */
  856. addEquiRectangularCubeTextureAssetTask(taskName, url, size, noMipmap = false, gammaSpace = true) {
  857. const task = new EquiRectangularCubeTextureAssetTask(taskName, url, size, noMipmap, gammaSpace);
  858. this._tasks.push(task);
  859. return task;
  860. }
  861. /**
  862. * Remove a task from the assets manager.
  863. * @param task the task to remove
  864. */
  865. removeTask(task) {
  866. const index = this._tasks.indexOf(task);
  867. if (index > -1) {
  868. this._tasks.splice(index, 1);
  869. }
  870. }
  871. _decreaseWaitingTasksCount(task) {
  872. this._waitingTasksCount--;
  873. try {
  874. if (this.onProgress) {
  875. this.onProgress(this._waitingTasksCount, this._totalTasksCount, task);
  876. }
  877. this.onProgressObservable.notifyObservers(new AssetsProgressEvent(this._waitingTasksCount, this._totalTasksCount, task));
  878. }
  879. catch (e) {
  880. Logger.Error("Error running progress callbacks.");
  881. Logger.Log(e);
  882. }
  883. if (this._waitingTasksCount === 0) {
  884. try {
  885. const currentTasks = this._tasks.slice();
  886. if (this.onFinish) {
  887. // Calling onFinish with immutable array of tasks
  888. this.onFinish(currentTasks);
  889. }
  890. // Let's remove successful tasks
  891. for (const task of currentTasks) {
  892. if (task.taskState === AssetTaskState.DONE) {
  893. const index = this._tasks.indexOf(task);
  894. if (index > -1) {
  895. this._tasks.splice(index, 1);
  896. }
  897. }
  898. }
  899. this.onTasksDoneObservable.notifyObservers(this._tasks);
  900. }
  901. catch (e) {
  902. Logger.Error("Error running tasks-done callbacks.");
  903. Logger.Log(e);
  904. }
  905. this._isLoading = false;
  906. if (this.autoHideLoadingUI) {
  907. this._scene.getEngine().hideLoadingUI();
  908. }
  909. }
  910. }
  911. _runTask(task) {
  912. const done = () => {
  913. try {
  914. if (this.onTaskSuccess) {
  915. this.onTaskSuccess(task);
  916. }
  917. this.onTaskSuccessObservable.notifyObservers(task);
  918. this._decreaseWaitingTasksCount(task);
  919. }
  920. catch (e) {
  921. error("Error executing task success callbacks", e);
  922. }
  923. };
  924. const error = (message, exception) => {
  925. task._setErrorObject(message, exception);
  926. if (this.onTaskError) {
  927. this.onTaskError(task);
  928. }
  929. else if (!task.onError) {
  930. Logger.Error(this._formatTaskErrorMessage(task));
  931. }
  932. this.onTaskErrorObservable.notifyObservers(task);
  933. this._decreaseWaitingTasksCount(task);
  934. };
  935. task.run(this._scene, done, error);
  936. }
  937. _formatTaskErrorMessage(task) {
  938. let errorMessage = "Unable to complete task " + task.name;
  939. if (task.errorObject.message) {
  940. errorMessage += `: ${task.errorObject.message}`;
  941. }
  942. if (task.errorObject.exception) {
  943. errorMessage += `: ${task.errorObject.exception}`;
  944. }
  945. return errorMessage;
  946. }
  947. /**
  948. * Reset the AssetsManager and remove all tasks
  949. * @returns the current instance of the AssetsManager
  950. */
  951. reset() {
  952. this._isLoading = false;
  953. this._tasks = new Array();
  954. return this;
  955. }
  956. /**
  957. * Start the loading process
  958. * @returns the current instance of the AssetsManager
  959. */
  960. load() {
  961. if (this._isLoading) {
  962. return this;
  963. }
  964. this._isLoading = true;
  965. this._waitingTasksCount = this._tasks.length;
  966. this._totalTasksCount = this._tasks.length;
  967. if (this._waitingTasksCount === 0) {
  968. this._isLoading = false;
  969. if (this.onFinish) {
  970. this.onFinish(this._tasks);
  971. }
  972. this.onTasksDoneObservable.notifyObservers(this._tasks);
  973. return this;
  974. }
  975. if (this.useDefaultLoadingScreen) {
  976. this._scene.getEngine().displayLoadingUI();
  977. }
  978. for (let index = 0; index < this._tasks.length; index++) {
  979. const task = this._tasks[index];
  980. if (task.taskState === AssetTaskState.INIT) {
  981. this._runTask(task);
  982. }
  983. }
  984. return this;
  985. }
  986. /**
  987. * Start the loading process as an async operation
  988. * @returns a promise returning the list of failed tasks
  989. */
  990. loadAsync() {
  991. return new Promise((resolve, reject) => {
  992. if (this._isLoading) {
  993. resolve();
  994. return;
  995. }
  996. this.onTasksDoneObservable.addOnce((remainingTasks) => {
  997. if (remainingTasks && remainingTasks.length) {
  998. reject(remainingTasks);
  999. }
  1000. else {
  1001. resolve();
  1002. }
  1003. });
  1004. this.load();
  1005. });
  1006. }
  1007. }
  1008. //# sourceMappingURL=assetsManager.js.map