@neutrinoparticles/js-v1.1-phaser 1.0.0 → 1.1.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/CHANGELOG.md +13 -1
- package/README.md +37 -0
- package/dist/Effect.d.ts +11 -1
- package/dist/NeutrinoRenderer.d.ts +8 -0
- package/dist/PerspectiveProjection.d.ts +10 -0
- package/dist/neutrinoparticles.js-v1.1-phaser.cjs.js +202 -57
- package/dist/neutrinoparticles.js-v1.1-phaser.cjs.js.map +1 -1
- package/dist/neutrinoparticles.js-v1.1-phaser.d.ts +37 -1
- package/dist/neutrinoparticles.js-v1.1-phaser.es.js +307 -119
- package/dist/neutrinoparticles.js-v1.1-phaser.es.js.map +1 -1
- package/dist/neutrinoparticles.js-v1.1-phaser.umd.js +202 -57
- package/dist/neutrinoparticles.js-v1.1-phaser.umd.js.map +1 -1
- package/dist/types.d.ts +12 -0
- package/package.json +4 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var K=Object.defineProperty;var
|
|
1
|
+
"use strict";var K=Object.defineProperty;var z=(s,e,t)=>e in s?K(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t;var a=(s,e,t)=>z(s,typeof e!="symbol"?e+"":e,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Phaser=require("phaser"),Neutrino=require("@neutrinoparticles/js-v1.1");function _interopNamespaceDefault(s){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(s){for(const t in s)if(t!=="default"){const n=Object.getOwnPropertyDescriptor(s,t);Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>s[t]})}}return e.default=s,Object.freeze(e)}const Neutrino__namespace=_interopNamespaceDefault(Neutrino),vertexShaderSource=`#version 300 es
|
|
2
2
|
precision highp float;
|
|
3
3
|
|
|
4
4
|
uniform sampler2D uDataTexture;
|
|
@@ -49,7 +49,8 @@ vec4 fetchTexel(int globalTexelIndex) {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
// Strip geometry helpers (port of GPU33 makeScreenSpaceStrip).
|
|
52
|
-
// 2D screen-space variant
|
|
52
|
+
// 2D screen-space variant used by the Faced strip frame; world Z reaches
|
|
53
|
+
// gl_Position only through uViewProjMatrix (ortho or v1.0-parity perspective).
|
|
53
54
|
vec2 stripOrtho(vec2 v) {
|
|
54
55
|
return vec2(-v.y, v.x);
|
|
55
56
|
}
|
|
@@ -86,9 +87,9 @@ void main() {
|
|
|
86
87
|
// 0 (Faced): screen-space ortho to dir12 — equivalent to camera-faced
|
|
87
88
|
// billboard normal in a 2D camera setup.
|
|
88
89
|
// 1 (Free): the quaternion stored in texel 2 nominally encodes a 3D
|
|
89
|
-
// orientation. The
|
|
90
|
-
//
|
|
91
|
-
// the quat is read but its 3D y-axis is projected to screen
|
|
90
|
+
// orientation. The PIXI7 renderer has no true 3D camera
|
|
91
|
+
// (uViewProjMatrix is ortho or the v1.0-parity perspective),
|
|
92
|
+
// so the quat is read but its 3D y-axis is projected to screen
|
|
92
93
|
// and used as the section normal. When the projection
|
|
93
94
|
// degenerates (looking along the y-axis) we fall back to
|
|
94
95
|
// the screen-space ortho. Real 3D free-rotation requires a
|
|
@@ -123,6 +124,10 @@ void main() {
|
|
|
123
124
|
float((packedColorNex >> 8u) & 0xFFu) / 255.0,
|
|
124
125
|
float((packedColorNex >> 16u) & 0xFFu) / 255.0,
|
|
125
126
|
float((packedColorNex >> 24u) & 0xFFu) / 255.0);
|
|
127
|
+
// HDR color scale S (RGBS, bloom TDD #175 §13.12): offset+60 (t3.a) per-particle
|
|
128
|
+
// float scale; multiply BEFORE the cross-fade. S=1 for LDR (no-op).
|
|
129
|
+
color1.rgb *= (isCur ? t3.a : ts3.a);
|
|
130
|
+
color2.rgb *= (isCur ? ts3.a : t3.a);
|
|
126
131
|
|
|
127
132
|
// neighborIdxP0 / neighborIdxP3 are stored on every meta of a pair
|
|
128
133
|
// (both meta_cur and meta_nex hold the same pair of indices), so we
|
|
@@ -169,6 +174,10 @@ void main() {
|
|
|
169
174
|
// by the sign of w). Forces a discard outside the [-w,w] cube at the end.
|
|
170
175
|
bool nearPlaneClipped = (sp1.w < 1e-3) || (sp2.w < 1e-3);
|
|
171
176
|
|
|
177
|
+
// #236: set when the segment itself is degenerate (much shorter than
|
|
178
|
+
// the ribbon half-width) — the pair is discarded like nearPlaneClipped.
|
|
179
|
+
bool stripDegenerate = false;
|
|
180
|
+
|
|
172
181
|
// Aspect correction so the 2D Faced ortho gives visually-perpendicular
|
|
173
182
|
// dirs on non-square viewports (inverted before gl_Position).
|
|
174
183
|
vec2 aspectMul = vec2(1.0, 1.0 / max(uViewportAspect, 1e-6));
|
|
@@ -206,9 +215,15 @@ void main() {
|
|
|
206
215
|
float wlen01 = length(wp01);
|
|
207
216
|
float wlen12 = length(wp12);
|
|
208
217
|
float wlen23 = length(wp23);
|
|
218
|
+
// #236: degeneracy guards at visual scale (mirror of GPU33).
|
|
219
|
+
// A segment much shorter than the ribbon half-width cannot define
|
|
220
|
+
// a visually meaningful direction; a degenerate neighbour falls
|
|
221
|
+
// back to the straight cap instead of a noise knee.
|
|
222
|
+
float wDegenEps = max(max(abs(halfSize1), abs(halfSize2)) * 0.02, 1e-6);
|
|
223
|
+
if (wlen12 < wDegenEps) stripDegenerate = true;
|
|
209
224
|
vec3 wdir12 = (wlen12 > 1e-6) ? (wp12 / wlen12) : vec3(1.0, 0.0, 0.0);
|
|
210
|
-
vec3 wdir01 = (wlen01 >
|
|
211
|
-
vec3 wdir23 = (wlen23 >
|
|
225
|
+
vec3 wdir01 = (wlen01 > wDegenEps) ? (wp01 / wlen01) : wdir12;
|
|
226
|
+
vec3 wdir23 = (wlen23 > wDegenEps) ? (wp23 / wlen23) : wdir12;
|
|
212
227
|
noKnee1 = dot(wdir01, wdir12) > 0.999;
|
|
213
228
|
noKnee2 = dot(wdir12, wdir23) > 0.999;
|
|
214
229
|
pathLen12 = wlen12;
|
|
@@ -220,9 +235,12 @@ void main() {
|
|
|
220
235
|
vec3 K1 = Kmul1 * normalize(cross(wdir01 + wdir12, n1));
|
|
221
236
|
Bmul1 = sign(dot(B1raw, K1));
|
|
222
237
|
vec3 B1 = B1raw * Bmul1;
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
238
|
+
// #236: inner vertex at the ribbon half-width along the
|
|
239
|
+
// bisector, symmetric to the outer vertex (mirror of GPU33).
|
|
240
|
+
// The old true-miter-with-neighbour-length-clamp cut an
|
|
241
|
+
// uncovered wedge out of sharp bends whenever halfSize
|
|
242
|
+
// exceeded the particle spacing.
|
|
243
|
+
float ik1 = halfSize1;
|
|
226
244
|
worldK1 = p1 + K1 * halfSize1;
|
|
227
245
|
worldB1 = p1 + B1 * halfSize1;
|
|
228
246
|
worldIK1 = p1 - K1 * ik1;
|
|
@@ -243,9 +261,8 @@ void main() {
|
|
|
243
261
|
vec3 K2 = Kmul2 * normalize(cross(wdir12 + wdir23, n2));
|
|
244
262
|
Bmul2 = sign(dot(B2raw, K2));
|
|
245
263
|
vec3 B2 = B2raw * Bmul2;
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
if (dot( wdir23, ik2 * -K2) > wlen23) ik2 = wlen23;
|
|
264
|
+
// #236: see ik1 — inner vertex at the ribbon half-width.
|
|
265
|
+
float ik2 = halfSize2;
|
|
249
266
|
worldK2 = p2 + K2 * halfSize2;
|
|
250
267
|
worldB2 = p2 + B2 * halfSize2;
|
|
251
268
|
worldIK2 = p2 - K2 * ik2;
|
|
@@ -262,10 +279,16 @@ void main() {
|
|
|
262
279
|
// Faced: screen-space NDC frame around dir12.
|
|
263
280
|
vec4 sp0 = mvpMatrix * vec4(p0, 1.0);
|
|
264
281
|
vec4 sp3 = mvpMatrix * vec4(p3, 1.0);
|
|
265
|
-
vec2 ndc0 = (sp0.xy / sp0.w) * aspectMul;
|
|
266
282
|
vec2 ndc1 = (sp1.xy / sp1.w) * aspectMul;
|
|
267
283
|
vec2 ndc2 = (sp2.xy / sp2.w) * aspectMul;
|
|
268
|
-
|
|
284
|
+
// Neighbor anchors behind the near plane produce garbage NDC after
|
|
285
|
+
// the perspective divide (possible only with Projection3D, where w
|
|
286
|
+
// varies); collapse them onto their segment anchor so the existing
|
|
287
|
+
// zero-length degeneracy path (dir01 = dir12 / dir23 = dir12)
|
|
288
|
+
// handles the knee instead of a poisoned miter. spU1/spU2 need no
|
|
289
|
+
// guard: uCameraUp has zero Z, so their w equals sp1.w / sp2.w.
|
|
290
|
+
vec2 ndc0 = (sp0.w < 1e-3) ? ndc1 : (sp0.xy / sp0.w) * aspectMul;
|
|
291
|
+
vec2 ndc3 = (sp3.w < 1e-3) ? ndc2 : (sp3.xy / sp3.w) * aspectMul;
|
|
269
292
|
|
|
270
293
|
vec2 d01 = ndc1 - ndc0;
|
|
271
294
|
vec2 d12 = ndc2 - ndc1;
|
|
@@ -273,12 +296,6 @@ void main() {
|
|
|
273
296
|
float len01 = length(d01);
|
|
274
297
|
float len12 = length(d12);
|
|
275
298
|
float len23 = length(d23);
|
|
276
|
-
vec2 dir12 = (len12 > 1e-6) ? (d12 / len12) : vec2(1.0, 0.0);
|
|
277
|
-
vec2 dir01 = (len01 > 1e-6) ? (d01 / len01) : dir12;
|
|
278
|
-
vec2 dir23 = (len23 > 1e-6) ? (d23 / len23) : dir12;
|
|
279
|
-
noKnee1 = dot(dir01, dir12) > 0.999;
|
|
280
|
-
noKnee2 = dot(dir12, dir23) > 0.999;
|
|
281
|
-
pathLen12 = len12;
|
|
282
299
|
|
|
283
300
|
// Section magnitude: project camera_up*halfSize per anchor into NDC.
|
|
284
301
|
vec4 spU1 = mvpMatrix * vec4(p1 + uCameraUp * halfSize1, 1.0);
|
|
@@ -286,15 +303,25 @@ void main() {
|
|
|
286
303
|
float ndcHalfSize1 = length((spU1.xy / spU1.w) * aspectMul - ndc1);
|
|
287
304
|
float ndcHalfSize2 = length((spU2.xy / spU2.w) * aspectMul - ndc2);
|
|
288
305
|
|
|
306
|
+
// #236: degeneracy guards at visual scale (mirror of GPU33).
|
|
307
|
+
float degenEps = max(max(ndcHalfSize1, ndcHalfSize2) * 0.02, 1e-6);
|
|
308
|
+
if (len12 < degenEps) stripDegenerate = true;
|
|
309
|
+
vec2 dir12 = (len12 > 1e-6) ? (d12 / len12) : vec2(1.0, 0.0);
|
|
310
|
+
vec2 dir01 = (len01 > degenEps) ? (d01 / len01) : dir12;
|
|
311
|
+
vec2 dir23 = (len23 > degenEps) ? (d23 / len23) : dir12;
|
|
312
|
+
noKnee1 = dot(dir01, dir12) > 0.999;
|
|
313
|
+
noKnee2 = dot(dir12, dir23) > 0.999;
|
|
314
|
+
pathLen12 = len12;
|
|
315
|
+
|
|
289
316
|
vec2 B = stripOrtho(dir12);
|
|
290
317
|
if (!noKnee1) {
|
|
291
318
|
float Kmul1 = -sign(dot(stripOrtho(dir01), dir12));
|
|
292
319
|
vec2 K1 = Kmul1 * normalize(stripOrtho(dir01 + dir12));
|
|
293
320
|
Bmul1 = sign(dot(B, K1));
|
|
294
321
|
vec2 B1 = B * Bmul1;
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
322
|
+
// #236: inner vertex at the ribbon half-width (see the Free
|
|
323
|
+
// branch comment above).
|
|
324
|
+
float ik1 = ndcHalfSize1;
|
|
298
325
|
k1 = ndc1 + K1 * ndcHalfSize1;
|
|
299
326
|
b1 = ndc1 + B1 * ndcHalfSize1;
|
|
300
327
|
IK1 = ndc1 - K1 * ik1;
|
|
@@ -312,9 +339,8 @@ void main() {
|
|
|
312
339
|
vec2 K2 = Kmul2 * normalize(stripOrtho(dir12 + dir23));
|
|
313
340
|
Bmul2 = sign(dot(B, K2));
|
|
314
341
|
vec2 B2 = B * Bmul2;
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
if (dot(dir23, ik2 * -K2) > len23) ik2 = len23;
|
|
342
|
+
// #236: see ik1 — inner vertex at the ribbon half-width.
|
|
343
|
+
float ik2 = ndcHalfSize2;
|
|
318
344
|
k2 = ndc2 + K2 * ndcHalfSize2;
|
|
319
345
|
b2 = ndc2 + B2 * ndcHalfSize2;
|
|
320
346
|
IK2 = ndc2 - K2 * ik2;
|
|
@@ -329,6 +355,34 @@ void main() {
|
|
|
329
355
|
}
|
|
330
356
|
}
|
|
331
357
|
|
|
358
|
+
// #236: a noKnee (straight-cap) end carries no bend side of its own —
|
|
359
|
+
// its raw side label is always the +B side. If the segment's other
|
|
360
|
+
// end is a real knee on the -B side, the mismatched labels would send
|
|
361
|
+
// the ladder into the opposite-sides (twist) branch and flip the
|
|
362
|
+
// texture V across a segment that does not actually change bend side.
|
|
363
|
+
// Relabel the straight end to the knee end's side (swap its k/IK and
|
|
364
|
+
// re-collapse b onto the new k) so the ladder stays untwisted. Both
|
|
365
|
+
// frames are swapped; only the active one is meaningful.
|
|
366
|
+
if (noKnee1 && !noKnee2 && Bmul2 < 0.0) {
|
|
367
|
+
// Swap only the ACTIVE frame's variables - the inactive frame's
|
|
368
|
+
// are uninitialized and must not be read.
|
|
369
|
+
if (isFreeRotation) {
|
|
370
|
+
vec3 tRw1 = worldK1; worldK1 = worldIK1; worldIK1 = tRw1; worldB1 = worldK1;
|
|
371
|
+
} else {
|
|
372
|
+
vec2 tRl1 = k1; k1 = IK1; IK1 = tRl1; b1 = k1;
|
|
373
|
+
}
|
|
374
|
+
Bmul1 = Bmul2;
|
|
375
|
+
}
|
|
376
|
+
if (noKnee2 && !noKnee1 && Bmul1 < 0.0) {
|
|
377
|
+
if (isFreeRotation) {
|
|
378
|
+
vec3 tRw2 = worldK2; worldK2 = worldIK2; worldIK2 = tRw2; worldB2 = worldK2;
|
|
379
|
+
} else {
|
|
380
|
+
vec2 tRl2 = k2; k2 = IK2; IK2 = tRl2; b2 = k2;
|
|
381
|
+
}
|
|
382
|
+
Bmul2 = Bmul1;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
|
|
332
386
|
// V coords (mirror of preview3 / GPU33 make*Strip):
|
|
333
387
|
// V at outer knee (k) = (Bmul + 1) * 0.5
|
|
334
388
|
// V at inner knee (IK) = 1 - V_outer ; bend (b) = outer
|
|
@@ -430,7 +484,10 @@ void main() {
|
|
|
430
484
|
|
|
431
485
|
// Free projects the world-space vertex through MVP directly; Faced
|
|
432
486
|
// reconstructs clip space from aspect-corrected NDC (mirror of preview3).
|
|
433
|
-
if (
|
|
487
|
+
if (stripDegenerate) {
|
|
488
|
+
// #236: sub-visual segment — discard the pair entirely.
|
|
489
|
+
gl_Position = vec4(2.0, 2.0, 2.0, 1.0);
|
|
490
|
+
} else if (isFreeRotation) {
|
|
434
491
|
gl_Position = mvpMatrix * vec4(vertPos3D, 1.0);
|
|
435
492
|
} else if (nearPlaneClipped) {
|
|
436
493
|
// At least one anchor is at / behind the near plane → the NDC math
|
|
@@ -467,6 +524,10 @@ void main() {
|
|
|
467
524
|
float((packedColor >> 16u) & 0xFFu) / 255.0,
|
|
468
525
|
float((packedColor >> 24u) & 0xFFu) / 255.0
|
|
469
526
|
);
|
|
527
|
+
// HDR color scale S (RGBS, bloom TDD #175 §13.12): offset+60 (t3.a) is a
|
|
528
|
+
// per-particle float scale. RGB was normalized by S at pack time; restore HDR
|
|
529
|
+
// here. S=1 for LDR colors (no-op). Alpha is untouched.
|
|
530
|
+
vColor.rgb *= t3.a;
|
|
470
531
|
|
|
471
532
|
uint gridConfig = floatBitsToUint(t3.g);
|
|
472
533
|
float gridWidth = max(float(gridConfig & 0xFFFFu), 1.0);
|
|
@@ -514,7 +575,23 @@ void main() {
|
|
|
514
575
|
|
|
515
576
|
mat4 mvpMatrix = uViewProjMatrix * uModelMatrix;
|
|
516
577
|
vec3 worldPos = position + posDisp;
|
|
517
|
-
gl_Position = mvpMatrix * vec4(worldPos
|
|
578
|
+
gl_Position = mvpMatrix * vec4(worldPos, 1.0);
|
|
579
|
+
|
|
580
|
+
// v1.0-parity near-plane culling for the perspective projection: the
|
|
581
|
+
// whole quad is discarded when ANY of its 4 corners is behind the near
|
|
582
|
+
// plane (w < 0.01 == pos.z > 0.99 * z_cam in PerspectiveProjection
|
|
583
|
+
// terms). w is linear in position, so the corner minimum comes from the
|
|
584
|
+
// w-row and the corner offsets (x in {-ox, 1-ox}, y in {-oy, 1-oy}).
|
|
585
|
+
// Without a projection every w is 1.0 and this is a no-op.
|
|
586
|
+
vec4 wRow = vec4(mvpMatrix[0].w, mvpMatrix[1].w, mvpMatrix[2].w, mvpMatrix[3].w);
|
|
587
|
+
float wx = dot(wRow.xyz, xaxis);
|
|
588
|
+
float wy = dot(wRow.xyz, yaxis);
|
|
589
|
+
float minW = dot(wRow.xyz, position) + wRow.w
|
|
590
|
+
- origin.x * wx + min(wx, 0.0)
|
|
591
|
+
- origin.y * wy + min(wy, 0.0);
|
|
592
|
+
if (minW < 0.01) {
|
|
593
|
+
gl_Position = vec4(2.0, 2.0, 2.0, 1.0);
|
|
594
|
+
}
|
|
518
595
|
|
|
519
596
|
// Texture coordinates with grid + atlas remap
|
|
520
597
|
vec2 baseTexCoord = TEX_COORD[vertexIndex];
|
|
@@ -734,6 +811,11 @@ void main() {
|
|
|
734
811
|
// Colors: the meta M1 sample is the normalized RGBA directly.
|
|
735
812
|
vec4 color1 = fetchMeta(curBase + 1.0);
|
|
736
813
|
vec4 color2 = fetchMeta(nexBase + 1.0);
|
|
814
|
+
// HDR color scale S (RGBS, bloom TDD #175 §13.12): a plain float at offset+60,
|
|
815
|
+
// read straight from the float DATA texture (texel 3, .a) — like gridIndex — not
|
|
816
|
+
// the meta texture. Multiply BEFORE the cross-fade. S=1 → no-op.
|
|
817
|
+
color1.rgb *= fetchData(curBase + 3.0).a;
|
|
818
|
+
color2.rgb *= fetchData(nexBase + 3.0).a;
|
|
737
819
|
|
|
738
820
|
// Neighbor RECORD indices (system.js convention: neighborIdxP0 on the
|
|
739
821
|
// pair-cur meta, neighborIdxP3 on the pair-nex meta; boundary
|
|
@@ -765,6 +847,10 @@ void main() {
|
|
|
765
847
|
// unaffected by the sign of w).
|
|
766
848
|
bool nearPlaneClipped = (sp1.w < 1e-3) || (sp2.w < 1e-3);
|
|
767
849
|
|
|
850
|
+
// #236: set when the segment itself is degenerate (much shorter than
|
|
851
|
+
// the ribbon half-width) - the pair is discarded like nearPlaneClipped.
|
|
852
|
+
bool stripDegenerate = false;
|
|
853
|
+
|
|
768
854
|
// Aspect correction for the 2D Faced ortho on non-square viewports.
|
|
769
855
|
vec2 aspectMul = vec2(1.0, 1.0 / max(uViewportAspect, 1e-6));
|
|
770
856
|
|
|
@@ -807,9 +893,12 @@ void main() {
|
|
|
807
893
|
float wlen01 = length(wp01);
|
|
808
894
|
float wlen12 = length(wp12);
|
|
809
895
|
float wlen23 = length(wp23);
|
|
896
|
+
// #236: degeneracy guards at visual scale (mirror of GPU33).
|
|
897
|
+
float wDegenEps = max(max(abs(halfSize1), abs(halfSize2)) * 0.02, 1e-6);
|
|
898
|
+
if (wlen12 < wDegenEps) stripDegenerate = true;
|
|
810
899
|
vec3 wdir12 = (wlen12 > 1e-6) ? (wp12 / wlen12) : vec3(1.0, 0.0, 0.0);
|
|
811
|
-
vec3 wdir01 = (wlen01 >
|
|
812
|
-
vec3 wdir23 = (wlen23 >
|
|
900
|
+
vec3 wdir01 = (wlen01 > wDegenEps) ? (wp01 / wlen01) : wdir12;
|
|
901
|
+
vec3 wdir23 = (wlen23 > wDegenEps) ? (wp23 / wlen23) : wdir12;
|
|
813
902
|
noKnee1 = dot(wdir01, wdir12) > 0.999;
|
|
814
903
|
noKnee2 = dot(wdir12, wdir23) > 0.999;
|
|
815
904
|
pathLen12 = wlen12;
|
|
@@ -821,9 +910,9 @@ void main() {
|
|
|
821
910
|
vec3 K1 = Kmul1 * normalize(cross(wdir01 + wdir12, n1));
|
|
822
911
|
Bmul1 = sign(dot(B1raw, K1));
|
|
823
912
|
vec3 B1 = B1raw * Bmul1;
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
913
|
+
// #236: inner vertex at the ribbon half-width (mirror of
|
|
914
|
+
// GPU33; see the ES 3.00 shader for the rationale).
|
|
915
|
+
float ik1 = halfSize1;
|
|
827
916
|
worldK1 = p1 + K1 * halfSize1;
|
|
828
917
|
worldB1 = p1 + B1 * halfSize1;
|
|
829
918
|
worldIK1 = p1 - K1 * ik1;
|
|
@@ -844,9 +933,8 @@ void main() {
|
|
|
844
933
|
vec3 K2 = Kmul2 * normalize(cross(wdir12 + wdir23, n2));
|
|
845
934
|
Bmul2 = sign(dot(B2raw, K2));
|
|
846
935
|
vec3 B2 = B2raw * Bmul2;
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
if (dot( wdir23, ik2 * -K2) > wlen23) ik2 = wlen23;
|
|
936
|
+
// #236: see ik1 - inner vertex at the ribbon half-width.
|
|
937
|
+
float ik2 = halfSize2;
|
|
850
938
|
worldK2 = p2 + K2 * halfSize2;
|
|
851
939
|
worldB2 = p2 + B2 * halfSize2;
|
|
852
940
|
worldIK2 = p2 - K2 * ik2;
|
|
@@ -863,10 +951,16 @@ void main() {
|
|
|
863
951
|
// Faced: screen-space NDC frame around dir12.
|
|
864
952
|
vec4 sp0 = mvpMatrix * vec4(p0, 1.0);
|
|
865
953
|
vec4 sp3 = mvpMatrix * vec4(p3, 1.0);
|
|
866
|
-
vec2 ndc0 = (sp0.xy / sp0.w) * aspectMul;
|
|
867
954
|
vec2 ndc1 = (sp1.xy / sp1.w) * aspectMul;
|
|
868
955
|
vec2 ndc2 = (sp2.xy / sp2.w) * aspectMul;
|
|
869
|
-
|
|
956
|
+
// Neighbor anchors behind the near plane produce garbage NDC after
|
|
957
|
+
// the perspective divide (possible only with Projection3D, where w
|
|
958
|
+
// varies); collapse them onto their segment anchor so the existing
|
|
959
|
+
// zero-length degeneracy path (dir01 = dir12 / dir23 = dir12)
|
|
960
|
+
// handles the knee instead of a poisoned miter. spU1/spU2 need no
|
|
961
|
+
// guard: uCameraUp has zero Z, so their w equals sp1.w / sp2.w.
|
|
962
|
+
vec2 ndc0 = (sp0.w < 1e-3) ? ndc1 : (sp0.xy / sp0.w) * aspectMul;
|
|
963
|
+
vec2 ndc3 = (sp3.w < 1e-3) ? ndc2 : (sp3.xy / sp3.w) * aspectMul;
|
|
870
964
|
|
|
871
965
|
vec2 d01 = ndc1 - ndc0;
|
|
872
966
|
vec2 d12 = ndc2 - ndc1;
|
|
@@ -874,12 +968,6 @@ void main() {
|
|
|
874
968
|
float len01 = length(d01);
|
|
875
969
|
float len12 = length(d12);
|
|
876
970
|
float len23 = length(d23);
|
|
877
|
-
vec2 dir12 = (len12 > 1e-6) ? (d12 / len12) : vec2(1.0, 0.0);
|
|
878
|
-
vec2 dir01 = (len01 > 1e-6) ? (d01 / len01) : dir12;
|
|
879
|
-
vec2 dir23 = (len23 > 1e-6) ? (d23 / len23) : dir12;
|
|
880
|
-
noKnee1 = dot(dir01, dir12) > 0.999;
|
|
881
|
-
noKnee2 = dot(dir12, dir23) > 0.999;
|
|
882
|
-
pathLen12 = len12;
|
|
883
971
|
|
|
884
972
|
// Section magnitude: project camera_up*halfSize per anchor into NDC.
|
|
885
973
|
vec4 spU1 = mvpMatrix * vec4(p1 + uCameraUp * halfSize1, 1.0);
|
|
@@ -887,15 +975,24 @@ void main() {
|
|
|
887
975
|
float ndcHalfSize1 = length((spU1.xy / spU1.w) * aspectMul - ndc1);
|
|
888
976
|
float ndcHalfSize2 = length((spU2.xy / spU2.w) * aspectMul - ndc2);
|
|
889
977
|
|
|
978
|
+
// #236: degeneracy guards at visual scale (mirror of GPU33).
|
|
979
|
+
float degenEps = max(max(ndcHalfSize1, ndcHalfSize2) * 0.02, 1e-6);
|
|
980
|
+
if (len12 < degenEps) stripDegenerate = true;
|
|
981
|
+
vec2 dir12 = (len12 > 1e-6) ? (d12 / len12) : vec2(1.0, 0.0);
|
|
982
|
+
vec2 dir01 = (len01 > degenEps) ? (d01 / len01) : dir12;
|
|
983
|
+
vec2 dir23 = (len23 > degenEps) ? (d23 / len23) : dir12;
|
|
984
|
+
noKnee1 = dot(dir01, dir12) > 0.999;
|
|
985
|
+
noKnee2 = dot(dir12, dir23) > 0.999;
|
|
986
|
+
pathLen12 = len12;
|
|
987
|
+
|
|
890
988
|
vec2 B = stripOrtho(dir12);
|
|
891
989
|
if (!noKnee1) {
|
|
892
990
|
float Kmul1 = -sign(dot(stripOrtho(dir01), dir12));
|
|
893
991
|
vec2 K1 = Kmul1 * normalize(stripOrtho(dir01 + dir12));
|
|
894
992
|
Bmul1 = sign(dot(B, K1));
|
|
895
993
|
vec2 B1 = B * Bmul1;
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
if (dot(dir12, ik1 * -K1) > len12) ik1 = len12;
|
|
994
|
+
// #236: inner vertex at the ribbon half-width.
|
|
995
|
+
float ik1 = ndcHalfSize1;
|
|
899
996
|
k1 = ndc1 + K1 * ndcHalfSize1;
|
|
900
997
|
b1 = ndc1 + B1 * ndcHalfSize1;
|
|
901
998
|
IK1 = ndc1 - K1 * ik1;
|
|
@@ -913,9 +1010,8 @@ void main() {
|
|
|
913
1010
|
vec2 K2 = Kmul2 * normalize(stripOrtho(dir12 + dir23));
|
|
914
1011
|
Bmul2 = sign(dot(B, K2));
|
|
915
1012
|
vec2 B2 = B * Bmul2;
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
if (dot(dir23, ik2 * -K2) > len23) ik2 = len23;
|
|
1013
|
+
// #236: see ik1 - inner vertex at the ribbon half-width.
|
|
1014
|
+
float ik2 = ndcHalfSize2;
|
|
919
1015
|
k2 = ndc2 + K2 * ndcHalfSize2;
|
|
920
1016
|
b2 = ndc2 + B2 * ndcHalfSize2;
|
|
921
1017
|
IK2 = ndc2 - K2 * ik2;
|
|
@@ -930,6 +1026,33 @@ void main() {
|
|
|
930
1026
|
}
|
|
931
1027
|
}
|
|
932
1028
|
|
|
1029
|
+
// #236: a noKnee (straight-cap) end carries no bend side of its own -
|
|
1030
|
+
// its raw side label is always the +B side. If the segment's other
|
|
1031
|
+
// end is a real knee on the -B side, the mismatched labels would send
|
|
1032
|
+
// the ladder into the opposite-sides (twist) branch and flip the
|
|
1033
|
+
// texture V across a segment that does not actually change bend side.
|
|
1034
|
+
// Relabel the straight end to the knee end's side (swap its k/IK and
|
|
1035
|
+
// re-collapse b onto the new k) so the ladder stays untwisted. Both
|
|
1036
|
+
// frames are swapped; only the active one is meaningful.
|
|
1037
|
+
if (noKnee1 && !noKnee2 && Bmul2 < 0.0) {
|
|
1038
|
+
// Swap only the ACTIVE frame's variables - the inactive frame's
|
|
1039
|
+
// are uninitialized and must not be read.
|
|
1040
|
+
if (isFreeRotation) {
|
|
1041
|
+
vec3 tRw1 = worldK1; worldK1 = worldIK1; worldIK1 = tRw1; worldB1 = worldK1;
|
|
1042
|
+
} else {
|
|
1043
|
+
vec2 tRl1 = k1; k1 = IK1; IK1 = tRl1; b1 = k1;
|
|
1044
|
+
}
|
|
1045
|
+
Bmul1 = Bmul2;
|
|
1046
|
+
}
|
|
1047
|
+
if (noKnee2 && !noKnee1 && Bmul1 < 0.0) {
|
|
1048
|
+
if (isFreeRotation) {
|
|
1049
|
+
vec3 tRw2 = worldK2; worldK2 = worldIK2; worldIK2 = tRw2; worldB2 = worldK2;
|
|
1050
|
+
} else {
|
|
1051
|
+
vec2 tRl2 = k2; k2 = IK2; IK2 = tRl2; b2 = k2;
|
|
1052
|
+
}
|
|
1053
|
+
Bmul2 = Bmul1;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
933
1056
|
// V coords: V at outer knee (k) = (Bmul + 1) * 0.5; inner = 1 - outer.
|
|
934
1057
|
float Vtop1 = (Bmul1 + 1.0) * 0.5;
|
|
935
1058
|
float Vbot1 = 1.0 - Vtop1;
|
|
@@ -1001,7 +1124,10 @@ void main() {
|
|
|
1001
1124
|
|
|
1002
1125
|
// Free projects the world-space vertex through MVP directly; Faced
|
|
1003
1126
|
// reconstructs clip space from aspect-corrected NDC.
|
|
1004
|
-
if (
|
|
1127
|
+
if (stripDegenerate) {
|
|
1128
|
+
// #236: sub-visual segment - discard the pair entirely.
|
|
1129
|
+
gl_Position = vec4(2.0, 2.0, 2.0, 1.0);
|
|
1130
|
+
} else if (isFreeRotation) {
|
|
1005
1131
|
gl_Position = mvpMatrix * vec4(vertPos3D, 1.0);
|
|
1006
1132
|
} else if (nearPlaneClipped) {
|
|
1007
1133
|
gl_Position = vec4(2.0, 2.0, 2.0, 1.0);
|
|
@@ -1026,6 +1152,9 @@ void main() {
|
|
|
1026
1152
|
|
|
1027
1153
|
// Meta M1: the packedColor u32 LE bytes ARE the normalized RGBA sample.
|
|
1028
1154
|
vColor = fetchMeta(baseTexel + 1.0);
|
|
1155
|
+
// HDR color scale S (RGBS, bloom TDD #175 §13.12): a plain float at offset+60,
|
|
1156
|
+
// read directly from the float DATA texture (t3.a) like gridIndex. S=1 → no-op.
|
|
1157
|
+
vColor.rgb *= t3.a;
|
|
1029
1158
|
|
|
1030
1159
|
// Meta M2: gridConfig — [gridW lo, gridW hi, gridH lo, gridH hi].
|
|
1031
1160
|
vec4 m2 = fetchMeta(baseTexel + 2.0);
|
|
@@ -1072,7 +1201,23 @@ void main() {
|
|
|
1072
1201
|
|
|
1073
1202
|
mat4 mvpMatrix = uViewProjMatrix * uModelMatrix;
|
|
1074
1203
|
vec3 worldPos = position + posDisp;
|
|
1075
|
-
gl_Position = mvpMatrix * vec4(worldPos
|
|
1204
|
+
gl_Position = mvpMatrix * vec4(worldPos, 1.0);
|
|
1205
|
+
|
|
1206
|
+
// v1.0-parity near-plane culling for the perspective projection: the
|
|
1207
|
+
// whole quad is discarded when ANY of its 4 corners is behind the near
|
|
1208
|
+
// plane (w < 0.01 == pos.z > 0.99 * z_cam in PerspectiveProjection
|
|
1209
|
+
// terms). w is linear in position, so the corner minimum comes from the
|
|
1210
|
+
// w-row and the corner offsets (x in {-ox, 1-ox}, y in {-oy, 1-oy}).
|
|
1211
|
+
// Without a projection every w is 1.0 and this is a no-op.
|
|
1212
|
+
vec4 wRow = vec4(mvpMatrix[0].w, mvpMatrix[1].w, mvpMatrix[2].w, mvpMatrix[3].w);
|
|
1213
|
+
float wx = dot(wRow.xyz, xaxis);
|
|
1214
|
+
float wy = dot(wRow.xyz, yaxis);
|
|
1215
|
+
float minW = dot(wRow.xyz, position) + wRow.w
|
|
1216
|
+
- origin.x * wx + min(wx, 0.0)
|
|
1217
|
+
- origin.y * wy + min(wy, 0.0);
|
|
1218
|
+
if (minW < 0.01) {
|
|
1219
|
+
gl_Position = vec4(2.0, 2.0, 2.0, 1.0);
|
|
1220
|
+
}
|
|
1076
1221
|
|
|
1077
1222
|
// Texture coordinates with grid + atlas remap
|
|
1078
1223
|
vec2 baseTexCoord = texCoordOf(corner);
|
|
@@ -1147,7 +1292,7 @@ void main() {
|
|
|
1147
1292
|
// world alpha scales the whole RGBA (mirror of the ES 3.00 shader).
|
|
1148
1293
|
gl_FragColor = texColor * vColor * uWorldAlpha;
|
|
1149
1294
|
}
|
|
1150
|
-
`,A=class A{constructor(e,t){
|
|
1295
|
+
`,A=class A{constructor(e,t){a(this,"neutrino");a(this,"gl");a(this,"_shaderProgram",null);a(this,"_indexBuffer",null);a(this,"_dummyVB",null);a(this,"_indexBufferCapacity",0);a(this,"_vao",null);a(this,"_isWebGL1",!1);a(this,"_maxBatchTextures",A.MAX_BATCH_TEXTURES);a(this,"_hasElementIndexUint",!1);a(this,"_vaoExt",null);a(this,"_aIdBuffer",null);a(this,"_aIdLocation",-1);a(this,"_uDataTexture",null);a(this,"_uDataTextureWidth",null);a(this,"_uMetaTexture",null);a(this,"_uDataTexSize",null);a(this,"_uCameraRight",null);a(this,"_uCameraUp",null);a(this,"_uCameraDir",null);a(this,"_uViewProjMatrix",null);a(this,"_uModelMatrix",null);a(this,"_uViewportAspect",null);a(this,"_uWorldAlpha",null);a(this,"_uTextures",[]);a(this,"_uTexRemaps",[]);a(this,"_noiseInitialized",!1);this.gl=e,this.neutrino=t,this._isWebGL1=typeof e.createVertexArray!="function",this._isWebGL1&&this._probeWebGL1Capabilities(),this._initShader(),this._isWebGL1&&this._smokeTestVertexTextureFetch()}initializeNoise(e,t,n){if(this._noiseInitialized){t&&t();return}this.neutrino.initializeNoise(e,()=>{this._noiseInitialized=!0,t&&t()},n)}generateNoise(){if(this._noiseInitialized)return;const e=new this.neutrino.NoiseGenerator;for(;!e.step(););this._noiseInitialized=!0}get shaderProgram(){return this._shaderProgram}get isWebGL1(){return this._isWebGL1}get maxBatchTextures(){return this._maxBatchTextures}get uDataTexture(){return this._uDataTexture}get uDataTextureWidth(){return this._uDataTextureWidth}get uMetaTexture(){return this._uMetaTexture}get uDataTexSize(){return this._uDataTexSize}get uCameraRight(){return this._uCameraRight}get uCameraUp(){return this._uCameraUp}get uCameraDir(){return this._uCameraDir}get uViewProjMatrix(){return this._uViewProjMatrix}get uModelMatrix(){return this._uModelMatrix}get uViewportAspect(){return this._uViewportAspect}get uWorldAlpha(){return this._uWorldAlpha}get uTextures(){return this._uTextures}get uTexRemaps(){return this._uTexRemaps}ensureIndexBuffer(e){if(e<=this._indexBufferCapacity)return;const t=this.gl,n=this._isWebGL1?null:t.getParameter(t.VERTEX_ARRAY_BINDING),r=t.getParameter(t.ARRAY_BUFFER_BINDING),o=t.getParameter(t.ELEMENT_ARRAY_BUFFER_BINDING);this._indexBuffer&&t.deleteBuffer(this._indexBuffer),this._dummyVB&&(t.deleteBuffer(this._dummyVB),this._dummyVB=null),this._vao&&(t.deleteVertexArray(this._vao),this._vao=null),this._aIdBuffer&&(t.deleteBuffer(this._aIdBuffer),this._aIdBuffer=null);const l=e>16383;if(l&&this._isWebGL1&&!this._hasElementIndexUint)throw new Error(`NeutrinoParticles (js-v1.1): the effect needs 32-bit indices (${e} particles) but this WebGL1 context lacks OES_element_index_uint.`);const c=l?new Uint32Array(e*6):new Uint16Array(e*6);for(let i=0;i<e;i++){const u=i*4,_=i*6;c[_+0]=u+0,c[_+1]=u+1,c[_+2]=u+2,c[_+3]=u+0,c[_+4]=u+2,c[_+5]=u+3}if(this._indexBuffer=t.createBuffer(),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this._indexBuffer),t.bufferData(t.ELEMENT_ARRAY_BUFFER,c,t.STATIC_DRAW),this._isWebGL1){const i=new Float32Array(e*4);for(let u=0;u<i.length;u++)i[u]=u;this._aIdBuffer=t.createBuffer(),t.bindBuffer(t.ARRAY_BUFFER,this._aIdBuffer),t.bufferData(t.ARRAY_BUFFER,i,t.STATIC_DRAW)}else this._dummyVB=t.createBuffer(),t.bindBuffer(t.ARRAY_BUFFER,this._dummyVB),t.bufferData(t.ARRAY_BUFFER,e*4,t.STATIC_DRAW),this._vao=t.createVertexArray(),t.bindVertexArray(this._vao),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this._indexBuffer),t.bindBuffer(t.ARRAY_BUFFER,this._dummyVB),t.enableVertexAttribArray(0),t.vertexAttribPointer(0,1,t.UNSIGNED_BYTE,!1,0,0),t.bindVertexArray(n);t.bindBuffer(t.ARRAY_BUFFER,r),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,o),this._indexBufferCapacity=e}get vao(){return this._vao}get indexBuffer(){return this._indexBuffer}get aIdBuffer(){return this._aIdBuffer}get aIdLocation(){return this._aIdLocation}get indexType(){return this._indexBufferCapacity>16383?this.gl.UNSIGNED_INT:this.gl.UNSIGNED_SHORT}unbindVao(){this._isWebGL1?this._vaoExt&&this._vaoExt.bindVertexArrayOES(null):this.gl.bindVertexArray(null)}destroy(){const e=this.gl;this._shaderProgram&&e.deleteProgram(this._shaderProgram),this._indexBuffer&&e.deleteBuffer(this._indexBuffer),this._dummyVB&&e.deleteBuffer(this._dummyVB),this._vao&&e.deleteVertexArray(this._vao),this._aIdBuffer&&e.deleteBuffer(this._aIdBuffer)}_probeWebGL1Capabilities(){const e=this.gl;if(!e.getExtension("OES_texture_float"))throw new Error("NeutrinoParticles (js-v1.1): WebGL1 context lacks OES_texture_float; WebGL2 or WebGL1 with vertex float textures is required.");const t=e.getParameter(e.MAX_VERTEX_TEXTURE_IMAGE_UNITS);if(t<2)throw new Error("NeutrinoParticles (js-v1.1): WebGL1 context has "+t+" vertex texture units (2 required); WebGL2 or WebGL1 with vertex float textures is required.");const n=e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_FLOAT);if(!n||n.precision===0)throw new Error("NeutrinoParticles (js-v1.1): WebGL1 context lacks highp float in fragment shaders; WebGL2 or WebGL1 with fragment highp is required.");this._hasElementIndexUint=!!e.getExtension("OES_element_index_uint"),this._vaoExt=e.getExtension("OES_vertex_array_object");const r=e.getParameter(e.MAX_COMBINED_TEXTURE_IMAGE_UNITS),o=e.getParameter(e.MAX_TEXTURE_IMAGE_UNITS);this._maxBatchTextures=Math.max(1,Math.min(A.MAX_BATCH_TEXTURES,r-2,o))}_smokeTestVertexTextureFetch(){const e=this.gl,t=`precision highp float;
|
|
1151
1296
|
attribute float aId;
|
|
1152
1297
|
uniform sampler2D uF;
|
|
1153
1298
|
uniform sampler2D uB;
|
|
@@ -1159,11 +1304,11 @@ void main() {
|
|
|
1159
1304
|
gl_Position = vec4(aId, 0.0, 0.0, 1.0);
|
|
1160
1305
|
gl_PointSize = 1.0;
|
|
1161
1306
|
}
|
|
1162
|
-
`,
|
|
1307
|
+
`,n=`precision mediump float;
|
|
1163
1308
|
varying vec4 vC;
|
|
1164
1309
|
void main() { gl_FragColor = vC; }
|
|
1165
|
-
`,r=e.getParameter(e.VIEWPORT),o=e.getParameter(e.CURRENT_PROGRAM),l=e.getParameter(e.ARRAY_BUFFER_BINDING),c=e.getParameter(e.FRAMEBUFFER_BINDING),i=e.getParameter(e.ACTIVE_TEXTURE);e.activeTexture(e.TEXTURE0);const u=e.getParameter(e.TEXTURE_BINDING_2D);e.activeTexture(e.TEXTURE1);const _=e.getParameter(e.TEXTURE_BINDING_2D),
|
|
1310
|
+
`,r=e.getParameter(e.VIEWPORT),o=e.getParameter(e.CURRENT_PROGRAM),l=e.getParameter(e.ARRAY_BUFFER_BINDING),c=e.getParameter(e.FRAMEBUFFER_BINDING),i=e.getParameter(e.ACTIVE_TEXTURE);e.activeTexture(e.TEXTURE0);const u=e.getParameter(e.TEXTURE_BINDING_2D);e.activeTexture(e.TEXTURE1);const _=e.getParameter(e.TEXTURE_BINDING_2D),y=e.isEnabled(e.BLEND),E=e.isEnabled(e.DEPTH_TEST),I=e.isEnabled(e.SCISSOR_TEST);let m=null,b=null,B=null,f=null,v=null,g=null,d=-1,w=!1,x=null,h=4,U=0,p=0,P=0,D=!1,S=!1;const T=new Uint8Array(4);try{m=e.createProgram(),e.attachShader(m,this._compileShader(e.VERTEX_SHADER,t)),e.attachShader(m,this._compileShader(e.FRAGMENT_SHADER,n)),e.linkProgram(m);const C=(R,F)=>{const M=e.createTexture();return e.bindTexture(e.TEXTURE_2D,M),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,1,1,0,e.RGBA,R,F),M};e.activeTexture(e.TEXTURE0),b=C(e.FLOAT,new Float32Array([1,.5,.25,1])),B=C(e.UNSIGNED_BYTE,new Uint8Array([51,102,153,255])),f=e.createTexture(),e.bindTexture(e.TEXTURE_2D,f),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,1,1,0,e.RGBA,e.UNSIGNED_BYTE,null),v=e.createFramebuffer(),e.bindFramebuffer(e.FRAMEBUFFER,v),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,f,0),g=e.createBuffer(),e.bindBuffer(e.ARRAY_BUFFER,g),e.bufferData(e.ARRAY_BUFFER,new Float32Array([0]),e.STATIC_DRAW),S=e.getProgramParameter(m,e.LINK_STATUS),S&&(e.useProgram(m),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,b),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,B),e.uniform1i(e.getUniformLocation(m,"uF"),0),e.uniform1i(e.getUniformLocation(m,"uB"),1),d=e.getAttribLocation(m,"aId"),w=e.getVertexAttrib(d,e.VERTEX_ATTRIB_ARRAY_ENABLED),x=e.getVertexAttrib(d,e.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING),h=e.getVertexAttrib(d,e.VERTEX_ATTRIB_ARRAY_SIZE),U=e.getVertexAttrib(d,e.VERTEX_ATTRIB_ARRAY_TYPE),D=e.getVertexAttrib(d,e.VERTEX_ATTRIB_ARRAY_NORMALIZED),p=e.getVertexAttrib(d,e.VERTEX_ATTRIB_ARRAY_STRIDE),P=e.getVertexAttribOffset(d,e.VERTEX_ATTRIB_ARRAY_POINTER),e.enableVertexAttribArray(d),e.vertexAttribPointer(d,1,e.FLOAT,!1,0,0),e.viewport(0,0,1,1),e.disable(e.BLEND),e.disable(e.DEPTH_TEST),e.disable(e.SCISSOR_TEST),e.drawArrays(e.POINTS,0,1),e.readPixels(0,0,1,1,e.RGBA,e.UNSIGNED_BYTE,T),S=Math.abs(T[0]-51)<=2&&Math.abs(T[1]-51)<=2&&Math.abs(T[2]-38)<=2)}finally{d>=0&&(x&&(e.bindBuffer(e.ARRAY_BUFFER,x),e.vertexAttribPointer(d,h,U,D,p,P)),w?e.enableVertexAttribArray(d):e.disableVertexAttribArray(d)),v&&e.deleteFramebuffer(v),f&&e.deleteTexture(f),b&&e.deleteTexture(b),B&&e.deleteTexture(B),g&&e.deleteBuffer(g),m&&e.deleteProgram(m),e.bindFramebuffer(e.FRAMEBUFFER,c),e.bindBuffer(e.ARRAY_BUFFER,l),e.useProgram(o),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,u),e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,_),e.activeTexture(i),y&&e.enable(e.BLEND),E&&e.enable(e.DEPTH_TEST),I&&e.enable(e.SCISSOR_TEST),e.viewport(r[0],r[1],r[2],r[3])}if(!S)throw new Error(`NeutrinoParticles (js-v1.1): WebGL1 vertex texture fetch smoke test failed (got ${T[0]},${T[1]},${T[2]}); WebGL2 or WebGL1 with working vertex float textures is required.`)}_initShader(){const e=this.gl,t=this._isWebGL1?vertexShaderSourceGL1:vertexShaderSource,n=this._isWebGL1?fragmentShaderSourceGL1:fragmentShaderSource,r=this._compileShader(e.VERTEX_SHADER,t),o=this._compileShader(e.FRAGMENT_SHADER,n);if(this._shaderProgram=e.createProgram(),e.attachShader(this._shaderProgram,r),e.attachShader(this._shaderProgram,o),e.linkProgram(this._shaderProgram),!e.getProgramParameter(this._shaderProgram,e.LINK_STATUS))throw new Error("Shader link error: "+e.getProgramInfoLog(this._shaderProgram));e.deleteShader(r),e.deleteShader(o),this._uDataTexture=e.getUniformLocation(this._shaderProgram,"uDataTexture"),this._uCameraRight=e.getUniformLocation(this._shaderProgram,"uCameraRight"),this._uCameraUp=e.getUniformLocation(this._shaderProgram,"uCameraUp"),this._uCameraDir=e.getUniformLocation(this._shaderProgram,"uCameraDir"),this._uViewProjMatrix=e.getUniformLocation(this._shaderProgram,"uViewProjMatrix"),this._uModelMatrix=e.getUniformLocation(this._shaderProgram,"uModelMatrix"),this._uViewportAspect=e.getUniformLocation(this._shaderProgram,"uViewportAspect"),this._uWorldAlpha=e.getUniformLocation(this._shaderProgram,"uWorldAlpha"),this._isWebGL1?(this._uMetaTexture=e.getUniformLocation(this._shaderProgram,"uMetaTexture"),this._uDataTexSize=e.getUniformLocation(this._shaderProgram,"uDataTexSize"),this._aIdLocation=e.getAttribLocation(this._shaderProgram,"aId")):this._uDataTextureWidth=e.getUniformLocation(this._shaderProgram,"uDataTextureWidth"),this._uTextures=[],this._uTexRemaps=[];for(let l=0;l<A.MAX_BATCH_TEXTURES;l++)this._uTextures.push(e.getUniformLocation(this._shaderProgram,`uTextures[${l}]`)),this._uTexRemaps.push(e.getUniformLocation(this._shaderProgram,`uTexRemaps[${l}]`))}_compileShader(e,t){const n=this.gl,r=n.createShader(e);if(n.shaderSource(r,t),n.compileShader(r),!n.getShaderParameter(r,n.COMPILE_STATUS)){const o=n.getShaderInfoLog(r);throw n.deleteShader(r),new Error("Shader compile error: "+o)}return r}};a(A,"MAX_BATCH_TEXTURES",8);let NeutrinoContext=A;class GamePlugin extends Phaser.Plugins.BasePlugin{constructor(){super(...arguments);a(this,"neutrino");a(this,"ctx");a(this,"texturesBasePath","")}init(t){if(t=Object.assign({texturesBasePath:"",generateNoise:!1},t),this.game.renderer.type!==Phaser.WEBGL)throw new Error("NeutrinoParticles (js-v1.1): a WebGL renderer is required (Canvas not supported).");const r=this.game.renderer.gl;this.texturesBasePath=t.texturesBasePath,this.neutrino=new Neutrino__namespace.Context,this.ctx=new NeutrinoContext(r,this.neutrino),t.generateNoise&&this.generateNoise()}start(){}stop(){}destroy(){this.ctx&&this.ctx.destroy(),this.neutrino=null,super.destroy()}loadNoise(t,n,r){this.ctx.initializeNoise(t,n||(()=>{}),r||(()=>{}))}generateNoise(){this.ctx.generateNoise()}}function noext(s){return s.replace(/\.[^/.]+$/,"")}class EffectModel{constructor(scene,scriptText,options){a(this,"gamePlugin");a(this,"scene");a(this,"effectModel");a(this,"textureFrames",[]);a(this,"texturesRemap",[]);a(this,"_numTexturesToLoadLeft",0);options=Object.assign({atlases:[]},options),this.gamePlugin=scene.plugins.get("neutrino"),this.scene=scene;const evalScript=`(function(ctx) {
|
|
1166
1311
|
`+scriptText+`
|
|
1167
1312
|
return new NeutrinoEffect(ctx);
|
|
1168
|
-
})(this.gamePlugin.neutrino);`;this.effectModel=eval(evalScript),this._startLoadTextures(options.atlases)}get ready(){return this._numTexturesToLoadLeft===0}glTexture(s){const e=this.textureFrames[s];return e?e.glTexture.webGLTexture:null}_startLoadTextures(s){const e=this.effectModel.textures.length;this._numTexturesToLoadLeft=e;for(let t=0;t<e;++t){const a=this.effectModel.textures[t],r=this.gamePlugin.texturesBasePath+a,o=noext(r);let l=this._findFrameInAtlases(s,a);if(l||(l=this._findFrameInAtlases(s,noext(a))),!l&&this.scene.sys.textures.exists(o)){const c=this.scene.sys.textures.get(o);l=c.get(c.firstFrame)}l?this._onTextureLoaded(t,l):(this.scene.load.once("filecomplete-image-"+o,((c,i)=>()=>{const u=this.scene.sys.textures.get(i);this._onTextureLoaded(c,u.get(u.firstFrame))})(t,o)),this.scene.load.image(o,r))}}_findFrameInAtlases(s,e){for(let t=0;t<s.length;++t){const a=s[t];if(!this.scene.sys.textures.exists(a))continue;const r=this.scene.sys.textures.get(a);if(r.has(e))return r.get(e)}return null}_onTextureLoaded(s,e){this.textureFrames[s]=e,this._numTexturesToLoadLeft--,this._numTexturesToLoadLeft===0&&this._initTexturesRemapIfNeeded()}_fullCover(s){return s.width===s.source.width&&s.height===s.source.height}_initTexturesRemapIfNeeded(){let s=!1;for(let e=0;e<this.textureFrames.length;++e)if(!this._fullCover(this.textureFrames[e])){s=!0;break}if(s)for(let e=0;e<this.textureFrames.length;++e){const t=this.textureFrames[e];this.texturesRemap[e]={x:t.u0,y:1-t.v1,width:t.u1-t.u0,height:t.v1-t.v0}}}}class NeutrinoFile extends Phaser.Loader.File{constructor(t,a){const{key:r,url:o,options:l,xhrSettings:c}=a;super(t,{type:"binary",extension:"js",responseType:"text",key:r,url:o,xhrSettings:c});n(this,"_options");this.cache=t.cacheManager.binary,this._options=l}onProcess(){this.state=Phaser.Loader.FILE_PROCESSING;const t=this.xhrLoader.response;this.data=new EffectModel(this.loader.scene,t,this._options),this.onProcessComplete()}}var Pause=(s=>(s[s.NO=0]="NO",s[s.BEFORE_UPDATE_OR_RENDER=1]="BEFORE_UPDATE_OR_RENDER",s[s.YES=2]="YES",s))(Pause||{});const RING_BUFFER_SIZE$1=3;class DataTextureManager{constructor(e,t,a,r){n(this,"textureWidth");n(this,"textureHeight");n(this,"_gl");n(this,"_floatView");n(this,"_textures",[]);n(this,"_currentIndex",0);const o=e.getParameter(e.MAX_TEXTURE_SIZE);if(a>o||r>o)throw new Error(`NeutrinoParticles: data texture ${a}x${r} exceeds GL MAX_TEXTURE_SIZE (${o}). Reduce effect particle capacity.`);this._gl=e,this.textureWidth=a,this.textureHeight=r,this._floatView=new Float32Array(t.buffer,t.byteOffset,t.length);for(let l=0;l<RING_BUFFER_SIZE$1;l++){const c=e.createTexture();e.bindTexture(e.TEXTURE_2D,c),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texImage2D(e.TEXTURE_2D,0,e.RGBA32F,a,r,0,e.RGBA,e.FLOAT,null),this._textures.push(c)}e.bindTexture(e.TEXTURE_2D,null)}get currentTexture(){return this._textures[this._currentIndex]}uploadAndBind(e){const t=this._gl;t.activeTexture(t.TEXTURE0+e),t.bindTexture(t.TEXTURE_2D,this._textures[this._currentIndex]),t.pixelStorei(t.UNPACK_ALIGNMENT,4),t.pixelStorei(t.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texSubImage2D(t.TEXTURE_2D,0,0,0,this.textureWidth,this.textureHeight,t.RGBA,t.FLOAT,this._floatView)}advance(){this._currentIndex=(this._currentIndex+1)%RING_BUFFER_SIZE$1}destroy(){const e=this._gl;for(const t of this._textures)t&&e.deleteTexture(t);this._textures=[]}}class MetaTextureManager{constructor(e,t){n(this,"bytes");n(this,"_u32");this.bytes=new Uint8Array(e*t*4),this._u32=new Uint32Array(this.bytes.buffer)}build(e,t){const a=this._u32;for(let r=0;r<t;r++){const o=r*16,l=r*4;a[l]=e[o],a[l+1]=e[o+12],a[l+2]=e[o+13],a[l+3]=e[o+14]}}patchSlot(e,t,a){const r=this.bytes;let o=e*16;for(let l=0;l<t;l++)r[o]=a,o+=16}}const RING_BUFFER_SIZE=3;class DataTextureManagerGL1{constructor(e,t,a,r){n(this,"textureWidth");n(this,"textureHeight");n(this,"meta");n(this,"_gl");n(this,"_floatView");n(this,"_dataTextures",[]);n(this,"_metaTextures",[]);n(this,"_currentIndex",0);const o=e.getParameter(e.MAX_TEXTURE_SIZE);if(a>o||r>o)throw new Error(`NeutrinoParticles: data texture ${a}x${r} exceeds GL MAX_TEXTURE_SIZE (${o}). Reduce effect particle capacity.`);if(a*r>16777216)throw new Error(`NeutrinoParticles: data texture ${a}x${r} exceeds the WebGL1 render path texel cap (2^24). Reduce effect particle capacity.`);this._gl=e,this.textureWidth=a,this.textureHeight=r,this._floatView=new Float32Array(t.buffer,t.byteOffset,t.length),this.meta=new MetaTextureManager(a,r);const l=e.getParameter(e.ACTIVE_TEXTURE);e.activeTexture(e.TEXTURE0);const c=e.getParameter(e.TEXTURE_BINDING_2D);for(let i=0;i<RING_BUFFER_SIZE;i++)this._dataTextures.push(this._createTexture(e.FLOAT)),this._metaTextures.push(this._createTexture(e.UNSIGNED_BYTE));e.bindTexture(e.TEXTURE_2D,c),e.activeTexture(l)}get currentDataTexture(){return this._dataTextures[this._currentIndex]}get currentMetaTexture(){return this._metaTextures[this._currentIndex]}upload(e,t,a){const r=this._gl,o=this.textureWidth,l=Math.min(this.textureHeight,Math.ceil(e*4/o));if(l===0)return;const c=l*o*4;r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL,!1),r.pixelStorei(r.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1),r.pixelStorei(r.UNPACK_ALIGNMENT,4),r.activeTexture(r.TEXTURE0+t),r.bindTexture(r.TEXTURE_2D,this.currentDataTexture),r.texSubImage2D(r.TEXTURE_2D,0,0,0,o,l,r.RGBA,r.FLOAT,this._floatView.subarray(0,c)),r.activeTexture(r.TEXTURE0+a),r.bindTexture(r.TEXTURE_2D,this.currentMetaTexture),r.texSubImage2D(r.TEXTURE_2D,0,0,0,o,l,r.RGBA,r.UNSIGNED_BYTE,this.meta.bytes.subarray(0,c))}advance(){this._currentIndex=(this._currentIndex+1)%RING_BUFFER_SIZE}destroy(){const e=this._gl;for(const t of this._dataTextures)e.deleteTexture(t);for(const t of this._metaTextures)e.deleteTexture(t);this._dataTextures=[],this._metaTextures=[]}_createTexture(e){const t=this._gl,a=t.createTexture();return t.bindTexture(t.TEXTURE_2D,a),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureWidth,this.textureHeight,0,t.RGBA,e,null),a}}const DATA_TEXTURE_UNIT=0,META_TEXTURE_UNIT=1,PARTICLE_TEXTURE_START_UNIT=1,PARTICLE_TEXTURE_START_UNIT_GL1=2,FLOATS_PER_PARTICLE=16,BYTES_PER_PARTICLE=FLOATS_PER_PARTICLE*4,MAX_BATCHES=64;class DrawBatch{constructor(){n(this,"blendMode",0);n(this,"startParticle",0);n(this,"numParticles",0);n(this,"numTextures",0);n(this,"glTextures",new Array(NeutrinoContext.MAX_BATCH_TEXTURES).fill(null));n(this,"remaps",new Array(NeutrinoContext.MAX_BATCH_TEXTURES).fill(null))}reset(){this.blendMode=0,this.startParticle=0,this.numParticles=0,this.numTextures=0}}class NeutrinoRenderer{constructor(){n(this,"_orthoMatrix",new Float32Array(16));n(this,"_modelMatrix",new Float32Array(16));n(this,"_texSlotMap",new Map);n(this,"_batchPool");n(this,"_batchCount",0);this._batchPool=[];for(let e=0;e<MAX_BATCHES;e++)this._batchPool.push(new DrawBatch)}render(e,t,a,r,o,l,c){if(l===0)return;const i=e.gl,u=e.isWebGL1,_=e.maxBatchTextures,U=c.renderStyles,E=c.materials,I=u?t.meta:null;I&&I.build(r,l),this._batchCount=0;const x=this._texSlotMap;for(;this._batchPool.length<o.length;)this._batchPool.push(new DrawBatch);let b=0;for(;b<o.length;){const p=this._batchPool[this._batchCount];p.reset(),p.blendMode=this._resolveBlend(o[b].blendMode,E),p.startParticle=o[b].startParticleIndex,x.clear();let v=b;for(;v<o.length&&this._resolveBlend(o[v].blendMode,E)===p.blendMode;){const T=U[o[v].renderStyleIndex].textureIndices[0];if(!x.has(T)){if(x.size>=_)break;const f=x.size;x.set(T,f),p.glTextures[f]=c.glTextures[T]||null,p.remaps[f]=c.remaps[T]||null,p.numTextures=f+1}const d=x.get(T),w=o[v];if(I)I.patchSlot(w.startParticleIndex,w.numParticles,d);else for(let f=0;f<w.numParticles;f++){const h=(w.startParticleIndex+f)*BYTES_PER_PARTICLE,y=a.getUint32(h,!0);a.setUint32(h,y&4294967040|d,!0)}p.numParticles+=w.numParticles,v++}this._batchCount++,b=v}const B=i.isEnabled(i.SCISSOR_TEST);try{if(i.disable(i.DEPTH_TEST),i.disable(i.STENCIL_TEST),i.disable(i.SCISSOR_TEST),i.disable(i.CULL_FACE),i.depthMask(!1),i.colorMask(!0,!0,!0,!0),i.useProgram(e.shaderProgram),u){const g=t;g.upload(l,DATA_TEXTURE_UNIT,META_TEXTURE_UNIT),i.uniform1i(e.uDataTexture,DATA_TEXTURE_UNIT),i.uniform1i(e.uMetaTexture,META_TEXTURE_UNIT),i.uniform2f(e.uDataTexSize,g.textureWidth,g.textureHeight)}else{const g=t;g.uploadAndBind(DATA_TEXTURE_UNIT),i.uniform1i(e.uDataTexture,DATA_TEXTURE_UNIT),i.uniform1i(e.uDataTextureWidth,g.textureWidth)}i.uniform3f(e.uCameraRight,1,0,0),i.uniform3f(e.uCameraUp,0,-1,0),i.uniform3f(e.uCameraDir,0,0,-1);const p=c.viewportWidth,v=c.viewportHeight,T=c.zoom||1,d=this._orthoMatrix;d.fill(0),d[0]=2/p*T,d[5]=-2/v*T,d[10]=1,d[15]=1,d[12]=-1-2/p*T*c.scrollX,d[13]=1+2/v*T*c.scrollY,i.uniformMatrix4fv(e.uViewProjMatrix,!1,d);const w=v>0?p/v:1;e.uViewportAspect&&i.uniform1f(e.uViewportAspect,w),e.uWorldAlpha&&i.uniform1f(e.uWorldAlpha,c.worldAlpha);const f=c.model,h=this._modelMatrix;h[0]=f.a,h[1]=f.b,h[2]=0,h[3]=0,h[4]=f.c,h[5]=f.d,h[6]=0,h[7]=0,h[8]=0,h[9]=0,h[10]=1,h[11]=0,h[12]=f.tx,h[13]=f.ty,h[14]=0,h[15]=1,i.uniformMatrix4fv(e.uModelMatrix,!1,h),u?(e.unbindVao(),i.bindBuffer(i.ARRAY_BUFFER,e.aIdBuffer),i.enableVertexAttribArray(e.aIdLocation),i.vertexAttribPointer(e.aIdLocation,1,i.FLOAT,!1,0,0),i.bindBuffer(i.ELEMENT_ARRAY_BUFFER,e.indexBuffer)):i.bindVertexArray(e.vao);const y=u?PARTICLE_TEXTURE_START_UNIT_GL1:PARTICLE_TEXTURE_START_UNIT;i.enable(i.BLEND);for(let g=0;g<this._batchCount;g++){const P=this._batchPool[g];this._applyBlendMode(i,P.blendMode);for(let m=0;m<P.numTextures;m++){const C=y+m;i.activeTexture(i.TEXTURE0+C),i.bindTexture(i.TEXTURE_2D,P.glTextures[m]),i.uniform1i(e.uTextures[m],C);const R=P.remaps[m];R?i.uniform4f(e.uTexRemaps[m],R.x,R.y,R.width,R.height):i.uniform4f(e.uTexRemaps[m],0,0,1,1)}const D=P.startParticle*6,S=P.numParticles*6;i.drawElements(i.TRIANGLES,S,e.indexType,D*(e.indexType===i.UNSIGNED_INT?4:2))}}finally{u?(i.disableVertexAttribArray(e.aIdLocation),i.bindBuffer(i.ARRAY_BUFFER,null),i.bindBuffer(i.ELEMENT_ARRAY_BUFFER,null)):i.bindVertexArray(null),i.useProgram(null),B&&i.enable(i.SCISSOR_TEST)}}_resolveBlend(e,t){return t&&e>=0&&e<t.length?t[e]:e}_applyBlendMode(e,t){switch(t){default:case 0:e.blendFuncSeparate(e.ONE,e.ONE_MINUS_SRC_ALPHA,e.ONE,e.ONE_MINUS_SRC_ALPHA);break;case 1:e.blendFunc(e.ONE,e.ONE);break;case 2:e.blendFunc(e.DST_COLOR,e.ONE_MINUS_SRC_ALPHA);break}}}const sharedRenderer=new NeutrinoRenderer;class Effect extends Phaser.GameObjects.GameObject{constructor(t,a,r){r=Object.assign({position:[0,0,0],angle:0,scale:1,pause:Pause.BEFORE_UPDATE_OR_RENDER,generatorsPaused:!1},r||{});super(a,"Neutrino");n(this,"gamePlugin");n(this,"effectModel");n(this,"effect",null);n(this,"x",0);n(this,"y",0);n(this,"z",0);n(this,"angle",0);n(this,"rotation",0);n(this,"scaleX",1);n(this,"scaleY",1);n(this,"scrollFactorX",1);n(this,"scrollFactorY",1);n(this,"alpha",1);n(this,"depth",0);n(this,"blendMode",Phaser.BlendModes.NORMAL);n(this,"_dataTextureManager",null);n(this,"_worldPosition");n(this,"_worldScaledPosition");n(this,"_worldRotation",[0,0,0,1]);n(this,"_worldScale");n(this,"_tempMatrix1");n(this,"_tempMatrix2");n(this,"_unpauseOnUpdateRender");n(this,"_glTexturesScratch",[]);this.gamePlugin=a.plugins.get("neutrino"),this.effectModel=t,this.x=r.position[0],this.y=r.position[1],this.z=r.position[2],this.angle=r.angle,this.scaleX=r.scale,this.scaleY=r.scale,this._worldPosition=new Phaser.Math.Vector2,this._worldScaledPosition=[0,0,0],this._worldScale=1,this._tempMatrix1=new Phaser.GameObjects.Components.TransformMatrix,this._tempMatrix2=new Phaser.GameObjects.Components.TransformMatrix,this._unpauseOnUpdateRender=r.pause===Pause.BEFORE_UPDATE_OR_RENDER,this._updateWorldTransform();const o={paused:r.pause!==Pause.NO,generatorsPaused:r.generatorsPaused};this.effectModel&&(this.effect=this.effectModel.effectModel.createInstance(this._renderPosition(),this._renderRotation(),o),this._dataTextureManager=this.gamePlugin.ctx.isWebGL1?new DataTextureManagerGL1(this.gamePlugin.ctx.gl,this.effect.particleDataUint32,this.effect.dataTextureWidth,this.effect.dataTextureHeight):new DataTextureManager(this.gamePlugin.ctx.gl,this.effect.particleDataUint32,this.effect.dataTextureWidth,this.effect.dataTextureHeight),this.gamePlugin.ctx.ensureIndexBuffer(this.effectModel.effectModel.totalParticles))}get ready(){return this.effectModel!=null&&this.effectModel.ready&&this.effect!=null}preUpdate(t,a){this.ready&&(this._checkUnpauseOnUpdateRender()||this._updateWorldTransform(),this.effect.update(a/1e3,this._renderPosition(),this._renderRotation()))}renderWebGL(t,a,r){if(!this.ready||this.alpha<=0)return;this._checkUnpauseOnUpdateRender();const o=this.gamePlugin.ctx,l=this._dataTextureManager;this.effect.construct([0,0,-1]);const c=this.effect.renderInstructions,i=c._totalParticles;if(i===0)return;t.flush();const u=this.effectModel.effectModel.textures.length,_=this._glTexturesScratch;_.length=u;for(let E=0;E<u;++E)_[E]=this.effectModel.glTexture(E);const U=this._worldScale;try{sharedRenderer.render(o,l,this.effect.particleDataView,this.effect.particleDataUint32,c,i,{model:{a:U,b:0,c:0,d:U,tx:0,ty:0},viewportWidth:t.width,viewportHeight:t.height,scrollX:r.scrollX*this.scrollFactorX,scrollY:r.scrollY*this.scrollFactorY,zoom:r.zoom,worldAlpha:this.alpha,glTextures:_,remaps:this.effectModel.texturesRemap,renderStyles:this.effect.model.renderStyles,materials:this.effect.model.materials}),l.advance()}finally{t.pipelines.rebind()}}restart(t){this.ready&&(this._applyTransformOptions(t),this._updateWorldTransform(),this.effect.restart(this._renderPosition(),this._renderRotation()))}resetPosition(t){this.ready&&(this._applyTransformOptions(t),this._updateWorldTransform(),this.effect.resetPosition(this._renderPosition(),this._renderRotation()))}pause(){this.ready&&this.effect.pauseAllEmitters()}unpause(){this.ready&&this.effect.unpauseAllEmitters()}get paused(){return this.ready?this.effect.areAllEmittersPaused():!1}pauseGenerators(){this.ready&&this.effect.pauseGeneratorsInAllEmitters()}unpauseGenerators(){this.ready&&this.effect.unpauseGeneratorsInAllEmitters()}get generatorsPaused(){return this.ready?this.effect.areGeneratorsInAllEmittersPaused():!1}setPropertyInAllEmitters(t,a){this.ready&&this.effect.setPropertyInAllEmitters(t,a)}getNumParticles(){return this.ready?this.effect.getNumParticles():0}setScrollFactor(t,a){return this.scrollFactorX=t,this.scrollFactorY=a===void 0?t:a,this}setAlpha(t,a,r,o){return this.alpha=t===void 0?1:t,this}destroy(t){this._dataTextureManager&&(this._dataTextureManager.destroy(),this._dataTextureManager=null),super.destroy(t)}_applyTransformOptions(t){t&&(t.position&&(this.x=t.position[0],this.y=t.position[1],this.z=t.position[2]),t.angle!==void 0?(this.angle=t.angle,this.rotation=Phaser.Math.DegToRad(t.angle)):t.rotation!==void 0&&(this.rotation=t.rotation,this.angle=Phaser.Math.RadToDeg(t.rotation)))}_updateWorldTransform(){const t=(o,l)=>{if(!o)return;const c=this._tempMatrix2;c.applyITRS(o.x,o.y,o.rotation,o.scaleX,o.scaleY),c.multiply(l.matrix,l.matrix),l.angle+=o.angle,l.scale*=(o.scaleX+o.scaleY)*.5,t(o.parentContainer,l)},a={matrix:this._tempMatrix1.loadIdentity(),angle:this.angle,scale:(this.scaleX+this.scaleY)*.5};t(this.parentContainer,a),a.matrix.transformPoint(this.x,this.y,this._worldPosition),this._worldRotation=this.gamePlugin.neutrino.axisangle2quat_([0,0,1],a.angle),this._worldScale=a.scale;const r=this._worldScale!==0?1/this._worldScale:0;this._worldScaledPosition[0]=this._worldPosition.x*r,this._worldScaledPosition[1]=this._worldPosition.y*r,this._worldScaledPosition[2]=this.z*r}_renderPosition(){return this._worldScaledPosition}_renderRotation(){return this._worldRotation}_checkUnpauseOnUpdateRender(){return this._unpauseOnUpdateRender?(this.resetPosition(),this.unpause(),this._unpauseOnUpdateRender=!1,!0):!1}}class PerspectiveProjection{constructor(e){n(this,"_angleTan",0);n(this,"_screenWidth",0);n(this,"_screenPosX",0);n(this,"_screenPosY",0);n(this,"_z",0);n(this,"_near",0);this.horizontalAngle=e}set horizontalAngle(e){this._angleTan=Math.tan(e*.5/180*Math.PI)}setScreenFrame(e){this._screenWidth=e.width,this._screenPosX=e.x+e.width*.5,this._screenPosY=e.y+e.height*.5,this._z=this._screenWidth*.5/this._angleTan,this._near=this._z*.99}transformPosition(e,t){if(t[2]>this._near)return!1;const a=this._getScale(t);return e[0]=(t[0]-this._screenPosX)*a+this._screenPosX,e[1]=(t[1]-this._screenPosY)*a+this._screenPosY,!0}transformSize(e,t,a){const r=this._getScale(t);e[0]=a[0]*r,e[1]=a[1]*r}_getScale(e){return this._z/(this._z-e[2])}}let _installed=!1;function installPlugin(){_installed||(_installed=!0,Phaser.Loader.FileTypesManager.register("neutrino",function(s,e,t,a){if(Array.isArray(s))for(const r of s)this.addFile(new NeutrinoFile(this,r));else typeof s=="object"?this.addFile(new NeutrinoFile(this,s)):this.addFile(new NeutrinoFile(this,{key:s,url:e,options:t,xhrSettings:a}));return this}),Phaser.GameObjects.GameObjectFactory.register("neutrino",function(s,e){const t=new Effect(s,this.scene,e);return this.displayList.add(t),this.updateList.add(t),t}),Phaser.GameObjects.GameObjectCreator.register("neutrino",function(s){const e=new Effect(s.effectModel,this.scene,s);return s.add!==!1&&(this.scene.sys.displayList.add(e),this.scene.sys.updateList.add(e)),e}))}installPlugin();exports.DataTextureManager=DataTextureManager;exports.Effect=Effect;exports.EffectModel=EffectModel;exports.GamePlugin=GamePlugin;exports.NeutrinoContext=NeutrinoContext;exports.NeutrinoFile=NeutrinoFile;exports.NeutrinoRenderer=NeutrinoRenderer;exports.Pause=Pause;exports.PerspectiveProjection=PerspectiveProjection;exports.installPlugin=installPlugin;
|
|
1313
|
+
})(this.gamePlugin.neutrino);`;this.effectModel=eval(evalScript),this._startLoadTextures(options.atlases)}get ready(){return this._numTexturesToLoadLeft===0}glTexture(s){const e=this.textureFrames[s];return e?e.glTexture.webGLTexture:null}_startLoadTextures(s){const e=this.effectModel.textures.length;this._numTexturesToLoadLeft=e;for(let t=0;t<e;++t){const n=this.effectModel.textures[t],r=this.gamePlugin.texturesBasePath+n,o=noext(r);let l=this._findFrameInAtlases(s,n);if(l||(l=this._findFrameInAtlases(s,noext(n))),!l&&this.scene.sys.textures.exists(o)){const c=this.scene.sys.textures.get(o);l=c.get(c.firstFrame)}l?this._onTextureLoaded(t,l):(this.scene.load.once("filecomplete-image-"+o,((c,i)=>()=>{const u=this.scene.sys.textures.get(i);this._onTextureLoaded(c,u.get(u.firstFrame))})(t,o)),this.scene.load.image(o,r))}}_findFrameInAtlases(s,e){for(let t=0;t<s.length;++t){const n=s[t];if(!this.scene.sys.textures.exists(n))continue;const r=this.scene.sys.textures.get(n);if(r.has(e))return r.get(e)}return null}_onTextureLoaded(s,e){this.textureFrames[s]=e,this._numTexturesToLoadLeft--,this._numTexturesToLoadLeft===0&&this._initTexturesRemapIfNeeded()}_fullCover(s){return s.width===s.source.width&&s.height===s.source.height}_initTexturesRemapIfNeeded(){let s=!1;for(let e=0;e<this.textureFrames.length;++e)if(!this._fullCover(this.textureFrames[e])){s=!0;break}if(s)for(let e=0;e<this.textureFrames.length;++e){const t=this.textureFrames[e];this.texturesRemap[e]={x:t.u0,y:1-t.v1,width:t.u1-t.u0,height:t.v1-t.v0}}}}class NeutrinoFile extends Phaser.Loader.File{constructor(t,n){const{key:r,url:o,options:l,xhrSettings:c}=n;super(t,{type:"binary",extension:"js",responseType:"text",key:r,url:o,xhrSettings:c});a(this,"_options");this.cache=t.cacheManager.binary,this._options=l}onProcess(){this.state=Phaser.Loader.FILE_PROCESSING;const t=this.xhrLoader.response;this.data=new EffectModel(this.loader.scene,t,this._options),this.onProcessComplete()}}var Pause=(s=>(s[s.NO=0]="NO",s[s.BEFORE_UPDATE_OR_RENDER=1]="BEFORE_UPDATE_OR_RENDER",s[s.YES=2]="YES",s))(Pause||{});const RING_BUFFER_SIZE$1=3;class DataTextureManager{constructor(e,t,n,r){a(this,"textureWidth");a(this,"textureHeight");a(this,"_gl");a(this,"_floatView");a(this,"_textures",[]);a(this,"_currentIndex",0);const o=e.getParameter(e.MAX_TEXTURE_SIZE);if(n>o||r>o)throw new Error(`NeutrinoParticles: data texture ${n}x${r} exceeds GL MAX_TEXTURE_SIZE (${o}). Reduce effect particle capacity.`);this._gl=e,this.textureWidth=n,this.textureHeight=r,this._floatView=new Float32Array(t.buffer,t.byteOffset,t.length);for(let l=0;l<RING_BUFFER_SIZE$1;l++){const c=e.createTexture();e.bindTexture(e.TEXTURE_2D,c),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texImage2D(e.TEXTURE_2D,0,e.RGBA32F,n,r,0,e.RGBA,e.FLOAT,null),this._textures.push(c)}e.bindTexture(e.TEXTURE_2D,null)}get currentTexture(){return this._textures[this._currentIndex]}uploadAndBind(e){const t=this._gl;t.activeTexture(t.TEXTURE0+e),t.bindTexture(t.TEXTURE_2D,this._textures[this._currentIndex]),t.pixelStorei(t.UNPACK_ALIGNMENT,4),t.pixelStorei(t.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texSubImage2D(t.TEXTURE_2D,0,0,0,this.textureWidth,this.textureHeight,t.RGBA,t.FLOAT,this._floatView)}advance(){this._currentIndex=(this._currentIndex+1)%RING_BUFFER_SIZE$1}destroy(){const e=this._gl;for(const t of this._textures)t&&e.deleteTexture(t);this._textures=[]}}class MetaTextureManager{constructor(e,t){a(this,"bytes");a(this,"_u32");this.bytes=new Uint8Array(e*t*4),this._u32=new Uint32Array(this.bytes.buffer)}build(e,t){const n=this._u32;for(let r=0;r<t;r++){const o=r*16,l=r*4;n[l]=e[o],n[l+1]=e[o+12],n[l+2]=e[o+13],n[l+3]=e[o+14]}}patchSlot(e,t,n){const r=this.bytes;let o=e*16;for(let l=0;l<t;l++)r[o]=n,o+=16}}const RING_BUFFER_SIZE=3;class DataTextureManagerGL1{constructor(e,t,n,r){a(this,"textureWidth");a(this,"textureHeight");a(this,"meta");a(this,"_gl");a(this,"_floatView");a(this,"_dataTextures",[]);a(this,"_metaTextures",[]);a(this,"_currentIndex",0);const o=e.getParameter(e.MAX_TEXTURE_SIZE);if(n>o||r>o)throw new Error(`NeutrinoParticles: data texture ${n}x${r} exceeds GL MAX_TEXTURE_SIZE (${o}). Reduce effect particle capacity.`);if(n*r>16777216)throw new Error(`NeutrinoParticles: data texture ${n}x${r} exceeds the WebGL1 render path texel cap (2^24). Reduce effect particle capacity.`);this._gl=e,this.textureWidth=n,this.textureHeight=r,this._floatView=new Float32Array(t.buffer,t.byteOffset,t.length),this.meta=new MetaTextureManager(n,r);const l=e.getParameter(e.ACTIVE_TEXTURE);e.activeTexture(e.TEXTURE0);const c=e.getParameter(e.TEXTURE_BINDING_2D);for(let i=0;i<RING_BUFFER_SIZE;i++)this._dataTextures.push(this._createTexture(e.FLOAT)),this._metaTextures.push(this._createTexture(e.UNSIGNED_BYTE));e.bindTexture(e.TEXTURE_2D,c),e.activeTexture(l)}get currentDataTexture(){return this._dataTextures[this._currentIndex]}get currentMetaTexture(){return this._metaTextures[this._currentIndex]}upload(e,t,n){const r=this._gl,o=this.textureWidth,l=Math.min(this.textureHeight,Math.ceil(e*4/o));if(l===0)return;const c=l*o*4;r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL,!1),r.pixelStorei(r.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1),r.pixelStorei(r.UNPACK_ALIGNMENT,4),r.activeTexture(r.TEXTURE0+t),r.bindTexture(r.TEXTURE_2D,this.currentDataTexture),r.texSubImage2D(r.TEXTURE_2D,0,0,0,o,l,r.RGBA,r.FLOAT,this._floatView.subarray(0,c)),r.activeTexture(r.TEXTURE0+n),r.bindTexture(r.TEXTURE_2D,this.currentMetaTexture),r.texSubImage2D(r.TEXTURE_2D,0,0,0,o,l,r.RGBA,r.UNSIGNED_BYTE,this.meta.bytes.subarray(0,c))}advance(){this._currentIndex=(this._currentIndex+1)%RING_BUFFER_SIZE}destroy(){const e=this._gl;for(const t of this._dataTextures)e.deleteTexture(t);for(const t of this._metaTextures)e.deleteTexture(t);this._dataTextures=[],this._metaTextures=[]}_createTexture(e){const t=this._gl,n=t.createTexture();return t.bindTexture(t.TEXTURE_2D,n),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureWidth,this.textureHeight,0,t.RGBA,e,null),n}}const DATA_TEXTURE_UNIT=0,META_TEXTURE_UNIT=1,PARTICLE_TEXTURE_START_UNIT=1,PARTICLE_TEXTURE_START_UNIT_GL1=2,FLOATS_PER_PARTICLE=16,BYTES_PER_PARTICLE=FLOATS_PER_PARTICLE*4,MAX_BATCHES=64;class DrawBatch{constructor(){a(this,"blendMode",0);a(this,"startParticle",0);a(this,"numParticles",0);a(this,"numTextures",0);a(this,"glTextures",new Array(NeutrinoContext.MAX_BATCH_TEXTURES).fill(null));a(this,"remaps",new Array(NeutrinoContext.MAX_BATCH_TEXTURES).fill(null))}reset(){this.blendMode=0,this.startParticle=0,this.numParticles=0,this.numTextures=0}}class NeutrinoRenderer{constructor(){a(this,"_orthoMatrix",new Float32Array(16));a(this,"_perspMatrix",new Float32Array(16));a(this,"_vpMatrix",new Float32Array(16));a(this,"_projFrame",{x:0,y:0,width:0,height:0});a(this,"_modelMatrix",new Float32Array(16));a(this,"_texSlotMap",new Map);a(this,"_batchPool");a(this,"_batchCount",0);this._batchPool=[];for(let e=0;e<MAX_BATCHES;e++)this._batchPool.push(new DrawBatch)}render(e,t,n,r,o,l,c){if(l===0)return;const i=e.gl,u=e.isWebGL1,_=e.maxBatchTextures,y=c.renderStyles,E=c.materials,I=u?t.meta:null;I&&I.build(r,l),this._batchCount=0;const m=this._texSlotMap;for(;this._batchPool.length<o.length;)this._batchPool.push(new DrawBatch);let b=0;for(;b<o.length;){const f=this._batchPool[this._batchCount];f.reset(),f.blendMode=this._resolveBlend(o[b].blendMode,E),f.startParticle=o[b].startParticleIndex,m.clear();let v=b;for(;v<o.length&&this._resolveBlend(o[v].blendMode,E)===f.blendMode;){const g=y[o[v].renderStyleIndex].textureIndices[0];if(!m.has(g)){if(m.size>=_)break;const x=m.size;m.set(g,x),f.glTextures[x]=c.glTextures[g]||null,f.remaps[x]=c.remaps[g]||null,f.numTextures=x+1}const d=m.get(g),w=o[v];if(I)I.patchSlot(w.startParticleIndex,w.numParticles,d);else if(d!==0)for(let x=0;x<w.numParticles;x++){const h=(w.startParticleIndex+x)*BYTES_PER_PARTICLE,U=n.getUint32(h,!0);n.setUint32(h,U&4294967040|d,!0)}f.numParticles+=w.numParticles,v++}this._batchCount++,b=v}const B=i.isEnabled(i.SCISSOR_TEST);try{if(i.disable(i.DEPTH_TEST),i.disable(i.STENCIL_TEST),i.disable(i.SCISSOR_TEST),i.disable(i.CULL_FACE),i.depthMask(!1),i.colorMask(!0,!0,!0,!0),i.useProgram(e.shaderProgram),u){const p=t;p.upload(l,DATA_TEXTURE_UNIT,META_TEXTURE_UNIT),i.uniform1i(e.uDataTexture,DATA_TEXTURE_UNIT),i.uniform1i(e.uMetaTexture,META_TEXTURE_UNIT),i.uniform2f(e.uDataTexSize,p.textureWidth,p.textureHeight)}else{const p=t;p.uploadAndBind(DATA_TEXTURE_UNIT),i.uniform1i(e.uDataTexture,DATA_TEXTURE_UNIT),i.uniform1i(e.uDataTextureWidth,p.textureWidth)}i.uniform3f(e.uCameraRight,1,0,0),i.uniform3f(e.uCameraUp,0,-1,0),i.uniform3f(e.uCameraDir,0,0,-1);const f=c.viewportWidth,v=c.viewportHeight,g=c.zoom||1,d=this._orthoMatrix;if(d.fill(0),d[0]=2/f*g,d[5]=-2/v*g,d[10]=0,d[15]=1,d[12]=-1-2/f*g*c.scrollX,d[13]=1+2/v*g*c.scrollY,c.projection){const p=this._projFrame;p.x=0,p.y=0,p.width=f,p.height=v,c.projection.setScreenFrame(p),c.projection.writeMatrix(this._perspMatrix),this._mulMatrix(this._vpMatrix,d,this._perspMatrix),i.uniformMatrix4fv(e.uViewProjMatrix,!1,this._vpMatrix)}else i.uniformMatrix4fv(e.uViewProjMatrix,!1,d);const w=v>0?f/v:1;e.uViewportAspect&&i.uniform1f(e.uViewportAspect,w),e.uWorldAlpha&&i.uniform1f(e.uWorldAlpha,c.worldAlpha);const x=c.model,h=this._modelMatrix;h[0]=x.a,h[1]=x.b,h[2]=0,h[3]=0,h[4]=x.c,h[5]=x.d,h[6]=0,h[7]=0,h[8]=0,h[9]=0,h[10]=1,h[11]=0,h[12]=x.tx,h[13]=x.ty,h[14]=0,h[15]=1,i.uniformMatrix4fv(e.uModelMatrix,!1,h),u?(e.unbindVao(),i.bindBuffer(i.ARRAY_BUFFER,e.aIdBuffer),i.enableVertexAttribArray(e.aIdLocation),i.vertexAttribPointer(e.aIdLocation,1,i.FLOAT,!1,0,0),i.bindBuffer(i.ELEMENT_ARRAY_BUFFER,e.indexBuffer)):i.bindVertexArray(e.vao);const U=u?PARTICLE_TEXTURE_START_UNIT_GL1:PARTICLE_TEXTURE_START_UNIT;i.enable(i.BLEND);for(let p=0;p<this._batchCount;p++){const P=this._batchPool[p];this._applyBlendMode(i,P.blendMode);for(let T=0;T<P.numTextures;T++){const C=U+T;i.activeTexture(i.TEXTURE0+C),i.bindTexture(i.TEXTURE_2D,P.glTextures[T]),i.uniform1i(e.uTextures[T],C);const R=P.remaps[T];R?i.uniform4f(e.uTexRemaps[T],R.x,R.y,R.width,R.height):i.uniform4f(e.uTexRemaps[T],0,0,1,1)}const D=P.startParticle*6,S=P.numParticles*6;i.drawElements(i.TRIANGLES,S,e.indexType,D*(e.indexType===i.UNSIGNED_INT?4:2))}}finally{u?(i.disableVertexAttribArray(e.aIdLocation),i.bindBuffer(i.ARRAY_BUFFER,null),i.bindBuffer(i.ELEMENT_ARRAY_BUFFER,null)):i.bindVertexArray(null),i.useProgram(null),B&&i.enable(i.SCISSOR_TEST)}}_mulMatrix(e,t,n){for(let r=0;r<16;r+=4){const o=n[r],l=n[r+1],c=n[r+2],i=n[r+3];e[r]=t[0]*o+t[4]*l+t[8]*c+t[12]*i,e[r+1]=t[1]*o+t[5]*l+t[9]*c+t[13]*i,e[r+2]=t[2]*o+t[6]*l+t[10]*c+t[14]*i,e[r+3]=t[3]*o+t[7]*l+t[11]*c+t[15]*i}}_resolveBlend(e,t){return t&&e>=0&&e<t.length?t[e]:e}_applyBlendMode(e,t){switch(t){default:case 0:e.blendFuncSeparate(e.ONE,e.ONE_MINUS_SRC_ALPHA,e.ONE,e.ONE_MINUS_SRC_ALPHA);break;case 1:e.blendFunc(e.ONE,e.ONE);break;case 2:e.blendFunc(e.DST_COLOR,e.ONE_MINUS_SRC_ALPHA);break}}}const sharedRenderer=new NeutrinoRenderer;class Effect extends Phaser.GameObjects.GameObject{constructor(t,n,r){r=Object.assign({position:[0,0,0],angle:0,scale:1,pause:Pause.BEFORE_UPDATE_OR_RENDER,generatorsPaused:!1},r||{});super(n,"Neutrino");a(this,"gamePlugin");a(this,"effectModel");a(this,"effect",null);a(this,"x",0);a(this,"y",0);a(this,"z",0);a(this,"angle",0);a(this,"rotation",0);a(this,"scaleX",1);a(this,"scaleY",1);a(this,"scrollFactorX",1);a(this,"scrollFactorY",1);a(this,"alpha",1);a(this,"depth",0);a(this,"blendMode",Phaser.BlendModes.NORMAL);a(this,"projection");a(this,"_dataTextureManager",null);a(this,"_worldPosition");a(this,"_worldScaledPosition");a(this,"_worldRotation",[0,0,0,1]);a(this,"_worldScale");a(this,"_tempMatrix1");a(this,"_tempMatrix2");a(this,"_unpauseOnUpdateRender");a(this,"_glTexturesScratch",[]);this.gamePlugin=n.plugins.get("neutrino"),this.effectModel=t,this.x=r.position[0],this.y=r.position[1],this.z=r.position[2],this.angle=r.angle,this.scaleX=r.scale,this.scaleY=r.scale,this.projection=r.projection,this._worldPosition=new Phaser.Math.Vector2,this._worldScaledPosition=[0,0,0],this._worldScale=1,this._tempMatrix1=new Phaser.GameObjects.Components.TransformMatrix,this._tempMatrix2=new Phaser.GameObjects.Components.TransformMatrix,this._unpauseOnUpdateRender=r.pause===Pause.BEFORE_UPDATE_OR_RENDER,this._updateWorldTransform();const o={paused:r.pause!==Pause.NO,generatorsPaused:r.generatorsPaused};this.effectModel&&(this.effect=this.effectModel.effectModel.createInstance(this._renderPosition(),this._renderRotation(),o),this._dataTextureManager=this.gamePlugin.ctx.isWebGL1?new DataTextureManagerGL1(this.gamePlugin.ctx.gl,this.effect.particleDataUint32,this.effect.dataTextureWidth,this.effect.dataTextureHeight):new DataTextureManager(this.gamePlugin.ctx.gl,this.effect.particleDataUint32,this.effect.dataTextureWidth,this.effect.dataTextureHeight),this.gamePlugin.ctx.ensureIndexBuffer(this.effectModel.effectModel.totalParticles))}get ready(){return this.effectModel!=null&&this.effectModel.ready&&this.effect!=null}preUpdate(t,n){this.ready&&(this._checkUnpauseOnUpdateRender()||this._updateWorldTransform(),this.effect.update(n/1e3,this._renderPosition(),this._renderRotation()))}renderWebGL(t,n,r){if(!this.ready||this.alpha<=0)return;this._checkUnpauseOnUpdateRender();const o=this.gamePlugin.ctx,l=this._dataTextureManager;this.effect.construct([0,0,-1]);const c=this.effect.renderInstructions,i=c._totalParticles;if(i===0)return;t.flush();const u=this.effectModel.effectModel.textures.length,_=this._glTexturesScratch;_.length=u;for(let E=0;E<u;++E)_[E]=this.effectModel.glTexture(E);const y=this._worldScale;try{sharedRenderer.render(o,l,this.effect.particleDataView,this.effect.particleDataUint32,c,i,{model:{a:y,b:0,c:0,d:y,tx:0,ty:0},viewportWidth:t.width,viewportHeight:t.height,scrollX:r.scrollX*this.scrollFactorX,scrollY:r.scrollY*this.scrollFactorY,zoom:r.zoom,worldAlpha:this.alpha,projection:this.projection,glTextures:_,remaps:this.effectModel.texturesRemap,renderStyles:this.effect.model.renderStyles,materials:this.effect.model.materials}),l.advance()}finally{t.pipelines.rebind()}}restart(t){this.ready&&(this._applyTransformOptions(t),this._updateWorldTransform(),this.effect.restart(this._renderPosition(),this._renderRotation()))}resetPosition(t){this.ready&&(this._applyTransformOptions(t),this._updateWorldTransform(),this.effect.resetPosition(this._renderPosition(),this._renderRotation()))}pause(){this.ready&&this.effect.pauseAllEmitters()}unpause(){this.ready&&this.effect.unpauseAllEmitters()}get paused(){return this.ready?this.effect.areAllEmittersPaused():!1}pauseGenerators(){this.ready&&this.effect.pauseGeneratorsInAllEmitters()}unpauseGenerators(){this.ready&&this.effect.unpauseGeneratorsInAllEmitters()}get generatorsPaused(){return this.ready?this.effect.areGeneratorsInAllEmittersPaused():!1}setPropertyInAllEmitters(t,n){this.ready&&this.effect.setPropertyInAllEmitters(t,n)}setPropertyInEmitter(t,n,r){this.ready&&this.effect.setPropertyInEmitter(t,n,r)}getEmitterPropertyValue(t,n){if(this.ready)return n===void 0?this.effect.getEmitterPropertyValue(t):this.effect.getEmitterPropertyValue(t,n)}hasEmitterProperty(t,n){return this.ready?n===void 0?this.effect.hasEmitterProperty(t):this.effect.hasEmitterProperty(t,n):!1}getEmitterProperties(){return this.ready?this.effect.getEmitterProperties():[]}getNumParticles(){return this.ready?this.effect.getNumParticles():0}setScrollFactor(t,n){return this.scrollFactorX=t,this.scrollFactorY=n===void 0?t:n,this}setAlpha(t,n,r,o){return this.alpha=t===void 0?1:t,this}destroy(t){this._dataTextureManager&&(this._dataTextureManager.destroy(),this._dataTextureManager=null),super.destroy(t)}_applyTransformOptions(t){t&&(t.position&&(this.x=t.position[0],this.y=t.position[1],this.z=t.position[2]),t.angle!==void 0?(this.angle=t.angle,this.rotation=Phaser.Math.DegToRad(t.angle)):t.rotation!==void 0&&(this.rotation=t.rotation,this.angle=Phaser.Math.RadToDeg(t.rotation)))}_updateWorldTransform(){const t=(o,l)=>{if(!o)return;const c=this._tempMatrix2;c.applyITRS(o.x,o.y,o.rotation,o.scaleX,o.scaleY),c.multiply(l.matrix,l.matrix),l.angle+=o.angle,l.scale*=(o.scaleX+o.scaleY)*.5,t(o.parentContainer,l)},n={matrix:this._tempMatrix1.loadIdentity(),angle:this.angle,scale:(this.scaleX+this.scaleY)*.5};t(this.parentContainer,n),n.matrix.transformPoint(this.x,this.y,this._worldPosition),this._worldRotation=this.gamePlugin.neutrino.axisangle2quat_([0,0,1],n.angle),this._worldScale=n.scale;const r=this._worldScale!==0?1/this._worldScale:0;this._worldScaledPosition[0]=this._worldPosition.x*r,this._worldScaledPosition[1]=this._worldPosition.y*r,this._worldScaledPosition[2]=this.z*r}_renderPosition(){return this._worldScaledPosition}_renderRotation(){return this._worldRotation}_checkUnpauseOnUpdateRender(){return this._unpauseOnUpdateRender?(this.resetPosition(),this.unpause(),this._unpauseOnUpdateRender=!1,!0):!1}}class PerspectiveProjection{constructor(e){a(this,"_angleTan",0);a(this,"_screenWidth",0);a(this,"_screenPosX",0);a(this,"_screenPosY",0);a(this,"_z",0);a(this,"_near",0);this.horizontalAngle=e}set horizontalAngle(e){this._angleTan=Math.tan(e*.5/180*Math.PI)}setScreenFrame(e){this._screenWidth=e.width,this._screenPosX=e.x+e.width*.5,this._screenPosY=e.y+e.height*.5,this._z=this._screenWidth*.5/this._angleTan,this._near=this._z*.99}transformPosition(e,t){if(t[2]>this._near)return!1;const n=this._getScale(t);return e[0]=(t[0]-this._screenPosX)*n+this._screenPosX,e[1]=(t[1]-this._screenPosY)*n+this._screenPosY,!0}transformSize(e,t,n){const r=this._getScale(t);e[0]=n[0]*r,e[1]=n[1]*r}_getScale(e){return this._z/(this._z-e[2])}writeMatrix(e){const t=this._z,n=Number.isFinite(t)&&t>0?1/t:0;e.fill(0),e[0]=1,e[5]=1,e[8]=-this._screenPosX*n,e[9]=-this._screenPosY*n,e[11]=-n,e[15]=1}}let _installed=!1;function installPlugin(){_installed||(_installed=!0,Phaser.Loader.FileTypesManager.register("neutrino",function(s,e,t,n){if(Array.isArray(s))for(const r of s)this.addFile(new NeutrinoFile(this,r));else typeof s=="object"?this.addFile(new NeutrinoFile(this,s)):this.addFile(new NeutrinoFile(this,{key:s,url:e,options:t,xhrSettings:n}));return this}),Phaser.GameObjects.GameObjectFactory.register("neutrino",function(s,e){const t=new Effect(s,this.scene,e);return this.displayList.add(t),this.updateList.add(t),t}),Phaser.GameObjects.GameObjectCreator.register("neutrino",function(s){const e=new Effect(s.effectModel,this.scene,s);return s.add!==!1&&(this.scene.sys.displayList.add(e),this.scene.sys.updateList.add(e)),e}))}installPlugin();exports.DataTextureManager=DataTextureManager;exports.Effect=Effect;exports.EffectModel=EffectModel;exports.GamePlugin=GamePlugin;exports.NeutrinoContext=NeutrinoContext;exports.NeutrinoFile=NeutrinoFile;exports.NeutrinoRenderer=NeutrinoRenderer;exports.Pause=Pause;exports.PerspectiveProjection=PerspectiveProjection;exports.installPlugin=installPlugin;
|
|
1169
1314
|
//# sourceMappingURL=neutrinoparticles.js-v1.1-phaser.cjs.js.map
|