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

core/renderers/webgl/managers/StencilManager.js

  1. import WebGLManager from './WebGLManager';
  2. /**
  3. * @class
  4. * @extends PIXI.WebGLManager
  5. * @memberof PIXI
  6. */
  7. export default class StencilManager extends WebGLManager
  8. {
  9. /**
  10. * @param {PIXI.WebGLRenderer} renderer - The renderer this manager works for.
  11. */
  12. constructor(renderer)
  13. {
  14. super(renderer);
  15. this.stencilMaskStack = null;
  16. }
  17. /**
  18. * Changes the mask stack that is used by this manager.
  19. *
  20. * @param {PIXI.Graphics[]} stencilMaskStack - The mask stack
  21. */
  22. setMaskStack(stencilMaskStack)
  23. {
  24. this.stencilMaskStack = stencilMaskStack;
  25. const gl = this.renderer.gl;
  26. if (stencilMaskStack.length === 0)
  27. {
  28. gl.disable(gl.STENCIL_TEST);
  29. }
  30. else
  31. {
  32. gl.enable(gl.STENCIL_TEST);
  33. }
  34. }
  35. /**
  36. * Applies the Mask and adds it to the current stencil stack. @alvin
  37. *
  38. * @param {PIXI.Graphics} graphics - The mask
  39. */
  40. pushStencil(graphics)
  41. {
  42. this.renderer.setObjectRenderer(this.renderer.plugins.graphics);
  43. this.renderer._activeRenderTarget.attachStencilBuffer();
  44. const gl = this.renderer.gl;
  45. const prevMaskCount = this.stencilMaskStack.length;
  46. if (prevMaskCount === 0)
  47. {
  48. gl.enable(gl.STENCIL_TEST);
  49. }
  50. this.stencilMaskStack.push(graphics);
  51. // Increment the reference stencil value where the new mask overlaps with the old ones.
  52. gl.colorMask(false, false, false, false);
  53. gl.stencilFunc(gl.EQUAL, prevMaskCount, this._getBitwiseMask());
  54. gl.stencilOp(gl.KEEP, gl.KEEP, gl.INCR);
  55. this.renderer.plugins.graphics.render(graphics);
  56. this._useCurrent();
  57. }
  58. /**
  59. * Removes the last mask from the stencil stack. @alvin
  60. */
  61. popStencil()
  62. {
  63. this.renderer.setObjectRenderer(this.renderer.plugins.graphics);
  64. const gl = this.renderer.gl;
  65. const graphics = this.stencilMaskStack.pop();
  66. if (this.stencilMaskStack.length === 0)
  67. {
  68. // the stack is empty!
  69. gl.disable(gl.STENCIL_TEST);
  70. gl.clear(gl.STENCIL_BUFFER_BIT);
  71. gl.clearStencil(0);
  72. }
  73. else
  74. {
  75. // Decrement the reference stencil value where the popped mask overlaps with the other ones
  76. gl.colorMask(false, false, false, false);
  77. gl.stencilOp(gl.KEEP, gl.KEEP, gl.DECR);
  78. this.renderer.plugins.graphics.render(graphics);
  79. this._useCurrent();
  80. }
  81. }
  82. /**
  83. * Setup renderer to use the current stencil data.
  84. */
  85. _useCurrent()
  86. {
  87. const gl = this.renderer.gl;
  88. gl.colorMask(true, true, true, true);
  89. gl.stencilFunc(gl.EQUAL, this.stencilMaskStack.length, this._getBitwiseMask());
  90. gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
  91. }
  92. /**
  93. * Fill 1s equal to the number of acitve stencil masks.
  94. *
  95. * @return {number} The bitwise mask.
  96. */
  97. _getBitwiseMask()
  98. {
  99. return (1 << this.stencilMaskStack.length) - 1;
  100. }
  101. /**
  102. * Destroys the mask stack.
  103. *
  104. */
  105. destroy()
  106. {
  107. WebGLManager.prototype.destroy.call(this);
  108. this.stencilMaskStack.stencilStack = null;
  109. }
  110. }