melonjs 20.1.0 → 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 +1399 -229
- package/build/index.js.map +4 -4
- package/build/input/pointerevent.d.ts.map +1 -1
- package/build/level/gltf/GLTFModel.d.ts +17 -1
- package/build/level/gltf/GLTFModel.d.ts.map +1 -1
- package/build/loader/parsers/fontface.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/physics/builtin/builtin-adapter.d.ts.map +1 -1
- package/build/physics/builtin/detector.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/frameAnimation.d.ts +20 -2
- package/build/renderable/frameAnimation.d.ts.map +1 -1
- package/build/renderable/renderable.d.ts +106 -22
- package/build/renderable/renderable.d.ts.map +1 -1
- package/build/system/timer.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;
|
|
@@ -12366,7 +12379,10 @@ var Timer = class {
|
|
|
12366
12379
|
* @ignore
|
|
12367
12380
|
*/
|
|
12368
12381
|
updateTimers() {
|
|
12369
|
-
for (const timer2 of this.timers) {
|
|
12382
|
+
for (const timer2 of [...this.timers]) {
|
|
12383
|
+
if (!this.timers.includes(timer2)) {
|
|
12384
|
+
continue;
|
|
12385
|
+
}
|
|
12370
12386
|
if (!(timer2.pauseable && state_default.isPaused())) {
|
|
12371
12387
|
timer2.elapsed += this.delta;
|
|
12372
12388
|
}
|
|
@@ -17549,6 +17565,8 @@ var Body = class {
|
|
|
17549
17565
|
};
|
|
17550
17566
|
|
|
17551
17567
|
// src/renderable/renderable.js
|
|
17568
|
+
var _chain = [];
|
|
17569
|
+
var _level = new Matrix3d();
|
|
17552
17570
|
var Renderable = class _Renderable extends Rect {
|
|
17553
17571
|
/**
|
|
17554
17572
|
* @param {number} x - position of the renderable object (accessible through inherited pos.x property)
|
|
@@ -17607,7 +17625,7 @@ var Renderable = class _Renderable extends Rect {
|
|
|
17607
17625
|
*/
|
|
17608
17626
|
get parentApp() {
|
|
17609
17627
|
if (!this._parentApp && this.ancestor) {
|
|
17610
|
-
this._parentApp = this.ancestor.getRootAncestor()
|
|
17628
|
+
this._parentApp = this.ancestor.getRootAncestor()?.app;
|
|
17611
17629
|
}
|
|
17612
17630
|
return this._parentApp;
|
|
17613
17631
|
}
|
|
@@ -17983,13 +18001,33 @@ var Renderable = class _Renderable extends Rect {
|
|
|
17983
18001
|
}
|
|
17984
18002
|
}
|
|
17985
18003
|
/**
|
|
17986
|
-
*
|
|
17987
|
-
*
|
|
17988
|
-
*
|
|
17989
|
-
*
|
|
17990
|
-
*
|
|
17991
|
-
*
|
|
17992
|
-
*
|
|
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
|
|
17993
18031
|
*/
|
|
17994
18032
|
getAbsolutePosition() {
|
|
17995
18033
|
if (typeof this._absPos === "undefined") {
|
|
@@ -18001,6 +18039,121 @@ var Renderable = class _Renderable extends Rect {
|
|
|
18001
18039
|
}
|
|
18002
18040
|
return this._absPos;
|
|
18003
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
|
+
}
|
|
18004
18157
|
/**
|
|
18005
18158
|
* Prepare the rendering context before drawing (automatically called by melonJS).
|
|
18006
18159
|
* This will apply any defined transforms, anchor point, tint or blend mode and translate the context accordingly to this renderable position.
|
|
@@ -18295,6 +18448,7 @@ function compileProgram(gl, vertex, fragment2, attributes) {
|
|
|
18295
18448
|
throw new Error(error_msg);
|
|
18296
18449
|
}
|
|
18297
18450
|
gl.useProgram(program);
|
|
18451
|
+
gl.__meCurrentProgram = program;
|
|
18298
18452
|
gl.deleteShader(vertShader);
|
|
18299
18453
|
gl.deleteShader(fragShader);
|
|
18300
18454
|
return program;
|
|
@@ -18592,6 +18746,7 @@ var GLShader = class _GLShader {
|
|
|
18592
18746
|
return;
|
|
18593
18747
|
}
|
|
18594
18748
|
this.gl.useProgram(this.program);
|
|
18749
|
+
this.gl.__meCurrentProgram = this.program;
|
|
18595
18750
|
}
|
|
18596
18751
|
/**
|
|
18597
18752
|
* returns the location of an attribute variable in this shader program
|
|
@@ -21076,6 +21231,9 @@ var FrameAnimation = class {
|
|
|
21076
21231
|
this.resetAnim = () => {
|
|
21077
21232
|
if (typeof onComplete === "function") {
|
|
21078
21233
|
onComplete();
|
|
21234
|
+
if (!this._isCurrentAnimationLive()) {
|
|
21235
|
+
return false;
|
|
21236
|
+
}
|
|
21079
21237
|
}
|
|
21080
21238
|
this.setCurrentAnimation(next, null, true);
|
|
21081
21239
|
};
|
|
@@ -21083,6 +21241,9 @@ var FrameAnimation = class {
|
|
|
21083
21241
|
this.resetAnim = () => {
|
|
21084
21242
|
if (typeof onComplete === "function") {
|
|
21085
21243
|
onComplete();
|
|
21244
|
+
if (!this._isCurrentAnimationLive()) {
|
|
21245
|
+
return false;
|
|
21246
|
+
}
|
|
21086
21247
|
}
|
|
21087
21248
|
this._animDone = true;
|
|
21088
21249
|
return false;
|
|
@@ -21168,6 +21329,26 @@ var FrameAnimation = class {
|
|
|
21168
21329
|
* @param {number} id - the frame id
|
|
21169
21330
|
* @returns {object} the frame data
|
|
21170
21331
|
*/
|
|
21332
|
+
/**
|
|
21333
|
+
* Whether the current animation is still resolvable.
|
|
21334
|
+
*
|
|
21335
|
+
* `update()` hands control to user code in the middle of its frame loop:
|
|
21336
|
+
* `onended`, and the completion callback behind `resetAnim`. That code is
|
|
21337
|
+
* free to tear the host down — "remove me once the animation finishes" is
|
|
21338
|
+
* an entirely reasonable reaction, and `removeChildNow()` destroys the
|
|
21339
|
+
* sprite, whose `destroy()` empties `anim`. Everything after the callback
|
|
21340
|
+
* reads out of `anim`, so the loop has to check it is still there rather
|
|
21341
|
+
* than resume into a map the callback just cleared.
|
|
21342
|
+
*
|
|
21343
|
+
* A callback that switches animations with `setCurrentAnimation()` leaves
|
|
21344
|
+
* this true, which is the point: only a genuinely torn-down host stops the
|
|
21345
|
+
* loop.
|
|
21346
|
+
* @ignore
|
|
21347
|
+
* @returns {boolean} true while the current animation can still be read
|
|
21348
|
+
*/
|
|
21349
|
+
_isCurrentAnimationLive() {
|
|
21350
|
+
return this.current !== void 0 && this.current !== null && this.anim[this.current.name] !== void 0;
|
|
21351
|
+
}
|
|
21171
21352
|
getAnimationFrameObjectByIndex(id) {
|
|
21172
21353
|
return this.anim[this.current.name].frames[id];
|
|
21173
21354
|
}
|
|
@@ -21201,6 +21382,9 @@ var FrameAnimation = class {
|
|
|
21201
21382
|
*/
|
|
21202
21383
|
update(dt) {
|
|
21203
21384
|
let changed = false;
|
|
21385
|
+
if (!this._isCurrentAnimationLive()) {
|
|
21386
|
+
return changed;
|
|
21387
|
+
}
|
|
21204
21388
|
if (!this.animationpause && !this._animDone && this.current.length > 1) {
|
|
21205
21389
|
let duration = this.getAnimationFrameObjectByIndex(
|
|
21206
21390
|
this.current.idx
|
|
@@ -21214,9 +21398,16 @@ var FrameAnimation = class {
|
|
|
21214
21398
|
if (this.current.idx === 0) {
|
|
21215
21399
|
if (typeof this.host.onended === "function") {
|
|
21216
21400
|
this.host.onended();
|
|
21401
|
+
if (!this._isCurrentAnimationLive()) {
|
|
21402
|
+
break;
|
|
21403
|
+
}
|
|
21217
21404
|
}
|
|
21218
21405
|
if (typeof this.resetAnim === "function") {
|
|
21219
|
-
|
|
21406
|
+
const keepPlaying = this.resetAnim();
|
|
21407
|
+
if (!this._isCurrentAnimationLive()) {
|
|
21408
|
+
break;
|
|
21409
|
+
}
|
|
21410
|
+
if (keepPlaying === false) {
|
|
21220
21411
|
this.setAnimationFrame(this.current.length - 1);
|
|
21221
21412
|
this.dt %= duration;
|
|
21222
21413
|
break;
|
|
@@ -23314,11 +23505,13 @@ function preloadBinary(data2, onload2, onerror, settings) {
|
|
|
23314
23505
|
// src/loader/parsers/fontface.js
|
|
23315
23506
|
function preloadFontFace(data2, onload2, onerror) {
|
|
23316
23507
|
const fontFaceSet = typeof globalThis.document !== "undefined" ? globalThis.document.fonts : void 0;
|
|
23317
|
-
|
|
23318
|
-
|
|
23508
|
+
let src = data2.src;
|
|
23509
|
+
if (!src.startsWith("url(") && !src.startsWith("local(")) {
|
|
23510
|
+
const escaped = src.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
23511
|
+
src = `url('${escaped}')`;
|
|
23319
23512
|
}
|
|
23320
23513
|
if (typeof fontFaceSet !== "undefined") {
|
|
23321
|
-
const font = new FontFace(data2.name,
|
|
23514
|
+
const font = new FontFace(data2.name, src);
|
|
23322
23515
|
font.load().then(
|
|
23323
23516
|
() => {
|
|
23324
23517
|
fontList[data2.name] = font;
|
|
@@ -26711,9 +26904,12 @@ var Container = class _Container extends Renderable {
|
|
|
26711
26904
|
let isFloating = false;
|
|
26712
26905
|
const isPaused = state_default.isPaused();
|
|
26713
26906
|
const children = this.getChildren();
|
|
26714
|
-
const childrenLength = children.length;
|
|
26715
26907
|
const cameras = state_default.current().cameras;
|
|
26716
|
-
|
|
26908
|
+
const pass = children.slice();
|
|
26909
|
+
for (let i = pass.length, obj; i--, obj = pass[i]; ) {
|
|
26910
|
+
if (obj.ancestor !== this) {
|
|
26911
|
+
continue;
|
|
26912
|
+
}
|
|
26717
26913
|
if (isPaused && !obj.updateWhenPaused) {
|
|
26718
26914
|
continue;
|
|
26719
26915
|
}
|
|
@@ -26735,6 +26931,20 @@ var Container = class _Container extends Renderable {
|
|
|
26735
26931
|
}
|
|
26736
26932
|
return super.update(dt);
|
|
26737
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
|
+
}
|
|
26738
26948
|
/**
|
|
26739
26949
|
* draw this renderable (automatically called by melonJS)
|
|
26740
26950
|
* @param {CanvasRenderer|WebGLRenderer} renderer - a renderer instance
|
|
@@ -27053,6 +27263,9 @@ var GLTFModel = class extends Container {
|
|
|
27053
27263
|
this.resetAnim = () => {
|
|
27054
27264
|
if (typeof onComplete === "function") {
|
|
27055
27265
|
onComplete();
|
|
27266
|
+
if (!this._isLive()) {
|
|
27267
|
+
return false;
|
|
27268
|
+
}
|
|
27056
27269
|
}
|
|
27057
27270
|
this.setCurrentAnimation(next);
|
|
27058
27271
|
};
|
|
@@ -27060,6 +27273,9 @@ var GLTFModel = class extends Container {
|
|
|
27060
27273
|
this.resetAnim = () => {
|
|
27061
27274
|
if (typeof onComplete === "function") {
|
|
27062
27275
|
onComplete();
|
|
27276
|
+
if (!this._isLive()) {
|
|
27277
|
+
return false;
|
|
27278
|
+
}
|
|
27063
27279
|
}
|
|
27064
27280
|
this._animDone = true;
|
|
27065
27281
|
return false;
|
|
@@ -27139,6 +27355,9 @@ var GLTFModel = class extends Container {
|
|
|
27139
27355
|
if (this.current.time >= duration) {
|
|
27140
27356
|
if (typeof this.onended === "function") {
|
|
27141
27357
|
this.onended();
|
|
27358
|
+
if (!this._isLive()) {
|
|
27359
|
+
return super.update(dt);
|
|
27360
|
+
}
|
|
27142
27361
|
}
|
|
27143
27362
|
if (typeof this.resetAnim === "function") {
|
|
27144
27363
|
if (this.resetAnim() === false) {
|
|
@@ -27150,6 +27369,9 @@ var GLTFModel = class extends Container {
|
|
|
27150
27369
|
this.current.time %= duration;
|
|
27151
27370
|
}
|
|
27152
27371
|
}
|
|
27372
|
+
if (!this._isLive()) {
|
|
27373
|
+
return super.update(dt);
|
|
27374
|
+
}
|
|
27153
27375
|
this._pose();
|
|
27154
27376
|
this.isDirty = true;
|
|
27155
27377
|
}
|
|
@@ -27161,6 +27383,24 @@ var GLTFModel = class extends Container {
|
|
|
27161
27383
|
* not animate use their cached rest matrix.
|
|
27162
27384
|
* @ignore
|
|
27163
27385
|
*/
|
|
27386
|
+
/**
|
|
27387
|
+
* Whether this model is still alive.
|
|
27388
|
+
*
|
|
27389
|
+
* `update()` hands control to user code — `onended`, and the completion
|
|
27390
|
+
* callback behind `resetAnim` — and then poses the hierarchy. A callback
|
|
27391
|
+
* that removed the model (a death animation removing its own model is the
|
|
27392
|
+
* obvious case) has had `Renderable.destroy()` run, which releases `pos` to
|
|
27393
|
+
* the pool and leaves it undefined on every part. `_pose()` writes
|
|
27394
|
+
* `mesh.pos`, so it must not run on a torn-down model.
|
|
27395
|
+
*
|
|
27396
|
+
* `pos` and not `ancestor`: a model that was never added to a container is
|
|
27397
|
+
* perfectly poseable, and several callers do exactly that.
|
|
27398
|
+
* @ignore
|
|
27399
|
+
* @returns {boolean} true while the model can still be posed
|
|
27400
|
+
*/
|
|
27401
|
+
_isLive() {
|
|
27402
|
+
return this.pos !== void 0;
|
|
27403
|
+
}
|
|
27164
27404
|
_pose() {
|
|
27165
27405
|
const clip = this.current.name ? this.anim[this.current.name] : null;
|
|
27166
27406
|
const t = this.current.time;
|
|
@@ -35686,7 +35926,7 @@ var CanvasRenderer = class extends Renderer {
|
|
|
35686
35926
|
}
|
|
35687
35927
|
/**
|
|
35688
35928
|
* set the current blend mode for this renderer. <br>
|
|
35689
|
-
*
|
|
35929
|
+
* Every renderer supports the full set: <br>
|
|
35690
35930
|
* - "normal" : draws new content on top of the existing content <br>
|
|
35691
35931
|
* <img src="../images/normal-blendmode.png" width="180"/> <br>
|
|
35692
35932
|
* - "add", "additive", or "lighter" : color values are added together <br>
|
|
@@ -35695,26 +35935,30 @@ var CanvasRenderer = class extends Renderer {
|
|
|
35695
35935
|
* <img src="../images/multiply-blendmode.png" width="180"/> <br>
|
|
35696
35936
|
* - "screen" : pixels are inverted, multiplied, and inverted again (opposite of multiply) <br>
|
|
35697
35937
|
* <img src="../images/screen-blendmode.png" width="180"/> <br>
|
|
35698
|
-
* Canvas (browser-dependent) and WebGL2: <br>
|
|
35699
35938
|
* - "darken" : retains the darkest pixels of both layers <br>
|
|
35700
35939
|
* <img src="../images/darken-blendmode.png" width="180"/> <br>
|
|
35701
35940
|
* - "lighten" : retains the lightest pixels of both layers <br>
|
|
35702
35941
|
* <img src="../images/lighten-blendmode.png" width="180"/> <br>
|
|
35703
|
-
*
|
|
35704
|
-
* - "overlay" <br>
|
|
35942
|
+
* - "overlay" : multiplies or screens, depending on the backdrop <br>
|
|
35705
35943
|
* <img src="../images/overlay-blendmode.png" width="180"/> <br>
|
|
35706
|
-
* - "
|
|
35707
|
-
* <img src="../images/color-dodge-blendmode.png" width="180"/> <br>
|
|
35708
|
-
* - "color-burn" <br>
|
|
35709
|
-
* <img src="../images/color-burn-blendmode.png" width="180"/> <br>
|
|
35710
|
-
* - "hard-light" <br>
|
|
35944
|
+
* - "hard-light" : overlay with the layers swapped — a harsh spotlight <br>
|
|
35711
35945
|
* <img src="../images/hard-light-blendmode.png" width="180"/> <br>
|
|
35712
|
-
* - "soft-light" <br>
|
|
35946
|
+
* - "soft-light" : a diffused spotlight, gentler than hard-light <br>
|
|
35713
35947
|
* <img src="../images/soft-light-blendmode.png" width="180"/> <br>
|
|
35714
|
-
* - "
|
|
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>
|
|
35715
35953
|
* <img src="../images/difference-blendmode.png" width="180"/> <br>
|
|
35716
|
-
* - "exclusion" <br>
|
|
35954
|
+
* - "exclusion" : like difference, but lower in contrast <br>
|
|
35717
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.
|
|
35718
35962
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
|
|
35719
35963
|
* @param {string} [mode="normal"] - blend mode
|
|
35720
35964
|
* @returns {string} the blend mode actually applied (may differ if the requested mode is unsupported)
|
|
@@ -36587,11 +36831,11 @@ var CanvasRenderer = class extends Renderer {
|
|
|
36587
36831
|
* Reset (overrides) the renderer transformation matrix to the
|
|
36588
36832
|
* identity one, and then apply the given transformation matrix.
|
|
36589
36833
|
* @param {Matrix2d|Matrix3d|number} a - a matrix to transform by, or the a component to multiply the current matrix by
|
|
36590
|
-
* @param {number} b - the b component to multiply the current matrix by
|
|
36591
|
-
* @param {number} c - the c component to multiply the current matrix by
|
|
36592
|
-
* @param {number} d - the d component to multiply the current matrix by
|
|
36593
|
-
* @param {number} e - the e component to multiply the current matrix by
|
|
36594
|
-
* @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
|
|
36595
36839
|
*/
|
|
36596
36840
|
setTransform(a, b, c, d, e, f) {
|
|
36597
36841
|
this.resetTransform();
|
|
@@ -36601,11 +36845,11 @@ var CanvasRenderer = class extends Renderer {
|
|
|
36601
36845
|
* Multiply given matrix into the renderer tranformation matrix
|
|
36602
36846
|
* @see {@link CanvasRenderer.setTransform} which will reset the current transform matrix prior to performing the new transformation
|
|
36603
36847
|
* @param {Matrix2d|Matrix3d|number} a - a matrix to transform by, or the a component to multiply the current matrix by
|
|
36604
|
-
* @param {number} b - the b component to multiply the current matrix by
|
|
36605
|
-
* @param {number} c - the c component to multiply the current matrix by
|
|
36606
|
-
* @param {number} d - the d component to multiply the current matrix by
|
|
36607
|
-
* @param {number} e - the e component to multiply the current matrix by
|
|
36608
|
-
* @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
|
|
36609
36853
|
*/
|
|
36610
36854
|
transform(a, b, c, d, e, f) {
|
|
36611
36855
|
if (typeof a === "object") {
|
|
@@ -37651,7 +37895,7 @@ var WebGLBatcher = class extends Batcher {
|
|
|
37651
37895
|
const gl = this.gl;
|
|
37652
37896
|
this.vertexState.bind();
|
|
37653
37897
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.uploadBuffer);
|
|
37654
|
-
if (this.renderer.currentProgram !== this.defaultShader.program) {
|
|
37898
|
+
if (this.currentShader !== this.defaultShader || this.renderer.currentProgram !== this.defaultShader.program) {
|
|
37655
37899
|
this.useShader(this.defaultShader);
|
|
37656
37900
|
}
|
|
37657
37901
|
}
|
|
@@ -38911,6 +39155,222 @@ var QuadBatcher = class extends MaterialBatcher {
|
|
|
38911
39155
|
}
|
|
38912
39156
|
};
|
|
38913
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
|
+
|
|
38914
39374
|
// src/video/effects/radialGradient.js
|
|
38915
39375
|
var RadialGradientEffect = class extends ShaderEffect {
|
|
38916
39376
|
/**
|
|
@@ -42616,7 +43076,30 @@ var GLSamplerCache = class {
|
|
|
42616
43076
|
var _tempMatrix = new Matrix3d();
|
|
42617
43077
|
var _savedTransform = new Matrix3d();
|
|
42618
43078
|
var _savedProjection = new Matrix3d();
|
|
42619
|
-
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 {
|
|
42620
43103
|
/**
|
|
42621
43104
|
* @param {ApplicationSettings} [options] - optional parameters for the renderer
|
|
42622
43105
|
*/
|
|
@@ -42633,6 +43116,14 @@ var WebGLRenderer = class extends Renderer {
|
|
|
42633
43116
|
});
|
|
42634
43117
|
this._effectProjectionStack = [];
|
|
42635
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();
|
|
42636
43127
|
this.lineWidth = 1;
|
|
42637
43128
|
this.lineJoin = "round";
|
|
42638
43129
|
this.vertexBuffer = this.gl.createBuffer();
|
|
@@ -42811,6 +43302,14 @@ var WebGLRenderer = class extends Renderer {
|
|
|
42811
43302
|
off(GAME_RESET, this.onGameReset);
|
|
42812
43303
|
off(ONCONTEXT_RESTORED, this.onContextRestoredInvalidate);
|
|
42813
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;
|
|
42814
43313
|
releaseShadowQuads(this);
|
|
42815
43314
|
if (this.batchers) {
|
|
42816
43315
|
this.batchers.forEach((batcher) => {
|
|
@@ -42939,6 +43438,18 @@ var WebGLRenderer = class extends Renderer {
|
|
|
42939
43438
|
if (typeof batcher === "undefined") {
|
|
42940
43439
|
throw new Error("Invalid Batcher");
|
|
42941
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
|
+
}
|
|
42942
43453
|
const targetShader = shader != null ? shader : batcher.defaultShader;
|
|
42943
43454
|
if (this.currentBatcher === batcher && batcher.currentShader === targetShader) {
|
|
42944
43455
|
return this.currentBatcher;
|
|
@@ -43008,6 +43519,10 @@ var WebGLRenderer = class extends Renderer {
|
|
|
43008
43519
|
* Flush the batcher to the frame buffer
|
|
43009
43520
|
*/
|
|
43010
43521
|
flush() {
|
|
43522
|
+
if (this._advancedBlendOpen === true && this._advancedBlendBusy === 0) {
|
|
43523
|
+
this._closeAdvancedBlend();
|
|
43524
|
+
return;
|
|
43525
|
+
}
|
|
43011
43526
|
this.currentBatcher.flush();
|
|
43012
43527
|
}
|
|
43013
43528
|
/**
|
|
@@ -43183,6 +43698,16 @@ var WebGLRenderer = class extends Renderer {
|
|
|
43183
43698
|
* }
|
|
43184
43699
|
*/
|
|
43185
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 = {}) {
|
|
43186
43711
|
const gl = this.gl;
|
|
43187
43712
|
const canvas = this.getCanvas();
|
|
43188
43713
|
let x = 0;
|
|
@@ -43418,6 +43943,125 @@ var WebGLRenderer = class extends Renderer {
|
|
|
43418
43943
|
);
|
|
43419
43944
|
this.currentBatcher.setProjection(this.projectionMatrix);
|
|
43420
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
|
+
}
|
|
43421
44065
|
/**
|
|
43422
44066
|
* Blit a texture to the screen through a shader effect.
|
|
43423
44067
|
* Draws a screen-aligned quad using the given texture as source
|
|
@@ -43431,6 +44075,7 @@ var WebGLRenderer = class extends Renderer {
|
|
|
43431
44075
|
* @param {boolean} [keepBlend=false] - if true, keep current blend mode (for sprite compositing)
|
|
43432
44076
|
*/
|
|
43433
44077
|
blitEffect(source, x, y, width, height, shader, keepBlend = false) {
|
|
44078
|
+
this._advancedBlendBusy++;
|
|
43434
44079
|
this.flush();
|
|
43435
44080
|
const batcher = this.setBatcher("quad");
|
|
43436
44081
|
_savedTransform.copy(this.currentTransform);
|
|
@@ -43448,6 +44093,7 @@ var WebGLRenderer = class extends Renderer {
|
|
|
43448
44093
|
this.currentTransform.copy(_savedTransform);
|
|
43449
44094
|
this.projectionMatrix.copy(_savedProjection);
|
|
43450
44095
|
batcher.setProjection(this.projectionMatrix);
|
|
44096
|
+
this._advancedBlendBusy--;
|
|
43451
44097
|
}
|
|
43452
44098
|
/**
|
|
43453
44099
|
* set/change the current projection matrix (WebGL only)
|
|
@@ -43534,6 +44180,7 @@ var WebGLRenderer = class extends Renderer {
|
|
|
43534
44180
|
* Clear the frame buffer
|
|
43535
44181
|
*/
|
|
43536
44182
|
clear() {
|
|
44183
|
+
this._drainAdvancedBlend();
|
|
43537
44184
|
const gl = this.gl;
|
|
43538
44185
|
const clearColor = this.backgroundColor.toArray();
|
|
43539
44186
|
gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
|
|
@@ -43547,6 +44194,7 @@ var WebGLRenderer = class extends Renderer {
|
|
|
43547
44194
|
* @param {boolean} [opaque=false] - Allow transparency [default] or clear the surface completely [true]
|
|
43548
44195
|
*/
|
|
43549
44196
|
clearColor(color = "#000000", opaque = false) {
|
|
44197
|
+
this._drainAdvancedBlend();
|
|
43550
44198
|
let glArray;
|
|
43551
44199
|
const gl = this.gl;
|
|
43552
44200
|
if (color instanceof Color) {
|
|
@@ -43911,12 +44559,31 @@ var WebGLRenderer = class extends Renderer {
|
|
|
43911
44559
|
* return a reference to the system 2d Context
|
|
43912
44560
|
* @returns {WebGLRenderingContext} the current WebGL context
|
|
43913
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
|
+
}
|
|
43914
44581
|
getContext() {
|
|
43915
44582
|
return this.gl;
|
|
43916
44583
|
}
|
|
43917
44584
|
/**
|
|
43918
44585
|
* set the current blend mode for this renderer. <br>
|
|
43919
|
-
*
|
|
44586
|
+
* Every renderer supports the full set: <br>
|
|
43920
44587
|
* - "normal" : draws new content on top of the existing content <br>
|
|
43921
44588
|
* <img src="../images/normal-blendmode.png" width="180"/> <br>
|
|
43922
44589
|
* - "add", "additive", or "lighter" : color values are added together <br>
|
|
@@ -43925,71 +44592,58 @@ var WebGLRenderer = class extends Renderer {
|
|
|
43925
44592
|
* <img src="../images/multiply-blendmode.png" width="180"/> <br>
|
|
43926
44593
|
* - "screen" : pixels are inverted, multiplied, and inverted again (opposite of multiply) <br>
|
|
43927
44594
|
* <img src="../images/screen-blendmode.png" width="180"/> <br>
|
|
43928
|
-
* WebGL2 additionally supports: <br>
|
|
43929
44595
|
* - "darken" : retains the darkest pixels of both layers <br>
|
|
43930
44596
|
* <img src="../images/darken-blendmode.png" width="180"/> <br>
|
|
43931
44597
|
* - "lighten" : retains the lightest pixels of both layers <br>
|
|
43932
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>
|
|
43933
44613
|
* - "none" : blending disabled — the source replaces the destination
|
|
43934
|
-
* outright, alpha included
|
|
43935
|
-
*
|
|
43936
|
-
*
|
|
43937
|
-
*
|
|
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.
|
|
43938
44619
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
|
|
43939
44620
|
* @param {string} [mode="normal"] - blend mode
|
|
43940
|
-
* @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)
|
|
43941
44622
|
* @returns {string} the blend mode actually applied (may differ if the requested mode is unsupported)
|
|
43942
44623
|
*/
|
|
43943
44624
|
setBlendMode(mode = "normal", premultipliedAlpha = true) {
|
|
43944
44625
|
if (this.currentBlendMode !== mode || this.currentPremultipliedAlpha !== premultipliedAlpha) {
|
|
43945
44626
|
const gl = this.gl;
|
|
44627
|
+
this._drainAdvancedBlend();
|
|
43946
44628
|
this.flush();
|
|
43947
|
-
gl.enable(gl.BLEND);
|
|
43948
44629
|
this.currentBlendMode = mode;
|
|
43949
44630
|
this.currentPremultipliedAlpha = premultipliedAlpha;
|
|
43950
|
-
|
|
43951
|
-
|
|
43952
|
-
|
|
43953
|
-
|
|
43954
|
-
|
|
43955
|
-
|
|
43956
|
-
|
|
43957
|
-
|
|
43958
|
-
|
|
43959
|
-
|
|
43960
|
-
|
|
43961
|
-
|
|
43962
|
-
|
|
43963
|
-
|
|
43964
|
-
|
|
43965
|
-
|
|
43966
|
-
break;
|
|
43967
|
-
case "lighter":
|
|
43968
|
-
case "additive":
|
|
43969
|
-
case "add":
|
|
43970
|
-
gl.blendEquation(gl.FUNC_ADD);
|
|
43971
|
-
gl.blendFunc(srcAlpha, gl.ONE);
|
|
43972
|
-
break;
|
|
43973
|
-
case "multiply":
|
|
43974
|
-
gl.blendEquation(gl.FUNC_ADD);
|
|
43975
|
-
gl.blendFunc(gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA);
|
|
43976
|
-
break;
|
|
43977
|
-
case "darken":
|
|
43978
|
-
gl.blendEquation(gl.MIN);
|
|
43979
|
-
gl.blendFunc(gl.ONE, gl.ONE);
|
|
43980
|
-
break;
|
|
43981
|
-
case "lighten":
|
|
43982
|
-
gl.blendEquation(gl.MAX);
|
|
43983
|
-
gl.blendFunc(gl.ONE, gl.ONE);
|
|
43984
|
-
break;
|
|
43985
|
-
case "none":
|
|
43986
|
-
gl.disable(gl.BLEND);
|
|
43987
|
-
break;
|
|
43988
|
-
default:
|
|
43989
|
-
gl.blendEquation(gl.FUNC_ADD);
|
|
43990
|
-
gl.blendFunc(srcAlpha, gl.ONE_MINUS_SRC_ALPHA);
|
|
43991
|
-
this.currentBlendMode = "normal";
|
|
43992
|
-
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";
|
|
43993
44647
|
}
|
|
43994
44648
|
}
|
|
43995
44649
|
return this.currentBlendMode;
|
|
@@ -44630,6 +45284,12 @@ var WebGLRenderer = class extends Renderer {
|
|
|
44630
45284
|
const grad = this._currentGradient;
|
|
44631
45285
|
const hasMask = this.maskLevel > 0;
|
|
44632
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++;
|
|
44633
45293
|
this.flush();
|
|
44634
45294
|
gl.enable(gl.STENCIL_TEST);
|
|
44635
45295
|
gl.colorMask(false, false, false, false);
|
|
@@ -44666,16 +45326,17 @@ var WebGLRenderer = class extends Renderer {
|
|
|
44666
45326
|
} else {
|
|
44667
45327
|
gl.disable(gl.STENCIL_TEST);
|
|
44668
45328
|
}
|
|
45329
|
+
this._advancedBlendBusy--;
|
|
44669
45330
|
}
|
|
44670
45331
|
/**
|
|
44671
45332
|
* Reset (overrides) the renderer transformation matrix to the
|
|
44672
45333
|
* identity one, and then apply the given transformation matrix.
|
|
44673
45334
|
* @param {Matrix2d|Matrix3d|number} a - a matrix to transform by, or the a component to multiply the current matrix by
|
|
44674
|
-
* @param {number} b - the b component to multiply the current matrix by
|
|
44675
|
-
* @param {number} c - the c component to multiply the current matrix by
|
|
44676
|
-
* @param {number} d - the d component to multiply the current matrix by
|
|
44677
|
-
* @param {number} e - the e component to multiply the current matrix by
|
|
44678
|
-
* @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
|
|
44679
45340
|
*/
|
|
44680
45341
|
setTransform(a, b, c, d, e, f) {
|
|
44681
45342
|
this.resetTransform();
|
|
@@ -44685,11 +45346,11 @@ var WebGLRenderer = class extends Renderer {
|
|
|
44685
45346
|
* Multiply given matrix into the renderer tranformation matrix
|
|
44686
45347
|
* @see {@link WebGLRenderer.setTransform} which will reset the current transform matrix prior to performing the new transformation
|
|
44687
45348
|
* @param {Matrix2d|Matrix3d|number} a - a matrix to transform by, or the a component to multiply the current matrix by
|
|
44688
|
-
* @param {number} b - the b component to multiply the current matrix by
|
|
44689
|
-
* @param {number} c - the c component to multiply the current matrix by
|
|
44690
|
-
* @param {number} d - the d component to multiply the current matrix by
|
|
44691
|
-
* @param {number} e - the e component to multiply the current matrix by
|
|
44692
|
-
* @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
|
|
44693
45354
|
*/
|
|
44694
45355
|
transform(a, b, c, d, e, f) {
|
|
44695
45356
|
if (typeof a === "object") {
|
|
@@ -45678,6 +46339,9 @@ function dispatchEvent(normalizedEvents2) {
|
|
|
45678
46339
|
}
|
|
45679
46340
|
lastTimeStamp = pointer2.event.timeStamp;
|
|
45680
46341
|
}
|
|
46342
|
+
const worldOffset = _app2.world.pos;
|
|
46343
|
+
const absoluteWorldX = pointer2.gameWorldX + worldOffset.x;
|
|
46344
|
+
const absoluteWorldY = pointer2.gameWorldY + worldOffset.y;
|
|
45681
46345
|
currentPointer.pos.set(pointer2.gameWorldX, pointer2.gameWorldY);
|
|
45682
46346
|
currentPointer.setSize(pointer2.width, pointer2.height);
|
|
45683
46347
|
if (POINTER_MOVE.includes(pointer2.type)) {
|
|
@@ -45690,6 +46354,22 @@ function dispatchEvent(normalizedEvents2) {
|
|
|
45690
46354
|
(a, b) => _app2.world._sortReverseZ(a, b),
|
|
45691
46355
|
void 0
|
|
45692
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
|
+
}
|
|
45693
46373
|
candidates = candidates.concat([_app2.viewport]);
|
|
45694
46374
|
for (let c = candidates.length, candidate; c--, candidate = candidates[c]; ) {
|
|
45695
46375
|
if (eventHandlers.has(candidate) && candidate.isKinematic !== true) {
|
|
@@ -45706,10 +46386,15 @@ function dispatchEvent(normalizedEvents2) {
|
|
|
45706
46386
|
}
|
|
45707
46387
|
if (typeof ancestor !== "undefined") {
|
|
45708
46388
|
const parentBounds = ancestor.getBounds();
|
|
45709
|
-
|
|
45710
|
-
|
|
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
|
+
}
|
|
45711
46396
|
}
|
|
45712
|
-
const eventInBounds = bounds.contains(pointer2.gameX, pointer2.gameY);
|
|
46397
|
+
const eventInBounds = region.isFloating === true ? bounds.contains(pointer2.gameX, pointer2.gameY) : bounds.contains(absoluteWorldX, absoluteWorldY);
|
|
45713
46398
|
switch (pointer2.type) {
|
|
45714
46399
|
case POINTER_MOVE[0]:
|
|
45715
46400
|
case POINTER_MOVE[1]:
|
|
@@ -48368,14 +49053,23 @@ var Detector = class {
|
|
|
48368
49053
|
objB.onCollisionActive(viewB, objA);
|
|
48369
49054
|
}
|
|
48370
49055
|
}
|
|
49056
|
+
if (objA.body === void 0 || objB.body === void 0) {
|
|
49057
|
+
continue;
|
|
49058
|
+
}
|
|
48371
49059
|
const eitherSensor = objA.body.isSensor === true || objB.body.isSensor === true || this.response.isTriggerContact === true;
|
|
48372
49060
|
const aHasModern = typeof objA.onCollisionActive === "function";
|
|
48373
49061
|
const bHasModern = typeof objB.onCollisionActive === "function";
|
|
48374
49062
|
const aOptsOut = !aHasModern && typeof objA.onCollision === "function" && objA.onCollision(this.response, objB) === false;
|
|
49063
|
+
if (objA.body === void 0 || objB.body === void 0) {
|
|
49064
|
+
continue;
|
|
49065
|
+
}
|
|
48375
49066
|
if (!aOptsOut && objA.body.isStatic === false && !eitherSensor) {
|
|
48376
49067
|
objA.body.respondToCollision.call(objA.body, this.response);
|
|
48377
49068
|
}
|
|
48378
49069
|
const bOptsOut = !bHasModern && typeof objB.onCollision === "function" && objB.onCollision(this.response, objA) === false;
|
|
49070
|
+
if (objA.body === void 0 || objB.body === void 0) {
|
|
49071
|
+
continue;
|
|
49072
|
+
}
|
|
48379
49073
|
if (!bOptsOut && objB.body.isStatic === false && !eitherSensor) {
|
|
48380
49074
|
objB.body.respondToCollision.call(objB.body, this.response);
|
|
48381
49075
|
}
|
|
@@ -48651,8 +49345,10 @@ var BuiltinAdapter = class {
|
|
|
48651
49345
|
this.detector.collisions(ancestor);
|
|
48652
49346
|
}
|
|
48653
49347
|
}
|
|
48654
|
-
body.force
|
|
48655
|
-
|
|
49348
|
+
if (body.force !== void 0) {
|
|
49349
|
+
body.force.set(0, 0);
|
|
49350
|
+
body.forceZ = 0;
|
|
49351
|
+
}
|
|
48656
49352
|
}
|
|
48657
49353
|
this.detector.endFrame();
|
|
48658
49354
|
}
|
|
@@ -49383,6 +50079,7 @@ var Light2d = class extends Renderable {
|
|
|
49383
50079
|
};
|
|
49384
50080
|
|
|
49385
50081
|
// src/particles/particle.ts
|
|
50082
|
+
var _spawn = new Vector2d();
|
|
49386
50083
|
var Particle = class extends Renderable {
|
|
49387
50084
|
vel;
|
|
49388
50085
|
image;
|
|
@@ -49394,7 +50091,6 @@ var Particle = class extends Renderable {
|
|
|
49394
50091
|
wind;
|
|
49395
50092
|
followTrajectory;
|
|
49396
50093
|
onlyInViewport;
|
|
49397
|
-
accurateBounds;
|
|
49398
50094
|
_deltaInv;
|
|
49399
50095
|
_halfW;
|
|
49400
50096
|
_halfH;
|
|
@@ -49414,13 +50110,40 @@ var Particle = class extends Renderable {
|
|
|
49414
50110
|
this.vel = vector2dPool.get();
|
|
49415
50111
|
this.onResetEvent(emitter, true);
|
|
49416
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;
|
|
49417
50133
|
/**
|
|
49418
50134
|
* @ignore
|
|
49419
50135
|
*/
|
|
49420
50136
|
onResetEvent(emitter, newInstance = false) {
|
|
49421
50137
|
const image = emitter.settings.image;
|
|
49422
|
-
|
|
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 {
|
|
49423
50144
|
this.pos.set(emitter.getRandomPointX(), emitter.getRandomPointY());
|
|
50145
|
+
}
|
|
50146
|
+
if (!newInstance) {
|
|
49424
50147
|
this.resize(image.width, image.height);
|
|
49425
50148
|
this.currentTransform.identity();
|
|
49426
50149
|
}
|
|
@@ -49428,7 +50151,13 @@ var Particle = class extends Renderable {
|
|
|
49428
50151
|
this._halfW = this.width / 2;
|
|
49429
50152
|
this._halfH = this.height / 2;
|
|
49430
50153
|
this.alwaysUpdate = true;
|
|
50154
|
+
this.pos.setCallback(() => {
|
|
50155
|
+
this._boundsDirty = true;
|
|
50156
|
+
this.isDirty = true;
|
|
50157
|
+
});
|
|
50158
|
+
this._boundsDirty = true;
|
|
49431
50159
|
this.anchorPoint.set(0, 0);
|
|
50160
|
+
this.autoTransform = false;
|
|
49432
50161
|
if (typeof emitter.settings.tint === "string") {
|
|
49433
50162
|
this.tint.parseCSS(emitter.settings.tint);
|
|
49434
50163
|
}
|
|
@@ -49453,7 +50182,6 @@ var Particle = class extends Renderable {
|
|
|
49453
50182
|
this.wind = emitter.settings.wind;
|
|
49454
50183
|
this.followTrajectory = emitter.settings.followTrajectory;
|
|
49455
50184
|
this.onlyInViewport = emitter.settings.onlyInViewport;
|
|
49456
|
-
this.accurateBounds = emitter.settings.accurateBounds;
|
|
49457
50185
|
this._deltaInv = emitter._deltaInv;
|
|
49458
50186
|
if (!emitter.settings.followTrajectory) {
|
|
49459
50187
|
this._angle = randomFloat(
|
|
@@ -49518,12 +50246,108 @@ var Particle = class extends Renderable {
|
|
|
49518
50246
|
0,
|
|
49519
50247
|
1
|
|
49520
50248
|
);
|
|
49521
|
-
if (this.accurateBounds) {
|
|
49522
|
-
this.updateBounds();
|
|
49523
|
-
}
|
|
49524
50249
|
this.isDirty = this.inViewport || !this.onlyInViewport;
|
|
49525
50250
|
return super.update(dt);
|
|
49526
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
|
+
}
|
|
49527
50351
|
/**
|
|
49528
50352
|
* @ignore
|
|
49529
50353
|
*/
|
|
@@ -49762,6 +50586,27 @@ var Entity = class _Entity extends Renderable {
|
|
|
49762
50586
|
);
|
|
49763
50587
|
}
|
|
49764
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
|
+
}
|
|
49765
50610
|
/**
|
|
49766
50611
|
* draw this entity (automatically called by melonJS)
|
|
49767
50612
|
* @param {CanvasRenderer|WebGLRenderer} renderer - a renderer instance
|
|
@@ -50392,7 +51237,7 @@ var Trigger = class extends Renderable {
|
|
|
50392
51237
|
};
|
|
50393
51238
|
|
|
50394
51239
|
// src/version.ts
|
|
50395
|
-
var version = "20.
|
|
51240
|
+
var version = "20.2.0";
|
|
50396
51241
|
|
|
50397
51242
|
// src/system/bootstrap.ts
|
|
50398
51243
|
var initialized = false;
|
|
@@ -52508,72 +53353,12 @@ var FRAME_UNIFORM_SIZE = 80;
|
|
|
52508
53353
|
var CLEAR_UNIFORM_SIZE = 16;
|
|
52509
53354
|
|
|
52510
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
|
+
}
|
|
52511
53360
|
var MAX_QUAD_TEXTURES = 8;
|
|
52512
53361
|
var DEPTH_STENCIL_FORMAT = "depth24plus-stencil8";
|
|
52513
|
-
function blendStateFor(mode, premultipliedAlpha) {
|
|
52514
|
-
const src = premultipliedAlpha ? "one" : "src-alpha";
|
|
52515
|
-
let component;
|
|
52516
|
-
switch (mode) {
|
|
52517
|
-
case "none":
|
|
52518
|
-
return void 0;
|
|
52519
|
-
case "additive":
|
|
52520
|
-
component = { operation: "add", srcFactor: src, dstFactor: "one" };
|
|
52521
|
-
break;
|
|
52522
|
-
case "multiply":
|
|
52523
|
-
component = {
|
|
52524
|
-
operation: "add",
|
|
52525
|
-
srcFactor: "dst",
|
|
52526
|
-
dstFactor: "one-minus-src-alpha"
|
|
52527
|
-
};
|
|
52528
|
-
break;
|
|
52529
|
-
case "exclusion":
|
|
52530
|
-
component = {
|
|
52531
|
-
operation: "add",
|
|
52532
|
-
srcFactor: "one-minus-dst",
|
|
52533
|
-
dstFactor: "one-minus-src"
|
|
52534
|
-
};
|
|
52535
|
-
break;
|
|
52536
|
-
case "screen":
|
|
52537
|
-
component = {
|
|
52538
|
-
operation: "add",
|
|
52539
|
-
srcFactor: "one",
|
|
52540
|
-
dstFactor: "one-minus-src"
|
|
52541
|
-
};
|
|
52542
|
-
break;
|
|
52543
|
-
case "darken":
|
|
52544
|
-
component = { operation: "min", srcFactor: "one", dstFactor: "one" };
|
|
52545
|
-
break;
|
|
52546
|
-
case "lighten":
|
|
52547
|
-
component = { operation: "max", srcFactor: "one", dstFactor: "one" };
|
|
52548
|
-
break;
|
|
52549
|
-
default:
|
|
52550
|
-
component = {
|
|
52551
|
-
operation: "add",
|
|
52552
|
-
srcFactor: src,
|
|
52553
|
-
dstFactor: "one-minus-src-alpha"
|
|
52554
|
-
};
|
|
52555
|
-
break;
|
|
52556
|
-
}
|
|
52557
|
-
return { color: component, alpha: component };
|
|
52558
|
-
}
|
|
52559
|
-
function normalizeBlendMode(mode) {
|
|
52560
|
-
switch (mode) {
|
|
52561
|
-
case "none":
|
|
52562
|
-
case "multiply":
|
|
52563
|
-
case "screen":
|
|
52564
|
-
case "darken":
|
|
52565
|
-
case "lighten":
|
|
52566
|
-
case "exclusion":
|
|
52567
|
-
case "normal":
|
|
52568
|
-
return mode;
|
|
52569
|
-
case "additive":
|
|
52570
|
-
case "add":
|
|
52571
|
-
case "lighter":
|
|
52572
|
-
return "additive";
|
|
52573
|
-
default:
|
|
52574
|
-
return "normal";
|
|
52575
|
-
}
|
|
52576
|
-
}
|
|
52577
53362
|
var STENCIL_STATES = {
|
|
52578
53363
|
none: {
|
|
52579
53364
|
stencil: {
|
|
@@ -52919,7 +53704,7 @@ var WebGPUPipelineCache = class _WebGPUPipelineCache {
|
|
|
52919
53704
|
targets: [
|
|
52920
53705
|
{
|
|
52921
53706
|
format: this.format,
|
|
52922
|
-
blend: shaderKey === "clear" ? void 0 :
|
|
53707
|
+
blend: shaderKey === "clear" ? void 0 : gpuBlendState(blend, pma),
|
|
52923
53708
|
writeMask: stencil.colorWriteMask
|
|
52924
53709
|
}
|
|
52925
53710
|
]
|
|
@@ -53000,9 +53785,16 @@ var WebGPUQuadBatcher = class extends WebGPUBatcher {
|
|
|
53000
53785
|
},
|
|
53001
53786
|
onEvict: (slot) => {
|
|
53002
53787
|
this.segmentEntries[slot] = void 0;
|
|
53788
|
+
if (this._memoSlot === slot) {
|
|
53789
|
+
this._memoView = null;
|
|
53790
|
+
}
|
|
53003
53791
|
}
|
|
53004
53792
|
});
|
|
53005
53793
|
this.segmentEntries = [];
|
|
53794
|
+
this._memoView = null;
|
|
53795
|
+
this._memoFilter = null;
|
|
53796
|
+
this._memoWrap = null;
|
|
53797
|
+
this._memoSlot = 0;
|
|
53006
53798
|
this.segmentGroup = null;
|
|
53007
53799
|
this.composedGroups = /* @__PURE__ */ new Map();
|
|
53008
53800
|
this.resourceIds = /* @__PURE__ */ new WeakMap();
|
|
@@ -53101,17 +53893,24 @@ var WebGPUQuadBatcher = class extends WebGPUBatcher {
|
|
|
53101
53893
|
const record = store.getResidentRecord(texture, { force: reupload });
|
|
53102
53894
|
const wrap = texture.repeat ?? "no-repeat";
|
|
53103
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
|
+
}
|
|
53104
53899
|
const slotKey = `${this.resourceId(record.view)}|${filter}|${wrap}`;
|
|
53105
|
-
|
|
53106
|
-
|
|
53107
|
-
|
|
53900
|
+
let resolved = this.slotTable.peek(slotKey);
|
|
53901
|
+
if (resolved === void 0) {
|
|
53902
|
+
resolved = this.slotTable.slotFor(slotKey);
|
|
53903
|
+
this.segmentEntries[resolved] = {
|
|
53108
53904
|
view: record.view,
|
|
53109
53905
|
sampler: store.getSampler(filter, wrap)
|
|
53110
53906
|
};
|
|
53111
53907
|
this.segmentGroup = null;
|
|
53112
|
-
return slot;
|
|
53113
53908
|
}
|
|
53114
|
-
|
|
53909
|
+
this._memoView = record.view;
|
|
53910
|
+
this._memoFilter = filter;
|
|
53911
|
+
this._memoWrap = wrap;
|
|
53912
|
+
this._memoSlot = resolved;
|
|
53913
|
+
return resolved;
|
|
53115
53914
|
}
|
|
53116
53915
|
/**
|
|
53117
53916
|
* a stable id for a GPU resource object (bind-group composition keys)
|
|
@@ -55151,7 +55950,7 @@ function resolveDepthOps(meshDepthActive, pendingDepthClear) {
|
|
|
55151
55950
|
depthStoreOp: "store"
|
|
55152
55951
|
};
|
|
55153
55952
|
}
|
|
55154
|
-
var WebGPURenderer = class extends Renderer {
|
|
55953
|
+
var WebGPURenderer = class _WebGPURenderer extends Renderer {
|
|
55155
55954
|
/**
|
|
55156
55955
|
* @param {ApplicationSettings} options - The renderer parameters
|
|
55157
55956
|
*/
|
|
@@ -55188,6 +55987,13 @@ var WebGPURenderer = class extends Renderer {
|
|
|
55188
55987
|
this.commandEncoder = null;
|
|
55189
55988
|
this.renderPass = null;
|
|
55190
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();
|
|
55191
55997
|
this.pendingColorClear = false;
|
|
55192
55998
|
this.pendingClearValue = null;
|
|
55193
55999
|
this.pendingStencilClear = false;
|
|
@@ -55726,6 +56532,16 @@ var WebGPURenderer = class extends Renderer {
|
|
|
55726
56532
|
* frame, or null when no device is available
|
|
55727
56533
|
*/
|
|
55728
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 = {}) {
|
|
55729
56545
|
if (typeof this.device === "undefined") {
|
|
55730
56546
|
return null;
|
|
55731
56547
|
}
|
|
@@ -55941,6 +56757,7 @@ var WebGPURenderer = class extends Renderer {
|
|
|
55941
56757
|
* @override
|
|
55942
56758
|
*/
|
|
55943
56759
|
blitEffect(source, x, y, width, height, effect, keepBlend = false) {
|
|
56760
|
+
this._advancedBlendBusy++;
|
|
55944
56761
|
const batcher = this.setBatcher("quad");
|
|
55945
56762
|
blitSavedProjection.copy(this.projectionMatrix);
|
|
55946
56763
|
this.projectionMatrix.ortho(0, width, height, 0, -1, 1);
|
|
@@ -55948,6 +56765,106 @@ var WebGPURenderer = class extends Renderer {
|
|
|
55948
56765
|
batcher.blitTexture(source, x, y, width, height, effect, keepBlend);
|
|
55949
56766
|
this.projectionMatrix.copy(blitSavedProjection);
|
|
55950
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--;
|
|
55951
56868
|
}
|
|
55952
56869
|
/**
|
|
55953
56870
|
* a draw is about to be recorded outside the clear()/flush() bracket
|
|
@@ -55971,6 +56888,9 @@ var WebGPURenderer = class extends Renderer {
|
|
|
55971
56888
|
* @override
|
|
55972
56889
|
*/
|
|
55973
56890
|
flush() {
|
|
56891
|
+
if (this._advancedBlendOpen === true && this._advancedBlendBusy === 0) {
|
|
56892
|
+
this._closeAdvancedBlend();
|
|
56893
|
+
}
|
|
55974
56894
|
this.currentBatcher?.flush();
|
|
55975
56895
|
if (this.renderPass !== null) {
|
|
55976
56896
|
this.renderPass.end();
|
|
@@ -56005,6 +56925,9 @@ var WebGPURenderer = class extends Renderer {
|
|
|
56005
56925
|
this.pendingColorClear = false;
|
|
56006
56926
|
this.pendingDepthClear = false;
|
|
56007
56927
|
this.currentPipeline = null;
|
|
56928
|
+
for (const batcher of this.batchers.values()) {
|
|
56929
|
+
batcher.reset();
|
|
56930
|
+
}
|
|
56008
56931
|
this.destroyRetiredTextures();
|
|
56009
56932
|
}
|
|
56010
56933
|
/**
|
|
@@ -56060,6 +56983,7 @@ var WebGPURenderer = class extends Renderer {
|
|
|
56060
56983
|
if (typeof this.device === "undefined") {
|
|
56061
56984
|
return;
|
|
56062
56985
|
}
|
|
56986
|
+
this._drainAdvancedBlend();
|
|
56063
56987
|
this.currentBatcher?.flush();
|
|
56064
56988
|
const pass = this.ensurePass();
|
|
56065
56989
|
let rgba;
|
|
@@ -56156,6 +57080,18 @@ var WebGPURenderer = class extends Renderer {
|
|
|
56156
57080
|
if (typeof batcher === "undefined") {
|
|
56157
57081
|
throw new Error("Invalid Batcher");
|
|
56158
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
|
+
}
|
|
56159
57095
|
if (this.currentBatcher !== batcher) {
|
|
56160
57096
|
if (name !== "mesh" && name !== "litMesh" && // see WebGLRenderer#_canDrainShadows: a transition raised while
|
|
56161
57097
|
// a mask is being stencilled in (colour writes off) or inside a
|
|
@@ -56392,22 +57328,56 @@ var WebGPURenderer = class extends Renderer {
|
|
|
56392
57328
|
}
|
|
56393
57329
|
}
|
|
56394
57330
|
/**
|
|
56395
|
-
*
|
|
56396
|
-
*
|
|
56397
|
-
*
|
|
56398
|
-
*
|
|
56399
|
-
*
|
|
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
|
|
56400
57367
|
* @param {boolean} [premultipliedAlpha=true] - whether textures use premultiplied alpha (affects the source blend factor)
|
|
56401
|
-
* @returns {string} the blend mode actually applied
|
|
57368
|
+
* @returns {string} the blend mode actually applied (may differ if the requested mode is unsupported)
|
|
56402
57369
|
*/
|
|
56403
57370
|
setBlendMode(mode = "normal", premultipliedAlpha = true) {
|
|
56404
57371
|
const normalized = normalizeBlendMode(mode);
|
|
56405
|
-
|
|
57372
|
+
const advanced = isAdvancedBlendMode(mode);
|
|
57373
|
+
const tracked = advanced === true ? mode : normalized;
|
|
57374
|
+
if (this.currentBlendMode !== tracked || this.premultipliedAlpha !== premultipliedAlpha) {
|
|
57375
|
+
this._drainAdvancedBlend();
|
|
56406
57376
|
this.currentBatcher?.flush();
|
|
56407
|
-
this.currentBlendMode =
|
|
57377
|
+
this.currentBlendMode = tracked;
|
|
56408
57378
|
this.premultipliedAlpha = premultipliedAlpha;
|
|
56409
57379
|
}
|
|
56410
|
-
return
|
|
57380
|
+
return reportedBlendMode(mode);
|
|
56411
57381
|
}
|
|
56412
57382
|
/**
|
|
56413
57383
|
* Set the projection matrix — pushes a fresh frame-globals slot so
|
|
@@ -56895,6 +57865,11 @@ var WebGPURenderer = class extends Renderer {
|
|
|
56895
57865
|
const grad = this.currentGradient;
|
|
56896
57866
|
const hasMask = this.maskLevel > 0;
|
|
56897
57867
|
this.currentGradient = null;
|
|
57868
|
+
if (isAdvancedBlendMode(this.currentBlendMode) === true) {
|
|
57869
|
+
this._warnAdvancedBlendFallback("gradient fills");
|
|
57870
|
+
this._drainAdvancedBlend();
|
|
57871
|
+
}
|
|
57872
|
+
this._advancedBlendBusy++;
|
|
56898
57873
|
this.currentBatcher?.flush();
|
|
56899
57874
|
const visibleRef = this.maskVisibleRef;
|
|
56900
57875
|
let markRef = 1;
|
|
@@ -56930,6 +57905,7 @@ var WebGPURenderer = class extends Renderer {
|
|
|
56930
57905
|
this.stencilMode = "none";
|
|
56931
57906
|
}
|
|
56932
57907
|
this.ensurePass().setStencilReference(this.maskVisibleRef);
|
|
57908
|
+
this._advancedBlendBusy--;
|
|
56933
57909
|
}
|
|
56934
57910
|
/**
|
|
56935
57911
|
* Stroke an arc at the specified coordinates with given radius, start and end points
|
|
@@ -57587,6 +58563,14 @@ var WebGPURenderer = class extends Renderer {
|
|
|
57587
58563
|
* @override
|
|
57588
58564
|
*/
|
|
57589
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;
|
|
57590
58574
|
releaseShadowQuads(this);
|
|
57591
58575
|
off(GAME_RESET, this.onGameReset);
|
|
57592
58576
|
off(CANVAS_ONRESIZE, this.onCanvasResize);
|
|
@@ -58467,6 +59451,7 @@ var defaultParticleEmitterSettings = {
|
|
|
58467
59451
|
blendMode: "normal",
|
|
58468
59452
|
onlyInViewport: true,
|
|
58469
59453
|
floating: false,
|
|
59454
|
+
referenceSpace: "local",
|
|
58470
59455
|
maxParticles: 10,
|
|
58471
59456
|
frequency: 100,
|
|
58472
59457
|
duration: Infinity,
|
|
@@ -58478,6 +59463,10 @@ var defaultParticleEmitterSettings = {
|
|
|
58478
59463
|
var settings_default = defaultParticleEmitterSettings;
|
|
58479
59464
|
|
|
58480
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();
|
|
58481
59470
|
function createDefaultParticleTexture(w = 8, h = 8) {
|
|
58482
59471
|
const defaultParticleTexture = new canvasrendertarget_default(w, h, {
|
|
58483
59472
|
offscreenCanvas: true
|
|
@@ -58510,6 +59499,12 @@ var ParticleEmitter = class extends Container {
|
|
|
58510
59499
|
_dt;
|
|
58511
59500
|
/** @ignore */
|
|
58512
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";
|
|
58513
59508
|
/**
|
|
58514
59509
|
* whether at least one particle has been spawned by this emitter — used as
|
|
58515
59510
|
* the precondition for completion detection (a brand-new emitter with zero
|
|
@@ -58523,6 +59518,19 @@ var ParticleEmitter = class extends Container {
|
|
|
58523
59518
|
* @ignore
|
|
58524
59519
|
*/
|
|
58525
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;
|
|
58526
59534
|
/**
|
|
58527
59535
|
* @param x - x position of the particle emitter
|
|
58528
59536
|
* @param y - y position of the particle emitter
|
|
@@ -58569,11 +59577,8 @@ var ParticleEmitter = class extends Container {
|
|
|
58569
59577
|
this._deltaInv = timer_default.maxfps / 1e3;
|
|
58570
59578
|
this.reset(settings);
|
|
58571
59579
|
}
|
|
58572
|
-
/**
|
|
58573
|
-
* Reset the emitter with particle emitter settings.
|
|
58574
|
-
* @param settings - object with emitter settings. See {@link ParticleEmitterSettings}
|
|
58575
|
-
*/
|
|
58576
59580
|
reset(settings = {}) {
|
|
59581
|
+
const previousFrame = this.#frameOf(this.settings?.referenceSpace);
|
|
58577
59582
|
Object.assign(this.settings, settings_default, settings);
|
|
58578
59583
|
clampMinToMax(this.settings, "minLife", "maxLife");
|
|
58579
59584
|
clampMinToMax(this.settings, "minStartScale", "maxStartScale");
|
|
@@ -58592,8 +59597,131 @@ var ParticleEmitter = class extends Container {
|
|
|
58592
59597
|
this.settings.image = this._defaultParticle.canvas;
|
|
58593
59598
|
}
|
|
58594
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;
|
|
58595
59655
|
this.isDirty = true;
|
|
58596
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
|
+
}
|
|
58597
59725
|
/**
|
|
58598
59726
|
* returns a random point on the x axis within the bounds of this emitter
|
|
58599
59727
|
* @returns a random x position within the emitter bounds
|
|
@@ -58608,10 +59736,39 @@ var ParticleEmitter = class extends Container {
|
|
|
58608
59736
|
getRandomPointY() {
|
|
58609
59737
|
return randomFloat(0, this.getBounds().height);
|
|
58610
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
|
+
}
|
|
58611
59755
|
// Add count particles in the game world
|
|
58612
59756
|
/** @ignore */
|
|
58613
59757
|
addParticles(count) {
|
|
58614
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
|
+
}
|
|
58615
59772
|
for (let i = 0; i < count; i++) {
|
|
58616
59773
|
this.addChild(particlePool.get(this), z);
|
|
58617
59774
|
}
|
|
@@ -58659,6 +59816,14 @@ var ParticleEmitter = class extends Container {
|
|
|
58659
59816
|
* @ignore
|
|
58660
59817
|
*/
|
|
58661
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
|
+
}
|
|
58662
59827
|
if (this.settings.framesToSkip > 0) {
|
|
58663
59828
|
if (++this._updateCount > this.settings.framesToSkip) {
|
|
58664
59829
|
this._updateCount = 0;
|
|
@@ -58672,6 +59837,9 @@ var ParticleEmitter = class extends Container {
|
|
|
58672
59837
|
}
|
|
58673
59838
|
const childrenDirty = super.update(dt);
|
|
58674
59839
|
this.isDirty = this.isDirty || childrenDirty;
|
|
59840
|
+
if (this.#frameOf(this.settings.referenceSpace) !== this && this.getChildren().length > 0) {
|
|
59841
|
+
this.inViewport = true;
|
|
59842
|
+
}
|
|
58675
59843
|
if (this._enabled && this._stream) {
|
|
58676
59844
|
if (this._durationTimer !== Infinity) {
|
|
58677
59845
|
this._durationTimer -= dt;
|
|
@@ -58715,6 +59883,8 @@ var ParticleEmitter = class extends Container {
|
|
|
58715
59883
|
this._defaultParticle = void 0;
|
|
58716
59884
|
}
|
|
58717
59885
|
this.settings.image = void 0;
|
|
59886
|
+
this.settings.referenceSpace = "local";
|
|
59887
|
+
this._spawnMap = void 0;
|
|
58718
59888
|
}
|
|
58719
59889
|
};
|
|
58720
59890
|
|
|
@@ -60298,7 +61468,7 @@ var UITextButton = class extends UIBaseElement {
|
|
|
60298
61468
|
};
|
|
60299
61469
|
|
|
60300
61470
|
// src/video/effects/blur.js
|
|
60301
|
-
var
|
|
61471
|
+
var wgslFragment3 = `
|
|
60302
61472
|
struct BlurUniforms {
|
|
60303
61473
|
uBlurStrength : f32,
|
|
60304
61474
|
uTextureSize : vec2f,
|
|
@@ -60349,7 +61519,7 @@ var BlurEffect = class extends ShaderEffect {
|
|
|
60349
61519
|
return (sum / 9.0) * vColor;
|
|
60350
61520
|
}
|
|
60351
61521
|
`,
|
|
60352
|
-
wgsl:
|
|
61522
|
+
wgsl: wgslFragment3
|
|
60353
61523
|
});
|
|
60354
61524
|
this.strength = options.strength ?? 1;
|
|
60355
61525
|
const texSize = options.textureSize ?? [256, 256];
|
|
@@ -60375,7 +61545,7 @@ var BlurEffect = class extends ShaderEffect {
|
|
|
60375
61545
|
};
|
|
60376
61546
|
|
|
60377
61547
|
// src/video/effects/chromaticAberration.js
|
|
60378
|
-
var
|
|
61548
|
+
var wgslFragment4 = `
|
|
60379
61549
|
struct AberrationUniforms {
|
|
60380
61550
|
uOffset : f32,
|
|
60381
61551
|
uTextureSize : vec2f,
|
|
@@ -60412,7 +61582,7 @@ var ChromaticAberrationEffect = class extends ShaderEffect {
|
|
|
60412
61582
|
return vec4(r, g, b, a) * vColor;
|
|
60413
61583
|
}
|
|
60414
61584
|
`,
|
|
60415
|
-
wgsl:
|
|
61585
|
+
wgsl: wgslFragment4
|
|
60416
61586
|
});
|
|
60417
61587
|
this.offset = options.offset ?? 3;
|
|
60418
61588
|
const texSize = options.textureSize ?? [256, 256];
|
|
@@ -60460,7 +61630,7 @@ var DesaturateEffect = class extends ColorMatrixEffect {
|
|
|
60460
61630
|
};
|
|
60461
61631
|
|
|
60462
61632
|
// src/video/effects/dissolve.js
|
|
60463
|
-
var
|
|
61633
|
+
var wgslFragment5 = `
|
|
60464
61634
|
struct DissolveUniforms {
|
|
60465
61635
|
uDissolveProgress : f32,
|
|
60466
61636
|
uEdgeColor : vec3f,
|
|
@@ -60572,7 +61742,7 @@ var DissolveEffect = class extends ShaderEffect {
|
|
|
60572
61742
|
return color;
|
|
60573
61743
|
}
|
|
60574
61744
|
`,
|
|
60575
|
-
wgsl:
|
|
61745
|
+
wgsl: wgslFragment5
|
|
60576
61746
|
});
|
|
60577
61747
|
this.progress = options.progress ?? 0;
|
|
60578
61748
|
this.setUniform("uDissolveProgress", this.progress);
|
|
@@ -60600,7 +61770,7 @@ var DissolveEffect = class extends ShaderEffect {
|
|
|
60600
61770
|
};
|
|
60601
61771
|
|
|
60602
61772
|
// src/video/effects/dropShadow.js
|
|
60603
|
-
var
|
|
61773
|
+
var wgslFragment6 = `
|
|
60604
61774
|
struct ShadowUniforms {
|
|
60605
61775
|
uShadowOffset : vec2f,
|
|
60606
61776
|
uShadowColor : vec3f,
|
|
@@ -60664,7 +61834,7 @@ var DropShadowEffect = class extends ShaderEffect {
|
|
|
60664
61834
|
return color;
|
|
60665
61835
|
}
|
|
60666
61836
|
`,
|
|
60667
|
-
wgsl:
|
|
61837
|
+
wgsl: wgslFragment6
|
|
60668
61838
|
});
|
|
60669
61839
|
const texSize = options.textureSize ?? [256, 256];
|
|
60670
61840
|
this.setUniform(
|
|
@@ -60698,7 +61868,7 @@ var DropShadowEffect = class extends ShaderEffect {
|
|
|
60698
61868
|
};
|
|
60699
61869
|
|
|
60700
61870
|
// src/video/effects/flash.js
|
|
60701
|
-
var
|
|
61871
|
+
var wgslFragment7 = `
|
|
60702
61872
|
struct FlashUniforms {
|
|
60703
61873
|
uFlashColor : vec3f,
|
|
60704
61874
|
uFlashIntensity : f32,
|
|
@@ -60725,7 +61895,7 @@ var FlashEffect = class extends ShaderEffect {
|
|
|
60725
61895
|
return vec4(mix(color.rgb, uFlashColor * color.a, uFlashIntensity), color.a);
|
|
60726
61896
|
}
|
|
60727
61897
|
`,
|
|
60728
|
-
wgsl:
|
|
61898
|
+
wgsl: wgslFragment7
|
|
60729
61899
|
});
|
|
60730
61900
|
const color = options.color ?? [1, 1, 1];
|
|
60731
61901
|
this.intensity = options.intensity ?? 0;
|
|
@@ -60750,7 +61920,7 @@ var FlashEffect = class extends ShaderEffect {
|
|
|
60750
61920
|
};
|
|
60751
61921
|
|
|
60752
61922
|
// src/video/effects/glow.js
|
|
60753
|
-
var
|
|
61923
|
+
var wgslFragment8 = `
|
|
60754
61924
|
struct GlowUniforms {
|
|
60755
61925
|
uGlowColor : vec3f,
|
|
60756
61926
|
uGlowWidth : f32,
|
|
@@ -60811,7 +61981,7 @@ var GlowEffect = class extends ShaderEffect {
|
|
|
60811
61981
|
return color;
|
|
60812
61982
|
}
|
|
60813
61983
|
`,
|
|
60814
|
-
wgsl:
|
|
61984
|
+
wgsl: wgslFragment8
|
|
60815
61985
|
});
|
|
60816
61986
|
const color = options.color ?? [1, 1, 1];
|
|
60817
61987
|
const width = options.width ?? 3;
|
|
@@ -60848,7 +62018,7 @@ var GlowEffect = class extends ShaderEffect {
|
|
|
60848
62018
|
};
|
|
60849
62019
|
|
|
60850
62020
|
// src/video/effects/hologram.js
|
|
60851
|
-
var
|
|
62021
|
+
var wgslFragment9 = `
|
|
60852
62022
|
struct HologramUniforms {
|
|
60853
62023
|
uHoloColor : vec3f,
|
|
60854
62024
|
uHoloIntensity : f32,
|
|
@@ -60891,7 +62061,7 @@ var HologramEffect = class extends ShaderEffect {
|
|
|
60891
62061
|
return vec4(holo, color.a * flicker);
|
|
60892
62062
|
}
|
|
60893
62063
|
`,
|
|
60894
|
-
wgsl:
|
|
62064
|
+
wgsl: wgslFragment9
|
|
60895
62065
|
});
|
|
60896
62066
|
const color = options.color ?? [0.1, 0.7, 1];
|
|
60897
62067
|
this.setUniform("uHoloColor", new Float32Array(color));
|
|
@@ -60930,7 +62100,7 @@ var InvertEffect = class extends ColorMatrixEffect {
|
|
|
60930
62100
|
};
|
|
60931
62101
|
|
|
60932
62102
|
// src/video/effects/outline.js
|
|
60933
|
-
var
|
|
62103
|
+
var wgslFragment10 = `
|
|
60934
62104
|
struct OutlineUniforms {
|
|
60935
62105
|
uOutlineColor : vec3f,
|
|
60936
62106
|
uOutlineWidth : f32,
|
|
@@ -60994,7 +62164,7 @@ var OutlineEffect = class extends ShaderEffect {
|
|
|
60994
62164
|
return color;
|
|
60995
62165
|
}
|
|
60996
62166
|
`,
|
|
60997
|
-
wgsl:
|
|
62167
|
+
wgsl: wgslFragment10
|
|
60998
62168
|
});
|
|
60999
62169
|
const color = options.color ?? [1, 1, 1];
|
|
61000
62170
|
const width = options.width ?? 1;
|
|
@@ -61028,7 +62198,7 @@ var OutlineEffect = class extends ShaderEffect {
|
|
|
61028
62198
|
};
|
|
61029
62199
|
|
|
61030
62200
|
// src/video/effects/pixelate.js
|
|
61031
|
-
var
|
|
62201
|
+
var wgslFragment11 = `
|
|
61032
62202
|
struct PixelateUniforms {
|
|
61033
62203
|
uPixelSize : f32,
|
|
61034
62204
|
uTextureSize : vec2f,
|
|
@@ -61059,7 +62229,7 @@ var PixelateEffect = class extends ShaderEffect {
|
|
|
61059
62229
|
return texture2D(uSampler, snapped) * vColor;
|
|
61060
62230
|
}
|
|
61061
62231
|
`,
|
|
61062
|
-
wgsl:
|
|
62232
|
+
wgsl: wgslFragment11
|
|
61063
62233
|
});
|
|
61064
62234
|
this.size = options.size ?? 4;
|
|
61065
62235
|
const texSize = options.textureSize ?? [256, 256];
|
|
@@ -61085,7 +62255,7 @@ var PixelateEffect = class extends ShaderEffect {
|
|
|
61085
62255
|
};
|
|
61086
62256
|
|
|
61087
62257
|
// src/video/effects/scanline.js
|
|
61088
|
-
var
|
|
62258
|
+
var wgslFragment12 = `
|
|
61089
62259
|
struct ScanlineUniforms {
|
|
61090
62260
|
uScanlineOpacity : f32,
|
|
61091
62261
|
uCurvature : f32,
|
|
@@ -61164,7 +62334,7 @@ var ScanlineEffect = class extends ShaderEffect {
|
|
|
61164
62334
|
return color;
|
|
61165
62335
|
}
|
|
61166
62336
|
`,
|
|
61167
|
-
wgsl:
|
|
62337
|
+
wgsl: wgslFragment12
|
|
61168
62338
|
});
|
|
61169
62339
|
this.setUniform("uScanlineOpacity", options.opacity ?? 0.25);
|
|
61170
62340
|
this.setUniform("uCurvature", options.curvature ?? 0);
|
|
@@ -61216,7 +62386,7 @@ var SepiaEffect = class extends ColorMatrixEffect {
|
|
|
61216
62386
|
};
|
|
61217
62387
|
|
|
61218
62388
|
// src/video/effects/shine.js
|
|
61219
|
-
var
|
|
62389
|
+
var wgslFragment13 = `
|
|
61220
62390
|
struct ShineUniforms {
|
|
61221
62391
|
uShineColor : vec3f,
|
|
61222
62392
|
uShineWidth : f32,
|
|
@@ -61312,7 +62482,7 @@ var ShineEffect = class extends ShaderEffect {
|
|
|
61312
62482
|
return vec4(result, color.a);
|
|
61313
62483
|
}
|
|
61314
62484
|
`,
|
|
61315
|
-
wgsl:
|
|
62485
|
+
wgsl: wgslFragment13
|
|
61316
62486
|
});
|
|
61317
62487
|
this.setUniform(
|
|
61318
62488
|
"uShineColor",
|
|
@@ -61359,7 +62529,7 @@ var ShineEffect = class extends ShaderEffect {
|
|
|
61359
62529
|
};
|
|
61360
62530
|
|
|
61361
62531
|
// src/video/effects/tintPulse.js
|
|
61362
|
-
var
|
|
62532
|
+
var wgslFragment14 = `
|
|
61363
62533
|
struct TintPulseUniforms {
|
|
61364
62534
|
uPulseColor : vec3f,
|
|
61365
62535
|
uPulseSpeed : f32,
|
|
@@ -61393,7 +62563,7 @@ var TintPulseEffect = class extends ShaderEffect {
|
|
|
61393
62563
|
return vec4(mix(color.rgb, uPulseColor * color.a, pulse), color.a);
|
|
61394
62564
|
}
|
|
61395
62565
|
`,
|
|
61396
|
-
wgsl:
|
|
62566
|
+
wgsl: wgslFragment14
|
|
61397
62567
|
});
|
|
61398
62568
|
const color = options.color ?? [1, 0, 0];
|
|
61399
62569
|
this.setUniform("uPulseColor", new Float32Array(color));
|
|
@@ -61427,7 +62597,7 @@ var fragment = `
|
|
|
61427
62597
|
return vec4(color.rgb * v, color.a);
|
|
61428
62598
|
}
|
|
61429
62599
|
`;
|
|
61430
|
-
var
|
|
62600
|
+
var wgslFragment15 = `
|
|
61431
62601
|
struct VignetteUniforms {
|
|
61432
62602
|
uStrength : f32,
|
|
61433
62603
|
uSize : f32,
|
|
@@ -61448,7 +62618,7 @@ var VignetteEffect = class extends ShaderEffect {
|
|
|
61448
62618
|
* @param {number} [options.size=25.0] - vignette spread multiplier (higher = smaller dark area)
|
|
61449
62619
|
*/
|
|
61450
62620
|
constructor(renderer, options = {}) {
|
|
61451
|
-
super(renderer, { glsl: fragment, wgsl:
|
|
62621
|
+
super(renderer, { glsl: fragment, wgsl: wgslFragment15 });
|
|
61452
62622
|
this.strength = options.strength ?? 0.15;
|
|
61453
62623
|
this.size = options.size ?? 25;
|
|
61454
62624
|
this.setUniform("uStrength", this.strength);
|
|
@@ -61473,7 +62643,7 @@ var VignetteEffect = class extends ShaderEffect {
|
|
|
61473
62643
|
};
|
|
61474
62644
|
|
|
61475
62645
|
// src/video/effects/wave.js
|
|
61476
|
-
var
|
|
62646
|
+
var wgslFragment16 = `
|
|
61477
62647
|
struct WaveUniforms {
|
|
61478
62648
|
uAmplitude : f32,
|
|
61479
62649
|
uFrequency : f32,
|
|
@@ -61509,7 +62679,7 @@ var WaveEffect = class extends ShaderEffect {
|
|
|
61509
62679
|
return texture2D(uSampler, distorted) * vColor;
|
|
61510
62680
|
}
|
|
61511
62681
|
`,
|
|
61512
|
-
wgsl:
|
|
62682
|
+
wgsl: wgslFragment16
|
|
61513
62683
|
});
|
|
61514
62684
|
this.setUniform("uAmplitude", options.amplitude ?? 0.01);
|
|
61515
62685
|
this.setUniform("uFrequency", options.frequency ?? 10);
|