@neutrinoparticles/js-v1.1-phaser 1.1.0 → 1.1.2

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.
@@ -1,12 +1,20 @@
1
1
  var K = Object.defineProperty;
2
- var z = (s, e, t) => e in s ? K(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t;
3
- var n = (s, e, t) => z(s, typeof e != "symbol" ? e + "" : e, t);
2
+ var N = (s, e, t) => e in s ? K(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t;
3
+ var n = (s, e, t) => N(s, typeof e != "symbol" ? e + "" : e, t);
4
4
  import Phaser from "phaser";
5
5
  import * as Neutrino from "@neutrinoparticles/js-v1.1";
6
6
  const vertexShaderSource = `#version 300 es
7
7
  precision highp float;
8
-
9
- uniform sampler2D uDataTexture;
8
+ precision highp int;
9
+ precision highp usampler2D;
10
+
11
+ // RGBA32UI, not RGBA32F: the record mixes f32 fields with u32-packed words
12
+ // (flags, color, grid config, strip neighbor indices). Fetched as floats those
13
+ // words are subnormal/NaN patterns, which a driver may flush or canonicalize —
14
+ // Mali does (issue #348) — and a lowp/mediump float sampler may even return
15
+ // them through fp16. An integer fetch is bit-exact by spec; the f32 fields are
16
+ // reinterpreted with uintBitsToFloat, which is lossless for normal floats.
17
+ uniform usampler2D uDataTexture;
10
18
  uniform int uDataTextureWidth;
11
19
  uniform vec3 uCameraRight;
12
20
  uniform vec3 uCameraUp;
@@ -47,12 +55,16 @@ flat out int vBatchTextureIndex;
47
55
  flat out vec4 vAtlasRemap;
48
56
  flat out int vStripPath;
49
57
 
50
- vec4 fetchTexel(int globalTexelIndex) {
58
+ uvec4 fetchTexelU(int globalTexelIndex) {
51
59
  int x = globalTexelIndex % uDataTextureWidth;
52
60
  int y = globalTexelIndex / uDataTextureWidth;
53
61
  return texelFetch(uDataTexture, ivec2(x, y), 0);
54
62
  }
55
63
 
64
+ vec4 fetchTexel(int globalTexelIndex) {
65
+ return uintBitsToFloat(fetchTexelU(globalTexelIndex));
66
+ }
67
+
56
68
  // Strip geometry helpers (port of GPU33 makeScreenSpaceStrip).
57
69
  // 2D screen-space variant used by the Faced strip frame; world Z reaches
58
70
  // gl_Position only through uViewProjMatrix (ortho or v1.0-parity perspective).
@@ -66,13 +78,17 @@ void main() {
66
78
 
67
79
  int baseTexel = particleIndex * 4;
68
80
 
69
- vec4 t0 = fetchTexel(baseTexel + 0);
81
+ // Texels 0 and 3 carry the u32-packed words: keep their raw uvec4 next to
82
+ // the float view so the words never pass through a float.
83
+ uvec4 u0 = fetchTexelU(baseTexel + 0);
84
+ uvec4 u3 = fetchTexelU(baseTexel + 3);
85
+ vec4 t0 = uintBitsToFloat(u0);
70
86
  vec4 t1 = fetchTexel(baseTexel + 1);
71
87
  vec4 t2 = fetchTexel(baseTexel + 2);
72
- vec4 t3 = fetchTexel(baseTexel + 3);
88
+ vec4 t3 = uintBitsToFloat(u3);
73
89
 
74
- // Texel 0: flags (uint32 bits in float), posX, posY, posZ
75
- uint flags = floatBitsToUint(t0.r);
90
+ // Texel 0: flags (u32), posX, posY, posZ
91
+ uint flags = u0.r;
76
92
  vec3 position = t0.gba;
77
93
  uint rotationType = (flags >> 8u) & 3u;
78
94
  uint ctorType = (flags >> 10u) & 3u;
@@ -105,7 +121,8 @@ void main() {
105
121
  int siblingTexel = isCur ? (baseTexel + 4) : (baseTexel - 4);
106
122
  vec4 ts0 = fetchTexel(siblingTexel + 0);
107
123
  vec4 ts1 = fetchTexel(siblingTexel + 1);
108
- vec4 ts3 = fetchTexel(siblingTexel + 3);
124
+ uvec4 us3 = fetchTexelU(siblingTexel + 3);
125
+ vec4 ts3 = uintBitsToFloat(us3);
109
126
 
110
127
  // p1 always = position of the meta_cur end; p2 = meta_nex end.
111
128
  vec3 p1 = isCur ? t0.gba : ts0.gba;
@@ -117,8 +134,8 @@ void main() {
117
134
  float texU2 = isCur ? ts1.g : t1.g;
118
135
 
119
136
  // Color: meta_cur stores color of p1, meta_nex stores color of p2.
120
- uint packedColorCur = floatBitsToUint(isCur ? t3.r : ts3.r);
121
- uint packedColorNex = floatBitsToUint(isCur ? ts3.r : t3.r);
137
+ uint packedColorCur = isCur ? u3.r : us3.r;
138
+ uint packedColorNex = isCur ? us3.r : u3.r;
122
139
  vec4 color1 = vec4(
123
140
  float(packedColorCur & 0xFFu) / 255.0,
124
141
  float((packedColorCur >> 8u) & 0xFFu) / 255.0,
@@ -147,8 +164,8 @@ void main() {
147
164
  // Both are direct position-texel indices (NOT pair-cur indices that
148
165
  // would need a +1 offset for the nex slot). Boundary detection uses
149
166
  // selfPairCurTexel for both.
150
- uint neighborIdxP0 = floatBitsToUint(isCur ? t3.g : ts3.g);
151
- uint neighborIdxP3 = floatBitsToUint(isCur ? ts3.b : t3.b);
167
+ uint neighborIdxP0 = isCur ? u3.g : us3.g;
168
+ uint neighborIdxP3 = isCur ? us3.b : u3.b;
152
169
  uint selfPairCurTexel = uint(isCur ? baseTexel : siblingTexel) / 4u;
153
170
 
154
171
  vec3 p0 = (neighborIdxP0 == selfPairCurTexel)
@@ -521,8 +538,8 @@ void main() {
521
538
  vec2 origin = t1.rg;
522
539
  vec2 size = t1.ba;
523
540
 
524
- // Texel 3: packed colorRGBA (uint32 bits in float), packed gridConfig (uint32 bits), gridIndex
525
- uint packedColor = floatBitsToUint(t3.r);
541
+ // Texel 3: packed colorRGBA (u32), packed gridConfig (u32), gridIndex (f32)
542
+ uint packedColor = u3.r;
526
543
  vColor = vec4(
527
544
  float(packedColor & 0xFFu) / 255.0,
528
545
  float((packedColor >> 8u) & 0xFFu) / 255.0,
@@ -534,7 +551,7 @@ void main() {
534
551
  // here. S=1 for LDR colors (no-op). Alpha is untouched.
535
552
  vColor.rgb *= t3.a;
536
553
 
537
- uint gridConfig = floatBitsToUint(t3.g);
554
+ uint gridConfig = u3.g;
538
555
  float gridWidth = max(float(gridConfig & 0xFFFFu), 1.0);
539
556
  float gridHeight = max(float((gridConfig >> 16u) & 0xFFFFu), 1.0);
540
557
  // gridIndex must be truncated to an integer to pick a single cell —
@@ -601,8 +618,16 @@ void main() {
601
618
  // Texture coordinates with grid + atlas remap
602
619
  vec2 baseTexCoord = TEX_COORD[vertexIndex];
603
620
 
604
- float gx = mod(gridIndex, gridWidth);
621
+ // #283: gx must come from the SAME quotient as gy. GLSL mod(x,y) is
622
+ // x - y*floor(x/y), but the driver may evaluate its internal quotient
623
+ // differently from the floor() below (reciprocal-multiply / FMA). At exact
624
+ // multiples of gridWidth the two disagreed — mod(15,15) gave 15 while
625
+ // floor(15/15) gave 0 — addressing column 15 of a 15-column grid, whose U
626
+ // range starts at 1.0 (off the atlas), so the first cell of every row
627
+ // sampled the clamped transparent edge and vanished. The clamp keeps a
628
+ // rounding-induced gx == gridWidth inside the last column.
605
629
  float gy = floor(gridIndex / gridWidth);
630
+ float gx = clamp(gridIndex - gy * gridWidth, 0.0, gridWidth - 1.0);
606
631
  float cellW = 1.0 / gridWidth;
607
632
  float cellH = 1.0 / gridHeight;
608
633
 
@@ -688,6 +713,13 @@ void main() {
688
713
  else texColor = useGrad ? textureGrad(uTextures[7], atlasUV, gradX, gradY) : texture(uTextures[7], atlasUV);
689
714
 
690
715
  fragColor = texColor * vColor;
716
+ // Premultiply the per-particle alpha into RGB. texColor is premultiplied but
717
+ // vColor.a is not, and every blend func expects a premultiplied source:
718
+ // NORMAL (ONE, 1-src.a) would only reduce how much background shows through,
719
+ // ADD (ONE, ONE) would ignore alpha entirely, and MULTIPLY
720
+ // (DST_COLOR, 1-src.a) would brighten the destination as alpha drops instead
721
+ // of leaving it untouched.
722
+ fragColor.rgb *= vColor.a;
691
723
  // Apply host world alpha. texColor is premultiplied and the blend funcs use
692
724
  // a src factor of ONE (NORMAL) / ONE,ONE (ADD), so the whole RGBA must be
693
725
  // scaled — fading RGB, not just the alpha channel — to dim correctly in both
@@ -1227,8 +1259,12 @@ void main() {
1227
1259
  // Texture coordinates with grid + atlas remap
1228
1260
  vec2 baseTexCoord = texCoordOf(corner);
1229
1261
 
1230
- float gx = mod(gridIndex, gridWidth);
1262
+ // #283: gx must come from the SAME quotient as gy — see particle.vert.
1263
+ // mod(x,y) and a separate floor(x/y) can disagree at exact multiples of
1264
+ // gridWidth (mod(15,15) -> 15, floor(15/15) -> 0), which addressed a
1265
+ // column past the grid and blanked the first cell of every row.
1231
1266
  float gy = floor(gridIndex / gridWidth);
1267
+ float gx = clamp(gridIndex - gy * gridWidth, 0.0, gridWidth - 1.0);
1232
1268
  float cellW = 1.0 / gridWidth;
1233
1269
  float cellH = 1.0 / gridHeight;
1234
1270
 
@@ -1296,8 +1332,13 @@ void main() {
1296
1332
  // texColor is premultiplied and blend src factors are ONE-based, so the
1297
1333
  // world alpha scales the whole RGBA (mirror of the ES 3.00 shader).
1298
1334
  gl_FragColor = texColor * vColor * uWorldAlpha;
1335
+ // Premultiply the per-particle alpha into RGB: vColor.a is not premultiplied,
1336
+ // so without this ADD ignores alpha entirely, NORMAL only reduces background
1337
+ // show-through, and MULTIPLY brightens the destination as alpha drops.
1338
+ // Mirror of the ES 3.00 shader.
1339
+ gl_FragColor.rgb *= vColor.a;
1299
1340
  }
1300
- `, A = class A {
1341
+ `, S = class S {
1301
1342
  constructor(e, t) {
1302
1343
  n(this, "neutrino");
1303
1344
  // On a WebGL1 context this actually holds a WebGLRenderingContext; the
@@ -1310,7 +1351,7 @@ void main() {
1310
1351
  n(this, "_vao", null);
1311
1352
  // WebGL1 render path state (TDD_js-v1.1-webgl1.md)
1312
1353
  n(this, "_isWebGL1", !1);
1313
- n(this, "_maxBatchTextures", A.MAX_BATCH_TEXTURES);
1354
+ n(this, "_maxBatchTextures", S.MAX_BATCH_TEXTURES);
1314
1355
  n(this, "_hasElementIndexUint", !1);
1315
1356
  n(this, "_vaoExt", null);
1316
1357
  n(this, "_aIdBuffer", null);
@@ -1413,14 +1454,14 @@ void main() {
1413
1454
  throw new Error(
1414
1455
  `NeutrinoParticles (js-v1.1): the effect needs 32-bit indices (${e} particles) but this WebGL1 context lacks OES_element_index_uint.`
1415
1456
  );
1416
- const c = l ? new Uint32Array(e * 6) : new Uint16Array(e * 6);
1457
+ const d = l ? new Uint32Array(e * 6) : new Uint16Array(e * 6);
1417
1458
  for (let i = 0; i < e; i++) {
1418
- const u = i * 4, _ = i * 6;
1419
- c[_ + 0] = u + 0, c[_ + 1] = u + 1, c[_ + 2] = u + 2, c[_ + 3] = u + 0, c[_ + 4] = u + 2, c[_ + 5] = u + 3;
1459
+ const c = i * 4, g = i * 6;
1460
+ d[g + 0] = c + 0, d[g + 1] = c + 1, d[g + 2] = c + 2, d[g + 3] = c + 0, d[g + 4] = c + 2, d[g + 5] = c + 3;
1420
1461
  }
1421
- 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) {
1462
+ if (this._indexBuffer = t.createBuffer(), t.bindBuffer(t.ELEMENT_ARRAY_BUFFER, this._indexBuffer), t.bufferData(t.ELEMENT_ARRAY_BUFFER, d, t.STATIC_DRAW), this._isWebGL1) {
1422
1463
  const i = new Float32Array(e * 4);
1423
- for (let u = 0; u < i.length; u++) i[u] = u;
1464
+ for (let c = 0; c < i.length; c++) i[c] = c;
1424
1465
  this._aIdBuffer = t.createBuffer(), t.bindBuffer(t.ARRAY_BUFFER, this._aIdBuffer), t.bufferData(t.ARRAY_BUFFER, i, t.STATIC_DRAW);
1425
1466
  } else
1426
1467
  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(a);
@@ -1470,7 +1511,7 @@ void main() {
1470
1511
  const r = e.getParameter(e.MAX_COMBINED_TEXTURE_IMAGE_UNITS), o = e.getParameter(e.MAX_TEXTURE_IMAGE_UNITS);
1471
1512
  this._maxBatchTextures = Math.max(
1472
1513
  1,
1473
- Math.min(A.MAX_BATCH_TEXTURES, r - 2, o)
1514
+ Math.min(S.MAX_BATCH_TEXTURES, r - 2, o)
1474
1515
  );
1475
1516
  }
1476
1517
  /**
@@ -1495,33 +1536,33 @@ void main() {
1495
1536
  `, a = `precision mediump float;
1496
1537
  varying vec4 vC;
1497
1538
  void main() { gl_FragColor = vC; }
1498
- `, 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);
1539
+ `, r = e.getParameter(e.VIEWPORT), o = e.getParameter(e.CURRENT_PROGRAM), l = e.getParameter(e.ARRAY_BUFFER_BINDING), d = e.getParameter(e.FRAMEBUFFER_BINDING), i = e.getParameter(e.ACTIVE_TEXTURE);
1499
1540
  e.activeTexture(e.TEXTURE0);
1500
- const u = e.getParameter(e.TEXTURE_BINDING_2D);
1541
+ const c = e.getParameter(e.TEXTURE_BINDING_2D);
1501
1542
  e.activeTexture(e.TEXTURE1);
1502
- const _ = e.getParameter(e.TEXTURE_BINDING_2D), y = e.isEnabled(e.BLEND), E = e.isEnabled(e.DEPTH_TEST), I = e.isEnabled(e.SCISSOR_TEST);
1503
- let m = null, w = null, B = null, f = null, v = null, g = null, d = -1, b = !1, x = null, h = 4, U = 0, p = 0, R = 0, D = !1, S = !1;
1504
- const T = new Uint8Array(4);
1543
+ const g = e.getParameter(e.TEXTURE_BINDING_2D), U = e.isEnabled(e.BLEND), P = e.isEnabled(e.DEPTH_TEST), A = e.isEnabled(e.SCISSOR_TEST);
1544
+ let v = null, b = null, R = null, y = null, x = null, m = null, u = -1, T = !1, E = null, p = 4, h = 0, f = 0, w = 0, C = !1, B = !1;
1545
+ const _ = new Uint8Array(4);
1505
1546
  try {
1506
- m = e.createProgram(), e.attachShader(m, this._compileShader(e.VERTEX_SHADER, t)), e.attachShader(m, this._compileShader(e.FRAGMENT_SHADER, a)), e.linkProgram(m);
1507
- const C = (P, F) => {
1547
+ v = e.createProgram(), e.attachShader(v, this._compileShader(e.VERTEX_SHADER, t)), e.attachShader(v, this._compileShader(e.FRAGMENT_SHADER, a)), e.linkProgram(v);
1548
+ const D = (I, F) => {
1508
1549
  const M = e.createTexture();
1509
- 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, P, F), M;
1550
+ 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, I, F), M;
1510
1551
  };
1511
- e.activeTexture(e.TEXTURE0), w = C(e.FLOAT, new Float32Array([1, 0.5, 0.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, w), 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"), b = 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), R = 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);
1552
+ e.activeTexture(e.TEXTURE0), b = D(e.FLOAT, new Float32Array([1, 0.5, 0.25, 1])), R = D(e.UNSIGNED_BYTE, new Uint8Array([51, 102, 153, 255])), y = e.createTexture(), e.bindTexture(e.TEXTURE_2D, y), e.texImage2D(e.TEXTURE_2D, 0, e.RGBA, 1, 1, 0, e.RGBA, e.UNSIGNED_BYTE, null), x = e.createFramebuffer(), e.bindFramebuffer(e.FRAMEBUFFER, x), e.framebufferTexture2D(e.FRAMEBUFFER, e.COLOR_ATTACHMENT0, e.TEXTURE_2D, y, 0), m = e.createBuffer(), e.bindBuffer(e.ARRAY_BUFFER, m), e.bufferData(e.ARRAY_BUFFER, new Float32Array([0]), e.STATIC_DRAW), B = e.getProgramParameter(v, e.LINK_STATUS), B && (e.useProgram(v), e.activeTexture(e.TEXTURE0), e.bindTexture(e.TEXTURE_2D, b), e.activeTexture(e.TEXTURE1), e.bindTexture(e.TEXTURE_2D, R), e.uniform1i(e.getUniformLocation(v, "uF"), 0), e.uniform1i(e.getUniformLocation(v, "uB"), 1), u = e.getAttribLocation(v, "aId"), T = e.getVertexAttrib(u, e.VERTEX_ATTRIB_ARRAY_ENABLED), E = e.getVertexAttrib(u, e.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING), p = e.getVertexAttrib(u, e.VERTEX_ATTRIB_ARRAY_SIZE), h = e.getVertexAttrib(u, e.VERTEX_ATTRIB_ARRAY_TYPE), C = e.getVertexAttrib(u, e.VERTEX_ATTRIB_ARRAY_NORMALIZED), f = e.getVertexAttrib(u, e.VERTEX_ATTRIB_ARRAY_STRIDE), w = e.getVertexAttribOffset(u, e.VERTEX_ATTRIB_ARRAY_POINTER), e.enableVertexAttribArray(u), e.vertexAttribPointer(u, 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, _), B = Math.abs(_[0] - 51) <= 2 && Math.abs(_[1] - 51) <= 2 && Math.abs(_[2] - 38) <= 2);
1512
1553
  } finally {
1513
- d >= 0 && (x && (e.bindBuffer(e.ARRAY_BUFFER, x), e.vertexAttribPointer(
1514
- d,
1515
- h,
1516
- U,
1517
- D,
1554
+ u >= 0 && (E && (e.bindBuffer(e.ARRAY_BUFFER, E), e.vertexAttribPointer(
1555
+ u,
1518
1556
  p,
1519
- R
1520
- )), b ? e.enableVertexAttribArray(d) : e.disableVertexAttribArray(d)), v && e.deleteFramebuffer(v), f && e.deleteTexture(f), w && e.deleteTexture(w), 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]);
1557
+ h,
1558
+ C,
1559
+ f,
1560
+ w
1561
+ )), T ? e.enableVertexAttribArray(u) : e.disableVertexAttribArray(u)), x && e.deleteFramebuffer(x), y && e.deleteTexture(y), b && e.deleteTexture(b), R && e.deleteTexture(R), m && e.deleteBuffer(m), v && e.deleteProgram(v), e.bindFramebuffer(e.FRAMEBUFFER, d), e.bindBuffer(e.ARRAY_BUFFER, l), e.useProgram(o), e.activeTexture(e.TEXTURE0), e.bindTexture(e.TEXTURE_2D, c), e.activeTexture(e.TEXTURE1), e.bindTexture(e.TEXTURE_2D, g), e.activeTexture(i), U && e.enable(e.BLEND), P && e.enable(e.DEPTH_TEST), A && e.enable(e.SCISSOR_TEST), e.viewport(r[0], r[1], r[2], r[3]);
1521
1562
  }
1522
- if (!S)
1563
+ if (!B)
1523
1564
  throw new Error(
1524
- `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.`
1565
+ `NeutrinoParticles (js-v1.1): WebGL1 vertex texture fetch smoke test failed (got ${_[0]},${_[1]},${_[2]}); WebGL2 or WebGL1 with working vertex float textures is required.`
1525
1566
  );
1526
1567
  }
1527
1568
  _initShader() {
@@ -1529,7 +1570,7 @@ void main() { gl_FragColor = vC; }
1529
1570
  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))
1530
1571
  throw new Error("Shader link error: " + e.getProgramInfoLog(this._shaderProgram));
1531
1572
  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 = [];
1532
- for (let l = 0; l < A.MAX_BATCH_TEXTURES; l++)
1573
+ for (let l = 0; l < S.MAX_BATCH_TEXTURES; l++)
1533
1574
  this._uTextures.push(e.getUniformLocation(this._shaderProgram, `uTextures[${l}]`)), this._uTexRemaps.push(e.getUniformLocation(this._shaderProgram, `uTexRemaps[${l}]`));
1534
1575
  }
1535
1576
  _compileShader(e, t) {
@@ -1541,8 +1582,8 @@ void main() { gl_FragColor = vC; }
1541
1582
  return r;
1542
1583
  }
1543
1584
  };
1544
- n(A, "MAX_BATCH_TEXTURES", 8);
1545
- let NeutrinoContext = A;
1585
+ n(S, "MAX_BATCH_TEXTURES", 8);
1586
+ let NeutrinoContext = S;
1546
1587
  class GamePlugin extends Phaser.Plugins.BasePlugin {
1547
1588
  constructor() {
1548
1589
  super(...arguments);
@@ -1610,14 +1651,14 @@ return new NeutrinoEffect(ctx);
1610
1651
  const a = this.effectModel.textures[t], r = this.gamePlugin.texturesBasePath + a, o = noext(r);
1611
1652
  let l = this._findFrameInAtlases(s, a);
1612
1653
  if (l || (l = this._findFrameInAtlases(s, noext(a))), !l && this.scene.sys.textures.exists(o)) {
1613
- const c = this.scene.sys.textures.get(o);
1614
- l = c.get(c.firstFrame);
1654
+ const d = this.scene.sys.textures.get(o);
1655
+ l = d.get(d.firstFrame);
1615
1656
  }
1616
1657
  l ? this._onTextureLoaded(t, l) : (this.scene.load.once(
1617
1658
  "filecomplete-image-" + o,
1618
- /* @__PURE__ */ ((c, i) => () => {
1619
- const u = this.scene.sys.textures.get(i);
1620
- this._onTextureLoaded(c, u.get(u.firstFrame));
1659
+ /* @__PURE__ */ ((d, i) => () => {
1660
+ const c = this.scene.sys.textures.get(i);
1661
+ this._onTextureLoaded(d, c.get(c.firstFrame));
1621
1662
  })(t, o)
1622
1663
  ), this.scene.load.image(o, r));
1623
1664
  }
@@ -1660,14 +1701,14 @@ return new NeutrinoEffect(ctx);
1660
1701
  }
1661
1702
  class NeutrinoFile extends Phaser.Loader.File {
1662
1703
  constructor(t, a) {
1663
- const { key: r, url: o, options: l, xhrSettings: c } = a;
1704
+ const { key: r, url: o, options: l, xhrSettings: d } = a;
1664
1705
  super(t, {
1665
1706
  type: "binary",
1666
1707
  extension: "js",
1667
1708
  responseType: "text",
1668
1709
  key: r,
1669
1710
  url: o,
1670
- xhrSettings: c
1711
+ xhrSettings: d
1671
1712
  });
1672
1713
  n(this, "_options");
1673
1714
  this.cache = t.cacheManager.binary, this._options = l;
@@ -1683,9 +1724,7 @@ const RING_BUFFER_SIZE$1 = 3;
1683
1724
  class DataTextureManager {
1684
1725
  /**
1685
1726
  * @param gl - WebGL2 context (from the host renderer)
1686
- * @param data - Uint32Array from the runtime. A Float32Array view over the
1687
- * same buffer is uploaded as RGBA32F — bit patterns (incl. NaN/Inf) pass
1688
- * through unchanged.
1727
+ * @param data - Uint32Array from the runtime, uploaded as-is as RGBA32UI.
1689
1728
  * @param textureWidth - from runtime (system.dataTextureWidth)
1690
1729
  * @param textureHeight - from runtime (system.dataTextureHeight)
1691
1730
  */
@@ -1693,7 +1732,7 @@ class DataTextureManager {
1693
1732
  n(this, "textureWidth");
1694
1733
  n(this, "textureHeight");
1695
1734
  n(this, "_gl");
1696
- n(this, "_floatView");
1735
+ n(this, "_data");
1697
1736
  n(this, "_textures", []);
1698
1737
  n(this, "_currentIndex", 0);
1699
1738
  const o = e.getParameter(e.MAX_TEXTURE_SIZE);
@@ -1701,20 +1740,20 @@ class DataTextureManager {
1701
1740
  throw new Error(
1702
1741
  `NeutrinoParticles: data texture ${a}x${r} exceeds GL MAX_TEXTURE_SIZE (${o}). Reduce effect particle capacity.`
1703
1742
  );
1704
- this._gl = e, this.textureWidth = a, this.textureHeight = r, this._floatView = new Float32Array(t.buffer, t.byteOffset, t.length);
1743
+ this._gl = e, this.textureWidth = a, this.textureHeight = r, this._data = t;
1705
1744
  for (let l = 0; l < RING_BUFFER_SIZE$1; l++) {
1706
- const c = e.createTexture();
1707
- 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(
1745
+ const d = e.createTexture();
1746
+ e.bindTexture(e.TEXTURE_2D, d), 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(
1708
1747
  e.TEXTURE_2D,
1709
1748
  0,
1710
- e.RGBA32F,
1749
+ e.RGBA32UI,
1711
1750
  a,
1712
1751
  r,
1713
1752
  0,
1714
- e.RGBA,
1715
- e.FLOAT,
1753
+ e.RGBA_INTEGER,
1754
+ e.UNSIGNED_INT,
1716
1755
  null
1717
- ), this._textures.push(c);
1756
+ ), this._textures.push(d);
1718
1757
  }
1719
1758
  e.bindTexture(e.TEXTURE_2D, null);
1720
1759
  }
@@ -1731,9 +1770,9 @@ class DataTextureManager {
1731
1770
  0,
1732
1771
  this.textureWidth,
1733
1772
  this.textureHeight,
1734
- t.RGBA,
1735
- t.FLOAT,
1736
- this._floatView
1773
+ t.RGBA_INTEGER,
1774
+ t.UNSIGNED_INT,
1775
+ this._data
1737
1776
  );
1738
1777
  }
1739
1778
  advance() {
@@ -1791,10 +1830,10 @@ class DataTextureManagerGL1 {
1791
1830
  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);
1792
1831
  const l = e.getParameter(e.ACTIVE_TEXTURE);
1793
1832
  e.activeTexture(e.TEXTURE0);
1794
- const c = e.getParameter(e.TEXTURE_BINDING_2D);
1833
+ const d = e.getParameter(e.TEXTURE_BINDING_2D);
1795
1834
  for (let i = 0; i < RING_BUFFER_SIZE; i++)
1796
1835
  this._dataTextures.push(this._createTexture(e.FLOAT)), this._metaTextures.push(this._createTexture(e.UNSIGNED_BYTE));
1797
- e.bindTexture(e.TEXTURE_2D, c), e.activeTexture(l);
1836
+ e.bindTexture(e.TEXTURE_2D, d), e.activeTexture(l);
1798
1837
  }
1799
1838
  get currentDataTexture() {
1800
1839
  return this._dataTextures[this._currentIndex];
@@ -1810,7 +1849,7 @@ class DataTextureManagerGL1 {
1810
1849
  upload(e, t, a) {
1811
1850
  const r = this._gl, o = this.textureWidth, l = Math.min(this.textureHeight, Math.ceil(e * 4 / o));
1812
1851
  if (l === 0) return;
1813
- const c = l * o * 4;
1852
+ const d = l * o * 4;
1814
1853
  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(
1815
1854
  r.TEXTURE_2D,
1816
1855
  0,
@@ -1820,7 +1859,7 @@ class DataTextureManagerGL1 {
1820
1859
  l,
1821
1860
  r.RGBA,
1822
1861
  r.FLOAT,
1823
- this._floatView.subarray(0, c)
1862
+ this._floatView.subarray(0, d)
1824
1863
  ), r.activeTexture(r.TEXTURE0 + a), r.bindTexture(r.TEXTURE_2D, this.currentMetaTexture), r.texSubImage2D(
1825
1864
  r.TEXTURE_2D,
1826
1865
  0,
@@ -1830,7 +1869,7 @@ class DataTextureManagerGL1 {
1830
1869
  l,
1831
1870
  r.RGBA,
1832
1871
  r.UNSIGNED_BYTE,
1833
- this.meta.bytes.subarray(0, c)
1872
+ this.meta.bytes.subarray(0, d)
1834
1873
  );
1835
1874
  }
1836
1875
  advance() {
@@ -1881,82 +1920,87 @@ class NeutrinoRenderer {
1881
1920
  n(this, "_texSlotMap", /* @__PURE__ */ new Map());
1882
1921
  n(this, "_batchPool");
1883
1922
  n(this, "_batchCount", 0);
1923
+ n(this, "_samplerUnitsProgram", null);
1884
1924
  this._batchPool = [];
1885
1925
  for (let e = 0; e < MAX_BATCHES; e++)
1886
1926
  this._batchPool.push(new DrawBatch());
1887
1927
  }
1888
- render(e, t, a, r, o, l, c) {
1928
+ render(e, t, a, r, o, l, d) {
1889
1929
  if (l === 0) return;
1890
- const i = e.gl, u = e.isWebGL1, _ = e.maxBatchTextures, y = c.renderStyles, E = c.materials, I = u ? t.meta : null;
1891
- I && I.build(r, l), this._batchCount = 0;
1892
- const m = this._texSlotMap;
1930
+ const i = e.gl, c = e.isWebGL1, g = c ? PARTICLE_TEXTURE_START_UNIT_GL1 : PARTICLE_TEXTURE_START_UNIT, U = e.maxBatchTextures, P = d.renderStyles, A = d.materials, v = c ? t.meta : null;
1931
+ v && v.build(r, l), this._batchCount = 0;
1932
+ const b = this._texSlotMap;
1893
1933
  for (; this._batchPool.length < o.length; )
1894
1934
  this._batchPool.push(new DrawBatch());
1895
- let w = 0;
1896
- for (; w < o.length; ) {
1897
- const f = this._batchPool[this._batchCount];
1898
- f.reset(), f.blendMode = this._resolveBlend(o[w].blendMode, E), f.startParticle = o[w].startParticleIndex, m.clear();
1899
- let v = w;
1900
- for (; v < o.length && this._resolveBlend(o[v].blendMode, E) === f.blendMode; ) {
1901
- const g = y[o[v].renderStyleIndex].textureIndices[0];
1902
- if (!m.has(g)) {
1903
- if (m.size >= _) break;
1904
- const x = m.size;
1905
- m.set(g, x), f.glTextures[x] = c.glTextures[g] || null, f.remaps[x] = c.remaps[g] || null, f.numTextures = x + 1;
1935
+ let R = 0;
1936
+ for (; R < o.length; ) {
1937
+ const x = this._batchPool[this._batchCount];
1938
+ x.reset(), x.blendMode = this._resolveBlend(o[R].blendMode, A), x.startParticle = o[R].startParticleIndex, b.clear();
1939
+ let m = R;
1940
+ for (; m < o.length && this._resolveBlend(o[m].blendMode, A) === x.blendMode; ) {
1941
+ const u = P[o[m].renderStyleIndex].textureIndices[0];
1942
+ if (!b.has(u)) {
1943
+ if (b.size >= U) break;
1944
+ const p = b.size;
1945
+ b.set(u, p), x.glTextures[p] = d.glTextures[u] || null, x.remaps[p] = d.remaps[u] || null, x.numTextures = p + 1;
1906
1946
  }
1907
- const d = m.get(g), b = o[v];
1908
- if (I)
1909
- I.patchSlot(b.startParticleIndex, b.numParticles, d);
1910
- else if (d !== 0)
1911
- for (let x = 0; x < b.numParticles; x++) {
1912
- const h = (b.startParticleIndex + x) * BYTES_PER_PARTICLE, U = a.getUint32(h, !0);
1913
- a.setUint32(h, U & 4294967040 | d, !0);
1947
+ const T = b.get(u), E = o[m];
1948
+ if (v)
1949
+ v.patchSlot(E.startParticleIndex, E.numParticles, T);
1950
+ else if (T !== 0)
1951
+ for (let p = 0; p < E.numParticles; p++) {
1952
+ const h = (E.startParticleIndex + p) * BYTES_PER_PARTICLE, f = a.getUint32(h, !0);
1953
+ a.setUint32(h, f & 4294967040 | T, !0);
1914
1954
  }
1915
- f.numParticles += b.numParticles, v++;
1955
+ x.numParticles += E.numParticles, m++;
1916
1956
  }
1917
- this._batchCount++, w = v;
1957
+ this._batchCount++, R = m;
1918
1958
  }
1919
- const B = i.isEnabled(i.SCISSOR_TEST);
1959
+ const y = i.isEnabled(i.SCISSOR_TEST);
1920
1960
  try {
1921
- 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) {
1922
- const p = t;
1923
- 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);
1961
+ 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), this._samplerUnitsProgram !== e.shaderProgram) {
1962
+ const f = c ? e.maxBatchTextures : NeutrinoContext.MAX_BATCH_TEXTURES;
1963
+ for (let w = 0; w < f; w++)
1964
+ i.uniform1i(e.uTextures[w], g + w);
1965
+ this._samplerUnitsProgram = e.shaderProgram;
1966
+ }
1967
+ if (c) {
1968
+ const f = t;
1969
+ f.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, f.textureWidth, f.textureHeight);
1924
1970
  } else {
1925
- const p = t;
1926
- p.uploadAndBind(DATA_TEXTURE_UNIT), i.uniform1i(e.uDataTexture, DATA_TEXTURE_UNIT), i.uniform1i(e.uDataTextureWidth, p.textureWidth);
1971
+ const f = t;
1972
+ f.uploadAndBind(DATA_TEXTURE_UNIT), i.uniform1i(e.uDataTexture, DATA_TEXTURE_UNIT), i.uniform1i(e.uDataTextureWidth, f.textureWidth);
1927
1973
  }
1928
1974
  i.uniform3f(e.uCameraRight, 1, 0, 0), i.uniform3f(e.uCameraUp, 0, -1, 0), i.uniform3f(e.uCameraDir, 0, 0, -1);
1929
- const f = c.viewportWidth, v = c.viewportHeight, g = c.zoom || 1, d = this._orthoMatrix;
1930
- 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) {
1931
- const p = this._projFrame;
1932
- 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);
1975
+ const x = d.viewportWidth, m = d.viewportHeight, u = d.zoom || 1, T = this._orthoMatrix;
1976
+ if (T.fill(0), T[0] = 2 / x * u, T[5] = -2 / m * u, T[10] = 0, T[15] = 1, T[12] = -1 - 2 / x * u * d.scrollX, T[13] = 1 + 2 / m * u * d.scrollY, d.projection) {
1977
+ const f = this._projFrame;
1978
+ f.x = 0, f.y = 0, f.width = x, f.height = m, d.projection.setScreenFrame(f), d.projection.writeMatrix(this._perspMatrix), this._mulMatrix(this._vpMatrix, T, this._perspMatrix), i.uniformMatrix4fv(e.uViewProjMatrix, !1, this._vpMatrix);
1933
1979
  } else
1934
- i.uniformMatrix4fv(e.uViewProjMatrix, !1, d);
1935
- const b = v > 0 ? f / v : 1;
1936
- e.uViewportAspect && i.uniform1f(e.uViewportAspect, b), e.uWorldAlpha && i.uniform1f(e.uWorldAlpha, c.worldAlpha);
1937
- const x = c.model, h = this._modelMatrix;
1938
- 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);
1939
- const U = u ? PARTICLE_TEXTURE_START_UNIT_GL1 : PARTICLE_TEXTURE_START_UNIT;
1940
- i.enable(i.BLEND);
1941
- for (let p = 0; p < this._batchCount; p++) {
1942
- const R = this._batchPool[p];
1943
- this._applyBlendMode(i, R.blendMode);
1944
- for (let T = 0; T < R.numTextures; T++) {
1945
- const C = U + T;
1946
- i.activeTexture(i.TEXTURE0 + C), i.bindTexture(i.TEXTURE_2D, R.glTextures[T]), i.uniform1i(e.uTextures[T], C);
1947
- const P = R.remaps[T];
1948
- P ? i.uniform4f(e.uTexRemaps[T], P.x, P.y, P.width, P.height) : i.uniform4f(e.uTexRemaps[T], 0, 0, 1, 1);
1980
+ i.uniformMatrix4fv(e.uViewProjMatrix, !1, T);
1981
+ const E = m > 0 ? x / m : 1;
1982
+ e.uViewportAspect && i.uniform1f(e.uViewportAspect, E), e.uWorldAlpha && i.uniform1f(e.uWorldAlpha, d.worldAlpha);
1983
+ const p = d.model, h = this._modelMatrix;
1984
+ h[0] = p.a, h[1] = p.b, h[2] = 0, h[3] = 0, h[4] = p.c, h[5] = p.d, h[6] = 0, h[7] = 0, h[8] = 0, h[9] = 0, h[10] = 1, h[11] = 0, h[12] = p.tx, h[13] = p.ty, h[14] = 0, h[15] = 1, i.uniformMatrix4fv(e.uModelMatrix, !1, h), c ? (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), i.enable(i.BLEND);
1985
+ for (let f = 0; f < this._batchCount; f++) {
1986
+ const w = this._batchPool[f];
1987
+ this._applyBlendMode(i, w.blendMode);
1988
+ for (let _ = 0; _ < w.numTextures; _++) {
1989
+ const D = g + _;
1990
+ i.activeTexture(i.TEXTURE0 + D), i.bindTexture(i.TEXTURE_2D, w.glTextures[_]);
1991
+ const I = w.remaps[_];
1992
+ I ? i.uniform4f(e.uTexRemaps[_], I.x, I.y, I.width, I.height) : i.uniform4f(e.uTexRemaps[_], 0, 0, 1, 1);
1949
1993
  }
1950
- const D = R.startParticle * 6, S = R.numParticles * 6;
1994
+ const C = w.startParticle * 6, B = w.numParticles * 6;
1951
1995
  i.drawElements(
1952
1996
  i.TRIANGLES,
1953
- S,
1997
+ B,
1954
1998
  e.indexType,
1955
- D * (e.indexType === i.UNSIGNED_INT ? 4 : 2)
1999
+ C * (e.indexType === i.UNSIGNED_INT ? 4 : 2)
1956
2000
  );
1957
2001
  }
1958
2002
  } finally {
1959
- 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);
2003
+ c ? (i.disableVertexAttribArray(e.aIdLocation), i.bindBuffer(i.ARRAY_BUFFER, null), i.bindBuffer(i.ELEMENT_ARRAY_BUFFER, null)) : i.bindVertexArray(null), i.useProgram(null), i.activeTexture(i.TEXTURE0 + DATA_TEXTURE_UNIT), i.bindTexture(i.TEXTURE_2D, null), y && i.enable(i.SCISSOR_TEST);
1960
2004
  }
1961
2005
  }
1962
2006
  // Resolve a renderStyle's compacted material INDEX to the real blend enum (0=Normal/
@@ -1968,8 +2012,8 @@ class NeutrinoRenderer {
1968
2012
  // Column-major 4x4 multiply: out = a * b. Preallocated outputs only.
1969
2013
  _mulMatrix(e, t, a) {
1970
2014
  for (let r = 0; r < 16; r += 4) {
1971
- const o = a[r], l = a[r + 1], c = a[r + 2], i = a[r + 3];
1972
- 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;
2015
+ const o = a[r], l = a[r + 1], d = a[r + 2], i = a[r + 3];
2016
+ e[r] = t[0] * o + t[4] * l + t[8] * d + t[12] * i, e[r + 1] = t[1] * o + t[5] * l + t[9] * d + t[13] * i, e[r + 2] = t[2] * o + t[6] * l + t[10] * d + t[14] * i, e[r + 3] = t[3] * o + t[7] * l + t[11] * d + t[15] * i;
1973
2017
  }
1974
2018
  }
1975
2019
  _resolveBlend(e, t) {
@@ -2060,24 +2104,24 @@ class Effect extends Phaser.GameObjects.GameObject {
2060
2104
  this._checkUnpauseOnUpdateRender();
2061
2105
  const o = this.gamePlugin.ctx, l = this._dataTextureManager;
2062
2106
  this.effect.construct([0, 0, -1]);
2063
- const c = this.effect.renderInstructions, i = c._totalParticles;
2107
+ const d = this.effect.renderInstructions, i = d._totalParticles;
2064
2108
  if (i === 0) return;
2065
2109
  t.flush();
2066
- const u = this.effectModel.effectModel.textures.length, _ = this._glTexturesScratch;
2067
- _.length = u;
2068
- for (let E = 0; E < u; ++E)
2069
- _[E] = this.effectModel.glTexture(E);
2070
- const y = this._worldScale;
2110
+ const c = this.effectModel.effectModel.textures.length, g = this._glTexturesScratch;
2111
+ g.length = c;
2112
+ for (let P = 0; P < c; ++P)
2113
+ g[P] = this.effectModel.glTexture(P);
2114
+ const U = this._worldScale;
2071
2115
  try {
2072
2116
  sharedRenderer.render(
2073
2117
  o,
2074
2118
  l,
2075
2119
  this.effect.particleDataView,
2076
2120
  this.effect.particleDataUint32,
2077
- c,
2121
+ d,
2078
2122
  i,
2079
2123
  {
2080
- model: { a: y, b: 0, c: 0, d: y, tx: 0, ty: 0 },
2124
+ model: { a: U, b: 0, c: 0, d: U, tx: 0, ty: 0 },
2081
2125
  viewportWidth: t.width,
2082
2126
  viewportHeight: t.height,
2083
2127
  scrollX: r.scrollX * this.scrollFactorX,
@@ -2085,7 +2129,7 @@ class Effect extends Phaser.GameObjects.GameObject {
2085
2129
  zoom: r.zoom,
2086
2130
  worldAlpha: this.alpha,
2087
2131
  projection: this.projection,
2088
- glTextures: _,
2132
+ glTextures: g,
2089
2133
  remaps: this.effectModel.texturesRemap,
2090
2134
  renderStyles: this.effect.model.renderStyles,
2091
2135
  materials: this.effect.model.materials
@@ -2156,8 +2200,8 @@ class Effect extends Phaser.GameObjects.GameObject {
2156
2200
  _updateWorldTransform() {
2157
2201
  const t = (o, l) => {
2158
2202
  if (!o) return;
2159
- const c = this._tempMatrix2;
2160
- 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) * 0.5, t(o.parentContainer, l);
2203
+ const d = this._tempMatrix2;
2204
+ d.applyITRS(o.x, o.y, o.rotation, o.scaleX, o.scaleY), d.multiply(l.matrix, l.matrix), l.angle += o.angle, l.scale *= (o.scaleX + o.scaleY) * 0.5, t(o.parentContainer, l);
2161
2205
  }, a = {
2162
2206
  matrix: this._tempMatrix1.loadIdentity(),
2163
2207
  angle: this.angle,