UNPKG

6.27 kBJavaScriptView Raw
1import { MASK_TYPES } from "@pixi/constants";
2import { ExtensionType, extensions } from "@pixi/extensions";
3import { SpriteMaskFilter } from "../filters/spriteMask/SpriteMaskFilter.mjs";
4import { MaskData } from "./MaskData.mjs";
5class MaskSystem {
6 /**
7 * @param renderer - The renderer this System works for.
8 */
9 constructor(renderer) {
10 this.renderer = renderer, this.enableScissor = !0, this.alphaMaskPool = [], this.maskDataPool = [], this.maskStack = [], this.alphaMaskIndex = 0;
11 }
12 /**
13 * Changes the mask stack that is used by this System.
14 * @param maskStack - The mask stack
15 */
16 setMaskStack(maskStack) {
17 this.maskStack = maskStack, this.renderer.scissor.setMaskStack(maskStack), this.renderer.stencil.setMaskStack(maskStack);
18 }
19 /**
20 * Enables the mask and appends it to the current mask stack.
21 *
22 * NOTE: The batch renderer should be flushed beforehand to prevent pending renders from being masked.
23 * @param {PIXI.DisplayObject} target - Display Object to push the mask to
24 * @param {PIXI.MaskData|PIXI.Sprite|PIXI.Graphics|PIXI.DisplayObject} maskDataOrTarget - The masking data.
25 */
26 push(target, maskDataOrTarget) {
27 let maskData = maskDataOrTarget;
28 if (!maskData.isMaskData) {
29 const d = this.maskDataPool.pop() || new MaskData();
30 d.pooled = !0, d.maskObject = maskDataOrTarget, maskData = d;
31 }
32 const maskAbove = this.maskStack.length !== 0 ? this.maskStack[this.maskStack.length - 1] : null;
33 if (maskData.copyCountersOrReset(maskAbove), maskData._colorMask = maskAbove ? maskAbove._colorMask : 15, maskData.autoDetect && this.detect(maskData), maskData._target = target, maskData.type !== MASK_TYPES.SPRITE && this.maskStack.push(maskData), maskData.enabled)
34 switch (maskData.type) {
35 case MASK_TYPES.SCISSOR:
36 this.renderer.scissor.push(maskData);
37 break;
38 case MASK_TYPES.STENCIL:
39 this.renderer.stencil.push(maskData);
40 break;
41 case MASK_TYPES.SPRITE:
42 maskData.copyCountersOrReset(null), this.pushSpriteMask(maskData);
43 break;
44 case MASK_TYPES.COLOR:
45 this.pushColorMask(maskData);
46 break;
47 default:
48 break;
49 }
50 maskData.type === MASK_TYPES.SPRITE && this.maskStack.push(maskData);
51 }
52 /**
53 * Removes the last mask from the mask stack and doesn't return it.
54 *
55 * NOTE: The batch renderer should be flushed beforehand to render the masked contents before the mask is removed.
56 * @param {PIXI.IMaskTarget} target - Display Object to pop the mask from
57 */
58 pop(target) {
59 const maskData = this.maskStack.pop();
60 if (!(!maskData || maskData._target !== target)) {
61 if (maskData.enabled)
62 switch (maskData.type) {
63 case MASK_TYPES.SCISSOR:
64 this.renderer.scissor.pop(maskData);
65 break;
66 case MASK_TYPES.STENCIL:
67 this.renderer.stencil.pop(maskData.maskObject);
68 break;
69 case MASK_TYPES.SPRITE:
70 this.popSpriteMask(maskData);
71 break;
72 case MASK_TYPES.COLOR:
73 this.popColorMask(maskData);
74 break;
75 default:
76 break;
77 }
78 if (maskData.reset(), maskData.pooled && this.maskDataPool.push(maskData), this.maskStack.length !== 0) {
79 const maskCurrent = this.maskStack[this.maskStack.length - 1];
80 maskCurrent.type === MASK_TYPES.SPRITE && maskCurrent._filters && (maskCurrent._filters[0].maskSprite = maskCurrent.maskObject);
81 }
82 }
83 }
84 /**
85 * Sets type of MaskData based on its maskObject.
86 * @param maskData
87 */
88 detect(maskData) {
89 const maskObject = maskData.maskObject;
90 maskObject ? maskObject.isSprite ? maskData.type = MASK_TYPES.SPRITE : this.enableScissor && this.renderer.scissor.testScissor(maskData) ? maskData.type = MASK_TYPES.SCISSOR : maskData.type = MASK_TYPES.STENCIL : maskData.type = MASK_TYPES.COLOR;
91 }
92 /**
93 * Applies the Mask and adds it to the current filter stack.
94 * @param maskData - Sprite to be used as the mask.
95 */
96 pushSpriteMask(maskData) {
97 const { maskObject } = maskData, target = maskData._target;
98 let alphaMaskFilter = maskData._filters;
99 alphaMaskFilter || (alphaMaskFilter = this.alphaMaskPool[this.alphaMaskIndex], alphaMaskFilter || (alphaMaskFilter = this.alphaMaskPool[this.alphaMaskIndex] = [new SpriteMaskFilter()])), alphaMaskFilter[0].resolution = maskData.resolution, alphaMaskFilter[0].multisample = maskData.multisample, alphaMaskFilter[0].maskSprite = maskObject;
100 const stashFilterArea = target.filterArea;
101 target.filterArea = maskObject.getBounds(!0), this.renderer.filter.push(target, alphaMaskFilter), target.filterArea = stashFilterArea, maskData._filters || this.alphaMaskIndex++;
102 }
103 /**
104 * Removes the last filter from the filter stack and doesn't return it.
105 * @param maskData - Sprite to be used as the mask.
106 */
107 popSpriteMask(maskData) {
108 this.renderer.filter.pop(), maskData._filters ? maskData._filters[0].maskSprite = null : (this.alphaMaskIndex--, this.alphaMaskPool[this.alphaMaskIndex][0].maskSprite = null);
109 }
110 /**
111 * Pushes the color mask.
112 * @param maskData - The mask data
113 */
114 pushColorMask(maskData) {
115 const currColorMask = maskData._colorMask, nextColorMask = maskData._colorMask = currColorMask & maskData.colorMask;
116 nextColorMask !== currColorMask && this.renderer.gl.colorMask(
117 (nextColorMask & 1) !== 0,
118 (nextColorMask & 2) !== 0,
119 (nextColorMask & 4) !== 0,
120 (nextColorMask & 8) !== 0
121 );
122 }
123 /**
124 * Pops the color mask.
125 * @param maskData - The mask data
126 */
127 popColorMask(maskData) {
128 const currColorMask = maskData._colorMask, nextColorMask = this.maskStack.length > 0 ? this.maskStack[this.maskStack.length - 1]._colorMask : 15;
129 nextColorMask !== currColorMask && this.renderer.gl.colorMask(
130 (nextColorMask & 1) !== 0,
131 (nextColorMask & 2) !== 0,
132 (nextColorMask & 4) !== 0,
133 (nextColorMask & 8) !== 0
134 );
135 }
136 destroy() {
137 this.renderer = null;
138 }
139}
140MaskSystem.extension = {
141 type: ExtensionType.RendererSystem,
142 name: "mask"
143};
144extensions.add(MaskSystem);
145export {
146 MaskSystem
147};
148//# sourceMappingURL=MaskSystem.mjs.map