Source: core/textures/BaseTexture.js

core/textures/BaseTexture.js

  1. import {
  2. uid, getUrlFileExtension, decomposeDataUri, getSvgSize,
  3. getResolutionOfUrl, BaseTextureCache, TextureCache,
  4. } from '../utils';
  5. import settings from '../settings';
  6. import EventEmitter from 'eventemitter3';
  7. import determineCrossOrigin from '../utils/determineCrossOrigin';
  8. import bitTwiddle from 'bit-twiddle';
  9. //引入小程序补丁
  10. import { documentAlias, Image, HTMLCanvasElement, atob, navigator, XMLHttpRequestAlias } from '@ali/pixi-miniprogram-adapter';
  11. /**
  12. * A texture stores the information that represents an image. All textures have a base texture.
  13. *
  14. * @class
  15. * @extends EventEmitter
  16. * @memberof PIXI
  17. */
  18. export default class BaseTexture extends EventEmitter
  19. {
  20. /**
  21. * @param {HTMLImageElement|HTMLCanvasElement} [source] - the source object of the texture.
  22. * @param {number} [scaleMode=PIXI.settings.SCALE_MODE] - See {@link PIXI.SCALE_MODES} for possible values
  23. * @param {number} [resolution=1] - The resolution / device pixel ratio of the texture
  24. */
  25. constructor(source, scaleMode, resolution)
  26. {
  27. super();
  28. this.uid = uid();
  29. this.touched = 0;
  30. /**
  31. * The resolution / device pixel ratio of the texture
  32. *
  33. * @member {number}
  34. * @default 1
  35. */
  36. this.resolution = resolution || settings.RESOLUTION;
  37. /**
  38. * The width of the base texture set when the image has loaded
  39. *
  40. * @readonly
  41. * @member {number}
  42. */
  43. this.width = 100;
  44. /**
  45. * The height of the base texture set when the image has loaded
  46. *
  47. * @readonly
  48. * @member {number}
  49. */
  50. this.height = 100;
  51. // TODO docs
  52. // used to store the actual dimensions of the source
  53. /**
  54. * Used to store the actual width of the source of this texture
  55. *
  56. * @readonly
  57. * @member {number}
  58. */
  59. this.realWidth = 100;
  60. /**
  61. * Used to store the actual height of the source of this texture
  62. *
  63. * @readonly
  64. * @member {number}
  65. */
  66. this.realHeight = 100;
  67. /**
  68. * The scale mode to apply when scaling this texture
  69. *
  70. * @member {number}
  71. * @default PIXI.settings.SCALE_MODE
  72. * @see PIXI.SCALE_MODES
  73. */
  74. this.scaleMode = scaleMode !== undefined ? scaleMode : settings.SCALE_MODE;
  75. /**
  76. * Set to true once the base texture has successfully loaded.
  77. *
  78. * This is never true if the underlying source fails to load or has no texture data.
  79. *
  80. * @readonly
  81. * @member {boolean}
  82. */
  83. this.hasLoaded = false;
  84. /**
  85. * Set to true if the source is currently loading.
  86. *
  87. * If an Image source is loading the 'loaded' or 'error' event will be
  88. * dispatched when the operation ends. An underyling source that is
  89. * immediately-available bypasses loading entirely.
  90. *
  91. * @readonly
  92. * @member {boolean}
  93. */
  94. this.isLoading = false;
  95. /**
  96. * The image source that is used to create the texture.
  97. *
  98. * TODO: Make this a setter that calls loadSource();
  99. *
  100. * @readonly
  101. * @member {HTMLImageElement|HTMLCanvasElement}
  102. */
  103. this.source = null; // set in loadSource, if at all
  104. /**
  105. * The image source that is used to create the texture. This is used to
  106. * store the original Svg source when it is replaced with a canvas element.
  107. *
  108. * TODO: Currently not in use but could be used when re-scaling svg.
  109. *
  110. * @readonly
  111. * @member {Image}
  112. */
  113. this.origSource = null; // set in loadSvg, if at all
  114. /**
  115. * Type of image defined in source, eg. `png` or `svg`
  116. *
  117. * @readonly
  118. * @member {string}
  119. */
  120. this.imageType = null; // set in updateImageType
  121. /**
  122. * Scale for source image. Used with Svg images to scale them before rasterization.
  123. *
  124. * @readonly
  125. * @member {number}
  126. */
  127. this.sourceScale = 1.0;
  128. /**
  129. * Controls if RGB channels should be pre-multiplied by Alpha (WebGL only)
  130. * All blend modes, and shaders written for default value. Change it on your own risk.
  131. *
  132. * @member {boolean}
  133. * @default true
  134. */
  135. this.premultipliedAlpha = true;
  136. /**
  137. * The image url of the texture
  138. *
  139. * @member {string}
  140. */
  141. this.imageUrl = null;
  142. /**
  143. * Whether or not the texture is a power of two, try to use power of two textures as much
  144. * as you can
  145. *
  146. * @private
  147. * @member {boolean}
  148. */
  149. this.isPowerOfTwo = false;
  150. // used for webGL
  151. /**
  152. *
  153. * Set this to true if a mipmap of this texture needs to be generated. This value needs
  154. * to be set before the texture is used
  155. * Also the texture must be a power of two size to work
  156. *
  157. * @member {boolean}
  158. * @see PIXI.MIPMAP_TEXTURES
  159. */
  160. this.mipmap = settings.MIPMAP_TEXTURES;
  161. /**
  162. *
  163. * WebGL Texture wrap mode
  164. *
  165. * @member {number}
  166. * @see PIXI.WRAP_MODES
  167. */
  168. this.wrapMode = settings.WRAP_MODE;
  169. /**
  170. * A map of renderer IDs to webgl textures
  171. *
  172. * @private
  173. * @member {object<number, WebGLTexture>}
  174. */
  175. this._glTextures = {};
  176. this._enabled = 0;
  177. this._virtalBoundId = -1;
  178. /**
  179. * If the object has been destroyed via destroy(). If true, it should not be used.
  180. *
  181. * @member {boolean}
  182. * @private
  183. * @readonly
  184. */
  185. this._destroyed = false;
  186. /**
  187. * The ids under which this BaseTexture has been added to the base texture cache. This is
  188. * automatically set as long as BaseTexture.addToCache is used, but may not be set if a
  189. * BaseTexture is added directly to the BaseTextureCache array.
  190. *
  191. * @member {string[]}
  192. */
  193. this.textureCacheIds = [];
  194. // if no source passed don't try to load
  195. if (source)
  196. {
  197. this.loadSource(source);
  198. }
  199. /**
  200. * Fired when a not-immediately-available source finishes loading.
  201. *
  202. * @protected
  203. * @event PIXI.BaseTexture#loaded
  204. * @param {PIXI.BaseTexture} baseTexture - Resource loaded.
  205. */
  206. /**
  207. * Fired when a not-immediately-available source fails to load.
  208. *
  209. * @protected
  210. * @event PIXI.BaseTexture#error
  211. * @param {PIXI.BaseTexture} baseTexture - Resource errored.
  212. */
  213. /**
  214. * Fired when BaseTexture is updated.
  215. *
  216. * @protected
  217. * @event PIXI.BaseTexture#update
  218. * @param {PIXI.BaseTexture} baseTexture - Instance of texture being updated.
  219. */
  220. /**
  221. * Fired when BaseTexture is destroyed.
  222. *
  223. * @protected
  224. * @event PIXI.BaseTexture#dispose
  225. * @param {PIXI.BaseTexture} baseTexture - Instance of texture being destroyed.
  226. */
  227. }
  228. /**
  229. * Updates the texture on all the webgl renderers, this also assumes the src has changed.
  230. *
  231. * @fires PIXI.BaseTexture#update
  232. */
  233. update()
  234. {
  235. // Svg size is handled during load
  236. if (this.imageType !== 'svg')
  237. {
  238. this.realWidth = this.source.naturalWidth || this.source.videoWidth || this.source.width;
  239. this.realHeight = this.source.naturalHeight || this.source.videoHeight || this.source.height;
  240. this._updateDimensions();
  241. }
  242. this.emit('update', this);
  243. }
  244. /**
  245. * Update dimensions from real values
  246. */
  247. _updateDimensions()
  248. {
  249. this.width = this.realWidth / this.resolution;
  250. this.height = this.realHeight / this.resolution;
  251. this.isPowerOfTwo = bitTwiddle.isPow2(this.realWidth) && bitTwiddle.isPow2(this.realHeight);
  252. }
  253. /**
  254. * Load a source.
  255. *
  256. * If the source is not-immediately-available, such as an image that needs to be
  257. * downloaded, then the 'loaded' or 'error' event will be dispatched in the future
  258. * and `hasLoaded` will remain false after this call.
  259. *
  260. * The logic state after calling `loadSource` directly or indirectly (eg. `fromImage`, `new BaseTexture`) is:
  261. *
  262. * if (texture.hasLoaded) {
  263. * // texture ready for use
  264. * } else if (texture.isLoading) {
  265. * // listen to 'loaded' and/or 'error' events on texture
  266. * } else {
  267. * // not loading, not going to load UNLESS the source is reloaded
  268. * // (it may still make sense to listen to the events)
  269. * }
  270. *
  271. * @protected
  272. * @param {HTMLImageElement|HTMLCanvasElement} source - the source object of the texture.
  273. */
  274. loadSource(source)
  275. {
  276. const wasLoading = this.isLoading;
  277. this.hasLoaded = false;
  278. this.isLoading = false;
  279. if (wasLoading && this.source)
  280. {
  281. this.source.onload = null;
  282. this.source.onerror = null;
  283. }
  284. const firstSourceLoaded = !this.source;
  285. this.source = source;
  286. // Apply source if loaded. Otherwise setup appropriate loading monitors.
  287. // 小程序安卓返回的Image无src,暂时去掉source.src判断
  288. // if (((source.src && source.complete) || source.getContext) && source.width && source.height)
  289. if ((source.complete || source.getContext) && source.width && source.height)
  290. {
  291. this._updateImageType();
  292. if (this.imageType === 'svg')
  293. {
  294. this._loadSvgSource();
  295. }
  296. else
  297. {
  298. this._sourceLoaded();
  299. }
  300. if (firstSourceLoaded)
  301. {
  302. // send loaded event if previous source was null and we have been passed a pre-loaded IMG element
  303. this.emit('loaded', this);
  304. }
  305. }
  306. else if (!source.getContext)
  307. {
  308. // Image fail / not ready
  309. this.isLoading = true;
  310. const scope = this;
  311. source.onload = () =>
  312. {
  313. scope._updateImageType();
  314. source.onload = null;
  315. source.onerror = null;
  316. if (!scope.isLoading)
  317. {
  318. return;
  319. }
  320. scope.isLoading = false;
  321. scope._sourceLoaded();
  322. if (scope.imageType === 'svg')
  323. {
  324. scope._loadSvgSource();
  325. return;
  326. }
  327. scope.emit('loaded', scope);
  328. };
  329. source.onerror = () =>
  330. {
  331. source.onload = null;
  332. source.onerror = null;
  333. if (!scope.isLoading)
  334. {
  335. return;
  336. }
  337. scope.isLoading = false;
  338. scope.emit('error', scope);
  339. };
  340. // Per http://www.w3.org/TR/html5/embedded-content-0.html#the-img-element
  341. // "The value of `complete` can thus change while a script is executing."
  342. // So complete needs to be re-checked after the callbacks have been added..
  343. // NOTE: complete will be true if the image has no src so best to check if the src is set.
  344. if (source.complete && source.src)
  345. {
  346. // ..and if we're complete now, no need for callbacks
  347. source.onload = null;
  348. source.onerror = null;
  349. if (scope.imageType === 'svg')
  350. {
  351. scope._loadSvgSource();
  352. return;
  353. }
  354. this.isLoading = false;
  355. if (source.width && source.height)
  356. {
  357. this._sourceLoaded();
  358. // If any previous subscribers possible
  359. if (wasLoading)
  360. {
  361. this.emit('loaded', this);
  362. }
  363. }
  364. // If any previous subscribers possible
  365. else if (wasLoading)
  366. {
  367. this.emit('error', this);
  368. }
  369. }
  370. }
  371. }
  372. /**
  373. * Updates type of the source image.
  374. */
  375. _updateImageType()
  376. {
  377. if (!this.imageUrl)
  378. {
  379. return;
  380. }
  381. const dataUri = decomposeDataUri(this.imageUrl);
  382. let imageType;
  383. if (dataUri && dataUri.mediaType === 'image')
  384. {
  385. // Check for subType validity
  386. const firstSubType = dataUri.subType.split('+')[0];
  387. imageType = getUrlFileExtension(`.${firstSubType}`);
  388. if (!imageType)
  389. {
  390. throw new Error('Invalid image type in data URI.');
  391. }
  392. }
  393. else
  394. {
  395. imageType = getUrlFileExtension(this.imageUrl);
  396. if (!imageType)
  397. {
  398. imageType = 'png';
  399. }
  400. }
  401. this.imageType = imageType;
  402. }
  403. /**
  404. * Checks if `source` is an SVG image and whether it's loaded via a URL or a data URI. Then calls
  405. * `_loadSvgSourceUsingDataUri` or `_loadSvgSourceUsingXhr`.
  406. */
  407. _loadSvgSource()
  408. {
  409. if (this.imageType !== 'svg')
  410. {
  411. // Do nothing if source is not svg
  412. return;
  413. }
  414. const dataUri = decomposeDataUri(this.imageUrl);
  415. if (dataUri)
  416. {
  417. this._loadSvgSourceUsingDataUri(dataUri);
  418. }
  419. else
  420. {
  421. // We got an URL, so we need to do an XHR to check the svg size
  422. this._loadSvgSourceUsingXhr();
  423. }
  424. }
  425. /**
  426. * Reads an SVG string from data URI and then calls `_loadSvgSourceUsingString`.
  427. *
  428. * @param {string} dataUri - The data uri to load from.
  429. */
  430. _loadSvgSourceUsingDataUri(dataUri)
  431. {
  432. let svgString;
  433. if (dataUri.encoding === 'base64')
  434. {
  435. if (!atob)
  436. {
  437. throw new Error('Your browser doesn\'t support base64 conversions.');
  438. }
  439. svgString = atob(dataUri.data);
  440. }
  441. else
  442. {
  443. svgString = dataUri.data;
  444. }
  445. this._loadSvgSourceUsingString(svgString);
  446. }
  447. /**
  448. * Loads an SVG string from `imageUrl` using XHR and then calls `_loadSvgSourceUsingString`.
  449. */
  450. _loadSvgSourceUsingXhr()
  451. {
  452. const svgXhr = new XMLHttpRequestAlias();
  453. // This throws error on IE, so SVG Document can't be used
  454. // svgXhr.responseType = 'document';
  455. // This is not needed since we load the svg as string (breaks IE too)
  456. // but overrideMimeType() can be used to force the response to be parsed as XML
  457. // svgXhr.overrideMimeType('image/svg+xml');
  458. svgXhr.onload = () =>
  459. {
  460. if (svgXhr.readyState !== svgXhr.DONE || svgXhr.status !== 200)
  461. {
  462. throw new Error('Failed to load SVG using XHR.');
  463. }
  464. this._loadSvgSourceUsingString(svgXhr.response);
  465. };
  466. svgXhr.onerror = () => this.emit('error', this);
  467. svgXhr.open('GET', this.imageUrl, true);
  468. svgXhr.send();
  469. }
  470. /**
  471. * Loads texture using an SVG string. The original SVG Image is stored as `origSource` and the
  472. * created canvas is the new `source`. The SVG is scaled using `sourceScale`. Called by
  473. * `_loadSvgSourceUsingXhr` or `_loadSvgSourceUsingDataUri`.
  474. *
  475. * @param {string} svgString SVG source as string
  476. *
  477. * @fires PIXI.BaseTexture#loaded
  478. */
  479. _loadSvgSourceUsingString(svgString)
  480. {
  481. const svgSize = getSvgSize(svgString);
  482. const svgWidth = svgSize.width;
  483. const svgHeight = svgSize.height;
  484. if (!svgWidth || !svgHeight)
  485. {
  486. throw new Error('The SVG image must have width and height defined (in pixels), canvas API needs them.');
  487. }
  488. // Scale realWidth and realHeight
  489. this.realWidth = Math.round(svgWidth * this.sourceScale);
  490. this.realHeight = Math.round(svgHeight * this.sourceScale);
  491. this._updateDimensions();
  492. // Create a canvas element
  493. const canvas = documentAlias.createElement('canvas');
  494. canvas.width = this.realWidth;
  495. canvas.height = this.realHeight;
  496. canvas._pixiId = `canvas_${uid()}`;
  497. // Draw the Svg to the canvas
  498. canvas
  499. .getContext('2d')
  500. .drawImage(this.source, 0, 0, svgWidth, svgHeight, 0, 0, this.realWidth, this.realHeight);
  501. // Replace the original source image with the canvas
  502. this.origSource = this.source;
  503. this.source = canvas;
  504. // Add also the canvas in cache (destroy clears by `imageUrl` and `source._pixiId`)
  505. BaseTexture.addToCache(this, canvas._pixiId);
  506. this.isLoading = false;
  507. this._sourceLoaded();
  508. this.emit('loaded', this);
  509. }
  510. /**
  511. * Used internally to update the width, height, and some other tracking vars once
  512. * a source has successfully loaded.
  513. *
  514. * @private
  515. */
  516. _sourceLoaded()
  517. {
  518. this.hasLoaded = true;
  519. this.update();
  520. }
  521. /**
  522. * Destroys this base texture
  523. *
  524. */
  525. destroy()
  526. {
  527. if (this.imageUrl)
  528. {
  529. delete TextureCache[this.imageUrl];
  530. this.imageUrl = null;
  531. if (!navigator.isCocoonJS)
  532. {
  533. this.source.src = '';
  534. }
  535. }
  536. this.source = null;
  537. this.dispose();
  538. BaseTexture.removeFromCache(this);
  539. this.textureCacheIds = null;
  540. this._destroyed = true;
  541. }
  542. /**
  543. * Frees the texture from WebGL memory without destroying this texture object.
  544. * This means you can still use the texture later which will upload it to GPU
  545. * memory again.
  546. *
  547. * @fires PIXI.BaseTexture#dispose
  548. */
  549. dispose()
  550. {
  551. this.emit('dispose', this);
  552. }
  553. /**
  554. * Changes the source image of the texture.
  555. * The original source must be an Image element.
  556. *
  557. * @param {string} newSrc - the path of the image
  558. */
  559. updateSourceImage(newSrc)
  560. {
  561. this.source.src = newSrc;
  562. this.loadSource(this.source);
  563. }
  564. /**
  565. * Helper function that creates a base texture from the given image url.
  566. * If the image is not in the base texture cache it will be created and loaded.
  567. *
  568. * @static
  569. * @param {string} imageUrl - The image url of the texture
  570. * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
  571. * @param {number} [scaleMode=PIXI.settings.SCALE_MODE] - See {@link PIXI.SCALE_MODES} for possible values
  572. * @param {number} [sourceScale=(auto)] - Scale for the original image, used with Svg images.
  573. * @return {PIXI.BaseTexture} The new base texture.
  574. */
  575. static fromImage(imageUrl, crossorigin, scaleMode, sourceScale)
  576. {
  577. let baseTexture = BaseTextureCache[imageUrl];
  578. if (!baseTexture)
  579. {
  580. // new Image() breaks tex loading in some versions of Chrome.
  581. // See https://code.google.com/p/chromium/issues/detail?id=238071
  582. const image = new Image();// document.createElement('img');
  583. if (crossorigin === undefined && imageUrl.indexOf('data:') !== 0)
  584. {
  585. image.crossOrigin = determineCrossOrigin(imageUrl);
  586. }
  587. else if (crossorigin)
  588. {
  589. image.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
  590. }
  591. baseTexture = new BaseTexture(image, scaleMode);
  592. baseTexture.imageUrl = imageUrl;
  593. if (sourceScale)
  594. {
  595. baseTexture.sourceScale = sourceScale;
  596. }
  597. // if there is an @2x at the end of the url we are going to assume its a highres image
  598. baseTexture.resolution = getResolutionOfUrl(imageUrl);
  599. image.src = imageUrl; // Setting this triggers load
  600. BaseTexture.addToCache(baseTexture, imageUrl);
  601. }
  602. return baseTexture;
  603. }
  604. /**
  605. * Helper function that creates a base texture from the given canvas element.
  606. *
  607. * @static
  608. * @param {HTMLCanvasElement} canvas - The canvas element source of the texture
  609. * @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
  610. * @param {string} [origin='canvas'] - A string origin of who created the base texture
  611. * @return {PIXI.BaseTexture} The new base texture.
  612. */
  613. static fromCanvas(canvas, scaleMode, origin = 'canvas')
  614. {
  615. if (!canvas._pixiId)
  616. {
  617. canvas._pixiId = `${origin}_${uid()}`;
  618. }
  619. let baseTexture = BaseTextureCache[canvas._pixiId];
  620. if (!baseTexture)
  621. {
  622. baseTexture = new BaseTexture(canvas, scaleMode);
  623. BaseTexture.addToCache(baseTexture, canvas._pixiId);
  624. }
  625. return baseTexture;
  626. }
  627. /**
  628. * Helper function that creates a base texture based on the source you provide.
  629. * The source can be - image url, image element, canvas element. If the
  630. * source is an image url or an image element and not in the base texture
  631. * cache, it will be created and loaded.
  632. *
  633. * @static
  634. * @param {string|HTMLImageElement|HTMLCanvasElement} source - The source to create base texture from.
  635. * @param {number} [scaleMode=PIXI.settings.SCALE_MODE] - See {@link PIXI.SCALE_MODES} for possible values
  636. * @param {number} [sourceScale=(auto)] - Scale for the original image, used with Svg images.
  637. * @return {PIXI.BaseTexture} The new base texture.
  638. */
  639. static from(source, scaleMode, sourceScale)
  640. {
  641. if (typeof source === 'string')
  642. {
  643. return BaseTexture.fromImage(source, undefined, scaleMode, sourceScale);
  644. }
  645. else if (source instanceof HTMLImageElement)
  646. {
  647. const imageUrl = source.src;
  648. let baseTexture = BaseTextureCache[imageUrl];
  649. if (!baseTexture)
  650. {
  651. baseTexture = new BaseTexture(source, scaleMode);
  652. baseTexture.imageUrl = imageUrl;
  653. if (sourceScale)
  654. {
  655. baseTexture.sourceScale = sourceScale;
  656. }
  657. // if there is an @2x at the end of the url we are going to assume its a highres image
  658. baseTexture.resolution = getResolutionOfUrl(imageUrl);
  659. BaseTexture.addToCache(baseTexture, imageUrl);
  660. }
  661. return baseTexture;
  662. }
  663. else if (source instanceof HTMLCanvasElement)
  664. {
  665. return BaseTexture.fromCanvas(source, scaleMode);
  666. }
  667. // lets assume its a base texture!
  668. return source;
  669. }
  670. /**
  671. * Adds a BaseTexture to the global BaseTextureCache. This cache is shared across the whole PIXI object.
  672. *
  673. * @static
  674. * @param {PIXI.BaseTexture} baseTexture - The BaseTexture to add to the cache.
  675. * @param {string} id - The id that the BaseTexture will be stored against.
  676. */
  677. static addToCache(baseTexture, id)
  678. {
  679. if (id)
  680. {
  681. if (baseTexture.textureCacheIds.indexOf(id) === -1)
  682. {
  683. baseTexture.textureCacheIds.push(id);
  684. }
  685. // @if DEBUG
  686. /* eslint-disable no-console */
  687. if (BaseTextureCache[id])
  688. {
  689. console.warn(`BaseTexture added to the cache with an id [${id}] that already had an entry`);
  690. }
  691. /* eslint-enable no-console */
  692. // @endif
  693. BaseTextureCache[id] = baseTexture;
  694. }
  695. }
  696. /**
  697. * Remove a BaseTexture from the global BaseTextureCache.
  698. *
  699. * @static
  700. * @param {string|PIXI.BaseTexture} baseTexture - id of a BaseTexture to be removed, or a BaseTexture instance itself.
  701. * @return {PIXI.BaseTexture|null} The BaseTexture that was removed.
  702. */
  703. static removeFromCache(baseTexture)
  704. {
  705. if (typeof baseTexture === 'string')
  706. {
  707. const baseTextureFromCache = BaseTextureCache[baseTexture];
  708. if (baseTextureFromCache)
  709. {
  710. const index = baseTextureFromCache.textureCacheIds.indexOf(baseTexture);
  711. if (index > -1)
  712. {
  713. baseTextureFromCache.textureCacheIds.splice(index, 1);
  714. }
  715. delete BaseTextureCache[baseTexture];
  716. return baseTextureFromCache;
  717. }
  718. }
  719. else if (baseTexture && baseTexture.textureCacheIds)
  720. {
  721. for (let i = 0; i < baseTexture.textureCacheIds.length; ++i)
  722. {
  723. delete BaseTextureCache[baseTexture.textureCacheIds[i]];
  724. }
  725. baseTexture.textureCacheIds.length = 0;
  726. return baseTexture;
  727. }
  728. return null;
  729. }
  730. }