spritesheet.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*!
  2. * @pixi/spritesheet - v6.5.10
  3. * Compiled Thu, 06 Jul 2023 15:25:11 UTC
  4. *
  5. * @pixi/spritesheet is licensed under the MIT License.
  6. * http://www.opensource.org/licenses/mit-license
  7. */
  8. this.PIXI = this.PIXI || {};
  9. var _pixi_spritesheet = (function (exports, math, core, utils, loaders) {
  10. 'use strict';
  11. /**
  12. * Utility class for maintaining reference to a collection
  13. * of Textures on a single Spritesheet.
  14. *
  15. * To access a sprite sheet from your code you may pass its JSON data file to Pixi's loader:
  16. *
  17. * ```js
  18. * PIXI.Loader.shared.add("images/spritesheet.json").load(setup);
  19. *
  20. * function setup() {
  21. * let sheet = PIXI.Loader.shared.resources["images/spritesheet.json"].spritesheet;
  22. * ...
  23. * }
  24. * ```
  25. *
  26. * Alternately, you may circumvent the loader by instantiating the Spritesheet directly:
  27. * ```js
  28. * const sheet = new PIXI.Spritesheet(texture, spritesheetData);
  29. * await sheet.parse();
  30. * console.log('Spritesheet ready to use!');
  31. * ```
  32. *
  33. * With the `sheet.textures` you can create Sprite objects,`sheet.animations` can be used to create an AnimatedSprite.
  34. *
  35. * Sprite sheets can be packed using tools like {@link https://codeandweb.com/texturepacker|TexturePacker},
  36. * {@link https://renderhjs.net/shoebox/|Shoebox} or {@link https://github.com/krzysztof-o/spritesheet.js|Spritesheet.js}.
  37. * Default anchor points (see {@link PIXI.Texture#defaultAnchor}) and grouping of animation sprites are currently only
  38. * supported by TexturePacker.
  39. * @memberof PIXI
  40. */
  41. var Spritesheet = /** @class */ (function () {
  42. /**
  43. * @param texture - Reference to the source BaseTexture object.
  44. * @param {object} data - Spritesheet image data.
  45. * @param resolutionFilename - The filename to consider when determining
  46. * the resolution of the spritesheet. If not provided, the imageUrl will
  47. * be used on the BaseTexture.
  48. */
  49. function Spritesheet(texture, data, resolutionFilename) {
  50. if (resolutionFilename === void 0) { resolutionFilename = null; }
  51. /** For multi-packed spritesheets, this contains a reference to all the other spritesheets it depends on. */
  52. this.linkedSheets = [];
  53. this._texture = texture instanceof core.Texture ? texture : null;
  54. this.baseTexture = texture instanceof core.BaseTexture ? texture : this._texture.baseTexture;
  55. this.textures = {};
  56. this.animations = {};
  57. this.data = data;
  58. var resource = this.baseTexture.resource;
  59. this.resolution = this._updateResolution(resolutionFilename || (resource ? resource.url : null));
  60. this._frames = this.data.frames;
  61. this._frameKeys = Object.keys(this._frames);
  62. this._batchIndex = 0;
  63. this._callback = null;
  64. }
  65. /**
  66. * Generate the resolution from the filename or fallback
  67. * to the meta.scale field of the JSON data.
  68. * @param resolutionFilename - The filename to use for resolving
  69. * the default resolution.
  70. * @returns Resolution to use for spritesheet.
  71. */
  72. Spritesheet.prototype._updateResolution = function (resolutionFilename) {
  73. if (resolutionFilename === void 0) { resolutionFilename = null; }
  74. var scale = this.data.meta.scale;
  75. // Use a defaultValue of `null` to check if a url-based resolution is set
  76. var resolution = utils.getResolutionOfUrl(resolutionFilename, null);
  77. // No resolution found via URL
  78. if (resolution === null) {
  79. // Use the scale value or default to 1
  80. resolution = scale !== undefined ? parseFloat(scale) : 1;
  81. }
  82. // For non-1 resolutions, update baseTexture
  83. if (resolution !== 1) {
  84. this.baseTexture.setResolution(resolution);
  85. }
  86. return resolution;
  87. };
  88. /** @ignore */
  89. Spritesheet.prototype.parse = function (callback) {
  90. var _this = this;
  91. if (callback) {
  92. utils.deprecation('6.5.0', 'Spritesheet.parse callback is deprecated, use the return Promise instead.');
  93. }
  94. return new Promise(function (resolve) {
  95. _this._callback = function (textures) {
  96. callback === null || callback === void 0 ? void 0 : callback(textures);
  97. resolve(textures);
  98. };
  99. _this._batchIndex = 0;
  100. if (_this._frameKeys.length <= Spritesheet.BATCH_SIZE) {
  101. _this._processFrames(0);
  102. _this._processAnimations();
  103. _this._parseComplete();
  104. }
  105. else {
  106. _this._nextBatch();
  107. }
  108. });
  109. };
  110. /**
  111. * Process a batch of frames
  112. * @param initialFrameIndex - The index of frame to start.
  113. */
  114. Spritesheet.prototype._processFrames = function (initialFrameIndex) {
  115. var frameIndex = initialFrameIndex;
  116. var maxFrames = Spritesheet.BATCH_SIZE;
  117. while (frameIndex - initialFrameIndex < maxFrames && frameIndex < this._frameKeys.length) {
  118. var i = this._frameKeys[frameIndex];
  119. var data = this._frames[i];
  120. var rect = data.frame;
  121. if (rect) {
  122. var frame = null;
  123. var trim = null;
  124. var sourceSize = data.trimmed !== false && data.sourceSize
  125. ? data.sourceSize : data.frame;
  126. var orig = new math.Rectangle(0, 0, Math.floor(sourceSize.w) / this.resolution, Math.floor(sourceSize.h) / this.resolution);
  127. if (data.rotated) {
  128. frame = new math.Rectangle(Math.floor(rect.x) / this.resolution, Math.floor(rect.y) / this.resolution, Math.floor(rect.h) / this.resolution, Math.floor(rect.w) / this.resolution);
  129. }
  130. else {
  131. frame = new math.Rectangle(Math.floor(rect.x) / this.resolution, Math.floor(rect.y) / this.resolution, Math.floor(rect.w) / this.resolution, Math.floor(rect.h) / this.resolution);
  132. }
  133. // Check to see if the sprite is trimmed
  134. if (data.trimmed !== false && data.spriteSourceSize) {
  135. trim = new math.Rectangle(Math.floor(data.spriteSourceSize.x) / this.resolution, Math.floor(data.spriteSourceSize.y) / this.resolution, Math.floor(rect.w) / this.resolution, Math.floor(rect.h) / this.resolution);
  136. }
  137. this.textures[i] = new core.Texture(this.baseTexture, frame, orig, trim, data.rotated ? 2 : 0, data.anchor);
  138. // lets also add the frame to pixi's global cache for 'from' and 'fromLoader' functions
  139. core.Texture.addToCache(this.textures[i], i);
  140. }
  141. frameIndex++;
  142. }
  143. };
  144. /** Parse animations config. */
  145. Spritesheet.prototype._processAnimations = function () {
  146. var animations = this.data.animations || {};
  147. for (var animName in animations) {
  148. this.animations[animName] = [];
  149. for (var i = 0; i < animations[animName].length; i++) {
  150. var frameName = animations[animName][i];
  151. this.animations[animName].push(this.textures[frameName]);
  152. }
  153. }
  154. };
  155. /** The parse has completed. */
  156. Spritesheet.prototype._parseComplete = function () {
  157. var callback = this._callback;
  158. this._callback = null;
  159. this._batchIndex = 0;
  160. callback.call(this, this.textures);
  161. };
  162. /** Begin the next batch of textures. */
  163. Spritesheet.prototype._nextBatch = function () {
  164. var _this = this;
  165. this._processFrames(this._batchIndex * Spritesheet.BATCH_SIZE);
  166. this._batchIndex++;
  167. setTimeout(function () {
  168. if (_this._batchIndex * Spritesheet.BATCH_SIZE < _this._frameKeys.length) {
  169. _this._nextBatch();
  170. }
  171. else {
  172. _this._processAnimations();
  173. _this._parseComplete();
  174. }
  175. }, 0);
  176. };
  177. /**
  178. * Destroy Spritesheet and don't use after this.
  179. * @param {boolean} [destroyBase=false] - Whether to destroy the base texture as well
  180. */
  181. Spritesheet.prototype.destroy = function (destroyBase) {
  182. var _a;
  183. if (destroyBase === void 0) { destroyBase = false; }
  184. for (var i in this.textures) {
  185. this.textures[i].destroy();
  186. }
  187. this._frames = null;
  188. this._frameKeys = null;
  189. this.data = null;
  190. this.textures = null;
  191. if (destroyBase) {
  192. (_a = this._texture) === null || _a === void 0 ? void 0 : _a.destroy();
  193. this.baseTexture.destroy();
  194. }
  195. this._texture = null;
  196. this.baseTexture = null;
  197. this.linkedSheets = [];
  198. };
  199. /** The maximum number of Textures to build per process. */
  200. Spritesheet.BATCH_SIZE = 1000;
  201. return Spritesheet;
  202. }());
  203. /**
  204. * Reference to Spritesheet object created.
  205. * @member {PIXI.Spritesheet} spritesheet
  206. * @memberof PIXI.LoaderResource
  207. * @instance
  208. */
  209. /**
  210. * Dictionary of textures from Spritesheet.
  211. * @member {Object<string, PIXI.Texture>} textures
  212. * @memberof PIXI.LoaderResource
  213. * @instance
  214. */
  215. /**
  216. * {@link PIXI.Loader} middleware for loading texture atlases that have been created with
  217. * TexturePacker or similar JSON-based spritesheet.
  218. *
  219. * This middleware automatically generates Texture resources.
  220. *
  221. * If you're using Webpack or other bundlers and plan on bundling the atlas' JSON,
  222. * use the {@link PIXI.Spritesheet} class to directly parse the JSON.
  223. *
  224. * The Loader's image Resource name is automatically appended with `"_image"`.
  225. * If a Resource with this name is already loaded, the Loader will skip parsing the
  226. * Spritesheet. The code below will generate an internal Loader Resource called `"myatlas_image"`.
  227. * @example
  228. * loader.add('myatlas', 'path/to/myatlas.json');
  229. * loader.load(() => {
  230. * loader.resources.myatlas; // atlas JSON resource
  231. * loader.resources.myatlas_image; // atlas Image resource
  232. * });
  233. * @memberof PIXI
  234. */
  235. var SpritesheetLoader = /** @class */ (function () {
  236. function SpritesheetLoader() {
  237. }
  238. /**
  239. * Called after a resource is loaded.
  240. * @see PIXI.Loader.loaderMiddleware
  241. * @param resource
  242. * @param next
  243. */
  244. SpritesheetLoader.use = function (resource, next) {
  245. var _a, _b;
  246. // because this is middleware, it execute in loader context. `this` = loader
  247. var loader = this;
  248. var imageResourceName = resource.name + "_image";
  249. // skip if no data, its not json, it isn't spritesheet data, or the image resource already exists
  250. if (!resource.data
  251. || resource.type !== loaders.LoaderResource.TYPE.JSON
  252. || !resource.data.frames
  253. || loader.resources[imageResourceName]) {
  254. next();
  255. return;
  256. }
  257. // Check and add the multi atlas
  258. // Heavily influenced and based on https://github.com/rocket-ua/pixi-tps-loader/blob/master/src/ResourceLoader.js
  259. // eslint-disable-next-line camelcase
  260. var multiPacks = (_b = (_a = resource.data) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.related_multi_packs;
  261. if (Array.isArray(multiPacks)) {
  262. var _loop_1 = function (item) {
  263. if (typeof item !== 'string') {
  264. return "continue";
  265. }
  266. var itemName = item.replace('.json', '');
  267. var itemUrl = utils.url.resolve(resource.url.replace(loader.baseUrl, ''), item);
  268. // Check if the file wasn't already added as multipacks are redundant
  269. if (loader.resources[itemName]
  270. || Object.values(loader.resources).some(function (r) { return utils.url.format(utils.url.parse(r.url)) === itemUrl; })) {
  271. return "continue";
  272. }
  273. var options = {
  274. crossOrigin: resource.crossOrigin,
  275. loadType: loaders.LoaderResource.LOAD_TYPE.XHR,
  276. xhrType: loaders.LoaderResource.XHR_RESPONSE_TYPE.JSON,
  277. parentResource: resource,
  278. metadata: resource.metadata
  279. };
  280. loader.add(itemName, itemUrl, options);
  281. };
  282. for (var _i = 0, multiPacks_1 = multiPacks; _i < multiPacks_1.length; _i++) {
  283. var item = multiPacks_1[_i];
  284. _loop_1(item);
  285. }
  286. }
  287. var loadOptions = {
  288. crossOrigin: resource.crossOrigin,
  289. metadata: resource.metadata.imageMetadata,
  290. parentResource: resource,
  291. };
  292. var resourcePath = SpritesheetLoader.getResourcePath(resource, loader.baseUrl);
  293. // load the image for this sheet
  294. loader.add(imageResourceName, resourcePath, loadOptions, function onImageLoad(res) {
  295. if (res.error) {
  296. next(res.error);
  297. return;
  298. }
  299. var spritesheet = new Spritesheet(res.texture, resource.data, resource.url);
  300. spritesheet.parse().then(function () {
  301. resource.spritesheet = spritesheet;
  302. resource.textures = spritesheet.textures;
  303. next();
  304. });
  305. });
  306. };
  307. /**
  308. * Get the spritesheets root path
  309. * @param resource - Resource to check path
  310. * @param baseUrl - Base root url
  311. */
  312. SpritesheetLoader.getResourcePath = function (resource, baseUrl) {
  313. // Prepend url path unless the resource image is a data url
  314. if (resource.isDataUrl) {
  315. return resource.data.meta.image;
  316. }
  317. return utils.url.resolve(resource.url.replace(baseUrl, ''), resource.data.meta.image);
  318. };
  319. /** @ignore */
  320. SpritesheetLoader.extension = core.ExtensionType.Loader;
  321. return SpritesheetLoader;
  322. }());
  323. exports.Spritesheet = Spritesheet;
  324. exports.SpritesheetLoader = SpritesheetLoader;
  325. Object.defineProperty(exports, '__esModule', { value: true });
  326. return exports;
  327. })({}, PIXI, PIXI, PIXI.utils, PIXI);
  328. Object.assign(this.PIXI, _pixi_spritesheet);
  329. //# sourceMappingURL=spritesheet.js.map