Source: core/renderers/webgl/managers/MaskManager.js

core/renderers/webgl/managers/MaskManager.js

  1. import WebGLManager from './WebGLManager';
  2. import AlphaMaskFilter from '../filters/spriteMask/SpriteMaskFilter';
  3. /**
  4. * @class
  5. * @extends PIXI.WebGLManager
  6. * @memberof PIXI
  7. */
  8. export default class MaskManager extends WebGLManager
  9. {
  10. /**
  11. * @param {PIXI.WebGLRenderer} renderer - The renderer this manager works for.
  12. */
  13. constructor(renderer)
  14. {
  15. super(renderer);
  16. // TODO - we don't need both!
  17. this.scissor = false;
  18. this.scissorData = null;
  19. this.scissorRenderTarget = null;
  20. this.enableScissor = true;
  21. this.alphaMaskPool = [];
  22. this.alphaMaskIndex = 0;
  23. }
  24. /**
  25. * Applies the Mask and adds it to the current filter stack.
  26. *
  27. * @param {PIXI.DisplayObject} target - Display Object to push the mask to
  28. * @param {PIXI.Sprite|PIXI.Graphics} maskData - The masking data.
  29. */
  30. pushMask(target, maskData)
  31. {
  32. // TODO the root check means scissor rect will not
  33. // be used on render textures more info here:
  34. // https://github.com/pixijs/pixi.js/pull/3545
  35. if (maskData.texture)
  36. {
  37. this.pushSpriteMask(target, maskData);
  38. }
  39. else if (this.enableScissor
  40. && !this.scissor
  41. && this.renderer._activeRenderTarget.root
  42. && !this.renderer.stencilManager.stencilMaskStack.length
  43. && maskData.isFastRect())
  44. {
  45. const matrix = maskData.worldTransform;
  46. let rot = Math.atan2(matrix.b, matrix.a);
  47. // use the nearest degree!
  48. rot = Math.round(rot * (180 / Math.PI));
  49. if (rot % 90)
  50. {
  51. this.pushStencilMask(maskData);
  52. }
  53. else
  54. {
  55. this.pushScissorMask(target, maskData);
  56. }
  57. }
  58. else
  59. {
  60. this.pushStencilMask(maskData);
  61. }
  62. }
  63. /**
  64. * Removes the last mask from the mask stack and doesn't return it.
  65. *
  66. * @param {PIXI.DisplayObject} target - Display Object to pop the mask from
  67. * @param {PIXI.Sprite|PIXI.Graphics} maskData - The masking data.
  68. */
  69. popMask(target, maskData)
  70. {
  71. if (maskData.texture)
  72. {
  73. this.popSpriteMask(target, maskData);
  74. }
  75. else if (this.enableScissor && !this.renderer.stencilManager.stencilMaskStack.length)
  76. {
  77. this.popScissorMask(target, maskData);
  78. }
  79. else
  80. {
  81. this.popStencilMask(target, maskData);
  82. }
  83. }
  84. /**
  85. * Applies the Mask and adds it to the current filter stack.
  86. *
  87. * @param {PIXI.RenderTarget} target - Display Object to push the sprite mask to
  88. * @param {PIXI.Sprite} maskData - Sprite to be used as the mask
  89. */
  90. pushSpriteMask(target, maskData)
  91. {
  92. let alphaMaskFilter = this.alphaMaskPool[this.alphaMaskIndex];
  93. if (!alphaMaskFilter)
  94. {
  95. alphaMaskFilter = this.alphaMaskPool[this.alphaMaskIndex] = [new AlphaMaskFilter(maskData)];
  96. }
  97. alphaMaskFilter[0].resolution = this.renderer.resolution;
  98. alphaMaskFilter[0].maskSprite = maskData;
  99. const stashFilterArea = target.filterArea;
  100. target.filterArea = maskData.getBounds(true);
  101. this.renderer.filterManager.pushFilter(target, alphaMaskFilter);
  102. target.filterArea = stashFilterArea;
  103. this.alphaMaskIndex++;
  104. }
  105. /**
  106. * Removes the last filter from the filter stack and doesn't return it.
  107. *
  108. */
  109. popSpriteMask()
  110. {
  111. this.renderer.filterManager.popFilter();
  112. this.alphaMaskIndex--;
  113. }
  114. /**
  115. * Applies the Mask and adds it to the current filter stack.
  116. *
  117. * @param {PIXI.Sprite|PIXI.Graphics} maskData - The masking data.
  118. */
  119. pushStencilMask(maskData)
  120. {
  121. this.renderer.currentRenderer.stop();
  122. this.renderer.stencilManager.pushStencil(maskData);
  123. }
  124. /**
  125. * Removes the last filter from the filter stack and doesn't return it.
  126. *
  127. */
  128. popStencilMask()
  129. {
  130. this.renderer.currentRenderer.stop();
  131. this.renderer.stencilManager.popStencil();
  132. }
  133. /**
  134. *
  135. * @param {PIXI.DisplayObject} target - Display Object to push the mask to
  136. * @param {PIXI.Graphics} maskData - The masking data.
  137. */
  138. pushScissorMask(target, maskData)
  139. {
  140. maskData.renderable = true;
  141. const renderTarget = this.renderer._activeRenderTarget;
  142. const bounds = maskData.getBounds();
  143. bounds.fit(renderTarget.size);
  144. maskData.renderable = false;
  145. this.renderer.gl.enable(this.renderer.gl.SCISSOR_TEST);
  146. const resolution = this.renderer.resolution;
  147. this.renderer.gl.scissor(
  148. bounds.x * resolution,
  149. (renderTarget.root ? renderTarget.size.height - bounds.y - bounds.height : bounds.y) * resolution,
  150. bounds.width * resolution,
  151. bounds.height * resolution
  152. );
  153. this.scissorRenderTarget = renderTarget;
  154. this.scissorData = maskData;
  155. this.scissor = true;
  156. }
  157. /**
  158. *
  159. *
  160. */
  161. popScissorMask()
  162. {
  163. this.scissorRenderTarget = null;
  164. this.scissorData = null;
  165. this.scissor = false;
  166. // must be scissor!
  167. const gl = this.renderer.gl;
  168. gl.disable(gl.SCISSOR_TEST);
  169. }
  170. }