mixin-cache-as-bitmap.js 16 KB

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