mixin-cache-as-bitmap.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /*!
  2. * @pixi/mixin-cache-as-bitmap - v6.5.10
  3. * Compiled Thu, 06 Jul 2023 15:25:11 UTC
  4. *
  5. * @pixi/mixin-cache-as-bitmap is licensed under the MIT License.
  6. * http://www.opensource.org/licenses/mit-license
  7. */
  8. this.PIXI = this.PIXI || {};
  9. var _pixi_mixin_cache_as_bitmap = (function (exports, core, sprite, display, math, utils, settings, constants) {
  10. 'use strict';
  11. var _tempMatrix = new math.Matrix();
  12. display.DisplayObject.prototype._cacheAsBitmap = false;
  13. display.DisplayObject.prototype._cacheData = null;
  14. display.DisplayObject.prototype._cacheAsBitmapResolution = null;
  15. display.DisplayObject.prototype._cacheAsBitmapMultisample = constants.MSAA_QUALITY.NONE;
  16. // figured there's no point adding ALL the extra variables to prototype.
  17. // this model can hold the information needed. This can also be generated on demand as
  18. // most objects are not cached as bitmaps.
  19. /**
  20. * @class
  21. * @ignore
  22. * @private
  23. */
  24. var CacheData = /** @class */ (function () {
  25. function CacheData() {
  26. this.textureCacheId = null;
  27. this.originalRender = null;
  28. this.originalRenderCanvas = null;
  29. this.originalCalculateBounds = null;
  30. this.originalGetLocalBounds = null;
  31. this.originalUpdateTransform = null;
  32. this.originalDestroy = null;
  33. this.originalMask = null;
  34. this.originalFilterArea = null;
  35. this.originalContainsPoint = null;
  36. this.sprite = null;
  37. }
  38. return CacheData;
  39. }());
  40. Object.defineProperties(display.DisplayObject.prototype, {
  41. /**
  42. * The resolution to use for cacheAsBitmap. By default this will use the renderer's resolution
  43. * but can be overriden for performance. Lower values will reduce memory usage at the expense
  44. * of render quality. A falsey value of `null` or `0` will default to the renderer's resolution.
  45. * If `cacheAsBitmap` is set to `true`, this will re-render with the new resolution.
  46. * @member {number} cacheAsBitmapResolution
  47. * @memberof PIXI.DisplayObject#
  48. * @default null
  49. */
  50. cacheAsBitmapResolution: {
  51. get: function () {
  52. return this._cacheAsBitmapResolution;
  53. },
  54. set: function (resolution) {
  55. if (resolution === this._cacheAsBitmapResolution) {
  56. return;
  57. }
  58. this._cacheAsBitmapResolution = resolution;
  59. if (this.cacheAsBitmap) {
  60. // Toggle to re-render at the new resolution
  61. this.cacheAsBitmap = false;
  62. this.cacheAsBitmap = true;
  63. }
  64. },
  65. },
  66. /**
  67. * The number of samples to use for cacheAsBitmap. If set to `null`, the renderer's
  68. * sample count is used.
  69. * If `cacheAsBitmap` is set to `true`, this will re-render with the new number of samples.
  70. * @member {number} cacheAsBitmapMultisample
  71. * @memberof PIXI.DisplayObject#
  72. * @default PIXI.MSAA_QUALITY.NONE
  73. */
  74. cacheAsBitmapMultisample: {
  75. get: function () {
  76. return this._cacheAsBitmapMultisample;
  77. },
  78. set: function (multisample) {
  79. if (multisample === this._cacheAsBitmapMultisample) {
  80. return;
  81. }
  82. this._cacheAsBitmapMultisample = multisample;
  83. if (this.cacheAsBitmap) {
  84. // Toggle to re-render with new multisample
  85. this.cacheAsBitmap = false;
  86. this.cacheAsBitmap = true;
  87. }
  88. },
  89. },
  90. /**
  91. * Set this to true if you want this display object to be cached as a bitmap.
  92. * This basically takes a snap shot of the display object as it is at that moment. It can
  93. * provide a performance benefit for complex static displayObjects.
  94. * To remove simply set this property to `false`
  95. *
  96. * IMPORTANT GOTCHA - Make sure that all your textures are preloaded BEFORE setting this property to true
  97. * as it will take a snapshot of what is currently there. If the textures have not loaded then they will not appear.
  98. * @member {boolean}
  99. * @memberof PIXI.DisplayObject#
  100. */
  101. cacheAsBitmap: {
  102. get: function () {
  103. return this._cacheAsBitmap;
  104. },
  105. set: function (value) {
  106. if (this._cacheAsBitmap === value) {
  107. return;
  108. }
  109. this._cacheAsBitmap = value;
  110. var data;
  111. if (value) {
  112. if (!this._cacheData) {
  113. this._cacheData = new CacheData();
  114. }
  115. data = this._cacheData;
  116. data.originalRender = this.render;
  117. data.originalRenderCanvas = this.renderCanvas;
  118. data.originalUpdateTransform = this.updateTransform;
  119. data.originalCalculateBounds = this.calculateBounds;
  120. data.originalGetLocalBounds = this.getLocalBounds;
  121. data.originalDestroy = this.destroy;
  122. data.originalContainsPoint = this.containsPoint;
  123. data.originalMask = this._mask;
  124. data.originalFilterArea = this.filterArea;
  125. this.render = this._renderCached;
  126. this.renderCanvas = this._renderCachedCanvas;
  127. this.destroy = this._cacheAsBitmapDestroy;
  128. }
  129. else {
  130. data = this._cacheData;
  131. if (data.sprite) {
  132. this._destroyCachedDisplayObject();
  133. }
  134. this.render = data.originalRender;
  135. this.renderCanvas = data.originalRenderCanvas;
  136. this.calculateBounds = data.originalCalculateBounds;
  137. this.getLocalBounds = data.originalGetLocalBounds;
  138. this.destroy = data.originalDestroy;
  139. this.updateTransform = data.originalUpdateTransform;
  140. this.containsPoint = data.originalContainsPoint;
  141. this._mask = data.originalMask;
  142. this.filterArea = data.originalFilterArea;
  143. }
  144. },
  145. },
  146. });
  147. /**
  148. * Renders a cached version of the sprite with WebGL
  149. * @private
  150. * @method _renderCached
  151. * @memberof PIXI.DisplayObject#
  152. * @param {PIXI.Renderer} renderer - the WebGL renderer
  153. */
  154. display.DisplayObject.prototype._renderCached = function _renderCached(renderer) {
  155. if (!this.visible || this.worldAlpha <= 0 || !this.renderable) {
  156. return;
  157. }
  158. this._initCachedDisplayObject(renderer);
  159. this._cacheData.sprite.transform._worldID = this.transform._worldID;
  160. this._cacheData.sprite.worldAlpha = this.worldAlpha;
  161. this._cacheData.sprite._render(renderer);
  162. };
  163. /**
  164. * Prepares the WebGL renderer to cache the sprite
  165. * @private
  166. * @method _initCachedDisplayObject
  167. * @memberof PIXI.DisplayObject#
  168. * @param {PIXI.Renderer} renderer - the WebGL renderer
  169. */
  170. display.DisplayObject.prototype._initCachedDisplayObject = function _initCachedDisplayObject(renderer) {
  171. var _a;
  172. if (this._cacheData && this._cacheData.sprite) {
  173. return;
  174. }
  175. // make sure alpha is set to 1 otherwise it will get rendered as invisible!
  176. var cacheAlpha = this.alpha;
  177. this.alpha = 1;
  178. // first we flush anything left in the renderer (otherwise it would get rendered to the cached texture)
  179. renderer.batch.flush();
  180. // this.filters= [];
  181. // next we find the dimensions of the untransformed object
  182. // this function also calls updatetransform on all its children as part of the measuring.
  183. // This means we don't need to update the transform again in this function
  184. // TODO pass an object to clone too? saves having to create a new one each time!
  185. var bounds = this.getLocalBounds(null, true).clone();
  186. // add some padding!
  187. if (this.filters && this.filters.length) {
  188. var padding = this.filters[0].padding;
  189. bounds.pad(padding);
  190. }
  191. bounds.ceil(settings.settings.RESOLUTION);
  192. // for now we cache the current renderTarget that the WebGL renderer is currently using.
  193. // this could be more elegant..
  194. var cachedRenderTexture = renderer.renderTexture.current;
  195. var cachedSourceFrame = renderer.renderTexture.sourceFrame.clone();
  196. var cachedDestinationFrame = renderer.renderTexture.destinationFrame.clone();
  197. var cachedProjectionTransform = renderer.projection.transform;
  198. // We also store the filter stack - I will definitely look to change how this works a little later down the line.
  199. // const stack = renderer.filterManager.filterStack;
  200. // this renderTexture will be used to store the cached DisplayObject
  201. var renderTexture = core.RenderTexture.create({
  202. width: bounds.width,
  203. height: bounds.height,
  204. resolution: this.cacheAsBitmapResolution || renderer.resolution,
  205. multisample: (_a = this.cacheAsBitmapMultisample) !== null && _a !== void 0 ? _a : renderer.multisample,
  206. });
  207. var textureCacheId = "cacheAsBitmap_" + utils.uid();
  208. this._cacheData.textureCacheId = textureCacheId;
  209. core.BaseTexture.addToCache(renderTexture.baseTexture, textureCacheId);
  210. core.Texture.addToCache(renderTexture, textureCacheId);
  211. // need to set //
  212. var m = this.transform.localTransform.copyTo(_tempMatrix).invert().translate(-bounds.x, -bounds.y);
  213. // set all properties to there original so we can render to a texture
  214. this.render = this._cacheData.originalRender;
  215. renderer.render(this, { renderTexture: renderTexture, clear: true, transform: m, skipUpdateTransform: false });
  216. renderer.framebuffer.blit();
  217. // now restore the state be setting the new properties
  218. renderer.projection.transform = cachedProjectionTransform;
  219. renderer.renderTexture.bind(cachedRenderTexture, cachedSourceFrame, cachedDestinationFrame);
  220. // renderer.filterManager.filterStack = stack;
  221. this.render = this._renderCached;
  222. // the rest is the same as for Canvas
  223. this.updateTransform = this.displayObjectUpdateTransform;
  224. this.calculateBounds = this._calculateCachedBounds;
  225. this.getLocalBounds = this._getCachedLocalBounds;
  226. this._mask = null;
  227. this.filterArea = null;
  228. this.alpha = cacheAlpha;
  229. // create our cached sprite
  230. var cachedSprite = new sprite.Sprite(renderTexture);
  231. cachedSprite.transform.worldTransform = this.transform.worldTransform;
  232. cachedSprite.anchor.x = -(bounds.x / bounds.width);
  233. cachedSprite.anchor.y = -(bounds.y / bounds.height);
  234. cachedSprite.alpha = cacheAlpha;
  235. cachedSprite._bounds = this._bounds;
  236. this._cacheData.sprite = cachedSprite;
  237. this.transform._parentID = -1;
  238. // restore the transform of the cached sprite to avoid the nasty flicker..
  239. if (!this.parent) {
  240. this.enableTempParent();
  241. this.updateTransform();
  242. this.disableTempParent(null);
  243. }
  244. else {
  245. this.updateTransform();
  246. }
  247. // map the hit test..
  248. this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
  249. };
  250. /**
  251. * Renders a cached version of the sprite with canvas
  252. * @private
  253. * @method _renderCachedCanvas
  254. * @memberof PIXI.DisplayObject#
  255. * @param {PIXI.CanvasRenderer} renderer - The canvas renderer
  256. */
  257. display.DisplayObject.prototype._renderCachedCanvas = function _renderCachedCanvas(renderer) {
  258. if (!this.visible || this.worldAlpha <= 0 || !this.renderable) {
  259. return;
  260. }
  261. this._initCachedDisplayObjectCanvas(renderer);
  262. this._cacheData.sprite.worldAlpha = this.worldAlpha;
  263. this._cacheData.sprite._renderCanvas(renderer);
  264. };
  265. // TODO this can be the same as the WebGL version.. will need to do a little tweaking first though..
  266. /**
  267. * Prepares the Canvas renderer to cache the sprite
  268. * @private
  269. * @method _initCachedDisplayObjectCanvas
  270. * @memberof PIXI.DisplayObject#
  271. * @param {PIXI.CanvasRenderer} renderer - The canvas renderer
  272. */
  273. display.DisplayObject.prototype._initCachedDisplayObjectCanvas = function _initCachedDisplayObjectCanvas(renderer) {
  274. if (this._cacheData && this._cacheData.sprite) {
  275. return;
  276. }
  277. // get bounds actually transforms the object for us already!
  278. var bounds = this.getLocalBounds(null, true);
  279. var cacheAlpha = this.alpha;
  280. this.alpha = 1;
  281. var cachedRenderTarget = renderer.context;
  282. var cachedProjectionTransform = renderer._projTransform;
  283. bounds.ceil(settings.settings.RESOLUTION);
  284. var renderTexture = core.RenderTexture.create({ width: bounds.width, height: bounds.height });
  285. var textureCacheId = "cacheAsBitmap_" + utils.uid();
  286. this._cacheData.textureCacheId = textureCacheId;
  287. core.BaseTexture.addToCache(renderTexture.baseTexture, textureCacheId);
  288. core.Texture.addToCache(renderTexture, textureCacheId);
  289. // need to set //
  290. var m = _tempMatrix;
  291. this.transform.localTransform.copyTo(m);
  292. m.invert();
  293. m.tx -= bounds.x;
  294. m.ty -= bounds.y;
  295. // m.append(this.transform.worldTransform.)
  296. // set all properties to there original so we can render to a texture
  297. this.renderCanvas = this._cacheData.originalRenderCanvas;
  298. renderer.render(this, { renderTexture: renderTexture, clear: true, transform: m, skipUpdateTransform: false });
  299. // now restore the state be setting the new properties
  300. renderer.context = cachedRenderTarget;
  301. renderer._projTransform = cachedProjectionTransform;
  302. this.renderCanvas = this._renderCachedCanvas;
  303. // the rest is the same as for WebGL
  304. this.updateTransform = this.displayObjectUpdateTransform;
  305. this.calculateBounds = this._calculateCachedBounds;
  306. this.getLocalBounds = this._getCachedLocalBounds;
  307. this._mask = null;
  308. this.filterArea = null;
  309. this.alpha = cacheAlpha;
  310. // create our cached sprite
  311. var cachedSprite = new sprite.Sprite(renderTexture);
  312. cachedSprite.transform.worldTransform = this.transform.worldTransform;
  313. cachedSprite.anchor.x = -(bounds.x / bounds.width);
  314. cachedSprite.anchor.y = -(bounds.y / bounds.height);
  315. cachedSprite.alpha = cacheAlpha;
  316. cachedSprite._bounds = this._bounds;
  317. this._cacheData.sprite = cachedSprite;
  318. this.transform._parentID = -1;
  319. // restore the transform of the cached sprite to avoid the nasty flicker..
  320. if (!this.parent) {
  321. this.parent = renderer._tempDisplayObjectParent;
  322. this.updateTransform();
  323. this.parent = null;
  324. }
  325. else {
  326. this.updateTransform();
  327. }
  328. // map the hit test..
  329. this.containsPoint = cachedSprite.containsPoint.bind(cachedSprite);
  330. };
  331. /**
  332. * Calculates the bounds of the cached sprite
  333. * @private
  334. * @method
  335. */
  336. display.DisplayObject.prototype._calculateCachedBounds = function _calculateCachedBounds() {
  337. this._bounds.clear();
  338. this._cacheData.sprite.transform._worldID = this.transform._worldID;
  339. this._cacheData.sprite._calculateBounds();
  340. this._bounds.updateID = this._boundsID;
  341. };
  342. /**
  343. * Gets the bounds of the cached sprite.
  344. * @private
  345. * @method
  346. * @returns {Rectangle} The local bounds.
  347. */
  348. display.DisplayObject.prototype._getCachedLocalBounds = function _getCachedLocalBounds() {
  349. return this._cacheData.sprite.getLocalBounds(null);
  350. };
  351. /**
  352. * Destroys the cached sprite.
  353. * @private
  354. * @method
  355. */
  356. display.DisplayObject.prototype._destroyCachedDisplayObject = function _destroyCachedDisplayObject() {
  357. this._cacheData.sprite._texture.destroy(true);
  358. this._cacheData.sprite = null;
  359. core.BaseTexture.removeFromCache(this._cacheData.textureCacheId);
  360. core.Texture.removeFromCache(this._cacheData.textureCacheId);
  361. this._cacheData.textureCacheId = null;
  362. };
  363. /**
  364. * Destroys the cached object.
  365. * @private
  366. * @method
  367. * @param {object|boolean} [options] - Options parameter. A boolean will act as if all options
  368. * have been set to that value.
  369. * Used when destroying containers, see the Container.destroy method.
  370. */
  371. display.DisplayObject.prototype._cacheAsBitmapDestroy = function _cacheAsBitmapDestroy(options) {
  372. this.cacheAsBitmap = false;
  373. this.destroy(options);
  374. };
  375. exports.CacheData = CacheData;
  376. Object.defineProperty(exports, '__esModule', { value: true });
  377. return exports;
  378. })({}, PIXI, PIXI, PIXI, PIXI, PIXI.utils, PIXI, PIXI);
  379. //# sourceMappingURL=mixin-cache-as-bitmap.js.map