melonjs 20.1.1 → 20.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/build/application/settings.d.ts +3 -2
- package/build/application/settings.d.ts.map +1 -1
- package/build/index.js +1304 -219
- package/build/index.js.map +4 -4
- package/build/input/pointerevent.d.ts.map +1 -1
- package/build/particles/emitter.d.ts +81 -3
- package/build/particles/emitter.d.ts.map +1 -1
- package/build/particles/particle.d.ts +62 -1
- package/build/particles/particle.d.ts.map +1 -1
- package/build/particles/settings.d.ts +50 -7
- package/build/particles/settings.d.ts.map +1 -1
- package/build/renderable/container.d.ts +10 -0
- package/build/renderable/container.d.ts.map +1 -1
- package/build/renderable/entity/entity.d.ts +10 -0
- package/build/renderable/entity/entity.d.ts.map +1 -1
- package/build/renderable/renderable.d.ts +106 -22
- package/build/renderable/renderable.d.ts.map +1 -1
- package/build/video/blendmodes.d.ts +107 -0
- package/build/video/blendmodes.d.ts.map +1 -0
- package/build/video/canvas/canvas_renderer.d.ts +28 -24
- package/build/video/canvas/canvas_renderer.d.ts.map +1 -1
- package/build/video/effects/blendEffect.d.ts +57 -0
- package/build/video/effects/blendEffect.d.ts.map +1 -0
- package/build/video/renderer.d.ts +3 -4
- package/build/video/renderer.d.ts.map +1 -1
- package/build/video/rendertarget/canvasrendertarget.d.ts +1 -0
- package/build/video/rendertarget/canvasrendertarget.d.ts.map +1 -1
- package/build/video/webgl/batchers/batcher.d.ts.map +1 -1
- package/build/video/webgl/glshader.d.ts.map +1 -1
- package/build/video/webgl/utils/program.d.ts.map +1 -1
- package/build/video/webgl/webgl_renderer.d.ts +116 -29
- package/build/video/webgl/webgl_renderer.d.ts.map +1 -1
- package/build/video/webgpu/batchers/quad_batcher.d.ts +7 -0
- package/build/video/webgpu/batchers/quad_batcher.d.ts.map +1 -1
- package/build/video/webgpu/pipeline/cache.d.ts +0 -9
- package/build/video/webgpu/pipeline/cache.d.ts.map +1 -1
- package/build/video/webgpu/webgpu_renderer.d.ts +100 -6
- package/build/video/webgpu/webgpu_renderer.d.ts.map +1 -1
- package/package.json +3 -3
package/build/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* melonJS Game Engine - 20.
|
|
2
|
+
* melonJS Game Engine - 20.2.0
|
|
3
3
|
* http://www.melonjs.org
|
|
4
4
|
* melonjs is licensed under the MIT License.
|
|
5
5
|
* http://www.opensource.org/licenses/mit-license
|
|
@@ -7770,6 +7770,20 @@ var CanvasRenderTarget = class extends RenderTarget {
|
|
|
7770
7770
|
* @param {CanvasRenderer|WebGLRenderer} renderer - the renderer to which this canvas texture is attached
|
|
7771
7771
|
*/
|
|
7772
7772
|
invalidate(renderer) {
|
|
7773
|
+
const busy = renderer._advancedBlendBusy;
|
|
7774
|
+
if (typeof busy === "number") {
|
|
7775
|
+
renderer._advancedBlendBusy = busy + 1;
|
|
7776
|
+
}
|
|
7777
|
+
try {
|
|
7778
|
+
this.#invalidate(renderer);
|
|
7779
|
+
} finally {
|
|
7780
|
+
if (typeof busy === "number") {
|
|
7781
|
+
renderer._advancedBlendBusy = busy;
|
|
7782
|
+
}
|
|
7783
|
+
}
|
|
7784
|
+
}
|
|
7785
|
+
/** @ignore */
|
|
7786
|
+
#invalidate(renderer) {
|
|
7773
7787
|
if (renderer.type.startsWith("WebGL")) {
|
|
7774
7788
|
renderer.flush();
|
|
7775
7789
|
renderer.setBatcher("quad");
|
|
@@ -10807,11 +10821,10 @@ var Renderer = class _Renderer {
|
|
|
10807
10821
|
return this.currentBlendMode;
|
|
10808
10822
|
}
|
|
10809
10823
|
/**
|
|
10810
|
-
* set the current blend mode.
|
|
10811
|
-
*
|
|
10812
|
-
* lands) implement the actual backend logic.
|
|
10824
|
+
* set the current blend mode. Every renderer supports the same set —
|
|
10825
|
+
* see {@link CanvasRenderer#setBlendMode} for the list and what each does.
|
|
10813
10826
|
* @param {string} [mode="normal"] - blend mode
|
|
10814
|
-
* @param {boolean} [premultipliedAlpha=true] - whether textures use premultiplied alpha
|
|
10827
|
+
* @param {boolean} [premultipliedAlpha=true] - whether textures use premultiplied alpha
|
|
10815
10828
|
*/
|
|
10816
10829
|
setBlendMode(mode = "normal") {
|
|
10817
10830
|
this.currentBlendMode = mode;
|
|
@@ -17552,6 +17565,8 @@ var Body = class {
|
|
|
17552
17565
|
};
|
|
17553
17566
|
|
|
17554
17567
|
// src/renderable/renderable.js
|
|
17568
|
+
var _chain = [];
|
|
17569
|
+
var _level = new Matrix3d();
|
|
17555
17570
|
var Renderable = class _Renderable extends Rect {
|
|
17556
17571
|
/**
|
|
17557
17572
|
* @param {number} x - position of the renderable object (accessible through inherited pos.x property)
|
|
@@ -17986,13 +18001,33 @@ var Renderable = class _Renderable extends Rect {
|
|
|
17986
18001
|
}
|
|
17987
18002
|
}
|
|
17988
18003
|
/**
|
|
17989
|
-
*
|
|
17990
|
-
*
|
|
17991
|
-
*
|
|
17992
|
-
*
|
|
17993
|
-
*
|
|
17994
|
-
*
|
|
17995
|
-
*
|
|
18004
|
+
* Where this renderable IS in the game world — its own `pos` plus every
|
|
18005
|
+
* ancestor's, as a {@link Vector3d} so the z component is summed across
|
|
18006
|
+
* the chain too (important for {@link Camera3d}'s frustum culling, which
|
|
18007
|
+
* previously read `obj.depth` — local `pos.z` — and mis-culled children
|
|
18008
|
+
* nested under a container with its own non-zero depth).
|
|
18009
|
+
*
|
|
18010
|
+
* **Reach for this** for anything positional: culling, distance checks,
|
|
18011
|
+
* hit tests, placing one renderable relative to another. It is cheap, and
|
|
18012
|
+
* it is what the engine's own culling uses.
|
|
18013
|
+
*
|
|
18014
|
+
* **Reach for {@link Renderable#getWorldTransform} instead** when a
|
|
18015
|
+
* position is not enough — when rotation, scale or flip along the ancestor
|
|
18016
|
+
* chain matters, or when you need to map an arbitrary point rather than
|
|
18017
|
+
* just the origin. This method sums translations only, so under a rotated
|
|
18018
|
+
* or scaled ancestor it reports where the renderable's *pivot* is and
|
|
18019
|
+
* nothing about how its content is oriented.
|
|
18020
|
+
*
|
|
18021
|
+
* Note the two also frame the question differently. This one is "where am
|
|
18022
|
+
* I"; `getWorldTransform()` is "what space is my content drawn in". For a
|
|
18023
|
+
* {@link Container} those coincide, because a container offsets its
|
|
18024
|
+
* children by its own position. For a leaf they differ by exactly that
|
|
18025
|
+
* position, which a leaf applies inside its own `draw()`.
|
|
18026
|
+
*
|
|
18027
|
+
* The returned vector is pooled and reused — copy it if you need to hold
|
|
18028
|
+
* onto the value across another call.
|
|
18029
|
+
* @returns {Vector3d} this renderable's absolute position
|
|
18030
|
+
* @see Renderable#getWorldTransform
|
|
17996
18031
|
*/
|
|
17997
18032
|
getAbsolutePosition() {
|
|
17998
18033
|
if (typeof this._absPos === "undefined") {
|
|
@@ -18004,6 +18039,121 @@ var Renderable = class _Renderable extends Rect {
|
|
|
18004
18039
|
}
|
|
18005
18040
|
return this._absPos;
|
|
18006
18041
|
}
|
|
18042
|
+
/**
|
|
18043
|
+
* The transform this renderable interposes between its ancestor's frame
|
|
18044
|
+
* and the frame its own content is drawn in — a mirror of what
|
|
18045
|
+
* {@link Renderable#preDraw} applies to the renderer, as a matrix.
|
|
18046
|
+
*
|
|
18047
|
+
* **This is not {@link Renderable#currentTransform}.** A renderable's
|
|
18048
|
+
* placement is split across two members: `pos` holds where it is, and
|
|
18049
|
+
* `currentTransform` holds only what `rotate()` / `scale()` / `translate()`
|
|
18050
|
+
* accumulate — it never contains the position. `preDraw` composes the two
|
|
18051
|
+
* by conjugation, so a rotation pivots about the renderable's position
|
|
18052
|
+
* rather than the origin. On a renderable you never rotated,
|
|
18053
|
+
* `currentTransform` is therefore the *identity* and says nothing about
|
|
18054
|
+
* where its content lands, while this method returns the translation that
|
|
18055
|
+
* actually places it.
|
|
18056
|
+
*
|
|
18057
|
+
* {@link Container} extends this with the offset it applies to its
|
|
18058
|
+
* children, which a leaf renderable does not have: a leaf's own `draw()`
|
|
18059
|
+
* places itself from `pos`.
|
|
18060
|
+
* @protected
|
|
18061
|
+
* @param {Matrix3d} out - matrix to write into; nothing is stored on the
|
|
18062
|
+
* renderable itself, so callers own the lifetime
|
|
18063
|
+
* @returns {Matrix3d} `out`, for chaining
|
|
18064
|
+
* @see Renderable#getWorldTransform
|
|
18065
|
+
*/
|
|
18066
|
+
getLocalTransform(out) {
|
|
18067
|
+
const ax = Number.isFinite(this.width) ? this.width * this.anchorPoint.x : 0;
|
|
18068
|
+
const ay = Number.isFinite(this.height) ? this.height * this.anchorPoint.y : 0;
|
|
18069
|
+
out.identity();
|
|
18070
|
+
if (this._flip.x || this._flip.y) {
|
|
18071
|
+
const dx = this._flip.x ? this.centerX - ax : 0;
|
|
18072
|
+
const dy = this._flip.y ? this.centerY - ay : 0;
|
|
18073
|
+
out.translate(dx, dy);
|
|
18074
|
+
out.scale(this._flip.x ? -1 : 1, this._flip.y ? -1 : 1);
|
|
18075
|
+
out.translate(-dx, -dy);
|
|
18076
|
+
}
|
|
18077
|
+
if (this.autoTransform === true && !this.currentTransform.isIdentity()) {
|
|
18078
|
+
out.translate(this.pos.x, this.pos.y);
|
|
18079
|
+
out.multiply(this.currentTransform);
|
|
18080
|
+
out.translate(-this.pos.x, -this.pos.y);
|
|
18081
|
+
}
|
|
18082
|
+
if (this.applyAnchorTransform !== false) {
|
|
18083
|
+
out.translate(-ax, -ay);
|
|
18084
|
+
}
|
|
18085
|
+
return out;
|
|
18086
|
+
}
|
|
18087
|
+
/**
|
|
18088
|
+
* The space this renderable's content is drawn IN, as a matrix — the full
|
|
18089
|
+
* form of {@link Renderable#getAbsolutePosition}, which sums positions up
|
|
18090
|
+
* the ancestor chain and therefore cannot represent the rotation, scale or
|
|
18091
|
+
* flip accumulated along the way.
|
|
18092
|
+
*
|
|
18093
|
+
* **Reach for `getAbsolutePosition()` instead** for ordinary positional
|
|
18094
|
+
* work — culling, distance checks, hit tests. It is cheaper and it is what
|
|
18095
|
+
* the engine culls with. **Use this** when a position is not enough:
|
|
18096
|
+
*
|
|
18097
|
+
* - an ancestor is rotated or scaled, so a translation cannot describe the
|
|
18098
|
+
* result
|
|
18099
|
+
* - you need to map an arbitrary point, not just the origin — a corner, a
|
|
18100
|
+
* click position, one renderable's coordinates into another's space
|
|
18101
|
+
* - you need to compose or invert the transform (`inv(A) · B` converts
|
|
18102
|
+
* between two frames, which is how `ParticleEmitter.referenceSpace`
|
|
18103
|
+
* measures particles against a container that is not their parent)
|
|
18104
|
+
*
|
|
18105
|
+
* The two also frame the question differently, and it shows on a leaf.
|
|
18106
|
+
* `getAbsolutePosition()` is "where am I"; this is "what space is my
|
|
18107
|
+
* content drawn in". For a {@link Container} those coincide, because a
|
|
18108
|
+
* container offsets its children by its own position. For a leaf they
|
|
18109
|
+
* differ by exactly that position, which a leaf applies inside its own
|
|
18110
|
+
* `draw()`. So with no rotation, scale or flip anywhere, a container's
|
|
18111
|
+
* translation column equals its `getAbsolutePosition()` while a leaf's
|
|
18112
|
+
* equals its PARENT's.
|
|
18113
|
+
*
|
|
18114
|
+
* The walk stops at a `floating` ancestor, because a floating renderable
|
|
18115
|
+
* draws in screen space: {@link Container#draw} resets the transform
|
|
18116
|
+
* outright for those, so the chain genuinely ends there rather than
|
|
18117
|
+
* continuing to the root.
|
|
18118
|
+
*
|
|
18119
|
+
* The camera needs no special handling — {@link Camera2d} folds its view
|
|
18120
|
+
* transform into the root container's `currentTransform`, so it is picked
|
|
18121
|
+
* up like any other level.
|
|
18122
|
+
* @param {Matrix3d} out - matrix to write into; nothing is stored on the
|
|
18123
|
+
* renderable itself, so callers own the lifetime
|
|
18124
|
+
* @returns {Matrix3d} `out`, for chaining
|
|
18125
|
+
* @see Renderable#getAbsolutePosition
|
|
18126
|
+
* @example
|
|
18127
|
+
* // map a point from one renderable's space into another's
|
|
18128
|
+
* const from = a.getWorldTransform(new Matrix3d());
|
|
18129
|
+
* const into = b.getWorldTransform(new Matrix3d()).invert();
|
|
18130
|
+
* const point = new Vector2d(10, 20); // in a's space
|
|
18131
|
+
* from.apply(point); // -> world
|
|
18132
|
+
* into.apply(point); // -> b's space
|
|
18133
|
+
* @example
|
|
18134
|
+
* // just need to know where something is? use the cheaper call
|
|
18135
|
+
* const where = renderable.getAbsolutePosition();
|
|
18136
|
+
*/
|
|
18137
|
+
getWorldTransform(out) {
|
|
18138
|
+
_chain.length = 0;
|
|
18139
|
+
_chain.push(this);
|
|
18140
|
+
if (this.floating !== true) {
|
|
18141
|
+
let node = this.ancestor;
|
|
18142
|
+
while (typeof node !== "undefined" && node !== null) {
|
|
18143
|
+
_chain.push(node);
|
|
18144
|
+
if (node.floating === true) {
|
|
18145
|
+
break;
|
|
18146
|
+
}
|
|
18147
|
+
node = node.ancestor;
|
|
18148
|
+
}
|
|
18149
|
+
}
|
|
18150
|
+
out.identity();
|
|
18151
|
+
for (let i = _chain.length; i-- > 0; ) {
|
|
18152
|
+
out.multiply(_chain[i].getLocalTransform(_level));
|
|
18153
|
+
}
|
|
18154
|
+
_chain.length = 0;
|
|
18155
|
+
return out;
|
|
18156
|
+
}
|
|
18007
18157
|
/**
|
|
18008
18158
|
* Prepare the rendering context before drawing (automatically called by melonJS).
|
|
18009
18159
|
* This will apply any defined transforms, anchor point, tint or blend mode and translate the context accordingly to this renderable position.
|
|
@@ -18298,6 +18448,7 @@ function compileProgram(gl, vertex, fragment2, attributes) {
|
|
|
18298
18448
|
throw new Error(error_msg);
|
|
18299
18449
|
}
|
|
18300
18450
|
gl.useProgram(program);
|
|
18451
|
+
gl.__meCurrentProgram = program;
|
|
18301
18452
|
gl.deleteShader(vertShader);
|
|
18302
18453
|
gl.deleteShader(fragShader);
|
|
18303
18454
|
return program;
|
|
@@ -18595,6 +18746,7 @@ var GLShader = class _GLShader {
|
|
|
18595
18746
|
return;
|
|
18596
18747
|
}
|
|
18597
18748
|
this.gl.useProgram(this.program);
|
|
18749
|
+
this.gl.__meCurrentProgram = this.program;
|
|
18598
18750
|
}
|
|
18599
18751
|
/**
|
|
18600
18752
|
* returns the location of an attribute variable in this shader program
|
|
@@ -26779,6 +26931,20 @@ var Container = class _Container extends Renderable {
|
|
|
26779
26931
|
}
|
|
26780
26932
|
return super.update(dt);
|
|
26781
26933
|
}
|
|
26934
|
+
/**
|
|
26935
|
+
* A container additionally offsets its children by its own position — the
|
|
26936
|
+
* `translate()` at the top of {@link Container#draw} — which is what makes
|
|
26937
|
+
* a child's coordinates mean "relative to my parent" rather than naming a
|
|
26938
|
+
* place in the world. A leaf renderable has no such term.
|
|
26939
|
+
* @protected
|
|
26940
|
+
* @param {Matrix3d} out - matrix to write into
|
|
26941
|
+
* @returns {Matrix3d} `out`, for chaining
|
|
26942
|
+
*/
|
|
26943
|
+
getLocalTransform(out) {
|
|
26944
|
+
super.getLocalTransform(out);
|
|
26945
|
+
out.translate(this.pos.x, this.pos.y);
|
|
26946
|
+
return out;
|
|
26947
|
+
}
|
|
26782
26948
|
/**
|
|
26783
26949
|
* draw this renderable (automatically called by melonJS)
|
|
26784
26950
|
* @param {CanvasRenderer|WebGLRenderer} renderer - a renderer instance
|
|
@@ -35760,7 +35926,7 @@ var CanvasRenderer = class extends Renderer {
|
|
|
35760
35926
|
}
|
|
35761
35927
|
/**
|
|
35762
35928
|
* set the current blend mode for this renderer. <br>
|
|
35763
|
-
*
|
|
35929
|
+
* Every renderer supports the full set: <br>
|
|
35764
35930
|
* - "normal" : draws new content on top of the existing content <br>
|
|
35765
35931
|
* <img src="../images/normal-blendmode.png" width="180"/> <br>
|
|
35766
35932
|
* - "add", "additive", or "lighter" : color values are added together <br>
|
|
@@ -35769,26 +35935,30 @@ var CanvasRenderer = class extends Renderer {
|
|
|
35769
35935
|
* <img src="../images/multiply-blendmode.png" width="180"/> <br>
|
|
35770
35936
|
* - "screen" : pixels are inverted, multiplied, and inverted again (opposite of multiply) <br>
|
|
35771
35937
|
* <img src="../images/screen-blendmode.png" width="180"/> <br>
|
|
35772
|
-
* Canvas (browser-dependent) and WebGL2: <br>
|
|
35773
35938
|
* - "darken" : retains the darkest pixels of both layers <br>
|
|
35774
35939
|
* <img src="../images/darken-blendmode.png" width="180"/> <br>
|
|
35775
35940
|
* - "lighten" : retains the lightest pixels of both layers <br>
|
|
35776
35941
|
* <img src="../images/lighten-blendmode.png" width="180"/> <br>
|
|
35777
|
-
*
|
|
35778
|
-
* - "overlay" <br>
|
|
35942
|
+
* - "overlay" : multiplies or screens, depending on the backdrop <br>
|
|
35779
35943
|
* <img src="../images/overlay-blendmode.png" width="180"/> <br>
|
|
35780
|
-
* - "
|
|
35781
|
-
* <img src="../images/color-dodge-blendmode.png" width="180"/> <br>
|
|
35782
|
-
* - "color-burn" <br>
|
|
35783
|
-
* <img src="../images/color-burn-blendmode.png" width="180"/> <br>
|
|
35784
|
-
* - "hard-light" <br>
|
|
35944
|
+
* - "hard-light" : overlay with the layers swapped — a harsh spotlight <br>
|
|
35785
35945
|
* <img src="../images/hard-light-blendmode.png" width="180"/> <br>
|
|
35786
|
-
* - "soft-light" <br>
|
|
35946
|
+
* - "soft-light" : a diffused spotlight, gentler than hard-light <br>
|
|
35787
35947
|
* <img src="../images/soft-light-blendmode.png" width="180"/> <br>
|
|
35788
|
-
* - "
|
|
35948
|
+
* - "color-dodge" : brightens the backdrop to reflect the source <br>
|
|
35949
|
+
* <img src="../images/color-dodge-blendmode.png" width="180"/> <br>
|
|
35950
|
+
* - "color-burn" : darkens the backdrop to reflect the source <br>
|
|
35951
|
+
* <img src="../images/color-burn-blendmode.png" width="180"/> <br>
|
|
35952
|
+
* - "difference" : the absolute difference of the two layers <br>
|
|
35789
35953
|
* <img src="../images/difference-blendmode.png" width="180"/> <br>
|
|
35790
|
-
* - "exclusion" <br>
|
|
35954
|
+
* - "exclusion" : like difference, but lower in contrast <br>
|
|
35791
35955
|
* <img src="../images/exclusion-blendmode.png" width="180"/> <br>
|
|
35956
|
+
* - "none" : blending disabled — the source replaces the destination
|
|
35957
|
+
* outright, alpha included <br>
|
|
35958
|
+
* A few draw types cannot honour every mode — 3D meshes, and fills using
|
|
35959
|
+
* a {@link Gradient} — and fall back to "normal" with a one-time console
|
|
35960
|
+
* warning. `setBlendMode` returns what it actually applied, so comparing
|
|
35961
|
+
* the result against your request detects that case.
|
|
35792
35962
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
|
|
35793
35963
|
* @param {string} [mode="normal"] - blend mode
|
|
35794
35964
|
* @returns {string} the blend mode actually applied (may differ if the requested mode is unsupported)
|
|
@@ -36661,11 +36831,11 @@ var CanvasRenderer = class extends Renderer {
|
|
|
36661
36831
|
* Reset (overrides) the renderer transformation matrix to the
|
|
36662
36832
|
* identity one, and then apply the given transformation matrix.
|
|
36663
36833
|
* @param {Matrix2d|Matrix3d|number} a - a matrix to transform by, or the a component to multiply the current matrix by
|
|
36664
|
-
* @param {number} b - the b component to multiply the current matrix by
|
|
36665
|
-
* @param {number} c - the c component to multiply the current matrix by
|
|
36666
|
-
* @param {number} d - the d component to multiply the current matrix by
|
|
36667
|
-
* @param {number} e - the e component to multiply the current matrix by
|
|
36668
|
-
* @param {number} f - the f component to multiply the current matrix by
|
|
36834
|
+
* @param {number} [b] - the b component to multiply the current matrix by; omitted when `a` is a matrix
|
|
36835
|
+
* @param {number} [c] - the c component to multiply the current matrix by; omitted when `a` is a matrix
|
|
36836
|
+
* @param {number} [d] - the d component to multiply the current matrix by; omitted when `a` is a matrix
|
|
36837
|
+
* @param {number} [e] - the e component to multiply the current matrix by; omitted when `a` is a matrix
|
|
36838
|
+
* @param {number} [f] - the f component to multiply the current matrix by; omitted when `a` is a matrix
|
|
36669
36839
|
*/
|
|
36670
36840
|
setTransform(a, b, c, d, e, f) {
|
|
36671
36841
|
this.resetTransform();
|
|
@@ -36675,11 +36845,11 @@ var CanvasRenderer = class extends Renderer {
|
|
|
36675
36845
|
* Multiply given matrix into the renderer tranformation matrix
|
|
36676
36846
|
* @see {@link CanvasRenderer.setTransform} which will reset the current transform matrix prior to performing the new transformation
|
|
36677
36847
|
* @param {Matrix2d|Matrix3d|number} a - a matrix to transform by, or the a component to multiply the current matrix by
|
|
36678
|
-
* @param {number} b - the b component to multiply the current matrix by
|
|
36679
|
-
* @param {number} c - the c component to multiply the current matrix by
|
|
36680
|
-
* @param {number} d - the d component to multiply the current matrix by
|
|
36681
|
-
* @param {number} e - the e component to multiply the current matrix by
|
|
36682
|
-
* @param {number} f - the f component to multiply the current matrix by
|
|
36848
|
+
* @param {number} [b] - the b component to multiply the current matrix by; omitted when `a` is a matrix
|
|
36849
|
+
* @param {number} [c] - the c component to multiply the current matrix by; omitted when `a` is a matrix
|
|
36850
|
+
* @param {number} [d] - the d component to multiply the current matrix by; omitted when `a` is a matrix
|
|
36851
|
+
* @param {number} [e] - the e component to multiply the current matrix by; omitted when `a` is a matrix
|
|
36852
|
+
* @param {number} [f] - the f component to multiply the current matrix by; omitted when `a` is a matrix
|
|
36683
36853
|
*/
|
|
36684
36854
|
transform(a, b, c, d, e, f) {
|
|
36685
36855
|
if (typeof a === "object") {
|
|
@@ -37725,7 +37895,7 @@ var WebGLBatcher = class extends Batcher {
|
|
|
37725
37895
|
const gl = this.gl;
|
|
37726
37896
|
this.vertexState.bind();
|
|
37727
37897
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.uploadBuffer);
|
|
37728
|
-
if (this.renderer.currentProgram !== this.defaultShader.program) {
|
|
37898
|
+
if (this.currentShader !== this.defaultShader || this.renderer.currentProgram !== this.defaultShader.program) {
|
|
37729
37899
|
this.useShader(this.defaultShader);
|
|
37730
37900
|
}
|
|
37731
37901
|
}
|
|
@@ -38985,6 +39155,222 @@ var QuadBatcher = class extends MaterialBatcher {
|
|
|
38985
39155
|
}
|
|
38986
39156
|
};
|
|
38987
39157
|
|
|
39158
|
+
// src/video/blendmodes.js
|
|
39159
|
+
var ADVANCED_BLEND_MODES = [
|
|
39160
|
+
"difference",
|
|
39161
|
+
"overlay",
|
|
39162
|
+
"hard-light",
|
|
39163
|
+
"color-dodge",
|
|
39164
|
+
"color-burn",
|
|
39165
|
+
"soft-light",
|
|
39166
|
+
// `darken` and `lighten` joined the shader path in 20.2: fixed-function
|
|
39167
|
+
// MIN/MAX compute `min(src, dst)` and nothing else, so there is nowhere to
|
|
39168
|
+
// put the `(1 - srcAlpha) * dst` term source-over contributes after the
|
|
39169
|
+
// blend. A translucent source lost the backdrop's share entirely — a white
|
|
39170
|
+
// `lighten` glow over a light backdrop rendered invisible. APPENDED, never
|
|
39171
|
+
// inserted: the index is the shader's branch value.
|
|
39172
|
+
"darken",
|
|
39173
|
+
"lighten"
|
|
39174
|
+
];
|
|
39175
|
+
function isAdvancedBlendMode(mode) {
|
|
39176
|
+
return ADVANCED_BLEND_MODES.indexOf(mode) !== -1;
|
|
39177
|
+
}
|
|
39178
|
+
function advancedBlendModeIndex(mode) {
|
|
39179
|
+
return ADVANCED_BLEND_MODES.indexOf(mode);
|
|
39180
|
+
}
|
|
39181
|
+
function normalizeBlendMode(mode) {
|
|
39182
|
+
switch (mode) {
|
|
39183
|
+
case "none":
|
|
39184
|
+
case "multiply":
|
|
39185
|
+
case "screen":
|
|
39186
|
+
case "exclusion":
|
|
39187
|
+
case "normal":
|
|
39188
|
+
return mode;
|
|
39189
|
+
case "additive":
|
|
39190
|
+
case "add":
|
|
39191
|
+
case "lighter":
|
|
39192
|
+
return "additive";
|
|
39193
|
+
default:
|
|
39194
|
+
return "normal";
|
|
39195
|
+
}
|
|
39196
|
+
}
|
|
39197
|
+
function isSupportedBlendMode(mode) {
|
|
39198
|
+
return isAdvancedBlendMode(mode) || mode === "normal" || normalizeBlendMode(mode) !== "normal";
|
|
39199
|
+
}
|
|
39200
|
+
function reportedBlendMode(mode) {
|
|
39201
|
+
return isSupportedBlendMode(mode) ? mode : "normal";
|
|
39202
|
+
}
|
|
39203
|
+
function blendStateFor(mode, premultipliedAlpha) {
|
|
39204
|
+
const src = premultipliedAlpha ? "one" : "src-alpha";
|
|
39205
|
+
switch (mode) {
|
|
39206
|
+
case "none":
|
|
39207
|
+
return void 0;
|
|
39208
|
+
case "additive":
|
|
39209
|
+
return { operation: "add", srcFactor: src, dstFactor: "one" };
|
|
39210
|
+
case "multiply":
|
|
39211
|
+
return {
|
|
39212
|
+
operation: "add",
|
|
39213
|
+
srcFactor: "dst",
|
|
39214
|
+
dstFactor: "one-minus-src-alpha"
|
|
39215
|
+
};
|
|
39216
|
+
case "exclusion":
|
|
39217
|
+
return {
|
|
39218
|
+
operation: "add",
|
|
39219
|
+
srcFactor: "one-minus-dst",
|
|
39220
|
+
dstFactor: "one-minus-src"
|
|
39221
|
+
};
|
|
39222
|
+
case "screen":
|
|
39223
|
+
return {
|
|
39224
|
+
operation: "add",
|
|
39225
|
+
srcFactor: "one",
|
|
39226
|
+
dstFactor: "one-minus-src"
|
|
39227
|
+
};
|
|
39228
|
+
default:
|
|
39229
|
+
return {
|
|
39230
|
+
operation: "add",
|
|
39231
|
+
srcFactor: src,
|
|
39232
|
+
dstFactor: "one-minus-src-alpha"
|
|
39233
|
+
};
|
|
39234
|
+
}
|
|
39235
|
+
}
|
|
39236
|
+
|
|
39237
|
+
// src/video/effects/blendEffect.js
|
|
39238
|
+
var wgslFragment2 = `
|
|
39239
|
+
struct BlendUniforms {
|
|
39240
|
+
uBlendMode : f32,
|
|
39241
|
+
};
|
|
39242
|
+
@group(3) @binding(0) var<uniform> fx : BlendUniforms;
|
|
39243
|
+
@group(3) @binding(1) var backdrop : texture_2d<f32>;
|
|
39244
|
+
@group(3) @binding(2) var backdrop_sampler : sampler;
|
|
39245
|
+
|
|
39246
|
+
// HardLight(Cb, Cs) \u2014 also the kernel for Overlay, which the W3C spec
|
|
39247
|
+
// defines as HardLight with the arguments swapped
|
|
39248
|
+
fn ME_hardLight(b : vec3f, s : vec3f) -> vec3f {
|
|
39249
|
+
let lo = 2.0 * b * s;
|
|
39250
|
+
let hi = 1.0 - 2.0 * (1.0 - b) * (1.0 - s);
|
|
39251
|
+
return mix(lo, hi, step(vec3f(0.5), s));
|
|
39252
|
+
}
|
|
39253
|
+
|
|
39254
|
+
fn ME_softLight(b : vec3f, s : vec3f) -> vec3f {
|
|
39255
|
+
let d = mix(((16.0 * b - 12.0) * b + 4.0) * b, sqrt(b), step(vec3f(0.25), b));
|
|
39256
|
+
let lo = b - (1.0 - 2.0 * s) * b * (1.0 - b);
|
|
39257
|
+
let hi = b + (2.0 * s - 1.0) * (d - b);
|
|
39258
|
+
return mix(lo, hi, step(vec3f(0.5), s));
|
|
39259
|
+
}
|
|
39260
|
+
|
|
39261
|
+
// Cb == 0 wins over Cs == 1, so it is applied last
|
|
39262
|
+
fn ME_colorDodge(b : vec3f, s : vec3f) -> vec3f {
|
|
39263
|
+
var r = min(vec3f(1.0), b / max(1.0 - s, vec3f(1e-4)));
|
|
39264
|
+
r = mix(r, vec3f(1.0), step(vec3f(1.0), s));
|
|
39265
|
+
return mix(r, vec3f(0.0), step(b, vec3f(0.0)));
|
|
39266
|
+
}
|
|
39267
|
+
|
|
39268
|
+
// Cb == 1 wins over Cs == 0, so it is applied last
|
|
39269
|
+
fn ME_colorBurn(b : vec3f, s : vec3f) -> vec3f {
|
|
39270
|
+
var r = 1.0 - min(vec3f(1.0), (1.0 - b) / max(s, vec3f(1e-4)));
|
|
39271
|
+
r = mix(r, vec3f(0.0), step(s, vec3f(0.0)));
|
|
39272
|
+
return mix(r, vec3f(1.0), step(vec3f(1.0), b));
|
|
39273
|
+
}
|
|
39274
|
+
|
|
39275
|
+
fn ME_blend(b : vec3f, s : vec3f) -> vec3f {
|
|
39276
|
+
if (fx.uBlendMode < 0.5) { return abs(b - s); }
|
|
39277
|
+
if (fx.uBlendMode < 1.5) { return ME_hardLight(s, b); }
|
|
39278
|
+
if (fx.uBlendMode < 2.5) { return ME_hardLight(b, s); }
|
|
39279
|
+
if (fx.uBlendMode < 3.5) { return ME_colorDodge(b, s); }
|
|
39280
|
+
if (fx.uBlendMode < 4.5) { return ME_colorBurn(b, s); }
|
|
39281
|
+
if (fx.uBlendMode < 5.5) { return ME_softLight(b, s); }
|
|
39282
|
+
if (fx.uBlendMode < 6.5) { return min(b, s); }
|
|
39283
|
+
return max(b, s);
|
|
39284
|
+
}
|
|
39285
|
+
|
|
39286
|
+
fn apply(color : vec4f, uv : vec2f) -> vec4f {
|
|
39287
|
+
// sampled BEFORE any branch, so plain textureSampleLevel is safe here
|
|
39288
|
+
let Cb = textureSampleLevel(backdrop, backdrop_sampler, screen_uv, 0.0).rgb;
|
|
39289
|
+
let a = color.a;
|
|
39290
|
+
let Cs = color.rgb / max(a, 1e-4);
|
|
39291
|
+
let B = clamp(ME_blend(Cb, Cs), vec3f(0.0), vec3f(1.0));
|
|
39292
|
+
return vec4f(a * B, a);
|
|
39293
|
+
}
|
|
39294
|
+
`;
|
|
39295
|
+
var BlendEffect = class extends ShaderEffect {
|
|
39296
|
+
/**
|
|
39297
|
+
* @param {import("../webgl/webgl_renderer.js").default|import("../webgpu/webgpu_renderer.js").default} renderer - the renderer that owns this effect
|
|
39298
|
+
*/
|
|
39299
|
+
constructor(renderer) {
|
|
39300
|
+
super(renderer, {
|
|
39301
|
+
glsl: `
|
|
39302
|
+
uniform sampler2D backdrop;
|
|
39303
|
+
uniform float uBlendMode;
|
|
39304
|
+
|
|
39305
|
+
// HardLight(Cb, Cs) \u2014 also the kernel for Overlay, which the W3C
|
|
39306
|
+
// spec defines as HardLight with the arguments swapped
|
|
39307
|
+
vec3 ME_hardLight(vec3 b, vec3 s) {
|
|
39308
|
+
vec3 lo = 2.0 * b * s;
|
|
39309
|
+
vec3 hi = 1.0 - 2.0 * (1.0 - b) * (1.0 - s);
|
|
39310
|
+
return mix(lo, hi, step(vec3(0.5), s));
|
|
39311
|
+
}
|
|
39312
|
+
|
|
39313
|
+
vec3 ME_softLight(vec3 b, vec3 s) {
|
|
39314
|
+
vec3 d = mix(((16.0 * b - 12.0) * b + 4.0) * b, sqrt(b), step(vec3(0.25), b));
|
|
39315
|
+
vec3 lo = b - (1.0 - 2.0 * s) * b * (1.0 - b);
|
|
39316
|
+
vec3 hi = b + (2.0 * s - 1.0) * (d - b);
|
|
39317
|
+
return mix(lo, hi, step(vec3(0.5), s));
|
|
39318
|
+
}
|
|
39319
|
+
|
|
39320
|
+
// Cb == 0 wins over Cs == 1, so it is applied last
|
|
39321
|
+
vec3 ME_colorDodge(vec3 b, vec3 s) {
|
|
39322
|
+
vec3 r = min(vec3(1.0), b / max(1.0 - s, vec3(1e-4)));
|
|
39323
|
+
r = mix(r, vec3(1.0), step(vec3(1.0), s));
|
|
39324
|
+
return mix(r, vec3(0.0), step(b, vec3(0.0)));
|
|
39325
|
+
}
|
|
39326
|
+
|
|
39327
|
+
// Cb == 1 wins over Cs == 0, so it is applied last
|
|
39328
|
+
vec3 ME_colorBurn(vec3 b, vec3 s) {
|
|
39329
|
+
vec3 r = 1.0 - min(vec3(1.0), (1.0 - b) / max(s, vec3(1e-4)));
|
|
39330
|
+
r = mix(r, vec3(0.0), step(s, vec3(0.0)));
|
|
39331
|
+
return mix(r, vec3(1.0), step(vec3(1.0), b));
|
|
39332
|
+
}
|
|
39333
|
+
|
|
39334
|
+
vec3 ME_blend(vec3 b, vec3 s) {
|
|
39335
|
+
if (uBlendMode < 0.5) { return abs(b - s); }
|
|
39336
|
+
if (uBlendMode < 1.5) { return ME_hardLight(s, b); }
|
|
39337
|
+
if (uBlendMode < 2.5) { return ME_hardLight(b, s); }
|
|
39338
|
+
if (uBlendMode < 3.5) { return ME_colorDodge(b, s); }
|
|
39339
|
+
if (uBlendMode < 4.5) { return ME_colorBurn(b, s); }
|
|
39340
|
+
if (uBlendMode < 5.5) { return ME_softLight(b, s); }
|
|
39341
|
+
if (uBlendMode < 6.5) { return min(b, s); }
|
|
39342
|
+
return max(b, s);
|
|
39343
|
+
}
|
|
39344
|
+
|
|
39345
|
+
vec4 apply(vec4 color, vec2 uv) {
|
|
39346
|
+
vec3 Cb = texture2D(backdrop, screen_uv).rgb;
|
|
39347
|
+
float a = color.a;
|
|
39348
|
+
vec3 Cs = color.rgb / max(a, 1e-4);
|
|
39349
|
+
vec3 B = clamp(ME_blend(Cb, Cs), 0.0, 1.0);
|
|
39350
|
+
return vec4(a * B, a);
|
|
39351
|
+
}
|
|
39352
|
+
`,
|
|
39353
|
+
wgsl: wgslFragment2
|
|
39354
|
+
});
|
|
39355
|
+
this.setUniform("uBlendMode", 0);
|
|
39356
|
+
}
|
|
39357
|
+
/**
|
|
39358
|
+
* Select which of the six formulas the shader evaluates.
|
|
39359
|
+
* @param {string} mode - one of the modes in {@link ADVANCED_BLEND_MODES}
|
|
39360
|
+
* @returns {boolean} false when the mode is not an advanced blend mode, in
|
|
39361
|
+
* which case the uniform is left untouched
|
|
39362
|
+
* @ignore
|
|
39363
|
+
*/
|
|
39364
|
+
setBlendMode(mode) {
|
|
39365
|
+
const index = advancedBlendModeIndex(mode);
|
|
39366
|
+
if (index === -1) {
|
|
39367
|
+
return false;
|
|
39368
|
+
}
|
|
39369
|
+
this.setUniform("uBlendMode", index);
|
|
39370
|
+
return true;
|
|
39371
|
+
}
|
|
39372
|
+
};
|
|
39373
|
+
|
|
38988
39374
|
// src/video/effects/radialGradient.js
|
|
38989
39375
|
var RadialGradientEffect = class extends ShaderEffect {
|
|
38990
39376
|
/**
|
|
@@ -42690,7 +43076,30 @@ var GLSamplerCache = class {
|
|
|
42690
43076
|
var _tempMatrix = new Matrix3d();
|
|
42691
43077
|
var _savedTransform = new Matrix3d();
|
|
42692
43078
|
var _savedProjection = new Matrix3d();
|
|
42693
|
-
var
|
|
43079
|
+
var GL_BLEND_OP;
|
|
43080
|
+
var GL_BLEND_FACTOR;
|
|
43081
|
+
function initBlendEnums(gl) {
|
|
43082
|
+
GL_BLEND_OP = {
|
|
43083
|
+
add: gl.FUNC_ADD,
|
|
43084
|
+
subtract: gl.FUNC_SUBTRACT,
|
|
43085
|
+
"reverse-subtract": gl.FUNC_REVERSE_SUBTRACT,
|
|
43086
|
+
min: gl.MIN,
|
|
43087
|
+
max: gl.MAX
|
|
43088
|
+
};
|
|
43089
|
+
GL_BLEND_FACTOR = {
|
|
43090
|
+
zero: gl.ZERO,
|
|
43091
|
+
one: gl.ONE,
|
|
43092
|
+
src: gl.SRC_COLOR,
|
|
43093
|
+
"one-minus-src": gl.ONE_MINUS_SRC_COLOR,
|
|
43094
|
+
"src-alpha": gl.SRC_ALPHA,
|
|
43095
|
+
"one-minus-src-alpha": gl.ONE_MINUS_SRC_ALPHA,
|
|
43096
|
+
dst: gl.DST_COLOR,
|
|
43097
|
+
"one-minus-dst": gl.ONE_MINUS_DST_COLOR,
|
|
43098
|
+
"dst-alpha": gl.DST_ALPHA,
|
|
43099
|
+
"one-minus-dst-alpha": gl.ONE_MINUS_DST_ALPHA
|
|
43100
|
+
};
|
|
43101
|
+
}
|
|
43102
|
+
var WebGLRenderer = class _WebGLRenderer extends Renderer {
|
|
42694
43103
|
/**
|
|
42695
43104
|
* @param {ApplicationSettings} [options] - optional parameters for the renderer
|
|
42696
43105
|
*/
|
|
@@ -42707,6 +43116,14 @@ var WebGLRenderer = class extends Renderer {
|
|
|
42707
43116
|
});
|
|
42708
43117
|
this._effectProjectionStack = [];
|
|
42709
43118
|
this._effectPassDepth = 0;
|
|
43119
|
+
this._advancedBlendEffect = void 0;
|
|
43120
|
+
this._advancedBlendCapture = void 0;
|
|
43121
|
+
this._advancedBlendTarget = void 0;
|
|
43122
|
+
this._advancedBlendOpen = false;
|
|
43123
|
+
this._advancedBlendBusy = 0;
|
|
43124
|
+
this._advancedBlendParent = null;
|
|
43125
|
+
this._advancedBlendStencil = false;
|
|
43126
|
+
this._advancedBlendWarned = /* @__PURE__ */ new Set();
|
|
42710
43127
|
this.lineWidth = 1;
|
|
42711
43128
|
this.lineJoin = "round";
|
|
42712
43129
|
this.vertexBuffer = this.gl.createBuffer();
|
|
@@ -42885,6 +43302,14 @@ var WebGLRenderer = class extends Renderer {
|
|
|
42885
43302
|
off(GAME_RESET, this.onGameReset);
|
|
42886
43303
|
off(ONCONTEXT_RESTORED, this.onContextRestoredInvalidate);
|
|
42887
43304
|
off(CANVAS_ONRESIZE, this.onCanvasResize);
|
|
43305
|
+
this._advancedBlendEffect?.destroy();
|
|
43306
|
+
this._advancedBlendEffect = void 0;
|
|
43307
|
+
this._advancedBlendCapture?.destroy();
|
|
43308
|
+
this._advancedBlendCapture = void 0;
|
|
43309
|
+
this._advancedBlendTarget?.destroy?.();
|
|
43310
|
+
this._advancedBlendTarget = void 0;
|
|
43311
|
+
this._advancedBlendOpen = false;
|
|
43312
|
+
this._advancedBlendBusy = 0;
|
|
42888
43313
|
releaseShadowQuads(this);
|
|
42889
43314
|
if (this.batchers) {
|
|
42890
43315
|
this.batchers.forEach((batcher) => {
|
|
@@ -43013,6 +43438,18 @@ var WebGLRenderer = class extends Renderer {
|
|
|
43013
43438
|
if (typeof batcher === "undefined") {
|
|
43014
43439
|
throw new Error("Invalid Batcher");
|
|
43015
43440
|
}
|
|
43441
|
+
if (this._advancedBlendBusy === 0) {
|
|
43442
|
+
if (this._advancedBlendOpen === true) {
|
|
43443
|
+
this._closeAdvancedBlend();
|
|
43444
|
+
}
|
|
43445
|
+
if (isAdvancedBlendMode(this.currentBlendMode) === true) {
|
|
43446
|
+
if (name === "mesh" || name === "litMesh") {
|
|
43447
|
+
this._warnAdvancedBlendFallback("3D meshes");
|
|
43448
|
+
} else {
|
|
43449
|
+
this._openAdvancedBlend();
|
|
43450
|
+
}
|
|
43451
|
+
}
|
|
43452
|
+
}
|
|
43016
43453
|
const targetShader = shader != null ? shader : batcher.defaultShader;
|
|
43017
43454
|
if (this.currentBatcher === batcher && batcher.currentShader === targetShader) {
|
|
43018
43455
|
return this.currentBatcher;
|
|
@@ -43082,6 +43519,10 @@ var WebGLRenderer = class extends Renderer {
|
|
|
43082
43519
|
* Flush the batcher to the frame buffer
|
|
43083
43520
|
*/
|
|
43084
43521
|
flush() {
|
|
43522
|
+
if (this._advancedBlendOpen === true && this._advancedBlendBusy === 0) {
|
|
43523
|
+
this._closeAdvancedBlend();
|
|
43524
|
+
return;
|
|
43525
|
+
}
|
|
43085
43526
|
this.currentBatcher.flush();
|
|
43086
43527
|
}
|
|
43087
43528
|
/**
|
|
@@ -43257,6 +43698,16 @@ var WebGLRenderer = class extends Renderer {
|
|
|
43257
43698
|
* }
|
|
43258
43699
|
*/
|
|
43259
43700
|
toFrameTexture(options = {}) {
|
|
43701
|
+
const busy = this._advancedBlendBusy;
|
|
43702
|
+
this._advancedBlendBusy = (busy ?? 0) + 1;
|
|
43703
|
+
try {
|
|
43704
|
+
return _WebGLRenderer.prototype._toFrameTexture.call(this, options);
|
|
43705
|
+
} finally {
|
|
43706
|
+
this._advancedBlendBusy = busy;
|
|
43707
|
+
}
|
|
43708
|
+
}
|
|
43709
|
+
/** @ignore */
|
|
43710
|
+
_toFrameTexture(options = {}) {
|
|
43260
43711
|
const gl = this.gl;
|
|
43261
43712
|
const canvas = this.getCanvas();
|
|
43262
43713
|
let x = 0;
|
|
@@ -43492,6 +43943,125 @@ var WebGLRenderer = class extends Renderer {
|
|
|
43492
43943
|
);
|
|
43493
43944
|
this.currentBatcher.setProjection(this.projectionMatrix);
|
|
43494
43945
|
}
|
|
43946
|
+
/**
|
|
43947
|
+
* Say once, per excluded path and mode, that an advanced blend mode is
|
|
43948
|
+
* falling back to `"normal"`. A silent data-dependent fallback is exactly
|
|
43949
|
+
* what the advanced-blend work exists to remove, so the exclusions are
|
|
43950
|
+
* loud.
|
|
43951
|
+
* @param {string} what - the excluded path, named for the message
|
|
43952
|
+
* @ignore
|
|
43953
|
+
*/
|
|
43954
|
+
_warnAdvancedBlendFallback(what) {
|
|
43955
|
+
const key = `${what}:${this.currentBlendMode}`;
|
|
43956
|
+
if (this._advancedBlendWarned.has(key)) {
|
|
43957
|
+
return;
|
|
43958
|
+
}
|
|
43959
|
+
this._advancedBlendWarned.add(key);
|
|
43960
|
+
console.warn(
|
|
43961
|
+
`WebGLRenderer: blend mode "${this.currentBlendMode}" is not supported for ${what} and falls back to "normal"`
|
|
43962
|
+
);
|
|
43963
|
+
}
|
|
43964
|
+
/**
|
|
43965
|
+
* Close a pending advanced-blend bracket, if one is open and we are not
|
|
43966
|
+
* already inside the bracket machinery. The safe form to call from any
|
|
43967
|
+
* path that is about to disturb the destination.
|
|
43968
|
+
* @ignore
|
|
43969
|
+
*/
|
|
43970
|
+
_drainAdvancedBlend() {
|
|
43971
|
+
if (this._advancedBlendOpen === true && this._advancedBlendBusy === 0) {
|
|
43972
|
+
this._closeAdvancedBlend();
|
|
43973
|
+
}
|
|
43974
|
+
}
|
|
43975
|
+
/**
|
|
43976
|
+
* Open an advanced-blend bracket: capture the destination, then redirect
|
|
43977
|
+
* this draw into an offscreen target. Closed by {@link _closeAdvancedBlend}
|
|
43978
|
+
* at the next draw, flush or clear.
|
|
43979
|
+
* @returns {boolean} false when the effect could not be realized, in which
|
|
43980
|
+
* case the draw proceeds unbracketed (plain source-over)
|
|
43981
|
+
* @ignore
|
|
43982
|
+
*/
|
|
43983
|
+
_openAdvancedBlend() {
|
|
43984
|
+
const gl = this.gl;
|
|
43985
|
+
const canvas = this.getCanvas();
|
|
43986
|
+
const w = canvas.width;
|
|
43987
|
+
const h = canvas.height;
|
|
43988
|
+
this._advancedBlendBusy++;
|
|
43989
|
+
if (typeof this._advancedBlendEffect === "undefined") {
|
|
43990
|
+
this._advancedBlendEffect = new BlendEffect(this);
|
|
43991
|
+
}
|
|
43992
|
+
if (this._advancedBlendEffect.enabled !== true) {
|
|
43993
|
+
this._advancedBlendBusy--;
|
|
43994
|
+
this._warnAdvancedBlendFallback("this device");
|
|
43995
|
+
return false;
|
|
43996
|
+
}
|
|
43997
|
+
this._advancedBlendEffect.setBlendMode(this.currentBlendMode);
|
|
43998
|
+
this.currentBatcher.flush();
|
|
43999
|
+
this._advancedBlendCapture = this.toFrameTexture({
|
|
44000
|
+
target: this._advancedBlendCapture ?? null
|
|
44001
|
+
});
|
|
44002
|
+
this._advancedBlendEffect.setTexture(
|
|
44003
|
+
"backdrop",
|
|
44004
|
+
this._advancedBlendCapture
|
|
44005
|
+
);
|
|
44006
|
+
this._advancedBlendParent = this._effectPassDepth > 0 ? this._renderTargetPool.getCaptureTarget() : null;
|
|
44007
|
+
if (typeof this._advancedBlendTarget === "undefined") {
|
|
44008
|
+
this._advancedBlendTarget = new WebGLRenderTarget(gl, w, h, {
|
|
44009
|
+
samples: 0
|
|
44010
|
+
});
|
|
44011
|
+
} else {
|
|
44012
|
+
this._advancedBlendTarget.resize(w, h);
|
|
44013
|
+
}
|
|
44014
|
+
this.invalidateTextureUnit(0);
|
|
44015
|
+
this._advancedBlendTarget.bind();
|
|
44016
|
+
this.setViewport(0, 0, w, h);
|
|
44017
|
+
this.clearRenderTarget();
|
|
44018
|
+
this._advancedBlendStencil = gl.isEnabled(gl.STENCIL_TEST);
|
|
44019
|
+
if (this._advancedBlendStencil === true) {
|
|
44020
|
+
gl.disable(gl.STENCIL_TEST);
|
|
44021
|
+
}
|
|
44022
|
+
this._advancedBlendOpen = true;
|
|
44023
|
+
this._advancedBlendBusy--;
|
|
44024
|
+
return true;
|
|
44025
|
+
}
|
|
44026
|
+
/**
|
|
44027
|
+
* Close an advanced-blend bracket: drain the offscreen, return to the
|
|
44028
|
+
* parent target, and composite through {@link BlendEffect}.
|
|
44029
|
+
* @ignore
|
|
44030
|
+
*/
|
|
44031
|
+
_closeAdvancedBlend() {
|
|
44032
|
+
const gl = this.gl;
|
|
44033
|
+
const canvas = this.getCanvas();
|
|
44034
|
+
const w = canvas.width;
|
|
44035
|
+
const h = canvas.height;
|
|
44036
|
+
this._advancedBlendBusy++;
|
|
44037
|
+
this._advancedBlendOpen = false;
|
|
44038
|
+
this.currentBatcher.flush();
|
|
44039
|
+
this._advancedBlendTarget.unbind();
|
|
44040
|
+
if (this._advancedBlendParent !== null) {
|
|
44041
|
+
this._advancedBlendParent.bind();
|
|
44042
|
+
}
|
|
44043
|
+
this._advancedBlendParent = null;
|
|
44044
|
+
this.invalidateTextureUnit(0);
|
|
44045
|
+
this.setViewport(0, 0, w, h);
|
|
44046
|
+
emit(RENDER_TARGET_CHANGED, this);
|
|
44047
|
+
if (this._advancedBlendStencil === true) {
|
|
44048
|
+
gl.enable(gl.STENCIL_TEST);
|
|
44049
|
+
}
|
|
44050
|
+
const mode = this.currentBlendMode;
|
|
44051
|
+
this.setBlendMode("normal", true);
|
|
44052
|
+
this.blitEffect(
|
|
44053
|
+
this._advancedBlendTarget.texture,
|
|
44054
|
+
0,
|
|
44055
|
+
0,
|
|
44056
|
+
w,
|
|
44057
|
+
h,
|
|
44058
|
+
this._advancedBlendEffect,
|
|
44059
|
+
true
|
|
44060
|
+
);
|
|
44061
|
+
this.currentBatcher.flush();
|
|
44062
|
+
this.currentBlendMode = mode;
|
|
44063
|
+
this._advancedBlendBusy--;
|
|
44064
|
+
}
|
|
43495
44065
|
/**
|
|
43496
44066
|
* Blit a texture to the screen through a shader effect.
|
|
43497
44067
|
* Draws a screen-aligned quad using the given texture as source
|
|
@@ -43505,6 +44075,7 @@ var WebGLRenderer = class extends Renderer {
|
|
|
43505
44075
|
* @param {boolean} [keepBlend=false] - if true, keep current blend mode (for sprite compositing)
|
|
43506
44076
|
*/
|
|
43507
44077
|
blitEffect(source, x, y, width, height, shader, keepBlend = false) {
|
|
44078
|
+
this._advancedBlendBusy++;
|
|
43508
44079
|
this.flush();
|
|
43509
44080
|
const batcher = this.setBatcher("quad");
|
|
43510
44081
|
_savedTransform.copy(this.currentTransform);
|
|
@@ -43522,6 +44093,7 @@ var WebGLRenderer = class extends Renderer {
|
|
|
43522
44093
|
this.currentTransform.copy(_savedTransform);
|
|
43523
44094
|
this.projectionMatrix.copy(_savedProjection);
|
|
43524
44095
|
batcher.setProjection(this.projectionMatrix);
|
|
44096
|
+
this._advancedBlendBusy--;
|
|
43525
44097
|
}
|
|
43526
44098
|
/**
|
|
43527
44099
|
* set/change the current projection matrix (WebGL only)
|
|
@@ -43608,6 +44180,7 @@ var WebGLRenderer = class extends Renderer {
|
|
|
43608
44180
|
* Clear the frame buffer
|
|
43609
44181
|
*/
|
|
43610
44182
|
clear() {
|
|
44183
|
+
this._drainAdvancedBlend();
|
|
43611
44184
|
const gl = this.gl;
|
|
43612
44185
|
const clearColor = this.backgroundColor.toArray();
|
|
43613
44186
|
gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
|
|
@@ -43621,6 +44194,7 @@ var WebGLRenderer = class extends Renderer {
|
|
|
43621
44194
|
* @param {boolean} [opaque=false] - Allow transparency [default] or clear the surface completely [true]
|
|
43622
44195
|
*/
|
|
43623
44196
|
clearColor(color = "#000000", opaque = false) {
|
|
44197
|
+
this._drainAdvancedBlend();
|
|
43624
44198
|
let glArray;
|
|
43625
44199
|
const gl = this.gl;
|
|
43626
44200
|
if (color instanceof Color) {
|
|
@@ -43985,12 +44559,31 @@ var WebGLRenderer = class extends Renderer {
|
|
|
43985
44559
|
* return a reference to the system 2d Context
|
|
43986
44560
|
* @returns {WebGLRenderingContext} the current WebGL context
|
|
43987
44561
|
*/
|
|
44562
|
+
/**
|
|
44563
|
+
* The shader program the GL context actually has bound.
|
|
44564
|
+
*
|
|
44565
|
+
* Backed by the CONTEXT rather than by a field on this renderer, because
|
|
44566
|
+
* `GLShader` binds programs too — writing a uniform calls `useProgram`,
|
|
44567
|
+
* and a freshly linked program is left bound — and it is constructed with
|
|
44568
|
+
* a bare `gl`, so it cannot reach a renderer-owned cache. A field here
|
|
44569
|
+
* would silently drift out of step with GL, and every batcher that
|
|
44570
|
+
* compares against it (`syncProgram`, the mesh and primitive paths) would
|
|
44571
|
+
* skip a rebind it actually needed, drawing a pending batch through the
|
|
44572
|
+
* wrong program.
|
|
44573
|
+
* @type {WebGLProgram|undefined}
|
|
44574
|
+
*/
|
|
44575
|
+
get currentProgram() {
|
|
44576
|
+
return this.gl.__meCurrentProgram;
|
|
44577
|
+
}
|
|
44578
|
+
set currentProgram(value) {
|
|
44579
|
+
this.gl.__meCurrentProgram = value;
|
|
44580
|
+
}
|
|
43988
44581
|
getContext() {
|
|
43989
44582
|
return this.gl;
|
|
43990
44583
|
}
|
|
43991
44584
|
/**
|
|
43992
44585
|
* set the current blend mode for this renderer. <br>
|
|
43993
|
-
*
|
|
44586
|
+
* Every renderer supports the full set: <br>
|
|
43994
44587
|
* - "normal" : draws new content on top of the existing content <br>
|
|
43995
44588
|
* <img src="../images/normal-blendmode.png" width="180"/> <br>
|
|
43996
44589
|
* - "add", "additive", or "lighter" : color values are added together <br>
|
|
@@ -43999,71 +44592,58 @@ var WebGLRenderer = class extends Renderer {
|
|
|
43999
44592
|
* <img src="../images/multiply-blendmode.png" width="180"/> <br>
|
|
44000
44593
|
* - "screen" : pixels are inverted, multiplied, and inverted again (opposite of multiply) <br>
|
|
44001
44594
|
* <img src="../images/screen-blendmode.png" width="180"/> <br>
|
|
44002
|
-
* WebGL2 additionally supports: <br>
|
|
44003
44595
|
* - "darken" : retains the darkest pixels of both layers <br>
|
|
44004
44596
|
* <img src="../images/darken-blendmode.png" width="180"/> <br>
|
|
44005
44597
|
* - "lighten" : retains the lightest pixels of both layers <br>
|
|
44006
44598
|
* <img src="../images/lighten-blendmode.png" width="180"/> <br>
|
|
44599
|
+
* - "overlay" : multiplies or screens, depending on the backdrop <br>
|
|
44600
|
+
* <img src="../images/overlay-blendmode.png" width="180"/> <br>
|
|
44601
|
+
* - "hard-light" : overlay with the layers swapped — a harsh spotlight <br>
|
|
44602
|
+
* <img src="../images/hard-light-blendmode.png" width="180"/> <br>
|
|
44603
|
+
* - "soft-light" : a diffused spotlight, gentler than hard-light <br>
|
|
44604
|
+
* <img src="../images/soft-light-blendmode.png" width="180"/> <br>
|
|
44605
|
+
* - "color-dodge" : brightens the backdrop to reflect the source <br>
|
|
44606
|
+
* <img src="../images/color-dodge-blendmode.png" width="180"/> <br>
|
|
44607
|
+
* - "color-burn" : darkens the backdrop to reflect the source <br>
|
|
44608
|
+
* <img src="../images/color-burn-blendmode.png" width="180"/> <br>
|
|
44609
|
+
* - "difference" : the absolute difference of the two layers <br>
|
|
44610
|
+
* <img src="../images/difference-blendmode.png" width="180"/> <br>
|
|
44611
|
+
* - "exclusion" : like difference, but lower in contrast <br>
|
|
44612
|
+
* <img src="../images/exclusion-blendmode.png" width="180"/> <br>
|
|
44007
44613
|
* - "none" : blending disabled — the source replaces the destination
|
|
44008
|
-
* outright, alpha included
|
|
44009
|
-
*
|
|
44010
|
-
*
|
|
44011
|
-
*
|
|
44614
|
+
* outright, alpha included <br>
|
|
44615
|
+
* A few draw types cannot honour every mode — 3D meshes, and fills using
|
|
44616
|
+
* a {@link Gradient} — and fall back to "normal" with a one-time console
|
|
44617
|
+
* warning. `setBlendMode` returns what it actually applied, so comparing
|
|
44618
|
+
* the result against your request detects that case.
|
|
44012
44619
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
|
|
44013
44620
|
* @param {string} [mode="normal"] - blend mode
|
|
44014
|
-
* @param {boolean} [premultipliedAlpha=true] - whether textures use premultiplied alpha (affects source blend factor)
|
|
44621
|
+
* @param {boolean} [premultipliedAlpha=true] - whether textures use premultiplied alpha (affects the source blend factor)
|
|
44015
44622
|
* @returns {string} the blend mode actually applied (may differ if the requested mode is unsupported)
|
|
44016
44623
|
*/
|
|
44017
44624
|
setBlendMode(mode = "normal", premultipliedAlpha = true) {
|
|
44018
44625
|
if (this.currentBlendMode !== mode || this.currentPremultipliedAlpha !== premultipliedAlpha) {
|
|
44019
44626
|
const gl = this.gl;
|
|
44627
|
+
this._drainAdvancedBlend();
|
|
44020
44628
|
this.flush();
|
|
44021
|
-
gl.enable(gl.BLEND);
|
|
44022
44629
|
this.currentBlendMode = mode;
|
|
44023
44630
|
this.currentPremultipliedAlpha = premultipliedAlpha;
|
|
44024
|
-
|
|
44025
|
-
|
|
44026
|
-
|
|
44027
|
-
|
|
44028
|
-
|
|
44029
|
-
|
|
44030
|
-
|
|
44031
|
-
|
|
44032
|
-
|
|
44033
|
-
|
|
44034
|
-
|
|
44035
|
-
|
|
44036
|
-
|
|
44037
|
-
|
|
44038
|
-
|
|
44039
|
-
|
|
44040
|
-
break;
|
|
44041
|
-
case "lighter":
|
|
44042
|
-
case "additive":
|
|
44043
|
-
case "add":
|
|
44044
|
-
gl.blendEquation(gl.FUNC_ADD);
|
|
44045
|
-
gl.blendFunc(srcAlpha, gl.ONE);
|
|
44046
|
-
break;
|
|
44047
|
-
case "multiply":
|
|
44048
|
-
gl.blendEquation(gl.FUNC_ADD);
|
|
44049
|
-
gl.blendFunc(gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA);
|
|
44050
|
-
break;
|
|
44051
|
-
case "darken":
|
|
44052
|
-
gl.blendEquation(gl.MIN);
|
|
44053
|
-
gl.blendFunc(gl.ONE, gl.ONE);
|
|
44054
|
-
break;
|
|
44055
|
-
case "lighten":
|
|
44056
|
-
gl.blendEquation(gl.MAX);
|
|
44057
|
-
gl.blendFunc(gl.ONE, gl.ONE);
|
|
44058
|
-
break;
|
|
44059
|
-
case "none":
|
|
44060
|
-
gl.disable(gl.BLEND);
|
|
44061
|
-
break;
|
|
44062
|
-
default:
|
|
44063
|
-
gl.blendEquation(gl.FUNC_ADD);
|
|
44064
|
-
gl.blendFunc(srcAlpha, gl.ONE_MINUS_SRC_ALPHA);
|
|
44065
|
-
this.currentBlendMode = "normal";
|
|
44066
|
-
break;
|
|
44631
|
+
if (typeof GL_BLEND_OP === "undefined") {
|
|
44632
|
+
initBlendEnums(gl);
|
|
44633
|
+
}
|
|
44634
|
+
const state3 = blendStateFor(normalizeBlendMode(mode), premultipliedAlpha);
|
|
44635
|
+
if (typeof state3 === "undefined") {
|
|
44636
|
+
gl.disable(gl.BLEND);
|
|
44637
|
+
} else {
|
|
44638
|
+
gl.enable(gl.BLEND);
|
|
44639
|
+
gl.blendEquation(GL_BLEND_OP[state3.operation]);
|
|
44640
|
+
gl.blendFunc(
|
|
44641
|
+
GL_BLEND_FACTOR[state3.srcFactor],
|
|
44642
|
+
GL_BLEND_FACTOR[state3.dstFactor]
|
|
44643
|
+
);
|
|
44644
|
+
}
|
|
44645
|
+
if (isSupportedBlendMode(mode) === false) {
|
|
44646
|
+
this.currentBlendMode = "normal";
|
|
44067
44647
|
}
|
|
44068
44648
|
}
|
|
44069
44649
|
return this.currentBlendMode;
|
|
@@ -44704,6 +45284,12 @@ var WebGLRenderer = class extends Renderer {
|
|
|
44704
45284
|
const grad = this._currentGradient;
|
|
44705
45285
|
const hasMask = this.maskLevel > 0;
|
|
44706
45286
|
this._currentGradient = null;
|
|
45287
|
+
const bracketed = isAdvancedBlendMode(this.currentBlendMode);
|
|
45288
|
+
if (bracketed === true) {
|
|
45289
|
+
this._warnAdvancedBlendFallback("gradient fills");
|
|
45290
|
+
this._drainAdvancedBlend();
|
|
45291
|
+
}
|
|
45292
|
+
this._advancedBlendBusy++;
|
|
44707
45293
|
this.flush();
|
|
44708
45294
|
gl.enable(gl.STENCIL_TEST);
|
|
44709
45295
|
gl.colorMask(false, false, false, false);
|
|
@@ -44740,16 +45326,17 @@ var WebGLRenderer = class extends Renderer {
|
|
|
44740
45326
|
} else {
|
|
44741
45327
|
gl.disable(gl.STENCIL_TEST);
|
|
44742
45328
|
}
|
|
45329
|
+
this._advancedBlendBusy--;
|
|
44743
45330
|
}
|
|
44744
45331
|
/**
|
|
44745
45332
|
* Reset (overrides) the renderer transformation matrix to the
|
|
44746
45333
|
* identity one, and then apply the given transformation matrix.
|
|
44747
45334
|
* @param {Matrix2d|Matrix3d|number} a - a matrix to transform by, or the a component to multiply the current matrix by
|
|
44748
|
-
* @param {number} b - the b component to multiply the current matrix by
|
|
44749
|
-
* @param {number} c - the c component to multiply the current matrix by
|
|
44750
|
-
* @param {number} d - the d component to multiply the current matrix by
|
|
44751
|
-
* @param {number} e - the e component to multiply the current matrix by
|
|
44752
|
-
* @param {number} f - the f component to multiply the current matrix by
|
|
45335
|
+
* @param {number} [b] - the b component to multiply the current matrix by; omitted when `a` is a matrix
|
|
45336
|
+
* @param {number} [c] - the c component to multiply the current matrix by; omitted when `a` is a matrix
|
|
45337
|
+
* @param {number} [d] - the d component to multiply the current matrix by; omitted when `a` is a matrix
|
|
45338
|
+
* @param {number} [e] - the e component to multiply the current matrix by; omitted when `a` is a matrix
|
|
45339
|
+
* @param {number} [f] - the f component to multiply the current matrix by; omitted when `a` is a matrix
|
|
44753
45340
|
*/
|
|
44754
45341
|
setTransform(a, b, c, d, e, f) {
|
|
44755
45342
|
this.resetTransform();
|
|
@@ -44759,11 +45346,11 @@ var WebGLRenderer = class extends Renderer {
|
|
|
44759
45346
|
* Multiply given matrix into the renderer tranformation matrix
|
|
44760
45347
|
* @see {@link WebGLRenderer.setTransform} which will reset the current transform matrix prior to performing the new transformation
|
|
44761
45348
|
* @param {Matrix2d|Matrix3d|number} a - a matrix to transform by, or the a component to multiply the current matrix by
|
|
44762
|
-
* @param {number} b - the b component to multiply the current matrix by
|
|
44763
|
-
* @param {number} c - the c component to multiply the current matrix by
|
|
44764
|
-
* @param {number} d - the d component to multiply the current matrix by
|
|
44765
|
-
* @param {number} e - the e component to multiply the current matrix by
|
|
44766
|
-
* @param {number} f - the f component to multiply the current matrix by
|
|
45349
|
+
* @param {number} [b] - the b component to multiply the current matrix by; omitted when `a` is a matrix
|
|
45350
|
+
* @param {number} [c] - the c component to multiply the current matrix by; omitted when `a` is a matrix
|
|
45351
|
+
* @param {number} [d] - the d component to multiply the current matrix by; omitted when `a` is a matrix
|
|
45352
|
+
* @param {number} [e] - the e component to multiply the current matrix by; omitted when `a` is a matrix
|
|
45353
|
+
* @param {number} [f] - the f component to multiply the current matrix by; omitted when `a` is a matrix
|
|
44767
45354
|
*/
|
|
44768
45355
|
transform(a, b, c, d, e, f) {
|
|
44769
45356
|
if (typeof a === "object") {
|
|
@@ -45752,6 +46339,9 @@ function dispatchEvent(normalizedEvents2) {
|
|
|
45752
46339
|
}
|
|
45753
46340
|
lastTimeStamp = pointer2.event.timeStamp;
|
|
45754
46341
|
}
|
|
46342
|
+
const worldOffset = _app2.world.pos;
|
|
46343
|
+
const absoluteWorldX = pointer2.gameWorldX + worldOffset.x;
|
|
46344
|
+
const absoluteWorldY = pointer2.gameWorldY + worldOffset.y;
|
|
45755
46345
|
currentPointer.pos.set(pointer2.gameWorldX, pointer2.gameWorldY);
|
|
45756
46346
|
currentPointer.setSize(pointer2.width, pointer2.height);
|
|
45757
46347
|
if (POINTER_MOVE.includes(pointer2.type)) {
|
|
@@ -45764,6 +46354,22 @@ function dispatchEvent(normalizedEvents2) {
|
|
|
45764
46354
|
(a, b) => _app2.world._sortReverseZ(a, b),
|
|
45765
46355
|
void 0
|
|
45766
46356
|
);
|
|
46357
|
+
if (worldOffset.x !== 0 || worldOffset.y !== 0) {
|
|
46358
|
+
currentPointer.pos.set(absoluteWorldX, absoluteWorldY);
|
|
46359
|
+
const absoluteCandidates = _app2.world.broadphase.retrieve(
|
|
46360
|
+
currentPointer,
|
|
46361
|
+
(a, b) => _app2.world._sortReverseZ(a, b),
|
|
46362
|
+
void 0
|
|
46363
|
+
);
|
|
46364
|
+
for (const candidate of candidates) {
|
|
46365
|
+
if (candidate.isFloating === true && !absoluteCandidates.includes(candidate)) {
|
|
46366
|
+
absoluteCandidates.push(candidate);
|
|
46367
|
+
}
|
|
46368
|
+
}
|
|
46369
|
+
candidates = absoluteCandidates.sort(
|
|
46370
|
+
(a, b) => _app2.world._sortReverseZ(a, b)
|
|
46371
|
+
);
|
|
46372
|
+
}
|
|
45767
46373
|
candidates = candidates.concat([_app2.viewport]);
|
|
45768
46374
|
for (let c = candidates.length, candidate; c--, candidate = candidates[c]; ) {
|
|
45769
46375
|
if (eventHandlers.has(candidate) && candidate.isKinematic !== true) {
|
|
@@ -45780,10 +46386,15 @@ function dispatchEvent(normalizedEvents2) {
|
|
|
45780
46386
|
}
|
|
45781
46387
|
if (typeof ancestor !== "undefined") {
|
|
45782
46388
|
const parentBounds = ancestor.getBounds();
|
|
45783
|
-
|
|
45784
|
-
|
|
46389
|
+
if (region.isFloating === true) {
|
|
46390
|
+
pointer2.gameLocalX = pointer2.gameX - parentBounds.x;
|
|
46391
|
+
pointer2.gameLocalY = pointer2.gameY - parentBounds.y;
|
|
46392
|
+
} else {
|
|
46393
|
+
pointer2.gameLocalX = absoluteWorldX - parentBounds.x;
|
|
46394
|
+
pointer2.gameLocalY = absoluteWorldY - parentBounds.y;
|
|
46395
|
+
}
|
|
45785
46396
|
}
|
|
45786
|
-
const eventInBounds = bounds.contains(pointer2.gameX, pointer2.gameY);
|
|
46397
|
+
const eventInBounds = region.isFloating === true ? bounds.contains(pointer2.gameX, pointer2.gameY) : bounds.contains(absoluteWorldX, absoluteWorldY);
|
|
45787
46398
|
switch (pointer2.type) {
|
|
45788
46399
|
case POINTER_MOVE[0]:
|
|
45789
46400
|
case POINTER_MOVE[1]:
|
|
@@ -49468,6 +50079,7 @@ var Light2d = class extends Renderable {
|
|
|
49468
50079
|
};
|
|
49469
50080
|
|
|
49470
50081
|
// src/particles/particle.ts
|
|
50082
|
+
var _spawn = new Vector2d();
|
|
49471
50083
|
var Particle = class extends Renderable {
|
|
49472
50084
|
vel;
|
|
49473
50085
|
image;
|
|
@@ -49479,7 +50091,6 @@ var Particle = class extends Renderable {
|
|
|
49479
50091
|
wind;
|
|
49480
50092
|
followTrajectory;
|
|
49481
50093
|
onlyInViewport;
|
|
49482
|
-
accurateBounds;
|
|
49483
50094
|
_deltaInv;
|
|
49484
50095
|
_halfW;
|
|
49485
50096
|
_halfH;
|
|
@@ -49499,13 +50110,40 @@ var Particle = class extends Renderable {
|
|
|
49499
50110
|
this.vel = vector2dPool.get();
|
|
49500
50111
|
this.onResetEvent(emitter, true);
|
|
49501
50112
|
}
|
|
50113
|
+
/**
|
|
50114
|
+
* Whether the bounds need recomputing before anyone reads them.
|
|
50115
|
+
*
|
|
50116
|
+
* A `Renderable` refreshes its bounds eagerly, from a callback fired on
|
|
50117
|
+
* every `pos` assignment. That is the right trade for a scene object, and
|
|
50118
|
+
* the wrong one for a particle: `update()` writes `pos.x` and `pos.y`
|
|
50119
|
+
* separately, so the callback fires TWICE per particle per frame, and both
|
|
50120
|
+
* runs happen before `currentTransform` is rebuilt — deriving bounds from
|
|
50121
|
+
* the previous frame's matrix and then throwing that away. Measured, the
|
|
50122
|
+
* redundant pass was about two thirds of the whole particle update loop.
|
|
50123
|
+
*
|
|
50124
|
+
* So a particle invalidates instead of recomputing, and pays once, on
|
|
50125
|
+
* read, for particles something actually looks at.
|
|
50126
|
+
*
|
|
50127
|
+
* Deliberately not a `#private` field: `updateBounds()` is reached from the
|
|
50128
|
+
* base constructor chain (`Polygon.setVertices`) before a subclass's field
|
|
50129
|
+
* initializers have run, and writing an undeclared private field throws.
|
|
50130
|
+
* @ignore
|
|
50131
|
+
*/
|
|
50132
|
+
_boundsDirty = true;
|
|
49502
50133
|
/**
|
|
49503
50134
|
* @ignore
|
|
49504
50135
|
*/
|
|
49505
50136
|
onResetEvent(emitter, newInstance = false) {
|
|
49506
50137
|
const image = emitter.settings.image;
|
|
49507
|
-
|
|
50138
|
+
const map = emitter._spawnMap;
|
|
50139
|
+
if (typeof map !== "undefined") {
|
|
50140
|
+
_spawn.set(emitter.getRandomPointX(), emitter.getRandomPointY());
|
|
50141
|
+
map.apply(_spawn);
|
|
50142
|
+
this.pos.set(_spawn.x, _spawn.y);
|
|
50143
|
+
} else {
|
|
49508
50144
|
this.pos.set(emitter.getRandomPointX(), emitter.getRandomPointY());
|
|
50145
|
+
}
|
|
50146
|
+
if (!newInstance) {
|
|
49509
50147
|
this.resize(image.width, image.height);
|
|
49510
50148
|
this.currentTransform.identity();
|
|
49511
50149
|
}
|
|
@@ -49513,7 +50151,13 @@ var Particle = class extends Renderable {
|
|
|
49513
50151
|
this._halfW = this.width / 2;
|
|
49514
50152
|
this._halfH = this.height / 2;
|
|
49515
50153
|
this.alwaysUpdate = true;
|
|
50154
|
+
this.pos.setCallback(() => {
|
|
50155
|
+
this._boundsDirty = true;
|
|
50156
|
+
this.isDirty = true;
|
|
50157
|
+
});
|
|
50158
|
+
this._boundsDirty = true;
|
|
49516
50159
|
this.anchorPoint.set(0, 0);
|
|
50160
|
+
this.autoTransform = false;
|
|
49517
50161
|
if (typeof emitter.settings.tint === "string") {
|
|
49518
50162
|
this.tint.parseCSS(emitter.settings.tint);
|
|
49519
50163
|
}
|
|
@@ -49538,7 +50182,6 @@ var Particle = class extends Renderable {
|
|
|
49538
50182
|
this.wind = emitter.settings.wind;
|
|
49539
50183
|
this.followTrajectory = emitter.settings.followTrajectory;
|
|
49540
50184
|
this.onlyInViewport = emitter.settings.onlyInViewport;
|
|
49541
|
-
this.accurateBounds = emitter.settings.accurateBounds;
|
|
49542
50185
|
this._deltaInv = emitter._deltaInv;
|
|
49543
50186
|
if (!emitter.settings.followTrajectory) {
|
|
49544
50187
|
this._angle = randomFloat(
|
|
@@ -49603,12 +50246,108 @@ var Particle = class extends Renderable {
|
|
|
49603
50246
|
0,
|
|
49604
50247
|
1
|
|
49605
50248
|
);
|
|
49606
|
-
if (this.accurateBounds) {
|
|
49607
|
-
this.updateBounds();
|
|
49608
|
-
}
|
|
49609
50249
|
this.isDirty = this.inViewport || !this.onlyInViewport;
|
|
49610
50250
|
return super.update(dt);
|
|
49611
50251
|
}
|
|
50252
|
+
/**
|
|
50253
|
+
* `autoTransform` is off (see `onResetEvent`), so the base `preDraw` will
|
|
50254
|
+
* not apply the matrix — append it here instead, unconjugated. Appending
|
|
50255
|
+
* after `super` rather than splicing into it is order-equivalent for a
|
|
50256
|
+
* particle specifically: no flip, no mask, and the anchor is zeroed, so
|
|
50257
|
+
* nothing the base method emits interacts with this.
|
|
50258
|
+
* @ignore
|
|
50259
|
+
*/
|
|
50260
|
+
preDraw(renderer) {
|
|
50261
|
+
super.preDraw(renderer);
|
|
50262
|
+
if (!this.currentTransform.isIdentity()) {
|
|
50263
|
+
renderer.transform(this.currentTransform);
|
|
50264
|
+
}
|
|
50265
|
+
}
|
|
50266
|
+
/**
|
|
50267
|
+
* `currentTransform` already places the particle, so the frame it
|
|
50268
|
+
* produces is positioned — only the ancestors' contribution is still
|
|
50269
|
+
* missing. The base implementation would add this particle's own `pos` on
|
|
50270
|
+
* top of a matrix that already contains it, counting it twice.
|
|
50271
|
+
* @ignore
|
|
50272
|
+
*/
|
|
50273
|
+
/**
|
|
50274
|
+
* Bounds are recomputed here rather than when `pos` moves, so a particle
|
|
50275
|
+
* nothing looks at this frame pays nothing at all.
|
|
50276
|
+
*
|
|
50277
|
+
* `updateBounds()` deliberately keeps its eager contract — a caller that
|
|
50278
|
+
* asks for a recompute, such as {@link Container} aggregating child bounds
|
|
50279
|
+
* under `enableChildBoundsUpdate`, still gets fresh values back.
|
|
50280
|
+
* @ignore
|
|
50281
|
+
*/
|
|
50282
|
+
getBounds() {
|
|
50283
|
+
const bounds = super.getBounds();
|
|
50284
|
+
if (this._boundsDirty) {
|
|
50285
|
+
this.updateBounds();
|
|
50286
|
+
}
|
|
50287
|
+
return bounds;
|
|
50288
|
+
}
|
|
50289
|
+
updateBounds(absolute = true) {
|
|
50290
|
+
this._boundsDirty = false;
|
|
50291
|
+
if (!this.isRenderable) {
|
|
50292
|
+
return super.updateBounds(absolute);
|
|
50293
|
+
}
|
|
50294
|
+
const bounds = this.getBounds();
|
|
50295
|
+
bounds.clear();
|
|
50296
|
+
bounds.addFrame(0, 0, this.width, this.height, this.currentTransform);
|
|
50297
|
+
if (absolute && this.ancestor) {
|
|
50298
|
+
const absPos = this.#frameOrigin().getAbsolutePosition();
|
|
50299
|
+
bounds.centerOn(
|
|
50300
|
+
absPos.x + bounds.x + bounds.width / 2,
|
|
50301
|
+
absPos.y + bounds.y + bounds.height / 2
|
|
50302
|
+
);
|
|
50303
|
+
}
|
|
50304
|
+
return bounds;
|
|
50305
|
+
}
|
|
50306
|
+
/**
|
|
50307
|
+
* The container this particle's position is measured from — its emitter
|
|
50308
|
+
* under the default local reference space, something else otherwise.
|
|
50309
|
+
* @ignore
|
|
50310
|
+
*/
|
|
50311
|
+
#frameOrigin() {
|
|
50312
|
+
const emitter = this.ancestor;
|
|
50313
|
+
const space = emitter?.settings?.referenceSpace;
|
|
50314
|
+
if (typeof space === "undefined" || space === "local") {
|
|
50315
|
+
return emitter;
|
|
50316
|
+
}
|
|
50317
|
+
if (space === "world") {
|
|
50318
|
+
return emitter.ancestor ?? emitter;
|
|
50319
|
+
}
|
|
50320
|
+
const target = space;
|
|
50321
|
+
return target && typeof target.pos !== "undefined" ? target : emitter;
|
|
50322
|
+
}
|
|
50323
|
+
/**
|
|
50324
|
+
* A particle is positioned within its reference frame, which is not
|
|
50325
|
+
* necessarily its parent — so summing up the ancestor chain, as the base
|
|
50326
|
+
* implementation does, would measure from the wrong place.
|
|
50327
|
+
* @ignore
|
|
50328
|
+
*/
|
|
50329
|
+
getAbsolutePosition() {
|
|
50330
|
+
const origin = this.#frameOrigin();
|
|
50331
|
+
if (origin === this.ancestor) {
|
|
50332
|
+
return super.getAbsolutePosition();
|
|
50333
|
+
}
|
|
50334
|
+
if (typeof this._absPos === "undefined") {
|
|
50335
|
+
this._absPos = vector3dPool.get();
|
|
50336
|
+
}
|
|
50337
|
+
this._absPos.set(this.pos.x, this.pos.y, this.depth);
|
|
50338
|
+
if (!this.floating) {
|
|
50339
|
+
this._absPos.add(origin.getAbsolutePosition());
|
|
50340
|
+
}
|
|
50341
|
+
return this._absPos;
|
|
50342
|
+
}
|
|
50343
|
+
/**
|
|
50344
|
+
* With the placement in `currentTransform` and `autoTransform` off, the
|
|
50345
|
+
* base composition would describe a transform this class never applies.
|
|
50346
|
+
* @ignore
|
|
50347
|
+
*/
|
|
50348
|
+
getLocalTransform(out) {
|
|
50349
|
+
return out.copy(this.currentTransform);
|
|
50350
|
+
}
|
|
49612
50351
|
/**
|
|
49613
50352
|
* @ignore
|
|
49614
50353
|
*/
|
|
@@ -49847,6 +50586,27 @@ var Entity = class _Entity extends Renderable {
|
|
|
49847
50586
|
);
|
|
49848
50587
|
}
|
|
49849
50588
|
}
|
|
50589
|
+
/**
|
|
50590
|
+
* An entity replaces {@link Renderable#preDraw} wholesale — no flip, no
|
|
50591
|
+
* conjugation, no anchor offset, just its position biased by the body
|
|
50592
|
+
* bounds — so the inherited composition would describe a transform this
|
|
50593
|
+
* class never applies. Mirrors the `preDraw` above instead.
|
|
50594
|
+
* @protected
|
|
50595
|
+
* @param {Matrix3d} out - matrix to write into
|
|
50596
|
+
* @returns {Matrix3d} `out`, for chaining
|
|
50597
|
+
*/
|
|
50598
|
+
getLocalTransform(out) {
|
|
50599
|
+
const bounds = this.body.getBounds();
|
|
50600
|
+
out.identity();
|
|
50601
|
+
out.translate(this.pos.x + bounds.x, this.pos.y + bounds.y);
|
|
50602
|
+
if (this.renderable instanceof Renderable) {
|
|
50603
|
+
out.translate(
|
|
50604
|
+
this.anchorPoint.x * bounds.width,
|
|
50605
|
+
this.anchorPoint.y * bounds.height
|
|
50606
|
+
);
|
|
50607
|
+
}
|
|
50608
|
+
return out;
|
|
50609
|
+
}
|
|
49850
50610
|
/**
|
|
49851
50611
|
* draw this entity (automatically called by melonJS)
|
|
49852
50612
|
* @param {CanvasRenderer|WebGLRenderer} renderer - a renderer instance
|
|
@@ -50477,7 +51237,7 @@ var Trigger = class extends Renderable {
|
|
|
50477
51237
|
};
|
|
50478
51238
|
|
|
50479
51239
|
// src/version.ts
|
|
50480
|
-
var version = "20.
|
|
51240
|
+
var version = "20.2.0";
|
|
50481
51241
|
|
|
50482
51242
|
// src/system/bootstrap.ts
|
|
50483
51243
|
var initialized = false;
|
|
@@ -52593,72 +53353,12 @@ var FRAME_UNIFORM_SIZE = 80;
|
|
|
52593
53353
|
var CLEAR_UNIFORM_SIZE = 16;
|
|
52594
53354
|
|
|
52595
53355
|
// src/video/webgpu/pipeline/cache.js
|
|
53356
|
+
function gpuBlendState(mode, premultipliedAlpha) {
|
|
53357
|
+
const component = blendStateFor(mode, premultipliedAlpha);
|
|
53358
|
+
return typeof component === "undefined" ? void 0 : { color: component, alpha: component };
|
|
53359
|
+
}
|
|
52596
53360
|
var MAX_QUAD_TEXTURES = 8;
|
|
52597
53361
|
var DEPTH_STENCIL_FORMAT = "depth24plus-stencil8";
|
|
52598
|
-
function blendStateFor(mode, premultipliedAlpha) {
|
|
52599
|
-
const src = premultipliedAlpha ? "one" : "src-alpha";
|
|
52600
|
-
let component;
|
|
52601
|
-
switch (mode) {
|
|
52602
|
-
case "none":
|
|
52603
|
-
return void 0;
|
|
52604
|
-
case "additive":
|
|
52605
|
-
component = { operation: "add", srcFactor: src, dstFactor: "one" };
|
|
52606
|
-
break;
|
|
52607
|
-
case "multiply":
|
|
52608
|
-
component = {
|
|
52609
|
-
operation: "add",
|
|
52610
|
-
srcFactor: "dst",
|
|
52611
|
-
dstFactor: "one-minus-src-alpha"
|
|
52612
|
-
};
|
|
52613
|
-
break;
|
|
52614
|
-
case "exclusion":
|
|
52615
|
-
component = {
|
|
52616
|
-
operation: "add",
|
|
52617
|
-
srcFactor: "one-minus-dst",
|
|
52618
|
-
dstFactor: "one-minus-src"
|
|
52619
|
-
};
|
|
52620
|
-
break;
|
|
52621
|
-
case "screen":
|
|
52622
|
-
component = {
|
|
52623
|
-
operation: "add",
|
|
52624
|
-
srcFactor: "one",
|
|
52625
|
-
dstFactor: "one-minus-src"
|
|
52626
|
-
};
|
|
52627
|
-
break;
|
|
52628
|
-
case "darken":
|
|
52629
|
-
component = { operation: "min", srcFactor: "one", dstFactor: "one" };
|
|
52630
|
-
break;
|
|
52631
|
-
case "lighten":
|
|
52632
|
-
component = { operation: "max", srcFactor: "one", dstFactor: "one" };
|
|
52633
|
-
break;
|
|
52634
|
-
default:
|
|
52635
|
-
component = {
|
|
52636
|
-
operation: "add",
|
|
52637
|
-
srcFactor: src,
|
|
52638
|
-
dstFactor: "one-minus-src-alpha"
|
|
52639
|
-
};
|
|
52640
|
-
break;
|
|
52641
|
-
}
|
|
52642
|
-
return { color: component, alpha: component };
|
|
52643
|
-
}
|
|
52644
|
-
function normalizeBlendMode(mode) {
|
|
52645
|
-
switch (mode) {
|
|
52646
|
-
case "none":
|
|
52647
|
-
case "multiply":
|
|
52648
|
-
case "screen":
|
|
52649
|
-
case "darken":
|
|
52650
|
-
case "lighten":
|
|
52651
|
-
case "exclusion":
|
|
52652
|
-
case "normal":
|
|
52653
|
-
return mode;
|
|
52654
|
-
case "additive":
|
|
52655
|
-
case "add":
|
|
52656
|
-
case "lighter":
|
|
52657
|
-
return "additive";
|
|
52658
|
-
default:
|
|
52659
|
-
return "normal";
|
|
52660
|
-
}
|
|
52661
|
-
}
|
|
52662
53362
|
var STENCIL_STATES = {
|
|
52663
53363
|
none: {
|
|
52664
53364
|
stencil: {
|
|
@@ -53004,7 +53704,7 @@ var WebGPUPipelineCache = class _WebGPUPipelineCache {
|
|
|
53004
53704
|
targets: [
|
|
53005
53705
|
{
|
|
53006
53706
|
format: this.format,
|
|
53007
|
-
blend: shaderKey === "clear" ? void 0 :
|
|
53707
|
+
blend: shaderKey === "clear" ? void 0 : gpuBlendState(blend, pma),
|
|
53008
53708
|
writeMask: stencil.colorWriteMask
|
|
53009
53709
|
}
|
|
53010
53710
|
]
|
|
@@ -53085,9 +53785,16 @@ var WebGPUQuadBatcher = class extends WebGPUBatcher {
|
|
|
53085
53785
|
},
|
|
53086
53786
|
onEvict: (slot) => {
|
|
53087
53787
|
this.segmentEntries[slot] = void 0;
|
|
53788
|
+
if (this._memoSlot === slot) {
|
|
53789
|
+
this._memoView = null;
|
|
53790
|
+
}
|
|
53088
53791
|
}
|
|
53089
53792
|
});
|
|
53090
53793
|
this.segmentEntries = [];
|
|
53794
|
+
this._memoView = null;
|
|
53795
|
+
this._memoFilter = null;
|
|
53796
|
+
this._memoWrap = null;
|
|
53797
|
+
this._memoSlot = 0;
|
|
53091
53798
|
this.segmentGroup = null;
|
|
53092
53799
|
this.composedGroups = /* @__PURE__ */ new Map();
|
|
53093
53800
|
this.resourceIds = /* @__PURE__ */ new WeakMap();
|
|
@@ -53186,17 +53893,24 @@ var WebGPUQuadBatcher = class extends WebGPUBatcher {
|
|
|
53186
53893
|
const record = store.getResidentRecord(texture, { force: reupload });
|
|
53187
53894
|
const wrap = texture.repeat ?? "no-repeat";
|
|
53188
53895
|
const filter = typeof texture.filter === "string" ? texture.filter : renderer.getDefaultTextureFilter();
|
|
53896
|
+
if (record.view === this._memoView && filter === this._memoFilter && wrap === this._memoWrap) {
|
|
53897
|
+
return this._memoSlot;
|
|
53898
|
+
}
|
|
53189
53899
|
const slotKey = `${this.resourceId(record.view)}|${filter}|${wrap}`;
|
|
53190
|
-
|
|
53191
|
-
|
|
53192
|
-
|
|
53900
|
+
let resolved = this.slotTable.peek(slotKey);
|
|
53901
|
+
if (resolved === void 0) {
|
|
53902
|
+
resolved = this.slotTable.slotFor(slotKey);
|
|
53903
|
+
this.segmentEntries[resolved] = {
|
|
53193
53904
|
view: record.view,
|
|
53194
53905
|
sampler: store.getSampler(filter, wrap)
|
|
53195
53906
|
};
|
|
53196
53907
|
this.segmentGroup = null;
|
|
53197
|
-
return slot;
|
|
53198
53908
|
}
|
|
53199
|
-
|
|
53909
|
+
this._memoView = record.view;
|
|
53910
|
+
this._memoFilter = filter;
|
|
53911
|
+
this._memoWrap = wrap;
|
|
53912
|
+
this._memoSlot = resolved;
|
|
53913
|
+
return resolved;
|
|
53200
53914
|
}
|
|
53201
53915
|
/**
|
|
53202
53916
|
* a stable id for a GPU resource object (bind-group composition keys)
|
|
@@ -55236,7 +55950,7 @@ function resolveDepthOps(meshDepthActive, pendingDepthClear) {
|
|
|
55236
55950
|
depthStoreOp: "store"
|
|
55237
55951
|
};
|
|
55238
55952
|
}
|
|
55239
|
-
var WebGPURenderer = class extends Renderer {
|
|
55953
|
+
var WebGPURenderer = class _WebGPURenderer extends Renderer {
|
|
55240
55954
|
/**
|
|
55241
55955
|
* @param {ApplicationSettings} options - The renderer parameters
|
|
55242
55956
|
*/
|
|
@@ -55273,6 +55987,13 @@ var WebGPURenderer = class extends Renderer {
|
|
|
55273
55987
|
this.commandEncoder = null;
|
|
55274
55988
|
this.renderPass = null;
|
|
55275
55989
|
this.currentRenderTarget = null;
|
|
55990
|
+
this._advancedBlendEffect = void 0;
|
|
55991
|
+
this._advancedBlendCapture = void 0;
|
|
55992
|
+
this._advancedBlendTarget = void 0;
|
|
55993
|
+
this._advancedBlendOpen = false;
|
|
55994
|
+
this._advancedBlendBusy = 0;
|
|
55995
|
+
this._advancedBlendParent = null;
|
|
55996
|
+
this._advancedBlendWarned = /* @__PURE__ */ new Set();
|
|
55276
55997
|
this.pendingColorClear = false;
|
|
55277
55998
|
this.pendingClearValue = null;
|
|
55278
55999
|
this.pendingStencilClear = false;
|
|
@@ -55811,6 +56532,16 @@ var WebGPURenderer = class extends Renderer {
|
|
|
55811
56532
|
* frame, or null when no device is available
|
|
55812
56533
|
*/
|
|
55813
56534
|
toFrameTexture(options = {}) {
|
|
56535
|
+
const busy = this._advancedBlendBusy;
|
|
56536
|
+
this._advancedBlendBusy = (busy ?? 0) + 1;
|
|
56537
|
+
try {
|
|
56538
|
+
return _WebGPURenderer.prototype._toFrameTexture.call(this, options);
|
|
56539
|
+
} finally {
|
|
56540
|
+
this._advancedBlendBusy = busy;
|
|
56541
|
+
}
|
|
56542
|
+
}
|
|
56543
|
+
/** @ignore */
|
|
56544
|
+
_toFrameTexture(options = {}) {
|
|
55814
56545
|
if (typeof this.device === "undefined") {
|
|
55815
56546
|
return null;
|
|
55816
56547
|
}
|
|
@@ -56026,6 +56757,7 @@ var WebGPURenderer = class extends Renderer {
|
|
|
56026
56757
|
* @override
|
|
56027
56758
|
*/
|
|
56028
56759
|
blitEffect(source, x, y, width, height, effect, keepBlend = false) {
|
|
56760
|
+
this._advancedBlendBusy++;
|
|
56029
56761
|
const batcher = this.setBatcher("quad");
|
|
56030
56762
|
blitSavedProjection.copy(this.projectionMatrix);
|
|
56031
56763
|
this.projectionMatrix.ortho(0, width, height, 0, -1, 1);
|
|
@@ -56033,6 +56765,106 @@ var WebGPURenderer = class extends Renderer {
|
|
|
56033
56765
|
batcher.blitTexture(source, x, y, width, height, effect, keepBlend);
|
|
56034
56766
|
this.projectionMatrix.copy(blitSavedProjection);
|
|
56035
56767
|
this.pushFrameGlobals();
|
|
56768
|
+
this._advancedBlendBusy--;
|
|
56769
|
+
}
|
|
56770
|
+
/**
|
|
56771
|
+
* Say once, per excluded path and mode, that an advanced blend mode is
|
|
56772
|
+
* falling back to `"normal"`. A silent data-dependent fallback is exactly
|
|
56773
|
+
* what the advanced-blend work exists to remove, so the exclusions are
|
|
56774
|
+
* loud.
|
|
56775
|
+
* @param {string} what - the excluded path, named for the message
|
|
56776
|
+
* @ignore
|
|
56777
|
+
*/
|
|
56778
|
+
_warnAdvancedBlendFallback(what) {
|
|
56779
|
+
const key = `${what}:${this.currentBlendMode}`;
|
|
56780
|
+
if (this._advancedBlendWarned.has(key)) {
|
|
56781
|
+
return;
|
|
56782
|
+
}
|
|
56783
|
+
this._advancedBlendWarned.add(key);
|
|
56784
|
+
console.warn(
|
|
56785
|
+
`WebGPURenderer: blend mode "${this.currentBlendMode}" is not supported for ${what} and falls back to "normal"`
|
|
56786
|
+
);
|
|
56787
|
+
}
|
|
56788
|
+
/**
|
|
56789
|
+
* Close a pending advanced-blend bracket, if one is open and we are not
|
|
56790
|
+
* already inside the bracket machinery.
|
|
56791
|
+
* @ignore
|
|
56792
|
+
*/
|
|
56793
|
+
_drainAdvancedBlend() {
|
|
56794
|
+
if (this._advancedBlendOpen === true && this._advancedBlendBusy === 0) {
|
|
56795
|
+
this._closeAdvancedBlend();
|
|
56796
|
+
}
|
|
56797
|
+
}
|
|
56798
|
+
/**
|
|
56799
|
+
* Open an advanced-blend bracket: capture the destination, then redirect
|
|
56800
|
+
* this draw into an offscreen target.
|
|
56801
|
+
* @returns {boolean} false when the effect could not be realized, in which
|
|
56802
|
+
* case the draw proceeds unbracketed (plain source-over)
|
|
56803
|
+
* @ignore
|
|
56804
|
+
*/
|
|
56805
|
+
_openAdvancedBlend() {
|
|
56806
|
+
const canvas = this.getCanvas();
|
|
56807
|
+
const w = canvas.width;
|
|
56808
|
+
const h = canvas.height;
|
|
56809
|
+
this._advancedBlendBusy++;
|
|
56810
|
+
if (typeof this._advancedBlendEffect === "undefined") {
|
|
56811
|
+
this._advancedBlendEffect = new BlendEffect(this);
|
|
56812
|
+
}
|
|
56813
|
+
if (this._advancedBlendEffect.enabled !== true) {
|
|
56814
|
+
this._advancedBlendBusy--;
|
|
56815
|
+
this._warnAdvancedBlendFallback("this device");
|
|
56816
|
+
return false;
|
|
56817
|
+
}
|
|
56818
|
+
this._advancedBlendEffect.setBlendMode(this.currentBlendMode);
|
|
56819
|
+
this.currentBatcher?.flush();
|
|
56820
|
+
this._advancedBlendCapture = this.toFrameTexture({
|
|
56821
|
+
target: this._advancedBlendCapture ?? null
|
|
56822
|
+
});
|
|
56823
|
+
this._advancedBlendEffect.setTexture(
|
|
56824
|
+
"backdrop",
|
|
56825
|
+
this._advancedBlendCapture
|
|
56826
|
+
);
|
|
56827
|
+
this._advancedBlendParent = this.currentRenderTarget;
|
|
56828
|
+
if (typeof this._advancedBlendTarget === "undefined") {
|
|
56829
|
+
this._advancedBlendTarget = new WebGPURenderTarget(this, w, h, {
|
|
56830
|
+
sampleCount: 1
|
|
56831
|
+
});
|
|
56832
|
+
} else {
|
|
56833
|
+
this._advancedBlendTarget.resize(w, h);
|
|
56834
|
+
}
|
|
56835
|
+
this.setRenderTarget(this._advancedBlendTarget, { clear: true });
|
|
56836
|
+
this._advancedBlendOpen = true;
|
|
56837
|
+
this._advancedBlendBusy--;
|
|
56838
|
+
return true;
|
|
56839
|
+
}
|
|
56840
|
+
/**
|
|
56841
|
+
* Close an advanced-blend bracket: drain the offscreen, retarget to the
|
|
56842
|
+
* parent, and composite through {@link BlendEffect}.
|
|
56843
|
+
* @ignore
|
|
56844
|
+
*/
|
|
56845
|
+
_closeAdvancedBlend() {
|
|
56846
|
+
const canvas = this.getCanvas();
|
|
56847
|
+
const w = canvas.width;
|
|
56848
|
+
const h = canvas.height;
|
|
56849
|
+
this._advancedBlendBusy++;
|
|
56850
|
+
this._advancedBlendOpen = false;
|
|
56851
|
+
this.currentBatcher?.flush();
|
|
56852
|
+
this.setRenderTarget(this._advancedBlendParent);
|
|
56853
|
+
this._advancedBlendParent = null;
|
|
56854
|
+
const mode = this.currentBlendMode;
|
|
56855
|
+
this.setBlendMode("normal", true);
|
|
56856
|
+
this.blitEffect(
|
|
56857
|
+
this._advancedBlendTarget,
|
|
56858
|
+
0,
|
|
56859
|
+
0,
|
|
56860
|
+
w,
|
|
56861
|
+
h,
|
|
56862
|
+
this._advancedBlendEffect,
|
|
56863
|
+
true
|
|
56864
|
+
);
|
|
56865
|
+
this.currentBatcher?.flush();
|
|
56866
|
+
this.currentBlendMode = mode;
|
|
56867
|
+
this._advancedBlendBusy--;
|
|
56036
56868
|
}
|
|
56037
56869
|
/**
|
|
56038
56870
|
* a draw is about to be recorded outside the clear()/flush() bracket
|
|
@@ -56056,6 +56888,9 @@ var WebGPURenderer = class extends Renderer {
|
|
|
56056
56888
|
* @override
|
|
56057
56889
|
*/
|
|
56058
56890
|
flush() {
|
|
56891
|
+
if (this._advancedBlendOpen === true && this._advancedBlendBusy === 0) {
|
|
56892
|
+
this._closeAdvancedBlend();
|
|
56893
|
+
}
|
|
56059
56894
|
this.currentBatcher?.flush();
|
|
56060
56895
|
if (this.renderPass !== null) {
|
|
56061
56896
|
this.renderPass.end();
|
|
@@ -56090,6 +56925,9 @@ var WebGPURenderer = class extends Renderer {
|
|
|
56090
56925
|
this.pendingColorClear = false;
|
|
56091
56926
|
this.pendingDepthClear = false;
|
|
56092
56927
|
this.currentPipeline = null;
|
|
56928
|
+
for (const batcher of this.batchers.values()) {
|
|
56929
|
+
batcher.reset();
|
|
56930
|
+
}
|
|
56093
56931
|
this.destroyRetiredTextures();
|
|
56094
56932
|
}
|
|
56095
56933
|
/**
|
|
@@ -56145,6 +56983,7 @@ var WebGPURenderer = class extends Renderer {
|
|
|
56145
56983
|
if (typeof this.device === "undefined") {
|
|
56146
56984
|
return;
|
|
56147
56985
|
}
|
|
56986
|
+
this._drainAdvancedBlend();
|
|
56148
56987
|
this.currentBatcher?.flush();
|
|
56149
56988
|
const pass = this.ensurePass();
|
|
56150
56989
|
let rgba;
|
|
@@ -56241,6 +57080,18 @@ var WebGPURenderer = class extends Renderer {
|
|
|
56241
57080
|
if (typeof batcher === "undefined") {
|
|
56242
57081
|
throw new Error("Invalid Batcher");
|
|
56243
57082
|
}
|
|
57083
|
+
if (this._advancedBlendBusy === 0) {
|
|
57084
|
+
if (this._advancedBlendOpen === true) {
|
|
57085
|
+
this._closeAdvancedBlend();
|
|
57086
|
+
}
|
|
57087
|
+
if (isAdvancedBlendMode(this.currentBlendMode) === true) {
|
|
57088
|
+
if (name === "mesh" || name === "litMesh") {
|
|
57089
|
+
this._warnAdvancedBlendFallback("3D meshes");
|
|
57090
|
+
} else {
|
|
57091
|
+
this._openAdvancedBlend();
|
|
57092
|
+
}
|
|
57093
|
+
}
|
|
57094
|
+
}
|
|
56244
57095
|
if (this.currentBatcher !== batcher) {
|
|
56245
57096
|
if (name !== "mesh" && name !== "litMesh" && // see WebGLRenderer#_canDrainShadows: a transition raised while
|
|
56246
57097
|
// a mask is being stencilled in (colour writes off) or inside a
|
|
@@ -56477,22 +57328,56 @@ var WebGPURenderer = class extends Renderer {
|
|
|
56477
57328
|
}
|
|
56478
57329
|
}
|
|
56479
57330
|
/**
|
|
56480
|
-
*
|
|
56481
|
-
*
|
|
56482
|
-
*
|
|
56483
|
-
*
|
|
56484
|
-
*
|
|
57331
|
+
* set the current blend mode for this renderer. <br>
|
|
57332
|
+
* Every renderer supports the full set: <br>
|
|
57333
|
+
* - "normal" : draws new content on top of the existing content <br>
|
|
57334
|
+
* <img src="../images/normal-blendmode.png" width="180"/> <br>
|
|
57335
|
+
* - "add", "additive", or "lighter" : color values are added together <br>
|
|
57336
|
+
* <img src="../images/add-blendmode.png" width="180"/> <br>
|
|
57337
|
+
* - "multiply" : pixels are multiplied, resulting in a darker picture <br>
|
|
57338
|
+
* <img src="../images/multiply-blendmode.png" width="180"/> <br>
|
|
57339
|
+
* - "screen" : pixels are inverted, multiplied, and inverted again (opposite of multiply) <br>
|
|
57340
|
+
* <img src="../images/screen-blendmode.png" width="180"/> <br>
|
|
57341
|
+
* - "darken" : retains the darkest pixels of both layers <br>
|
|
57342
|
+
* <img src="../images/darken-blendmode.png" width="180"/> <br>
|
|
57343
|
+
* - "lighten" : retains the lightest pixels of both layers <br>
|
|
57344
|
+
* <img src="../images/lighten-blendmode.png" width="180"/> <br>
|
|
57345
|
+
* - "overlay" : multiplies or screens, depending on the backdrop <br>
|
|
57346
|
+
* <img src="../images/overlay-blendmode.png" width="180"/> <br>
|
|
57347
|
+
* - "hard-light" : overlay with the layers swapped — a harsh spotlight <br>
|
|
57348
|
+
* <img src="../images/hard-light-blendmode.png" width="180"/> <br>
|
|
57349
|
+
* - "soft-light" : a diffused spotlight, gentler than hard-light <br>
|
|
57350
|
+
* <img src="../images/soft-light-blendmode.png" width="180"/> <br>
|
|
57351
|
+
* - "color-dodge" : brightens the backdrop to reflect the source <br>
|
|
57352
|
+
* <img src="../images/color-dodge-blendmode.png" width="180"/> <br>
|
|
57353
|
+
* - "color-burn" : darkens the backdrop to reflect the source <br>
|
|
57354
|
+
* <img src="../images/color-burn-blendmode.png" width="180"/> <br>
|
|
57355
|
+
* - "difference" : the absolute difference of the two layers <br>
|
|
57356
|
+
* <img src="../images/difference-blendmode.png" width="180"/> <br>
|
|
57357
|
+
* - "exclusion" : like difference, but lower in contrast <br>
|
|
57358
|
+
* <img src="../images/exclusion-blendmode.png" width="180"/> <br>
|
|
57359
|
+
* - "none" : blending disabled — the source replaces the destination
|
|
57360
|
+
* outright, alpha included <br>
|
|
57361
|
+
* A few draw types cannot honour every mode — 3D meshes, and fills using
|
|
57362
|
+
* a {@link Gradient} — and fall back to "normal" with a one-time console
|
|
57363
|
+
* warning. `setBlendMode` returns what it actually applied, so comparing
|
|
57364
|
+
* the result against your request detects that case.
|
|
57365
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
|
|
57366
|
+
* @param {string} [mode="normal"] - blend mode
|
|
56485
57367
|
* @param {boolean} [premultipliedAlpha=true] - whether textures use premultiplied alpha (affects the source blend factor)
|
|
56486
|
-
* @returns {string} the blend mode actually applied
|
|
57368
|
+
* @returns {string} the blend mode actually applied (may differ if the requested mode is unsupported)
|
|
56487
57369
|
*/
|
|
56488
57370
|
setBlendMode(mode = "normal", premultipliedAlpha = true) {
|
|
56489
57371
|
const normalized = normalizeBlendMode(mode);
|
|
56490
|
-
|
|
57372
|
+
const advanced = isAdvancedBlendMode(mode);
|
|
57373
|
+
const tracked = advanced === true ? mode : normalized;
|
|
57374
|
+
if (this.currentBlendMode !== tracked || this.premultipliedAlpha !== premultipliedAlpha) {
|
|
57375
|
+
this._drainAdvancedBlend();
|
|
56491
57376
|
this.currentBatcher?.flush();
|
|
56492
|
-
this.currentBlendMode =
|
|
57377
|
+
this.currentBlendMode = tracked;
|
|
56493
57378
|
this.premultipliedAlpha = premultipliedAlpha;
|
|
56494
57379
|
}
|
|
56495
|
-
return
|
|
57380
|
+
return reportedBlendMode(mode);
|
|
56496
57381
|
}
|
|
56497
57382
|
/**
|
|
56498
57383
|
* Set the projection matrix — pushes a fresh frame-globals slot so
|
|
@@ -56980,6 +57865,11 @@ var WebGPURenderer = class extends Renderer {
|
|
|
56980
57865
|
const grad = this.currentGradient;
|
|
56981
57866
|
const hasMask = this.maskLevel > 0;
|
|
56982
57867
|
this.currentGradient = null;
|
|
57868
|
+
if (isAdvancedBlendMode(this.currentBlendMode) === true) {
|
|
57869
|
+
this._warnAdvancedBlendFallback("gradient fills");
|
|
57870
|
+
this._drainAdvancedBlend();
|
|
57871
|
+
}
|
|
57872
|
+
this._advancedBlendBusy++;
|
|
56983
57873
|
this.currentBatcher?.flush();
|
|
56984
57874
|
const visibleRef = this.maskVisibleRef;
|
|
56985
57875
|
let markRef = 1;
|
|
@@ -57015,6 +57905,7 @@ var WebGPURenderer = class extends Renderer {
|
|
|
57015
57905
|
this.stencilMode = "none";
|
|
57016
57906
|
}
|
|
57017
57907
|
this.ensurePass().setStencilReference(this.maskVisibleRef);
|
|
57908
|
+
this._advancedBlendBusy--;
|
|
57018
57909
|
}
|
|
57019
57910
|
/**
|
|
57020
57911
|
* Stroke an arc at the specified coordinates with given radius, start and end points
|
|
@@ -57672,6 +58563,14 @@ var WebGPURenderer = class extends Renderer {
|
|
|
57672
58563
|
* @override
|
|
57673
58564
|
*/
|
|
57674
58565
|
destroy() {
|
|
58566
|
+
this._advancedBlendEffect?.destroy();
|
|
58567
|
+
this._advancedBlendEffect = void 0;
|
|
58568
|
+
this._advancedBlendCapture?.destroy();
|
|
58569
|
+
this._advancedBlendCapture = void 0;
|
|
58570
|
+
this._advancedBlendTarget?.destroy?.();
|
|
58571
|
+
this._advancedBlendTarget = void 0;
|
|
58572
|
+
this._advancedBlendOpen = false;
|
|
58573
|
+
this._advancedBlendBusy = 0;
|
|
57675
58574
|
releaseShadowQuads(this);
|
|
57676
58575
|
off(GAME_RESET, this.onGameReset);
|
|
57677
58576
|
off(CANVAS_ONRESIZE, this.onCanvasResize);
|
|
@@ -58552,6 +59451,7 @@ var defaultParticleEmitterSettings = {
|
|
|
58552
59451
|
blendMode: "normal",
|
|
58553
59452
|
onlyInViewport: true,
|
|
58554
59453
|
floating: false,
|
|
59454
|
+
referenceSpace: "local",
|
|
58555
59455
|
maxParticles: 10,
|
|
58556
59456
|
frequency: 100,
|
|
58557
59457
|
duration: Infinity,
|
|
@@ -58563,6 +59463,10 @@ var defaultParticleEmitterSettings = {
|
|
|
58563
59463
|
var settings_default = defaultParticleEmitterSettings;
|
|
58564
59464
|
|
|
58565
59465
|
// src/particles/emitter.ts
|
|
59466
|
+
var _m1 = new Matrix3d();
|
|
59467
|
+
var _m2 = new Matrix3d();
|
|
59468
|
+
var _correction = new Matrix3d();
|
|
59469
|
+
var _rebase = new Vector2d();
|
|
58566
59470
|
function createDefaultParticleTexture(w = 8, h = 8) {
|
|
58567
59471
|
const defaultParticleTexture = new canvasrendertarget_default(w, h, {
|
|
58568
59472
|
offscreenCanvas: true
|
|
@@ -58595,6 +59499,12 @@ var ParticleEmitter = class extends Container {
|
|
|
58595
59499
|
_dt;
|
|
58596
59500
|
/** @ignore */
|
|
58597
59501
|
_defaultParticle;
|
|
59502
|
+
/**
|
|
59503
|
+
* The blend mode last fanned out to the particles, so a change to
|
|
59504
|
+
* {@link ParticleEmitter#blendMode} can be detected per frame.
|
|
59505
|
+
* @ignore
|
|
59506
|
+
*/
|
|
59507
|
+
#appliedBlendMode = "normal";
|
|
58598
59508
|
/**
|
|
58599
59509
|
* whether at least one particle has been spawned by this emitter — used as
|
|
58600
59510
|
* the precondition for completion detection (a brand-new emitter with zero
|
|
@@ -58608,6 +59518,19 @@ var ParticleEmitter = class extends Container {
|
|
|
58608
59518
|
* @ignore
|
|
58609
59519
|
*/
|
|
58610
59520
|
_deltaInv;
|
|
59521
|
+
/**
|
|
59522
|
+
* Maps an emitter-local spawn point into the reference frame the particles
|
|
59523
|
+
* live in, so a particle is BORN where the emitter is even though its
|
|
59524
|
+
* position is thereafter measured from somewhere else. `undefined` in
|
|
59525
|
+
* local mode, where the two frames coincide and no mapping is needed.
|
|
59526
|
+
*
|
|
59527
|
+
* Held per emitter (not a module scratch) because particles read it during
|
|
59528
|
+
* their own reset, after `addParticles` has computed it. One matrix per
|
|
59529
|
+
* emitter that actually uses a non-local space — emitters are few, unlike
|
|
59530
|
+
* particles, which allocate nothing.
|
|
59531
|
+
* @ignore
|
|
59532
|
+
*/
|
|
59533
|
+
_spawnMap;
|
|
58611
59534
|
/**
|
|
58612
59535
|
* @param x - x position of the particle emitter
|
|
58613
59536
|
* @param y - y position of the particle emitter
|
|
@@ -58654,11 +59577,8 @@ var ParticleEmitter = class extends Container {
|
|
|
58654
59577
|
this._deltaInv = timer_default.maxfps / 1e3;
|
|
58655
59578
|
this.reset(settings);
|
|
58656
59579
|
}
|
|
58657
|
-
/**
|
|
58658
|
-
* Reset the emitter with particle emitter settings.
|
|
58659
|
-
* @param settings - object with emitter settings. See {@link ParticleEmitterSettings}
|
|
58660
|
-
*/
|
|
58661
59580
|
reset(settings = {}) {
|
|
59581
|
+
const previousFrame = this.#frameOf(this.settings?.referenceSpace);
|
|
58662
59582
|
Object.assign(this.settings, settings_default, settings);
|
|
58663
59583
|
clampMinToMax(this.settings, "minLife", "maxLife");
|
|
58664
59584
|
clampMinToMax(this.settings, "minStartScale", "maxStartScale");
|
|
@@ -58677,8 +59597,131 @@ var ParticleEmitter = class extends Container {
|
|
|
58677
59597
|
this.settings.image = this._defaultParticle.canvas;
|
|
58678
59598
|
}
|
|
58679
59599
|
this.floating = this.settings.floating;
|
|
59600
|
+
this.blendMode = this.settings.blendMode;
|
|
59601
|
+
this.#appliedBlendMode = this.settings.blendMode;
|
|
59602
|
+
this.#rebase(previousFrame);
|
|
59603
|
+
this.isDirty = true;
|
|
59604
|
+
}
|
|
59605
|
+
/**
|
|
59606
|
+
* What a particle's position is measured against — see
|
|
59607
|
+
* {@link ParticleEmitterSettings.referenceSpace}.
|
|
59608
|
+
*
|
|
59609
|
+
* Assigning this re-bases every particle already alive into the new frame,
|
|
59610
|
+
* so nothing jumps: the cloud stays exactly where it is on screen and only
|
|
59611
|
+
* its subsequent motion differs. Passing it through
|
|
59612
|
+
* {@link ParticleEmitter#reset} does the same.
|
|
59613
|
+
* @default "local"
|
|
59614
|
+
* @example
|
|
59615
|
+
* emitter.referenceSpace = "world"; // start leaving a trail
|
|
59616
|
+
*/
|
|
59617
|
+
get referenceSpace() {
|
|
59618
|
+
return this.settings.referenceSpace;
|
|
59619
|
+
}
|
|
59620
|
+
set referenceSpace(space) {
|
|
59621
|
+
if (space === this.settings.referenceSpace) {
|
|
59622
|
+
return;
|
|
59623
|
+
}
|
|
59624
|
+
const previous = this.#frameOf(this.settings.referenceSpace);
|
|
59625
|
+
this.settings.referenceSpace = space;
|
|
59626
|
+
this.#rebase(previous);
|
|
59627
|
+
}
|
|
59628
|
+
/**
|
|
59629
|
+
* Map the particles already alive out of the frame they were simulating
|
|
59630
|
+
* in and into the current one, so a change of reference space is
|
|
59631
|
+
* invisible at the instant it happens: the cloud stays exactly where it
|
|
59632
|
+
* is on screen and only its subsequent motion differs.
|
|
59633
|
+
*
|
|
59634
|
+
* Called from the accessor and from {@link ParticleEmitter#reset} alike —
|
|
59635
|
+
* `reset()` assigns `settings` wholesale and would otherwise leave live
|
|
59636
|
+
* particles holding coordinates measured against a frame that is no
|
|
59637
|
+
* longer theirs, teleporting the lot.
|
|
59638
|
+
* @ignore
|
|
59639
|
+
* @param previous - the frame the live particles are currently in
|
|
59640
|
+
*/
|
|
59641
|
+
#rebase(previous) {
|
|
59642
|
+
const next = this.#frameOf(this.settings.referenceSpace);
|
|
59643
|
+
if (previous !== next) {
|
|
59644
|
+
_m1.identity();
|
|
59645
|
+
_m1.multiply(this.#worldFrame(next, _m2).invert());
|
|
59646
|
+
_m1.multiply(this.#worldFrame(previous, _m2));
|
|
59647
|
+
for (const particle of this.getChildren()) {
|
|
59648
|
+
_rebase.set(particle.pos.x, particle.pos.y);
|
|
59649
|
+
_m1.apply(_rebase);
|
|
59650
|
+
particle.pos.x = _rebase.x;
|
|
59651
|
+
particle.pos.y = _rebase.y;
|
|
59652
|
+
}
|
|
59653
|
+
}
|
|
59654
|
+
this._spawnMap = void 0;
|
|
58680
59655
|
this.isDirty = true;
|
|
58681
59656
|
}
|
|
59657
|
+
/**
|
|
59658
|
+
* Resolve a reference-space value to the container whose frame the
|
|
59659
|
+
* particles live in. Returns `this` whenever the answer is "the emitter
|
|
59660
|
+
* itself" — including the degenerate cases (`"world"` on an emitter with no
|
|
59661
|
+
* parent, or a custom target that IS the emitter), which then take the
|
|
59662
|
+
* local fast path with no correction at all.
|
|
59663
|
+
* @ignore
|
|
59664
|
+
*/
|
|
59665
|
+
#frameOf(space) {
|
|
59666
|
+
if (space === "local") {
|
|
59667
|
+
return this;
|
|
59668
|
+
}
|
|
59669
|
+
if (space === "world") {
|
|
59670
|
+
return this.ancestor ?? this;
|
|
59671
|
+
}
|
|
59672
|
+
if (!space || typeof space.pos === "undefined") {
|
|
59673
|
+
return this;
|
|
59674
|
+
}
|
|
59675
|
+
return space;
|
|
59676
|
+
}
|
|
59677
|
+
/**
|
|
59678
|
+
* The world transform of a reference frame — i.e. of the space that
|
|
59679
|
+
* container's children are drawn in.
|
|
59680
|
+
* @ignore
|
|
59681
|
+
*/
|
|
59682
|
+
#worldFrame(frame, out) {
|
|
59683
|
+
return frame.getWorldTransform(out);
|
|
59684
|
+
}
|
|
59685
|
+
/**
|
|
59686
|
+
* The transform to insert before walking the children so they are drawn in
|
|
59687
|
+
* the reference frame instead of the emitter's own.
|
|
59688
|
+
*
|
|
59689
|
+
* At the insertion point the renderer holds `W_ancestor · preContrib`, and
|
|
59690
|
+
* `Container.draw` appends `T(pos)` afterwards, so what we need is
|
|
59691
|
+
*
|
|
59692
|
+
* ```
|
|
59693
|
+
* K = inv(preContrib) · inv(W_ancestor) · W_target · T(−pos)
|
|
59694
|
+
* ```
|
|
59695
|
+
*
|
|
59696
|
+
* expressed below via `inv(preContrib) = T(pos) · inv(L)`. Note this is
|
|
59697
|
+
* NOT `inv(W_emitter) · W_target` — matrices do not commute, and that form
|
|
59698
|
+
* only coincides with this one when both chains share the same linear
|
|
59699
|
+
* part, which hides the difference until something upstream is rotated.
|
|
59700
|
+
*
|
|
59701
|
+
* When the target is the emitter's own parent — the `"world"` case — the
|
|
59702
|
+
* whole ancestor chain cancels and no walk happens at all.
|
|
59703
|
+
* @ignore
|
|
59704
|
+
* @returns the correction, or `undefined` in local mode
|
|
59705
|
+
*/
|
|
59706
|
+
#correctionMatrix() {
|
|
59707
|
+
const target = this.#frameOf(this.settings.referenceSpace);
|
|
59708
|
+
if (target === this) {
|
|
59709
|
+
return void 0;
|
|
59710
|
+
}
|
|
59711
|
+
_correction.identity();
|
|
59712
|
+
_correction.translate(this.pos.x, this.pos.y);
|
|
59713
|
+
_correction.multiply(this.getLocalTransform(_m1).invert());
|
|
59714
|
+
if (target !== this.ancestor) {
|
|
59715
|
+
if (this.ancestor) {
|
|
59716
|
+
_correction.multiply(
|
|
59717
|
+
this.ancestor.getWorldTransform(_m1).invert()
|
|
59718
|
+
);
|
|
59719
|
+
}
|
|
59720
|
+
_correction.multiply(target.getWorldTransform(_m2));
|
|
59721
|
+
}
|
|
59722
|
+
_correction.translate(-this.pos.x, -this.pos.y);
|
|
59723
|
+
return _correction;
|
|
59724
|
+
}
|
|
58682
59725
|
/**
|
|
58683
59726
|
* returns a random point on the x axis within the bounds of this emitter
|
|
58684
59727
|
* @returns a random x position within the emitter bounds
|
|
@@ -58693,10 +59736,39 @@ var ParticleEmitter = class extends Container {
|
|
|
58693
59736
|
getRandomPointY() {
|
|
58694
59737
|
return randomFloat(0, this.getBounds().height);
|
|
58695
59738
|
}
|
|
59739
|
+
/**
|
|
59740
|
+
* Draw the particles in their reference frame rather than the emitter's.
|
|
59741
|
+
*
|
|
59742
|
+
* The correction goes in before `super.draw()` because that is where the
|
|
59743
|
+
* child walk happens; translations and the correction compose, and in
|
|
59744
|
+
* local mode there is no correction and this is the inherited path
|
|
59745
|
+
* untouched.
|
|
59746
|
+
* @ignore
|
|
59747
|
+
*/
|
|
59748
|
+
draw(renderer, viewport) {
|
|
59749
|
+
const correction = this.#correctionMatrix();
|
|
59750
|
+
if (correction !== void 0) {
|
|
59751
|
+
renderer.transform(correction);
|
|
59752
|
+
}
|
|
59753
|
+
super.draw(renderer, viewport);
|
|
59754
|
+
}
|
|
58696
59755
|
// Add count particles in the game world
|
|
58697
59756
|
/** @ignore */
|
|
58698
59757
|
addParticles(count) {
|
|
58699
59758
|
const z = this.depth;
|
|
59759
|
+
const target = this.#frameOf(this.settings.referenceSpace);
|
|
59760
|
+
if (target === this) {
|
|
59761
|
+
this._spawnMap = void 0;
|
|
59762
|
+
} else {
|
|
59763
|
+
const map = this._spawnMap ?? (this._spawnMap = new Matrix3d());
|
|
59764
|
+
if (target === this.ancestor) {
|
|
59765
|
+
map.copy(this.getLocalTransform(_m1));
|
|
59766
|
+
} else {
|
|
59767
|
+
map.identity();
|
|
59768
|
+
map.multiply(target.getWorldTransform(_m1).invert());
|
|
59769
|
+
map.multiply(this.getWorldTransform(_m2));
|
|
59770
|
+
}
|
|
59771
|
+
}
|
|
58700
59772
|
for (let i = 0; i < count; i++) {
|
|
58701
59773
|
this.addChild(particlePool.get(this), z);
|
|
58702
59774
|
}
|
|
@@ -58744,6 +59816,14 @@ var ParticleEmitter = class extends Container {
|
|
|
58744
59816
|
* @ignore
|
|
58745
59817
|
*/
|
|
58746
59818
|
update(dt) {
|
|
59819
|
+
if (this.blendMode !== this.#appliedBlendMode) {
|
|
59820
|
+
this.#appliedBlendMode = this.blendMode;
|
|
59821
|
+
this.settings.blendMode = this.blendMode;
|
|
59822
|
+
for (const particle of this.children ?? []) {
|
|
59823
|
+
particle.blendMode = this.blendMode;
|
|
59824
|
+
}
|
|
59825
|
+
this.isDirty = true;
|
|
59826
|
+
}
|
|
58747
59827
|
if (this.settings.framesToSkip > 0) {
|
|
58748
59828
|
if (++this._updateCount > this.settings.framesToSkip) {
|
|
58749
59829
|
this._updateCount = 0;
|
|
@@ -58757,6 +59837,9 @@ var ParticleEmitter = class extends Container {
|
|
|
58757
59837
|
}
|
|
58758
59838
|
const childrenDirty = super.update(dt);
|
|
58759
59839
|
this.isDirty = this.isDirty || childrenDirty;
|
|
59840
|
+
if (this.#frameOf(this.settings.referenceSpace) !== this && this.getChildren().length > 0) {
|
|
59841
|
+
this.inViewport = true;
|
|
59842
|
+
}
|
|
58760
59843
|
if (this._enabled && this._stream) {
|
|
58761
59844
|
if (this._durationTimer !== Infinity) {
|
|
58762
59845
|
this._durationTimer -= dt;
|
|
@@ -58800,6 +59883,8 @@ var ParticleEmitter = class extends Container {
|
|
|
58800
59883
|
this._defaultParticle = void 0;
|
|
58801
59884
|
}
|
|
58802
59885
|
this.settings.image = void 0;
|
|
59886
|
+
this.settings.referenceSpace = "local";
|
|
59887
|
+
this._spawnMap = void 0;
|
|
58803
59888
|
}
|
|
58804
59889
|
};
|
|
58805
59890
|
|
|
@@ -60383,7 +61468,7 @@ var UITextButton = class extends UIBaseElement {
|
|
|
60383
61468
|
};
|
|
60384
61469
|
|
|
60385
61470
|
// src/video/effects/blur.js
|
|
60386
|
-
var
|
|
61471
|
+
var wgslFragment3 = `
|
|
60387
61472
|
struct BlurUniforms {
|
|
60388
61473
|
uBlurStrength : f32,
|
|
60389
61474
|
uTextureSize : vec2f,
|
|
@@ -60434,7 +61519,7 @@ var BlurEffect = class extends ShaderEffect {
|
|
|
60434
61519
|
return (sum / 9.0) * vColor;
|
|
60435
61520
|
}
|
|
60436
61521
|
`,
|
|
60437
|
-
wgsl:
|
|
61522
|
+
wgsl: wgslFragment3
|
|
60438
61523
|
});
|
|
60439
61524
|
this.strength = options.strength ?? 1;
|
|
60440
61525
|
const texSize = options.textureSize ?? [256, 256];
|
|
@@ -60460,7 +61545,7 @@ var BlurEffect = class extends ShaderEffect {
|
|
|
60460
61545
|
};
|
|
60461
61546
|
|
|
60462
61547
|
// src/video/effects/chromaticAberration.js
|
|
60463
|
-
var
|
|
61548
|
+
var wgslFragment4 = `
|
|
60464
61549
|
struct AberrationUniforms {
|
|
60465
61550
|
uOffset : f32,
|
|
60466
61551
|
uTextureSize : vec2f,
|
|
@@ -60497,7 +61582,7 @@ var ChromaticAberrationEffect = class extends ShaderEffect {
|
|
|
60497
61582
|
return vec4(r, g, b, a) * vColor;
|
|
60498
61583
|
}
|
|
60499
61584
|
`,
|
|
60500
|
-
wgsl:
|
|
61585
|
+
wgsl: wgslFragment4
|
|
60501
61586
|
});
|
|
60502
61587
|
this.offset = options.offset ?? 3;
|
|
60503
61588
|
const texSize = options.textureSize ?? [256, 256];
|
|
@@ -60545,7 +61630,7 @@ var DesaturateEffect = class extends ColorMatrixEffect {
|
|
|
60545
61630
|
};
|
|
60546
61631
|
|
|
60547
61632
|
// src/video/effects/dissolve.js
|
|
60548
|
-
var
|
|
61633
|
+
var wgslFragment5 = `
|
|
60549
61634
|
struct DissolveUniforms {
|
|
60550
61635
|
uDissolveProgress : f32,
|
|
60551
61636
|
uEdgeColor : vec3f,
|
|
@@ -60657,7 +61742,7 @@ var DissolveEffect = class extends ShaderEffect {
|
|
|
60657
61742
|
return color;
|
|
60658
61743
|
}
|
|
60659
61744
|
`,
|
|
60660
|
-
wgsl:
|
|
61745
|
+
wgsl: wgslFragment5
|
|
60661
61746
|
});
|
|
60662
61747
|
this.progress = options.progress ?? 0;
|
|
60663
61748
|
this.setUniform("uDissolveProgress", this.progress);
|
|
@@ -60685,7 +61770,7 @@ var DissolveEffect = class extends ShaderEffect {
|
|
|
60685
61770
|
};
|
|
60686
61771
|
|
|
60687
61772
|
// src/video/effects/dropShadow.js
|
|
60688
|
-
var
|
|
61773
|
+
var wgslFragment6 = `
|
|
60689
61774
|
struct ShadowUniforms {
|
|
60690
61775
|
uShadowOffset : vec2f,
|
|
60691
61776
|
uShadowColor : vec3f,
|
|
@@ -60749,7 +61834,7 @@ var DropShadowEffect = class extends ShaderEffect {
|
|
|
60749
61834
|
return color;
|
|
60750
61835
|
}
|
|
60751
61836
|
`,
|
|
60752
|
-
wgsl:
|
|
61837
|
+
wgsl: wgslFragment6
|
|
60753
61838
|
});
|
|
60754
61839
|
const texSize = options.textureSize ?? [256, 256];
|
|
60755
61840
|
this.setUniform(
|
|
@@ -60783,7 +61868,7 @@ var DropShadowEffect = class extends ShaderEffect {
|
|
|
60783
61868
|
};
|
|
60784
61869
|
|
|
60785
61870
|
// src/video/effects/flash.js
|
|
60786
|
-
var
|
|
61871
|
+
var wgslFragment7 = `
|
|
60787
61872
|
struct FlashUniforms {
|
|
60788
61873
|
uFlashColor : vec3f,
|
|
60789
61874
|
uFlashIntensity : f32,
|
|
@@ -60810,7 +61895,7 @@ var FlashEffect = class extends ShaderEffect {
|
|
|
60810
61895
|
return vec4(mix(color.rgb, uFlashColor * color.a, uFlashIntensity), color.a);
|
|
60811
61896
|
}
|
|
60812
61897
|
`,
|
|
60813
|
-
wgsl:
|
|
61898
|
+
wgsl: wgslFragment7
|
|
60814
61899
|
});
|
|
60815
61900
|
const color = options.color ?? [1, 1, 1];
|
|
60816
61901
|
this.intensity = options.intensity ?? 0;
|
|
@@ -60835,7 +61920,7 @@ var FlashEffect = class extends ShaderEffect {
|
|
|
60835
61920
|
};
|
|
60836
61921
|
|
|
60837
61922
|
// src/video/effects/glow.js
|
|
60838
|
-
var
|
|
61923
|
+
var wgslFragment8 = `
|
|
60839
61924
|
struct GlowUniforms {
|
|
60840
61925
|
uGlowColor : vec3f,
|
|
60841
61926
|
uGlowWidth : f32,
|
|
@@ -60896,7 +61981,7 @@ var GlowEffect = class extends ShaderEffect {
|
|
|
60896
61981
|
return color;
|
|
60897
61982
|
}
|
|
60898
61983
|
`,
|
|
60899
|
-
wgsl:
|
|
61984
|
+
wgsl: wgslFragment8
|
|
60900
61985
|
});
|
|
60901
61986
|
const color = options.color ?? [1, 1, 1];
|
|
60902
61987
|
const width = options.width ?? 3;
|
|
@@ -60933,7 +62018,7 @@ var GlowEffect = class extends ShaderEffect {
|
|
|
60933
62018
|
};
|
|
60934
62019
|
|
|
60935
62020
|
// src/video/effects/hologram.js
|
|
60936
|
-
var
|
|
62021
|
+
var wgslFragment9 = `
|
|
60937
62022
|
struct HologramUniforms {
|
|
60938
62023
|
uHoloColor : vec3f,
|
|
60939
62024
|
uHoloIntensity : f32,
|
|
@@ -60976,7 +62061,7 @@ var HologramEffect = class extends ShaderEffect {
|
|
|
60976
62061
|
return vec4(holo, color.a * flicker);
|
|
60977
62062
|
}
|
|
60978
62063
|
`,
|
|
60979
|
-
wgsl:
|
|
62064
|
+
wgsl: wgslFragment9
|
|
60980
62065
|
});
|
|
60981
62066
|
const color = options.color ?? [0.1, 0.7, 1];
|
|
60982
62067
|
this.setUniform("uHoloColor", new Float32Array(color));
|
|
@@ -61015,7 +62100,7 @@ var InvertEffect = class extends ColorMatrixEffect {
|
|
|
61015
62100
|
};
|
|
61016
62101
|
|
|
61017
62102
|
// src/video/effects/outline.js
|
|
61018
|
-
var
|
|
62103
|
+
var wgslFragment10 = `
|
|
61019
62104
|
struct OutlineUniforms {
|
|
61020
62105
|
uOutlineColor : vec3f,
|
|
61021
62106
|
uOutlineWidth : f32,
|
|
@@ -61079,7 +62164,7 @@ var OutlineEffect = class extends ShaderEffect {
|
|
|
61079
62164
|
return color;
|
|
61080
62165
|
}
|
|
61081
62166
|
`,
|
|
61082
|
-
wgsl:
|
|
62167
|
+
wgsl: wgslFragment10
|
|
61083
62168
|
});
|
|
61084
62169
|
const color = options.color ?? [1, 1, 1];
|
|
61085
62170
|
const width = options.width ?? 1;
|
|
@@ -61113,7 +62198,7 @@ var OutlineEffect = class extends ShaderEffect {
|
|
|
61113
62198
|
};
|
|
61114
62199
|
|
|
61115
62200
|
// src/video/effects/pixelate.js
|
|
61116
|
-
var
|
|
62201
|
+
var wgslFragment11 = `
|
|
61117
62202
|
struct PixelateUniforms {
|
|
61118
62203
|
uPixelSize : f32,
|
|
61119
62204
|
uTextureSize : vec2f,
|
|
@@ -61144,7 +62229,7 @@ var PixelateEffect = class extends ShaderEffect {
|
|
|
61144
62229
|
return texture2D(uSampler, snapped) * vColor;
|
|
61145
62230
|
}
|
|
61146
62231
|
`,
|
|
61147
|
-
wgsl:
|
|
62232
|
+
wgsl: wgslFragment11
|
|
61148
62233
|
});
|
|
61149
62234
|
this.size = options.size ?? 4;
|
|
61150
62235
|
const texSize = options.textureSize ?? [256, 256];
|
|
@@ -61170,7 +62255,7 @@ var PixelateEffect = class extends ShaderEffect {
|
|
|
61170
62255
|
};
|
|
61171
62256
|
|
|
61172
62257
|
// src/video/effects/scanline.js
|
|
61173
|
-
var
|
|
62258
|
+
var wgslFragment12 = `
|
|
61174
62259
|
struct ScanlineUniforms {
|
|
61175
62260
|
uScanlineOpacity : f32,
|
|
61176
62261
|
uCurvature : f32,
|
|
@@ -61249,7 +62334,7 @@ var ScanlineEffect = class extends ShaderEffect {
|
|
|
61249
62334
|
return color;
|
|
61250
62335
|
}
|
|
61251
62336
|
`,
|
|
61252
|
-
wgsl:
|
|
62337
|
+
wgsl: wgslFragment12
|
|
61253
62338
|
});
|
|
61254
62339
|
this.setUniform("uScanlineOpacity", options.opacity ?? 0.25);
|
|
61255
62340
|
this.setUniform("uCurvature", options.curvature ?? 0);
|
|
@@ -61301,7 +62386,7 @@ var SepiaEffect = class extends ColorMatrixEffect {
|
|
|
61301
62386
|
};
|
|
61302
62387
|
|
|
61303
62388
|
// src/video/effects/shine.js
|
|
61304
|
-
var
|
|
62389
|
+
var wgslFragment13 = `
|
|
61305
62390
|
struct ShineUniforms {
|
|
61306
62391
|
uShineColor : vec3f,
|
|
61307
62392
|
uShineWidth : f32,
|
|
@@ -61397,7 +62482,7 @@ var ShineEffect = class extends ShaderEffect {
|
|
|
61397
62482
|
return vec4(result, color.a);
|
|
61398
62483
|
}
|
|
61399
62484
|
`,
|
|
61400
|
-
wgsl:
|
|
62485
|
+
wgsl: wgslFragment13
|
|
61401
62486
|
});
|
|
61402
62487
|
this.setUniform(
|
|
61403
62488
|
"uShineColor",
|
|
@@ -61444,7 +62529,7 @@ var ShineEffect = class extends ShaderEffect {
|
|
|
61444
62529
|
};
|
|
61445
62530
|
|
|
61446
62531
|
// src/video/effects/tintPulse.js
|
|
61447
|
-
var
|
|
62532
|
+
var wgslFragment14 = `
|
|
61448
62533
|
struct TintPulseUniforms {
|
|
61449
62534
|
uPulseColor : vec3f,
|
|
61450
62535
|
uPulseSpeed : f32,
|
|
@@ -61478,7 +62563,7 @@ var TintPulseEffect = class extends ShaderEffect {
|
|
|
61478
62563
|
return vec4(mix(color.rgb, uPulseColor * color.a, pulse), color.a);
|
|
61479
62564
|
}
|
|
61480
62565
|
`,
|
|
61481
|
-
wgsl:
|
|
62566
|
+
wgsl: wgslFragment14
|
|
61482
62567
|
});
|
|
61483
62568
|
const color = options.color ?? [1, 0, 0];
|
|
61484
62569
|
this.setUniform("uPulseColor", new Float32Array(color));
|
|
@@ -61512,7 +62597,7 @@ var fragment = `
|
|
|
61512
62597
|
return vec4(color.rgb * v, color.a);
|
|
61513
62598
|
}
|
|
61514
62599
|
`;
|
|
61515
|
-
var
|
|
62600
|
+
var wgslFragment15 = `
|
|
61516
62601
|
struct VignetteUniforms {
|
|
61517
62602
|
uStrength : f32,
|
|
61518
62603
|
uSize : f32,
|
|
@@ -61533,7 +62618,7 @@ var VignetteEffect = class extends ShaderEffect {
|
|
|
61533
62618
|
* @param {number} [options.size=25.0] - vignette spread multiplier (higher = smaller dark area)
|
|
61534
62619
|
*/
|
|
61535
62620
|
constructor(renderer, options = {}) {
|
|
61536
|
-
super(renderer, { glsl: fragment, wgsl:
|
|
62621
|
+
super(renderer, { glsl: fragment, wgsl: wgslFragment15 });
|
|
61537
62622
|
this.strength = options.strength ?? 0.15;
|
|
61538
62623
|
this.size = options.size ?? 25;
|
|
61539
62624
|
this.setUniform("uStrength", this.strength);
|
|
@@ -61558,7 +62643,7 @@ var VignetteEffect = class extends ShaderEffect {
|
|
|
61558
62643
|
};
|
|
61559
62644
|
|
|
61560
62645
|
// src/video/effects/wave.js
|
|
61561
|
-
var
|
|
62646
|
+
var wgslFragment16 = `
|
|
61562
62647
|
struct WaveUniforms {
|
|
61563
62648
|
uAmplitude : f32,
|
|
61564
62649
|
uFrequency : f32,
|
|
@@ -61594,7 +62679,7 @@ var WaveEffect = class extends ShaderEffect {
|
|
|
61594
62679
|
return texture2D(uSampler, distorted) * vColor;
|
|
61595
62680
|
}
|
|
61596
62681
|
`,
|
|
61597
|
-
wgsl:
|
|
62682
|
+
wgsl: wgslFragment16
|
|
61598
62683
|
});
|
|
61599
62684
|
this.setUniform("uAmplitude", options.amplitude ?? 0.01);
|
|
61600
62685
|
this.setUniform("uFrequency", options.frequency ?? 10);
|