mixin-cache-as-bitmap.mjs 15 KB

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