@number10/phaserjsx 4.1.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -1
- package/dist/clip/index.cjs +7 -695
- package/dist/clip/index.js +1 -687
- package/dist/clip/stencil-clip-depth.d.ts +10 -0
- package/dist/clip/stencil-clip-depth.d.ts.map +1 -0
- package/dist/clip/stencil-clip-fbo-bridge.d.ts +7 -0
- package/dist/clip/stencil-clip-fbo-bridge.d.ts.map +1 -0
- package/dist/clip/stencil-clip-renderer.d.ts +7 -0
- package/dist/clip/stencil-clip-renderer.d.ts.map +1 -0
- package/dist/clip/stencil-clip-state.d.ts +28 -0
- package/dist/clip/stencil-clip-state.d.ts.map +1 -0
- package/dist/clip/stencil-clip-types.d.ts +67 -0
- package/dist/clip/stencil-clip-types.d.ts.map +1 -0
- package/dist/clip/stencil-clip.d.ts +3 -84
- package/dist/clip/stencil-clip.d.ts.map +1 -1
- package/dist/clip-CHmjztBQ.cjs +705 -0
- package/dist/clip-CHmjztBQ.cjs.map +1 -0
- package/dist/clip-CPufWCSD.js +668 -0
- package/dist/clip-CPufWCSD.js.map +1 -0
- package/dist/components/appliers/applyParticles.d.ts.map +1 -1
- package/dist/components/custom/Badge.d.ts +73 -0
- package/dist/components/custom/Badge.d.ts.map +1 -0
- package/dist/components/custom/Checkbox.d.ts +41 -0
- package/dist/components/custom/Checkbox.d.ts.map +1 -0
- package/dist/components/custom/DebugPanel.d.ts +30 -0
- package/dist/components/custom/DebugPanel.d.ts.map +1 -0
- package/dist/components/custom/Particles.d.ts +14 -3
- package/dist/components/custom/Particles.d.ts.map +1 -1
- package/dist/components/custom/Popover.d.ts +89 -0
- package/dist/components/custom/Popover.d.ts.map +1 -0
- package/dist/components/custom/ProgressBar.d.ts +52 -0
- package/dist/components/custom/ProgressBar.d.ts.map +1 -0
- package/dist/components/custom/Toggle.d.ts.map +1 -1
- package/dist/components/custom/index.cjs +15 -1
- package/dist/components/custom/index.d.ts +5 -0
- package/dist/components/custom/index.d.ts.map +1 -1
- package/dist/components/custom/index.js +2 -2
- package/dist/components/index.d.ts +5 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/primitives/graphics.d.ts +2 -2
- package/dist/components/primitives/particles.d.ts +14 -4
- package/dist/components/primitives/particles.d.ts.map +1 -1
- package/dist/components/primitives/tilesprite.d.ts +15 -19
- package/dist/components/primitives/tilesprite.d.ts.map +1 -1
- package/dist/{custom-Dp3yAJdU.cjs → custom-37gL0VZG.cjs} +1578 -264
- package/dist/custom-37gL0VZG.cjs.map +1 -0
- package/dist/{custom-C_w8D39m.js → custom-DMZASXll.js} +1455 -231
- package/dist/custom-DMZASXll.js.map +1 -0
- package/dist/gestures/gesture-manager.d.ts +1 -1
- package/dist/index.cjs +49 -111
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +29 -105
- package/dist/index.js.map +1 -1
- package/dist/particles/emit-zone.d.ts +34 -12
- package/dist/particles/emit-zone.d.ts.map +1 -1
- package/dist/particles/index.d.ts +1 -1
- package/dist/particles/index.d.ts.map +1 -1
- package/dist/particles/use-particles.d.ts +6 -2
- package/dist/particles/use-particles.d.ts.map +1 -1
- package/dist/theme-custom.d.ts +68 -0
- package/dist/theme-custom.d.ts.map +1 -1
- package/dist/theme-defaults.d.ts.map +1 -1
- package/package.json +3 -2
- package/dist/clip/index.cjs.map +0 -1
- package/dist/clip/index.js.map +0 -1
- package/dist/custom-C_w8D39m.js.map +0 -1
- package/dist/custom-Dp3yAJdU.cjs.map +0 -1
|
@@ -0,0 +1,668 @@
|
|
|
1
|
+
import * as Phaser from "phaser";
|
|
2
|
+
//#region src/clip/stencil-clip-depth.ts
|
|
3
|
+
/**
|
|
4
|
+
* Shared depth counter per GL context.
|
|
5
|
+
* Incremented before each clip's INCR pass, decremented after the DECR pass.
|
|
6
|
+
*/
|
|
7
|
+
var _depthByGl = /* @__PURE__ */ new WeakMap();
|
|
8
|
+
var _prerenderHooked = /* @__PURE__ */ new WeakSet();
|
|
9
|
+
function getDepth(gl) {
|
|
10
|
+
let d = _depthByGl.get(gl);
|
|
11
|
+
if (!d) {
|
|
12
|
+
d = { value: 0 };
|
|
13
|
+
_depthByGl.set(gl, d);
|
|
14
|
+
}
|
|
15
|
+
return d;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Registers a per-frame prerender listener that resets stencil clip state.
|
|
19
|
+
* Registered at most once per Phaser.Game instance.
|
|
20
|
+
*/
|
|
21
|
+
function ensurePrerenderReset(gl, game, resetFboState) {
|
|
22
|
+
if (_prerenderHooked.has(game)) return;
|
|
23
|
+
_prerenderHooked.add(game);
|
|
24
|
+
game.events.on("prerender", () => {
|
|
25
|
+
const d = _depthByGl.get(gl);
|
|
26
|
+
if (d) d.value = 0;
|
|
27
|
+
resetFboState(gl);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/clip/stencil-clip-fbo-bridge.ts
|
|
32
|
+
var _fboPatchByGl = /* @__PURE__ */ new WeakMap();
|
|
33
|
+
function resetFboPatchState(gl) {
|
|
34
|
+
const fbo = _fboPatchByGl.get(gl);
|
|
35
|
+
if (fbo) {
|
|
36
|
+
fbo.current = null;
|
|
37
|
+
fbo.saved = null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Patches gl.bindFramebuffer once per GL context so that the stencil test is
|
|
42
|
+
* disabled while Phaser renders PostFX / RenderTextures into off-screen FBOs.
|
|
43
|
+
*/
|
|
44
|
+
function ensureFboPatch(gl) {
|
|
45
|
+
if (_fboPatchByGl.has(gl)) return;
|
|
46
|
+
const state = {
|
|
47
|
+
current: null,
|
|
48
|
+
saved: null
|
|
49
|
+
};
|
|
50
|
+
_fboPatchByGl.set(gl, state);
|
|
51
|
+
const origBind = gl.bindFramebuffer.bind(gl);
|
|
52
|
+
gl.bindFramebuffer = (target, fb) => {
|
|
53
|
+
const wasMain = state.current === null;
|
|
54
|
+
const willBeMain = fb === null;
|
|
55
|
+
const enteringOffscreen = wasMain && !willBeMain;
|
|
56
|
+
const leavingOffscreen = !wasMain && willBeMain;
|
|
57
|
+
if (enteringOffscreen && gl.getParameter(gl.STENCIL_TEST)) {
|
|
58
|
+
state.saved = {
|
|
59
|
+
func: gl.getParameter(gl.STENCIL_FUNC),
|
|
60
|
+
ref: gl.getParameter(gl.STENCIL_REF),
|
|
61
|
+
valueMask: gl.getParameter(gl.STENCIL_VALUE_MASK),
|
|
62
|
+
fail: gl.getParameter(gl.STENCIL_FAIL),
|
|
63
|
+
zfail: gl.getParameter(gl.STENCIL_PASS_DEPTH_FAIL),
|
|
64
|
+
zpass: gl.getParameter(gl.STENCIL_PASS_DEPTH_PASS),
|
|
65
|
+
writeMask: gl.getParameter(gl.STENCIL_WRITEMASK)
|
|
66
|
+
};
|
|
67
|
+
gl.disable(gl.STENCIL_TEST);
|
|
68
|
+
}
|
|
69
|
+
origBind(target, fb);
|
|
70
|
+
state.current = fb;
|
|
71
|
+
if (leavingOffscreen && state.saved) {
|
|
72
|
+
gl.enable(gl.STENCIL_TEST);
|
|
73
|
+
gl.stencilFunc(state.saved.func, state.saved.ref, state.saved.valueMask);
|
|
74
|
+
gl.stencilOp(state.saved.fail, state.saved.zfail, state.saved.zpass);
|
|
75
|
+
gl.stencilMask(state.saved.writeMask);
|
|
76
|
+
state.saved = null;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region src/clip/stencil-clip-renderer.ts
|
|
82
|
+
function savePhaserGLState(renderer) {
|
|
83
|
+
const glWrapper = renderer.glWrapper;
|
|
84
|
+
return {
|
|
85
|
+
activeTexture: glWrapper.state?.bindings?.activeTexture,
|
|
86
|
+
arrayBuffer: glWrapper.state?.bindings?.arrayBuffer ?? null,
|
|
87
|
+
program: glWrapper.state?.bindings?.program ?? null,
|
|
88
|
+
vao: glWrapper.state?.vao ?? null
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function restorePhaserGLState(renderer, saved, fallbackActiveTexture) {
|
|
92
|
+
const glWrapper = renderer.glWrapper;
|
|
93
|
+
if (glWrapper.update) {
|
|
94
|
+
glWrapper.update({
|
|
95
|
+
bindings: {
|
|
96
|
+
activeTexture: saved.activeTexture ?? fallbackActiveTexture,
|
|
97
|
+
arrayBuffer: saved.arrayBuffer,
|
|
98
|
+
program: saved.program
|
|
99
|
+
},
|
|
100
|
+
vao: saved.vao
|
|
101
|
+
}, true);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
glWrapper.updateBindingsActiveTexture?.({ bindings: { activeTexture: saved.activeTexture ?? fallbackActiveTexture } }, true);
|
|
105
|
+
}
|
|
106
|
+
var ROUND_RECT_VERT_SRC = `
|
|
107
|
+
attribute vec2 a_ndc;
|
|
108
|
+
attribute vec2 a_loc;
|
|
109
|
+
varying vec2 v_loc;
|
|
110
|
+
void main(){gl_Position=vec4(a_ndc,0.,1.);v_loc=a_loc;}
|
|
111
|
+
`;
|
|
112
|
+
var ROUND_RECT_FRAG_SRC = `
|
|
113
|
+
precision mediump float;
|
|
114
|
+
varying vec2 v_loc;
|
|
115
|
+
uniform vec2 u_halfSize;
|
|
116
|
+
uniform vec4 u_radii;
|
|
117
|
+
float sdRoundedBox(vec2 p,vec2 b,vec4 r){
|
|
118
|
+
r.xy=p.x>0.?r.yz:r.xw;
|
|
119
|
+
r.x =p.y>0.?r.y :r.x;
|
|
120
|
+
vec2 q=abs(p)-b+r.x;
|
|
121
|
+
return length(max(q,0.))+min(max(q.x,q.y),0.)-r.x;
|
|
122
|
+
}
|
|
123
|
+
void main(){
|
|
124
|
+
if(sdRoundedBox(v_loc,u_halfSize,u_radii)>0.)discard;
|
|
125
|
+
gl_FragColor=vec4(0.);
|
|
126
|
+
}
|
|
127
|
+
`;
|
|
128
|
+
var BITMAP_VERT_SRC = `
|
|
129
|
+
attribute vec2 a_ndc;
|
|
130
|
+
attribute vec2 a_uv;
|
|
131
|
+
varying vec2 v_uv;
|
|
132
|
+
void main(){gl_Position=vec4(a_ndc,0.,1.);v_uv=a_uv;}
|
|
133
|
+
`;
|
|
134
|
+
var BITMAP_FRAG_SRC = `
|
|
135
|
+
precision mediump float;
|
|
136
|
+
varying vec2 v_uv;
|
|
137
|
+
uniform sampler2D u_texture;
|
|
138
|
+
uniform float u_alphaThreshold;
|
|
139
|
+
uniform float u_invertAlpha;
|
|
140
|
+
void main(){
|
|
141
|
+
float a=texture2D(u_texture,v_uv).a;
|
|
142
|
+
bool keep=u_invertAlpha>0.5 ? a<u_alphaThreshold : a>=u_alphaThreshold;
|
|
143
|
+
if(!keep)discard;
|
|
144
|
+
gl_FragColor=vec4(0.);
|
|
145
|
+
}
|
|
146
|
+
`;
|
|
147
|
+
var _roundRectProgByGl = /* @__PURE__ */ new WeakMap();
|
|
148
|
+
var _bitmapProgByGl = /* @__PURE__ */ new WeakMap();
|
|
149
|
+
function createProgram(gl, vertSrc, fragSrc) {
|
|
150
|
+
const vs = gl.createShader(gl.VERTEX_SHADER);
|
|
151
|
+
gl.shaderSource(vs, vertSrc);
|
|
152
|
+
gl.compileShader(vs);
|
|
153
|
+
const fs = gl.createShader(gl.FRAGMENT_SHADER);
|
|
154
|
+
gl.shaderSource(fs, fragSrc);
|
|
155
|
+
gl.compileShader(fs);
|
|
156
|
+
const prog = gl.createProgram();
|
|
157
|
+
gl.attachShader(prog, vs);
|
|
158
|
+
gl.attachShader(prog, fs);
|
|
159
|
+
gl.linkProgram(prog);
|
|
160
|
+
return prog;
|
|
161
|
+
}
|
|
162
|
+
function getRoundRectProg(gl) {
|
|
163
|
+
let prog = _roundRectProgByGl.get(gl);
|
|
164
|
+
if (prog) return prog;
|
|
165
|
+
prog = createProgram(gl, ROUND_RECT_VERT_SRC, ROUND_RECT_FRAG_SRC);
|
|
166
|
+
_roundRectProgByGl.set(gl, prog);
|
|
167
|
+
return prog;
|
|
168
|
+
}
|
|
169
|
+
function getBitmapProg(gl) {
|
|
170
|
+
let prog = _bitmapProgByGl.get(gl);
|
|
171
|
+
if (prog) return prog;
|
|
172
|
+
prog = createProgram(gl, BITMAP_VERT_SRC, BITMAP_FRAG_SRC);
|
|
173
|
+
_bitmapProgByGl.set(gl, prog);
|
|
174
|
+
return prog;
|
|
175
|
+
}
|
|
176
|
+
var _roundRectLocsByProg = /* @__PURE__ */ new WeakMap();
|
|
177
|
+
var _bitmapLocsByProg = /* @__PURE__ */ new WeakMap();
|
|
178
|
+
function getRoundRectShaderLocs(gl, prog) {
|
|
179
|
+
let l = _roundRectLocsByProg.get(prog);
|
|
180
|
+
if (!l) {
|
|
181
|
+
l = {
|
|
182
|
+
ndc: gl.getAttribLocation(prog, "a_ndc"),
|
|
183
|
+
loc: gl.getAttribLocation(prog, "a_loc"),
|
|
184
|
+
halfSize: gl.getUniformLocation(prog, "u_halfSize"),
|
|
185
|
+
radii: gl.getUniformLocation(prog, "u_radii")
|
|
186
|
+
};
|
|
187
|
+
_roundRectLocsByProg.set(prog, l);
|
|
188
|
+
}
|
|
189
|
+
return l;
|
|
190
|
+
}
|
|
191
|
+
function getBitmapShaderLocs(gl, prog) {
|
|
192
|
+
let l = _bitmapLocsByProg.get(prog);
|
|
193
|
+
if (!l) {
|
|
194
|
+
l = {
|
|
195
|
+
ndc: gl.getAttribLocation(prog, "a_ndc"),
|
|
196
|
+
uv: gl.getAttribLocation(prog, "a_uv"),
|
|
197
|
+
texture: gl.getUniformLocation(prog, "u_texture"),
|
|
198
|
+
alphaThreshold: gl.getUniformLocation(prog, "u_alphaThreshold"),
|
|
199
|
+
invertAlpha: gl.getUniformLocation(prog, "u_invertAlpha")
|
|
200
|
+
};
|
|
201
|
+
_bitmapLocsByProg.set(prog, l);
|
|
202
|
+
}
|
|
203
|
+
return l;
|
|
204
|
+
}
|
|
205
|
+
var STRIDE = 16;
|
|
206
|
+
function drawRoundRectMaskShape(gl, scene, matrix, cameraMatrix, offsetX, offsetY, w, h, logW, logH, radii, vertBuf, verts) {
|
|
207
|
+
const { a, b, c, d, tx, ty } = matrix;
|
|
208
|
+
const hw = w / 2;
|
|
209
|
+
const hh = h / 2;
|
|
210
|
+
const cx = offsetX + hw;
|
|
211
|
+
const cy = offsetY + hh;
|
|
212
|
+
const corners = [
|
|
213
|
+
[cx - hw, cy - hh],
|
|
214
|
+
[cx + hw, cy - hh],
|
|
215
|
+
[cx + hw, cy + hh],
|
|
216
|
+
[cx - hw, cy + hh]
|
|
217
|
+
];
|
|
218
|
+
for (let i = 0; i < 4; i++) {
|
|
219
|
+
const corner = corners[i];
|
|
220
|
+
const lx = corner[0];
|
|
221
|
+
const ly = corner[1];
|
|
222
|
+
const wx = a * lx + c * ly + tx;
|
|
223
|
+
const wy = b * lx + d * ly + ty;
|
|
224
|
+
const sx = cameraMatrix ? cameraMatrix.getX(wx, wy) : wx;
|
|
225
|
+
const sy = cameraMatrix ? cameraMatrix.getY(wx, wy) : wy;
|
|
226
|
+
verts[i * 4 + 0] = sx / logW * 2 - 1;
|
|
227
|
+
verts[i * 4 + 1] = 1 - sy / logH * 2;
|
|
228
|
+
verts[i * 4 + 2] = lx - cx;
|
|
229
|
+
verts[i * 4 + 3] = ly - cy;
|
|
230
|
+
}
|
|
231
|
+
const prevProg = gl.getParameter(gl.CURRENT_PROGRAM);
|
|
232
|
+
const prevBuf = gl.getParameter(gl.ARRAY_BUFFER_BINDING);
|
|
233
|
+
const prevVAO = gl.getParameter(34229);
|
|
234
|
+
const prevActiveTextureUnit = gl.getParameter(gl.ACTIVE_TEXTURE) - gl.TEXTURE0;
|
|
235
|
+
const renderer = scene.renderer;
|
|
236
|
+
const savedPhaserState = savePhaserGLState(renderer);
|
|
237
|
+
gl.bindVertexArray(null);
|
|
238
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuf);
|
|
239
|
+
gl.bufferSubData(gl.ARRAY_BUFFER, 0, verts);
|
|
240
|
+
const prog = getRoundRectProg(gl);
|
|
241
|
+
gl.useProgram(prog);
|
|
242
|
+
const locs = getRoundRectShaderLocs(gl, prog);
|
|
243
|
+
gl.enableVertexAttribArray(locs.ndc);
|
|
244
|
+
gl.vertexAttribPointer(locs.ndc, 2, gl.FLOAT, false, STRIDE, 0);
|
|
245
|
+
gl.enableVertexAttribArray(locs.loc);
|
|
246
|
+
gl.vertexAttribPointer(locs.loc, 2, gl.FLOAT, false, STRIDE, 8);
|
|
247
|
+
gl.uniform2f(locs.halfSize, hw, hh);
|
|
248
|
+
gl.uniform4f(locs.radii, radii[0], radii[1], radii[2], radii[3]);
|
|
249
|
+
gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
|
|
250
|
+
gl.disableVertexAttribArray(locs.ndc);
|
|
251
|
+
gl.disableVertexAttribArray(locs.loc);
|
|
252
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, prevBuf);
|
|
253
|
+
gl.useProgram(prevProg);
|
|
254
|
+
gl.bindVertexArray(prevVAO);
|
|
255
|
+
restorePhaserGLState(renderer, savedPhaserState, prevActiveTextureUnit);
|
|
256
|
+
}
|
|
257
|
+
function isTextureFrame(value) {
|
|
258
|
+
return typeof value === "object" && value !== null && "glTexture" in value && "u0" in value;
|
|
259
|
+
}
|
|
260
|
+
function resolveBitmapFrame(scene, source) {
|
|
261
|
+
const frame = isTextureFrame(source.texture) ? source.texture : typeof source.texture === "string" ? scene.textures.getFrame(source.texture, source.frame) : source.texture.get(source.frame);
|
|
262
|
+
if (!frame?.glTexture?.webGLTexture) return null;
|
|
263
|
+
return {
|
|
264
|
+
glTexture: frame.glTexture,
|
|
265
|
+
width: source.width ?? frame.cutWidth ?? frame.realWidth,
|
|
266
|
+
height: source.height ?? frame.cutHeight ?? frame.realHeight,
|
|
267
|
+
u0: frame.u0,
|
|
268
|
+
v0: frame.v0,
|
|
269
|
+
u1: frame.u1,
|
|
270
|
+
v1: frame.v1
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
function drawBitmapMaskShape(gl, scene, matrix, cameraMatrix, source, frameInfo, logW, logH, vertBuf, verts) {
|
|
274
|
+
const { a, b, c, d, tx, ty } = matrix;
|
|
275
|
+
const x0 = source.offsetX;
|
|
276
|
+
const y0 = source.offsetY;
|
|
277
|
+
const x1 = x0 + frameInfo.width;
|
|
278
|
+
const y1 = y0 + frameInfo.height;
|
|
279
|
+
const corners = [
|
|
280
|
+
[
|
|
281
|
+
x0,
|
|
282
|
+
y0,
|
|
283
|
+
frameInfo.u0,
|
|
284
|
+
frameInfo.v0
|
|
285
|
+
],
|
|
286
|
+
[
|
|
287
|
+
x1,
|
|
288
|
+
y0,
|
|
289
|
+
frameInfo.u1,
|
|
290
|
+
frameInfo.v0
|
|
291
|
+
],
|
|
292
|
+
[
|
|
293
|
+
x1,
|
|
294
|
+
y1,
|
|
295
|
+
frameInfo.u1,
|
|
296
|
+
frameInfo.v1
|
|
297
|
+
],
|
|
298
|
+
[
|
|
299
|
+
x0,
|
|
300
|
+
y1,
|
|
301
|
+
frameInfo.u0,
|
|
302
|
+
frameInfo.v1
|
|
303
|
+
]
|
|
304
|
+
];
|
|
305
|
+
for (let i = 0; i < 4; i++) {
|
|
306
|
+
const corner = corners[i];
|
|
307
|
+
const lx = corner[0];
|
|
308
|
+
const ly = corner[1];
|
|
309
|
+
const wx = a * lx + c * ly + tx;
|
|
310
|
+
const wy = b * lx + d * ly + ty;
|
|
311
|
+
const sx = cameraMatrix ? cameraMatrix.getX(wx, wy) : wx;
|
|
312
|
+
const sy = cameraMatrix ? cameraMatrix.getY(wx, wy) : wy;
|
|
313
|
+
verts[i * 4 + 0] = sx / logW * 2 - 1;
|
|
314
|
+
verts[i * 4 + 1] = 1 - sy / logH * 2;
|
|
315
|
+
verts[i * 4 + 2] = corner[2];
|
|
316
|
+
verts[i * 4 + 3] = corner[3];
|
|
317
|
+
}
|
|
318
|
+
const prevProg = gl.getParameter(gl.CURRENT_PROGRAM);
|
|
319
|
+
const prevBuf = gl.getParameter(gl.ARRAY_BUFFER_BINDING);
|
|
320
|
+
const prevVAO = gl.getParameter(34229);
|
|
321
|
+
const prevActiveTextureUnit = gl.getParameter(gl.ACTIVE_TEXTURE) - gl.TEXTURE0;
|
|
322
|
+
const renderer = scene.renderer;
|
|
323
|
+
const savedPhaserState = savePhaserGLState(renderer);
|
|
324
|
+
gl.bindVertexArray(null);
|
|
325
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuf);
|
|
326
|
+
gl.bufferSubData(gl.ARRAY_BUFFER, 0, verts);
|
|
327
|
+
const prog = getBitmapProg(gl);
|
|
328
|
+
gl.useProgram(prog);
|
|
329
|
+
const locs = getBitmapShaderLocs(gl, prog);
|
|
330
|
+
gl.enableVertexAttribArray(locs.ndc);
|
|
331
|
+
gl.vertexAttribPointer(locs.ndc, 2, gl.FLOAT, false, STRIDE, 0);
|
|
332
|
+
gl.enableVertexAttribArray(locs.uv);
|
|
333
|
+
gl.vertexAttribPointer(locs.uv, 2, gl.FLOAT, false, STRIDE, 8);
|
|
334
|
+
const textureUnits = renderer.glTextureUnits;
|
|
335
|
+
const prevTexture = textureUnits.units[0] ?? null;
|
|
336
|
+
textureUnits.bind(frameInfo.glTexture, 0);
|
|
337
|
+
gl.uniform1i(locs.texture, 0);
|
|
338
|
+
gl.uniform1f(locs.alphaThreshold, source.alphaThreshold);
|
|
339
|
+
gl.uniform1f(locs.invertAlpha, source.invertAlpha ? 1 : 0);
|
|
340
|
+
gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
|
|
341
|
+
gl.disableVertexAttribArray(locs.ndc);
|
|
342
|
+
gl.disableVertexAttribArray(locs.uv);
|
|
343
|
+
textureUnits.bind(prevTexture, 0);
|
|
344
|
+
renderer.glWrapper.updateBindingsActiveTexture({ bindings: { activeTexture: prevActiveTextureUnit } });
|
|
345
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, prevBuf);
|
|
346
|
+
gl.useProgram(prevProg);
|
|
347
|
+
gl.bindVertexArray(prevVAO);
|
|
348
|
+
restorePhaserGLState(renderer, savedPhaserState, prevActiveTextureUnit);
|
|
349
|
+
}
|
|
350
|
+
function drawMaskShape(gl, scene, matrix, cameraMatrix, source, logW, logH, vertBuf, verts) {
|
|
351
|
+
if (source.kind === "bitmap") {
|
|
352
|
+
const frameInfo = resolveBitmapFrame(scene, source);
|
|
353
|
+
if (!frameInfo) return;
|
|
354
|
+
drawBitmapMaskShape(gl, scene, matrix, cameraMatrix, source, frameInfo, logW, logH, vertBuf, verts);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
drawRoundRectMaskShape(gl, scene, matrix, cameraMatrix, source.offsetX, source.offsetY, source.width, source.height, logW, logH, source.radii, vertBuf, verts);
|
|
358
|
+
}
|
|
359
|
+
//#endregion
|
|
360
|
+
//#region src/clip/stencil-clip-state.ts
|
|
361
|
+
function resolveRadii(r) {
|
|
362
|
+
if (!r) return [
|
|
363
|
+
0,
|
|
364
|
+
0,
|
|
365
|
+
0,
|
|
366
|
+
0
|
|
367
|
+
];
|
|
368
|
+
if (typeof r === "number") return [
|
|
369
|
+
r,
|
|
370
|
+
r,
|
|
371
|
+
r,
|
|
372
|
+
r
|
|
373
|
+
];
|
|
374
|
+
return [
|
|
375
|
+
r.tl ?? 0,
|
|
376
|
+
r.tr ?? 0,
|
|
377
|
+
r.br ?? 0,
|
|
378
|
+
r.bl ?? 0
|
|
379
|
+
];
|
|
380
|
+
}
|
|
381
|
+
/** Returns true when a source/update selects the bitmap mask renderer. */
|
|
382
|
+
function isBitmapStencilClipSource(source) {
|
|
383
|
+
return source.kind === "bitmap";
|
|
384
|
+
}
|
|
385
|
+
function toRoundRectState(source) {
|
|
386
|
+
return {
|
|
387
|
+
kind: "roundRect",
|
|
388
|
+
width: source.width,
|
|
389
|
+
height: source.height,
|
|
390
|
+
offsetX: source.offsetX ?? 0,
|
|
391
|
+
offsetY: source.offsetY ?? 0,
|
|
392
|
+
radii: source.kind === "rect" ? [
|
|
393
|
+
0,
|
|
394
|
+
0,
|
|
395
|
+
0,
|
|
396
|
+
0
|
|
397
|
+
] : resolveRadii(source.cornerRadius)
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
function toBitmapState(source) {
|
|
401
|
+
return {
|
|
402
|
+
kind: "bitmap",
|
|
403
|
+
texture: source.texture,
|
|
404
|
+
frame: source.frame,
|
|
405
|
+
width: source.width,
|
|
406
|
+
height: source.height,
|
|
407
|
+
offsetX: source.offsetX ?? 0,
|
|
408
|
+
offsetY: source.offsetY ?? 0,
|
|
409
|
+
alphaThreshold: source.alphaThreshold ?? .5,
|
|
410
|
+
invertAlpha: source.invertAlpha ?? false
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
function toMaskState(source) {
|
|
414
|
+
return isBitmapStencilClipSource(source) ? toBitmapState(source) : toRoundRectState(source);
|
|
415
|
+
}
|
|
416
|
+
function mergeMaskState(current, update) {
|
|
417
|
+
if (isBitmapStencilClipSource(update)) {
|
|
418
|
+
if (current.kind !== "bitmap" || update.texture !== void 0) return toBitmapState(update);
|
|
419
|
+
return {
|
|
420
|
+
kind: "bitmap",
|
|
421
|
+
texture: current.texture,
|
|
422
|
+
frame: update.frame !== void 0 ? update.frame : current.frame,
|
|
423
|
+
width: update.width !== void 0 ? update.width : current.width,
|
|
424
|
+
height: update.height !== void 0 ? update.height : current.height,
|
|
425
|
+
offsetX: update.offsetX !== void 0 ? update.offsetX : current.offsetX,
|
|
426
|
+
offsetY: update.offsetY !== void 0 ? update.offsetY : current.offsetY,
|
|
427
|
+
alphaThreshold: update.alphaThreshold !== void 0 ? update.alphaThreshold : current.alphaThreshold,
|
|
428
|
+
invertAlpha: update.invertAlpha !== void 0 ? update.invertAlpha : current.invertAlpha
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
if (current.kind === "bitmap" && update.kind === void 0) {
|
|
432
|
+
const bitmapUpdate = update;
|
|
433
|
+
return {
|
|
434
|
+
kind: "bitmap",
|
|
435
|
+
texture: current.texture,
|
|
436
|
+
frame: bitmapUpdate.frame !== void 0 ? bitmapUpdate.frame : current.frame,
|
|
437
|
+
width: bitmapUpdate.width !== void 0 ? bitmapUpdate.width : current.width,
|
|
438
|
+
height: bitmapUpdate.height !== void 0 ? bitmapUpdate.height : current.height,
|
|
439
|
+
offsetX: bitmapUpdate.offsetX !== void 0 ? bitmapUpdate.offsetX : current.offsetX,
|
|
440
|
+
offsetY: bitmapUpdate.offsetY !== void 0 ? bitmapUpdate.offsetY : current.offsetY,
|
|
441
|
+
alphaThreshold: bitmapUpdate.alphaThreshold !== void 0 ? bitmapUpdate.alphaThreshold : current.alphaThreshold,
|
|
442
|
+
invertAlpha: bitmapUpdate.invertAlpha !== void 0 ? bitmapUpdate.invertAlpha : current.invertAlpha
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
if (current.kind === "bitmap") return toRoundRectState(update);
|
|
446
|
+
const roundUpdate = update;
|
|
447
|
+
return {
|
|
448
|
+
kind: "roundRect",
|
|
449
|
+
width: roundUpdate.width !== void 0 ? roundUpdate.width : current.width,
|
|
450
|
+
height: roundUpdate.height !== void 0 ? roundUpdate.height : current.height,
|
|
451
|
+
offsetX: roundUpdate.offsetX !== void 0 ? roundUpdate.offsetX : current.offsetX,
|
|
452
|
+
offsetY: roundUpdate.offsetY !== void 0 ? roundUpdate.offsetY : current.offsetY,
|
|
453
|
+
radii: roundUpdate.kind === "rect" ? [
|
|
454
|
+
0,
|
|
455
|
+
0,
|
|
456
|
+
0,
|
|
457
|
+
0
|
|
458
|
+
] : "cornerRadius" in roundUpdate ? resolveRadii(roundUpdate.cornerRadius) : current.radii
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
//#endregion
|
|
462
|
+
//#region src/clip/stencil-clip.ts
|
|
463
|
+
/**
|
|
464
|
+
* WebGL stencil-buffer clip for Phaser 4 Containers.
|
|
465
|
+
*
|
|
466
|
+
* Supports arbitrary nesting via the INCR/DECR model: each clip level
|
|
467
|
+
* increments the stencil on enter and decrements on exit, so child clips are
|
|
468
|
+
* automatically intersected with their parent clips at the hardware level.
|
|
469
|
+
*
|
|
470
|
+
* Shape variants:
|
|
471
|
+
* - Plain rectangle (cornerRadius omitted or 0)
|
|
472
|
+
* - Rounded rectangle (uniform radius or per-corner object)
|
|
473
|
+
*
|
|
474
|
+
* A single SDF-based shader handles both variants. For plain rectangles
|
|
475
|
+
* u_radii is vec4(0) and the `discard` branch never fires — no overhead
|
|
476
|
+
* compared to a rectangle-only shader.
|
|
477
|
+
*
|
|
478
|
+
* Transforms (translate, scale, rotation) are fully supported: the quad
|
|
479
|
+
* corners are transformed through `container.getWorldTransformMatrix()` at
|
|
480
|
+
* render time, so no per-layout world-position tracking is needed.
|
|
481
|
+
*/
|
|
482
|
+
var STENCIL_HANDLE = Symbol("stencilClipHandle");
|
|
483
|
+
/** Returns the active stencil clip handle attached to a container, if any. */
|
|
484
|
+
function getStencilClipHandle(container) {
|
|
485
|
+
return container[STENCIL_HANDLE];
|
|
486
|
+
}
|
|
487
|
+
/** Removes any active stencil clip from a container. */
|
|
488
|
+
function clearStencilClip(container) {
|
|
489
|
+
getStencilClipHandle(container)?.destroy();
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Applies a WebGL stencil-buffer clip to a Phaser 4 Container.
|
|
493
|
+
*
|
|
494
|
+
* The clip rectangle is expressed in the container's **local coordinate
|
|
495
|
+
* space**. `offsetX`/`offsetY` mark the top-left corner (default 0/0), so
|
|
496
|
+
* a container whose visual area starts at its local origin can be clipped with
|
|
497
|
+
* `applyStencilClip(container, { width, height })`.
|
|
498
|
+
*
|
|
499
|
+
* **Nesting** is handled transparently: each clip level occupies one stencil
|
|
500
|
+
* value (0 = no clip, 1 = depth 0, 2 = depth 1, …). Child clips are always
|
|
501
|
+
* the intersection of their own shape and all ancestor shapes.
|
|
502
|
+
*
|
|
503
|
+
* **Transforms** (translate, scale, rotation) are re-evaluated from
|
|
504
|
+
* `container.getWorldTransformMatrix()` on every frame, so animated or
|
|
505
|
+
* scroll-driven containers clip correctly without any manual update call.
|
|
506
|
+
*
|
|
507
|
+
* If a stencil clip is already attached to the container, calling this
|
|
508
|
+
* function again calls `handle.update(shape)` on the existing handle and
|
|
509
|
+
* returns it.
|
|
510
|
+
*
|
|
511
|
+
* @param container - The container to clip.
|
|
512
|
+
* @param source - Clip source in the container's local coordinate space.
|
|
513
|
+
* @returns A handle to modify dimensions / corner radii or remove the clip.
|
|
514
|
+
*/
|
|
515
|
+
function applyStencilClip(container, source) {
|
|
516
|
+
const obj = container;
|
|
517
|
+
if (obj[STENCIL_HANDLE]) {
|
|
518
|
+
obj[STENCIL_HANDLE].update(source);
|
|
519
|
+
return obj[STENCIL_HANDLE];
|
|
520
|
+
}
|
|
521
|
+
if (container.scene.renderer.type !== Phaser.WEBGL) return {
|
|
522
|
+
update() {},
|
|
523
|
+
destroy() {}
|
|
524
|
+
};
|
|
525
|
+
const renderer = container.scene.renderer;
|
|
526
|
+
const gl = renderer.gl;
|
|
527
|
+
const glWrapper = renderer.glWrapper;
|
|
528
|
+
ensurePrerenderReset(gl, container.scene.game, resetFboPatchState);
|
|
529
|
+
ensureFboPatch(gl);
|
|
530
|
+
const previousArrayBuffer = glWrapper.state?.bindings?.arrayBuffer ?? null;
|
|
531
|
+
const vertBuf = gl.createBuffer();
|
|
532
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuf);
|
|
533
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(16), gl.DYNAMIC_DRAW);
|
|
534
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
535
|
+
glWrapper.updateBindingsArrayBuffer?.({ bindings: { arrayBuffer: previousArrayBuffer } }, true);
|
|
536
|
+
const verts = new Float32Array(16);
|
|
537
|
+
let maskSource = toMaskState(source);
|
|
538
|
+
let destroyed = false;
|
|
539
|
+
const wrapper = (webglRenderer, go, drawingContext, parentMatrix, renderStep = 0, displayList, displayListIndex) => {
|
|
540
|
+
const renderNext = () => {
|
|
541
|
+
go.renderWebGLStep(webglRenderer, go, drawingContext, parentMatrix, renderStep + 1, displayList, displayListIndex);
|
|
542
|
+
};
|
|
543
|
+
if (destroyed) {
|
|
544
|
+
renderNext();
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
const matrix = container.getWorldTransformMatrix();
|
|
548
|
+
const context = drawingContext;
|
|
549
|
+
const cameraMatrix = context.camera?.getViewMatrix(!context.useCanvas);
|
|
550
|
+
const rn = webglRenderer.renderNodes;
|
|
551
|
+
const depth = getDepth(gl);
|
|
552
|
+
const myDepth = depth.value++;
|
|
553
|
+
const logW = webglRenderer.width;
|
|
554
|
+
const logH = webglRenderer.height;
|
|
555
|
+
rn.finishBatch();
|
|
556
|
+
if (myDepth === 0) gl.enable(gl.STENCIL_TEST);
|
|
557
|
+
gl.colorMask(false, false, false, false);
|
|
558
|
+
gl.stencilMask(255);
|
|
559
|
+
gl.stencilFunc(gl.EQUAL, myDepth, 255);
|
|
560
|
+
gl.stencilOp(gl.KEEP, gl.KEEP, gl.INCR);
|
|
561
|
+
drawMaskShape(gl, container.scene, matrix, cameraMatrix, maskSource, logW, logH, vertBuf, verts);
|
|
562
|
+
gl.colorMask(true, true, true, true);
|
|
563
|
+
gl.stencilFunc(gl.EQUAL, myDepth + 1, 255);
|
|
564
|
+
gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
|
|
565
|
+
gl.stencilMask(0);
|
|
566
|
+
renderNext();
|
|
567
|
+
rn.finishBatch();
|
|
568
|
+
gl.colorMask(false, false, false, false);
|
|
569
|
+
gl.stencilMask(255);
|
|
570
|
+
gl.stencilFunc(gl.EQUAL, myDepth + 1, 255);
|
|
571
|
+
gl.stencilOp(gl.KEEP, gl.KEEP, gl.DECR);
|
|
572
|
+
drawMaskShape(gl, container.scene, matrix, cameraMatrix, maskSource, logW, logH, vertBuf, verts);
|
|
573
|
+
gl.colorMask(true, true, true, true);
|
|
574
|
+
depth.value--;
|
|
575
|
+
if (myDepth === 0) {
|
|
576
|
+
gl.disable(gl.STENCIL_TEST);
|
|
577
|
+
gl.stencilMask(255);
|
|
578
|
+
} else {
|
|
579
|
+
gl.stencilFunc(gl.EQUAL, myDepth, 255);
|
|
580
|
+
gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
|
|
581
|
+
gl.stencilMask(0);
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
const handle = {
|
|
585
|
+
update(s) {
|
|
586
|
+
maskSource = mergeMaskState(maskSource, s);
|
|
587
|
+
},
|
|
588
|
+
destroy() {
|
|
589
|
+
if (destroyed) return;
|
|
590
|
+
destroyed = true;
|
|
591
|
+
gl.deleteBuffer(vertBuf);
|
|
592
|
+
const index = obj._renderSteps.indexOf(wrapper);
|
|
593
|
+
if (index !== -1) obj._renderSteps.splice(index, 1);
|
|
594
|
+
delete obj[STENCIL_HANDLE];
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
obj.addRenderStep(wrapper, 0);
|
|
598
|
+
obj[STENCIL_HANDLE] = handle;
|
|
599
|
+
return handle;
|
|
600
|
+
}
|
|
601
|
+
//#endregion
|
|
602
|
+
//#region src/clip/stencil-clip-extension.ts
|
|
603
|
+
function addMethod(proto, methodName, fn) {
|
|
604
|
+
const hadOwn = Object.prototype.hasOwnProperty.call(proto, methodName);
|
|
605
|
+
const previous = proto[methodName];
|
|
606
|
+
if (!hadOwn) proto[methodName] = fn;
|
|
607
|
+
return { restore: () => {
|
|
608
|
+
if (!hadOwn) delete proto[methodName];
|
|
609
|
+
else proto[methodName] = previous;
|
|
610
|
+
} };
|
|
611
|
+
}
|
|
612
|
+
function wrapMethod(proto, methodName, wrapper) {
|
|
613
|
+
const original = proto[methodName];
|
|
614
|
+
if (typeof original !== "function") return { restore() {} };
|
|
615
|
+
const wrapped = function(...args) {
|
|
616
|
+
return wrapper(original, this, ...args);
|
|
617
|
+
};
|
|
618
|
+
proto[methodName] = wrapped;
|
|
619
|
+
return { restore: () => {
|
|
620
|
+
proto[methodName] = original;
|
|
621
|
+
} };
|
|
622
|
+
}
|
|
623
|
+
var installed = false;
|
|
624
|
+
var restoreHandles = [];
|
|
625
|
+
function canCreateStencilClipSource(source) {
|
|
626
|
+
if (source.kind === "bitmap") return source.texture !== void 0;
|
|
627
|
+
return source.width !== void 0 && source.height !== void 0;
|
|
628
|
+
}
|
|
629
|
+
/** Installs stencil clip helpers on Phaser.GameObjects.Container.prototype. */
|
|
630
|
+
function installStencilClipExtension() {
|
|
631
|
+
if (installed) return;
|
|
632
|
+
installed = true;
|
|
633
|
+
const proto = Phaser.GameObjects.Container.prototype;
|
|
634
|
+
restoreHandles.push(addMethod(proto, "setStencilClip", function(source) {
|
|
635
|
+
applyStencilClip(this, source);
|
|
636
|
+
return this;
|
|
637
|
+
}));
|
|
638
|
+
restoreHandles.push(addMethod(proto, "updateStencilClip", function(source) {
|
|
639
|
+
const handle = getStencilClipHandle(this);
|
|
640
|
+
if (handle) handle.update(source);
|
|
641
|
+
else if (canCreateStencilClipSource(source)) applyStencilClip(this, source);
|
|
642
|
+
return this;
|
|
643
|
+
}));
|
|
644
|
+
restoreHandles.push(addMethod(proto, "clearStencilClip", function() {
|
|
645
|
+
clearStencilClip(this);
|
|
646
|
+
return this;
|
|
647
|
+
}));
|
|
648
|
+
restoreHandles.push(addMethod(proto, "getStencilClipHandle", function() {
|
|
649
|
+
return getStencilClipHandle(this);
|
|
650
|
+
}));
|
|
651
|
+
restoreHandles.push(wrapMethod(proto, "destroy", (original, self, ...args) => {
|
|
652
|
+
clearStencilClip(self);
|
|
653
|
+
return original.apply(self, args);
|
|
654
|
+
}));
|
|
655
|
+
}
|
|
656
|
+
/** Restores Phaser prototypes to their previous state. Intended for tests/HMR. */
|
|
657
|
+
function uninstallStencilClipExtension() {
|
|
658
|
+
for (const handle of [...restoreHandles].reverse()) handle.restore();
|
|
659
|
+
restoreHandles = [];
|
|
660
|
+
installed = false;
|
|
661
|
+
}
|
|
662
|
+
//#endregion
|
|
663
|
+
//#region src/clip/index.ts
|
|
664
|
+
installStencilClipExtension();
|
|
665
|
+
//#endregion
|
|
666
|
+
export { getStencilClipHandle as a, clearStencilClip as i, uninstallStencilClipExtension as n, isBitmapStencilClipSource as o, applyStencilClip as r, installStencilClipExtension as t };
|
|
667
|
+
|
|
668
|
+
//# sourceMappingURL=clip-CPufWCSD.js.map
|