UNPKG

5.78 kBJavaScriptView Raw
1import { MaskData } from './MaskData.mjs';
2import { SpriteMaskFilter } from '../filters/spriteMask/SpriteMaskFilter.mjs';
3import { MASK_TYPES } from '@pixi/constants';
4import { ExtensionType, extensions } from '@pixi/extensions';
5
6class MaskSystem {
7 constructor(renderer) {
8 this.renderer = renderer;
9 this.enableScissor = true;
10 this.alphaMaskPool = [];
11 this.maskDataPool = [];
12 this.maskStack = [];
13 this.alphaMaskIndex = 0;
14 }
15 setMaskStack(maskStack) {
16 this.maskStack = maskStack;
17 this.renderer.scissor.setMaskStack(maskStack);
18 this.renderer.stencil.setMaskStack(maskStack);
19 }
20 push(target, maskDataOrTarget) {
21 let maskData = maskDataOrTarget;
22 if (!maskData.isMaskData) {
23 const d = this.maskDataPool.pop() || new MaskData();
24 d.pooled = true;
25 d.maskObject = maskDataOrTarget;
26 maskData = d;
27 }
28 const maskAbove = this.maskStack.length !== 0 ? this.maskStack[this.maskStack.length - 1] : null;
29 maskData.copyCountersOrReset(maskAbove);
30 maskData._colorMask = maskAbove ? maskAbove._colorMask : 15;
31 if (maskData.autoDetect) {
32 this.detect(maskData);
33 }
34 maskData._target = target;
35 if (maskData.type !== MASK_TYPES.SPRITE) {
36 this.maskStack.push(maskData);
37 }
38 if (maskData.enabled) {
39 switch (maskData.type) {
40 case MASK_TYPES.SCISSOR:
41 this.renderer.scissor.push(maskData);
42 break;
43 case MASK_TYPES.STENCIL:
44 this.renderer.stencil.push(maskData);
45 break;
46 case MASK_TYPES.SPRITE:
47 maskData.copyCountersOrReset(null);
48 this.pushSpriteMask(maskData);
49 break;
50 case MASK_TYPES.COLOR:
51 this.pushColorMask(maskData);
52 break;
53 default:
54 break;
55 }
56 }
57 if (maskData.type === MASK_TYPES.SPRITE) {
58 this.maskStack.push(maskData);
59 }
60 }
61 pop(target) {
62 const maskData = this.maskStack.pop();
63 if (!maskData || maskData._target !== target) {
64 return;
65 }
66 if (maskData.enabled) {
67 switch (maskData.type) {
68 case MASK_TYPES.SCISSOR:
69 this.renderer.scissor.pop(maskData);
70 break;
71 case MASK_TYPES.STENCIL:
72 this.renderer.stencil.pop(maskData.maskObject);
73 break;
74 case MASK_TYPES.SPRITE:
75 this.popSpriteMask(maskData);
76 break;
77 case MASK_TYPES.COLOR:
78 this.popColorMask(maskData);
79 break;
80 default:
81 break;
82 }
83 }
84 maskData.reset();
85 if (maskData.pooled) {
86 this.maskDataPool.push(maskData);
87 }
88 if (this.maskStack.length !== 0) {
89 const maskCurrent = this.maskStack[this.maskStack.length - 1];
90 if (maskCurrent.type === MASK_TYPES.SPRITE && maskCurrent._filters) {
91 maskCurrent._filters[0].maskSprite = maskCurrent.maskObject;
92 }
93 }
94 }
95 detect(maskData) {
96 const maskObject = maskData.maskObject;
97 if (!maskObject) {
98 maskData.type = MASK_TYPES.COLOR;
99 } else if (maskObject.isSprite) {
100 maskData.type = MASK_TYPES.SPRITE;
101 } else if (this.enableScissor && this.renderer.scissor.testScissor(maskData)) {
102 maskData.type = MASK_TYPES.SCISSOR;
103 } else {
104 maskData.type = MASK_TYPES.STENCIL;
105 }
106 }
107 pushSpriteMask(maskData) {
108 const { maskObject } = maskData;
109 const target = maskData._target;
110 let alphaMaskFilter = maskData._filters;
111 if (!alphaMaskFilter) {
112 alphaMaskFilter = this.alphaMaskPool[this.alphaMaskIndex];
113 if (!alphaMaskFilter) {
114 alphaMaskFilter = this.alphaMaskPool[this.alphaMaskIndex] = [new SpriteMaskFilter()];
115 }
116 }
117 const renderer = this.renderer;
118 const renderTextureSystem = renderer.renderTexture;
119 let resolution;
120 let multisample;
121 if (renderTextureSystem.current) {
122 const renderTexture = renderTextureSystem.current;
123 resolution = maskData.resolution || renderTexture.resolution;
124 multisample = maskData.multisample ?? renderTexture.multisample;
125 } else {
126 resolution = maskData.resolution || renderer.resolution;
127 multisample = maskData.multisample ?? renderer.multisample;
128 }
129 alphaMaskFilter[0].resolution = resolution;
130 alphaMaskFilter[0].multisample = multisample;
131 alphaMaskFilter[0].maskSprite = maskObject;
132 const stashFilterArea = target.filterArea;
133 target.filterArea = maskObject.getBounds(true);
134 renderer.filter.push(target, alphaMaskFilter);
135 target.filterArea = stashFilterArea;
136 if (!maskData._filters) {
137 this.alphaMaskIndex++;
138 }
139 }
140 popSpriteMask(maskData) {
141 this.renderer.filter.pop();
142 if (maskData._filters) {
143 maskData._filters[0].maskSprite = null;
144 } else {
145 this.alphaMaskIndex--;
146 this.alphaMaskPool[this.alphaMaskIndex][0].maskSprite = null;
147 }
148 }
149 pushColorMask(maskData) {
150 const currColorMask = maskData._colorMask;
151 const nextColorMask = maskData._colorMask = currColorMask & maskData.colorMask;
152 if (nextColorMask !== currColorMask) {
153 this.renderer.gl.colorMask((nextColorMask & 1) !== 0, (nextColorMask & 2) !== 0, (nextColorMask & 4) !== 0, (nextColorMask & 8) !== 0);
154 }
155 }
156 popColorMask(maskData) {
157 const currColorMask = maskData._colorMask;
158 const nextColorMask = this.maskStack.length > 0 ? this.maskStack[this.maskStack.length - 1]._colorMask : 15;
159 if (nextColorMask !== currColorMask) {
160 this.renderer.gl.colorMask((nextColorMask & 1) !== 0, (nextColorMask & 2) !== 0, (nextColorMask & 4) !== 0, (nextColorMask & 8) !== 0);
161 }
162 }
163 destroy() {
164 this.renderer = null;
165 }
166}
167MaskSystem.extension = {
168 type: ExtensionType.RendererSystem,
169 name: "mask"
170};
171extensions.add(MaskSystem);
172
173export { MaskSystem };
174//# sourceMappingURL=MaskSystem.mjs.map