1 | import { MaskData } from './MaskData.mjs';
|
2 | import { SpriteMaskFilter } from '../filters/spriteMask/SpriteMaskFilter.mjs';
|
3 | import { MASK_TYPES } from '@pixi/constants';
|
4 | import { ExtensionType, extensions } from '@pixi/extensions';
|
5 |
|
6 | class 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 | }
|
167 | MaskSystem.extension = {
|
168 | type: ExtensionType.RendererSystem,
|
169 | name: "mask"
|
170 | };
|
171 | extensions.add(MaskSystem);
|
172 |
|
173 | export { MaskSystem };
|
174 |
|