@flighthq/effects-gl 0.2.0 → 0.2.1-next.410.a23f189
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/dist/glBevelEffect.d.ts.map +1 -1
- package/dist/glBevelEffect.js +6 -4
- package/dist/glBevelEffect.js.map +1 -1
- package/dist/glBlendEffect.d.ts +8 -0
- package/dist/glBlendEffect.d.ts.map +1 -0
- package/dist/glBlendEffect.js +169 -0
- package/dist/glBlendEffect.js.map +1 -0
- package/dist/glCompositeEffect.d.ts +5 -0
- package/dist/glCompositeEffect.d.ts.map +1 -0
- package/dist/glCompositeEffect.js +90 -0
- package/dist/glCompositeEffect.js.map +1 -0
- package/dist/glDropShadowEffect.d.ts.map +1 -1
- package/dist/glDropShadowEffect.js +8 -6
- package/dist/glDropShadowEffect.js.map +1 -1
- package/dist/glEffectBlitShader.d.ts +2 -0
- package/dist/glEffectBlitShader.d.ts.map +1 -1
- package/dist/glEffectBlitShader.js +27 -0
- package/dist/glEffectBlitShader.js.map +1 -1
- package/dist/glEffectBoxBlur.d.ts +1 -0
- package/dist/glEffectBoxBlur.d.ts.map +1 -1
- package/dist/glEffectBoxBlur.js +28 -5
- package/dist/glEffectBoxBlur.js.map +1 -1
- package/dist/glEffectTintShader.d.ts.map +1 -1
- package/dist/glEffectTintShader.js +2 -0
- package/dist/glEffectTintShader.js.map +1 -1
- package/dist/glGradientBevelEffect.d.ts.map +1 -1
- package/dist/glGradientBevelEffect.js +8 -2
- package/dist/glGradientBevelEffect.js.map +1 -1
- package/dist/glGradientGlowEffect.d.ts.map +1 -1
- package/dist/glGradientGlowEffect.js +10 -3
- package/dist/glGradientGlowEffect.js.map +1 -1
- package/dist/glInnerGlowEffect.d.ts.map +1 -1
- package/dist/glInnerGlowEffect.js +24 -5
- package/dist/glInnerGlowEffect.js.map +1 -1
- package/dist/glInnerShadowEffect.d.ts.map +1 -1
- package/dist/glInnerShadowEffect.js +24 -5
- package/dist/glInnerShadowEffect.js.map +1 -1
- package/dist/glOuterGlowEffect.d.ts.map +1 -1
- package/dist/glOuterGlowEffect.js +8 -4
- package/dist/glOuterGlowEffect.js.map +1 -1
- package/dist/glRenderEffectPipeline.d.ts.map +1 -1
- package/dist/glRenderEffectPipeline.js +23 -7
- package/dist/glRenderEffectPipeline.js.map +1 -1
- package/dist/glRenderEffectRegistrar.d.ts.map +1 -1
- package/dist/glRenderEffectRegistrar.js +14 -4
- package/dist/glRenderEffectRegistrar.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/src/glBlendEffect.test.ts +111 -0
- package/src/glCompositeEffect.test.ts +39 -0
- package/src/glDropShadowEffect.test.ts +92 -0
- package/src/glEffectBlitShader.test.ts +7 -1
- package/src/glEffectBoxBlur.test.ts +50 -0
- package/src/glInnerGlowEffect.test.ts +132 -0
- package/src/glInnerShadowEffect.test.ts +132 -0
- package/src/glOuterGlowEffect.test.ts +91 -0
- package/src/glRenderEffectRegistrar.test.ts +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glBevelEffect.d.ts","sourceRoot":"","sources":["../src/glBevelEffect.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,WAAW,EAEX,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AAqBzB,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC,EAChC,IAAI,EAAE,QAAQ,CAAC,cAAc,CAAC,EAC9B,IAAI,EAAE,kBAAkB,EACxB,MAAM,EAAE,QAAQ,CAAC,WAAW,CAAC,GAC5B,IAAI,
|
|
1
|
+
{"version":3,"file":"glBevelEffect.d.ts","sourceRoot":"","sources":["../src/glBevelEffect.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,WAAW,EAEX,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AAqBzB,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC,EAChC,IAAI,EAAE,QAAQ,CAAC,cAAc,CAAC,EAC9B,IAAI,EAAE,kBAAkB,EACxB,MAAM,EAAE,QAAQ,CAAC,WAAW,CAAC,GAC5B,IAAI,CAsDN;AAED,eAAO,MAAM,0BAA0B,EAAE,oBAExC,CAAC"}
|
package/dist/glBevelEffect.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { acquireGlRenderTarget, clearGlRenderTarget, compileGlFullscreenProgram, drawGlFullscreenPass, releaseGlRenderTarget, } from '@flighthq/render-gl';
|
|
2
|
-
import { applyGlEffectBlitPass } from './glEffectBlitShader';
|
|
2
|
+
import { applyGlEffectBlitPass, applyGlEffectErasePass } from './glEffectBlitShader';
|
|
3
3
|
import { applyGlEffectBoxBlur } from './glEffectBoxBlur';
|
|
4
4
|
import { applyGlEffectTintPass } from './glEffectTintShader';
|
|
5
5
|
// Bevel composite effect: the directional gradient of the blurred silhouette drives a highlight/shadow edge band, clipped by bevelType and composited over the source.
|
|
@@ -35,7 +35,7 @@ export function applyBevelEffectToGl(state, source, dest, pool, effect) {
|
|
|
35
35
|
const highlightAlpha = effect.highlightAlpha ?? 1;
|
|
36
36
|
const strength = effect.strength ?? 1;
|
|
37
37
|
const quality = Math.max(1, Math.round(effect.quality ?? 1));
|
|
38
|
-
const
|
|
38
|
+
const sourceMode = effect.sourceMode ?? 'draw';
|
|
39
39
|
const bevelType = effect.bevelType ?? 'inner';
|
|
40
40
|
const [tinted, blurred, blurTemp] = [s0, s1, s2];
|
|
41
41
|
// Blurred alpha field (neutral white tint, strength 1 — strength is the gradient
|
|
@@ -47,7 +47,7 @@ export function applyBevelEffectToGl(state, source, dest, pool, effect) {
|
|
|
47
47
|
passes: quality,
|
|
48
48
|
});
|
|
49
49
|
clearGlRenderTarget(state, dst);
|
|
50
|
-
if (
|
|
50
|
+
if (sourceMode === 'draw')
|
|
51
51
|
applyGlEffectBlitPass(state, src, dst);
|
|
52
52
|
applyGlBevelCompositePass(state, blurred, src, dst, {
|
|
53
53
|
offsetX: offsetX / src.width,
|
|
@@ -60,6 +60,8 @@ export function applyBevelEffectToGl(state, source, dest, pool, effect) {
|
|
|
60
60
|
intensity: strength,
|
|
61
61
|
clipMode: bevelType === 'inner' ? 1 : bevelType === 'outer' ? 2 : 0,
|
|
62
62
|
});
|
|
63
|
+
if (sourceMode === 'knockout')
|
|
64
|
+
applyGlEffectErasePass(state, src, dst);
|
|
63
65
|
releaseGlRenderTarget(pool, s0);
|
|
64
66
|
releaseGlRenderTarget(pool, s1);
|
|
65
67
|
releaseGlRenderTarget(pool, s2);
|
|
@@ -68,7 +70,7 @@ export const defaultGlBevelEffectRunner = (ctx, effect) => {
|
|
|
68
70
|
applyBevelEffectToGl(ctx.state, ctx.source, ctx.dest, ctx.pool, effect);
|
|
69
71
|
};
|
|
70
72
|
// Reads the blurred alpha field (unit 0) and source (unit 1); writes the tinted, clipped bevel mask,
|
|
71
|
-
// premultiplied, blended over `dest` (which already holds the source
|
|
73
|
+
// premultiplied, blended over `dest` (which already holds the source when sourceMode is 'draw').
|
|
72
74
|
const BEVEL_COMPOSITE_FRAGMENT_SRC = `#version 300 es
|
|
73
75
|
precision mediump float;
|
|
74
76
|
in vec2 v_texCoord;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glBevelEffect.js","sourceRoot":"","sources":["../src/glBevelEffect.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,0BAA0B,EAC1B,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,qBAAqB,CAAC;AAU7B,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"glBevelEffect.js","sourceRoot":"","sources":["../src/glBevelEffect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AdvancedBlendMode, BlendEffect, GlRenderEffectRunner, GlRenderState, GlRenderTarget } from '@flighthq/types';
|
|
2
|
+
export declare function applyBlendEffectToGl(state: GlRenderState, source: Readonly<GlRenderTarget>, dest: Readonly<GlRenderTarget>, effect: Readonly<BlendEffect>): void;
|
|
3
|
+
export declare const defaultGlBlendEffectRunner: GlRenderEffectRunner;
|
|
4
|
+
export declare function getBlendEffectModeIndex(mode: AdvancedBlendMode): number;
|
|
5
|
+
export declare function getGlBlendEffectBackdrop(state: GlRenderState, backdropKey: string | null): WebGLTexture | null;
|
|
6
|
+
export declare function registerGlBlendEffectBackdrop(state: GlRenderState, backdropKey: string, texture: WebGLTexture): void;
|
|
7
|
+
export declare function unregisterGlBlendEffectBackdrop(state: GlRenderState, backdropKey: string): boolean;
|
|
8
|
+
//# sourceMappingURL=glBlendEffect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glBlendEffect.d.ts","sourceRoot":"","sources":["../src/glBlendEffect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,iBAAiB,EACjB,WAAW,EACX,oBAAoB,EACpB,aAAa,EACb,cAAc,EACf,MAAM,iBAAiB,CAAC;AAezB,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC,EAChC,IAAI,EAAE,QAAQ,CAAC,cAAc,CAAC,EAC9B,MAAM,EAAE,QAAQ,CAAC,WAAW,CAAC,GAC5B,IAAI,CAkBN;AAED,eAAO,MAAM,0BAA0B,EAAE,oBAExC,CAAC;AAIF,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAEvE;AAID,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,YAAY,GAAG,IAAI,CAG9G;AAKD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI,CAOpH;AAID,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAElG"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { drawGlFullscreenPass } from '@flighthq/render-gl';
|
|
2
|
+
import { AdvancedBlendMode as AdvancedBlendModeValues } from '@flighthq/types';
|
|
3
|
+
import { getGlEffectProgram, getGlEffectUniformLocation } from './glEffectProgramCache';
|
|
4
|
+
// Advanced-blend composite pass: sample the incoming layer (`u_texture0`, the effect's `source`) and a
|
|
5
|
+
// registered backdrop (`u_texture1`), compute the destination-reading / non-separable blend named by the
|
|
6
|
+
// effect's `mode`, composite the blended color over the backdrop (Porter-Duff source-over), and write to
|
|
7
|
+
// `dest`. This is the GL realization of the `BlendEffect` composite recipe — the escape hatch for the
|
|
8
|
+
// AdvancedBlendMode set the fixed-function BlendMode enum cannot express. The GLSL mirrors
|
|
9
|
+
// @flighthq/effects blendModeMath exactly, so the pass is verified against those plain-number tests.
|
|
10
|
+
//
|
|
11
|
+
// The backdrop is looked up by the effect's `backdropKey` in the per-state backdrop registry populated by
|
|
12
|
+
// registerGlBlendEffectBackdrop. An unregistered (or absent) key composites the layer over an implicit
|
|
13
|
+
// transparent backdrop, which reduces to source-over passthrough rather than erroring.
|
|
14
|
+
export function applyBlendEffectToGl(state, source, dest, effect) {
|
|
15
|
+
const backdrop = getGlBlendEffectBackdrop(state, effect.backdropKey ?? null);
|
|
16
|
+
const program = getGlEffectProgram(state, 'blend.advanced', BLEND_FRAGMENT_SRC);
|
|
17
|
+
const modeIndex = getBlendEffectModeIndex(effect.mode);
|
|
18
|
+
const opacity = effect.opacity ?? 1;
|
|
19
|
+
const hasBackdrop = backdrop !== null;
|
|
20
|
+
// Bind the layer to unit 0 and the backdrop (or the layer itself as a harmless stand-in) to unit 1;
|
|
21
|
+
// `u_hasBackdrop` gates whether unit 1 is used, so a missing backdrop is a source-over passthrough.
|
|
22
|
+
const inputs = [source.texture, hasBackdrop ? backdrop : source.texture];
|
|
23
|
+
drawGlFullscreenPass(state, program, inputs, dest, (gl, p) => {
|
|
24
|
+
const modeLoc = getGlEffectUniformLocation(state, p, 'u_mode');
|
|
25
|
+
const opacityLoc = getGlEffectUniformLocation(state, p, 'u_opacity');
|
|
26
|
+
const hasBackdropLoc = getGlEffectUniformLocation(state, p, 'u_hasBackdrop');
|
|
27
|
+
if (modeLoc !== null)
|
|
28
|
+
gl.uniform1i(modeLoc, modeIndex);
|
|
29
|
+
if (opacityLoc !== null)
|
|
30
|
+
gl.uniform1f(opacityLoc, opacity);
|
|
31
|
+
if (hasBackdropLoc !== null)
|
|
32
|
+
gl.uniform1i(hasBackdropLoc, hasBackdrop ? 1 : 0);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export const defaultGlBlendEffectRunner = (ctx, effect) => {
|
|
36
|
+
applyBlendEffectToGl(ctx.state, ctx.source, ctx.dest, effect);
|
|
37
|
+
};
|
|
38
|
+
// Maps an AdvancedBlendMode string to the integer the fragment shader switches on. Kept in lockstep with
|
|
39
|
+
// the BLEND_FRAGMENT_SRC branch order; an unknown mode maps to -1 (Normal passthrough in the shader).
|
|
40
|
+
export function getBlendEffectModeIndex(mode) {
|
|
41
|
+
return BLEND_MODE_INDEX[mode] ?? -1;
|
|
42
|
+
}
|
|
43
|
+
// Returns the backdrop texture registered under `backdropKey` for this state, or null when the key is
|
|
44
|
+
// null/absent or nothing is registered. Doubles as the introspection query for the passthrough fallback.
|
|
45
|
+
export function getGlBlendEffectBackdrop(state, backdropKey) {
|
|
46
|
+
if (backdropKey === null)
|
|
47
|
+
return null;
|
|
48
|
+
return _backdrops.get(state)?.get(backdropKey) ?? null;
|
|
49
|
+
}
|
|
50
|
+
// Registers a backdrop texture under `backdropKey` for this state, so a BlendEffect naming that key
|
|
51
|
+
// blends its layer over the texture. Last write wins. Pass a texture produced by the caller (e.g. a
|
|
52
|
+
// prior render target's `.texture`); the registry holds the handle only and never owns/frees it.
|
|
53
|
+
export function registerGlBlendEffectBackdrop(state, backdropKey, texture) {
|
|
54
|
+
let registry = _backdrops.get(state);
|
|
55
|
+
if (registry === undefined) {
|
|
56
|
+
registry = new Map();
|
|
57
|
+
_backdrops.set(state, registry);
|
|
58
|
+
}
|
|
59
|
+
registry.set(backdropKey, texture);
|
|
60
|
+
}
|
|
61
|
+
// Removes the backdrop registered under `backdropKey` for this state, returning true if one was present.
|
|
62
|
+
// The texture itself is the caller's to free; this only drops the registry reference.
|
|
63
|
+
export function unregisterGlBlendEffectBackdrop(state, backdropKey) {
|
|
64
|
+
return _backdrops.get(state)?.delete(backdropKey) ?? false;
|
|
65
|
+
}
|
|
66
|
+
// AdvancedBlendMode → shader branch index. Alphabetical by value; kept in lockstep with the switch in
|
|
67
|
+
// BLEND_FRAGMENT_SRC. The four HSL modes (Color/Hue/Luminosity/Saturation) take indices 7..10.
|
|
68
|
+
const BLEND_MODE_INDEX = {
|
|
69
|
+
[AdvancedBlendModeValues.Overlay]: 0,
|
|
70
|
+
[AdvancedBlendModeValues.HardLight]: 1,
|
|
71
|
+
[AdvancedBlendModeValues.SoftLight]: 2,
|
|
72
|
+
[AdvancedBlendModeValues.Difference]: 3,
|
|
73
|
+
[AdvancedBlendModeValues.Exclusion]: 4,
|
|
74
|
+
[AdvancedBlendModeValues.ColorDodge]: 5,
|
|
75
|
+
[AdvancedBlendModeValues.ColorBurn]: 6,
|
|
76
|
+
[AdvancedBlendModeValues.Hue]: 7,
|
|
77
|
+
[AdvancedBlendModeValues.Saturation]: 8,
|
|
78
|
+
[AdvancedBlendModeValues.Color]: 9,
|
|
79
|
+
[AdvancedBlendModeValues.Luminosity]: 10,
|
|
80
|
+
};
|
|
81
|
+
// Per-state backdrop registry. Off the render-state runtime type, freed with the state. Holds texture
|
|
82
|
+
// handles only — never owns or frees them.
|
|
83
|
+
const _backdrops = new WeakMap();
|
|
84
|
+
// The advanced-blend fragment shader. Layer = u_texture0 (premultiplied), backdrop = u_texture1. Both are
|
|
85
|
+
// un-premultiplied to straight RGB for the blend math, blended via the mode's B(cb, cs), then the blended
|
|
86
|
+
// color is composited over the backdrop with W3C mixing (cs' = (1 - ab)*cs + ab*B) and Porter-Duff
|
|
87
|
+
// source-over, re-premultiplied on output. The separable/HSL formulas mirror effects/blendModeMath.ts.
|
|
88
|
+
const BLEND_FRAGMENT_SRC = `#version 300 es
|
|
89
|
+
precision highp float;
|
|
90
|
+
in vec2 v_texCoord;
|
|
91
|
+
uniform sampler2D u_texture0;
|
|
92
|
+
uniform sampler2D u_texture1;
|
|
93
|
+
uniform int u_mode;
|
|
94
|
+
uniform float u_opacity;
|
|
95
|
+
uniform int u_hasBackdrop;
|
|
96
|
+
out vec4 o_color;
|
|
97
|
+
|
|
98
|
+
float lum(vec3 c) { return 0.3 * c.r + 0.59 * c.g + 0.11 * c.b; }
|
|
99
|
+
float sat(vec3 c) { return max(max(c.r, c.g), c.b) - min(min(c.r, c.g), c.b); }
|
|
100
|
+
|
|
101
|
+
vec3 clipColor(vec3 c) {
|
|
102
|
+
float l = lum(c);
|
|
103
|
+
float mn = min(min(c.r, c.g), c.b);
|
|
104
|
+
float mx = max(max(c.r, c.g), c.b);
|
|
105
|
+
if (mn < 0.0) c = l + (c - l) * l / (l - mn);
|
|
106
|
+
if (mx > 1.0) c = l + (c - l) * (1.0 - l) / (mx - l);
|
|
107
|
+
return c;
|
|
108
|
+
}
|
|
109
|
+
vec3 setLum(vec3 c, float l) { return clipColor(c + (l - lum(c))); }
|
|
110
|
+
|
|
111
|
+
vec3 setSat(vec3 c, float s) {
|
|
112
|
+
// Resolve min/mid/max channels, rescale mid+max to s, pin min to 0. Branchy but only three channels.
|
|
113
|
+
float mn = min(min(c.r, c.g), c.b);
|
|
114
|
+
float mx = max(max(c.r, c.g), c.b);
|
|
115
|
+
float md = (c.r + c.g + c.b) - mn - mx;
|
|
116
|
+
vec3 o;
|
|
117
|
+
float rmid = (mx > mn) ? (md - mn) * s / (mx - mn) : 0.0;
|
|
118
|
+
float rmax = (mx > mn) ? s : 0.0;
|
|
119
|
+
o.r = (c.r == mx) ? rmax : ((c.r == mn) ? 0.0 : rmid);
|
|
120
|
+
o.g = (c.g == mx) ? rmax : ((c.g == mn) ? 0.0 : rmid);
|
|
121
|
+
o.b = (c.b == mx) ? rmax : ((c.b == mn) ? 0.0 : rmid);
|
|
122
|
+
return o;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
float sepChannel(int mode, float cb, float cs) {
|
|
126
|
+
if (mode == 0) return cb <= 0.5 ? 2.0 * cb * cs : 1.0 - 2.0 * (1.0 - cb) * (1.0 - cs); // Overlay
|
|
127
|
+
if (mode == 1) return cs <= 0.5 ? 2.0 * cb * cs : 1.0 - 2.0 * (1.0 - cb) * (1.0 - cs); // HardLight
|
|
128
|
+
if (mode == 2) { // SoftLight
|
|
129
|
+
float d = cb <= 0.25 ? ((16.0 * cb - 12.0) * cb + 4.0) * cb : sqrt(cb);
|
|
130
|
+
return cs <= 0.5 ? cb - (1.0 - 2.0 * cs) * cb * (1.0 - cb) : cb + (2.0 * cs - 1.0) * (d - cb);
|
|
131
|
+
}
|
|
132
|
+
if (mode == 3) return abs(cb - cs); // Difference
|
|
133
|
+
if (mode == 4) return cb + cs - 2.0 * cb * cs; // Exclusion
|
|
134
|
+
if (mode == 5) return cb <= 0.0 ? 0.0 : (cs >= 1.0 ? 1.0 : min(1.0, cb / (1.0 - cs))); // ColorDodge
|
|
135
|
+
if (mode == 6) return cb >= 1.0 ? 1.0 : (cs <= 0.0 ? 0.0 : 1.0 - min(1.0, (1.0 - cb) / cs)); // ColorBurn
|
|
136
|
+
return cs; // Normal
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
vec3 blendRgb(int mode, vec3 cb, vec3 cs) {
|
|
140
|
+
if (mode == 7) return setLum(setSat(cs, sat(cb)), lum(cb)); // Hue
|
|
141
|
+
if (mode == 8) return setLum(setSat(cb, sat(cs)), lum(cb)); // Saturation
|
|
142
|
+
if (mode == 9) return setLum(cs, lum(cb)); // Color
|
|
143
|
+
if (mode == 10) return setLum(cb, lum(cs)); // Luminosity
|
|
144
|
+
return vec3(sepChannel(mode, cb.r, cs.r), sepChannel(mode, cb.g, cs.g), sepChannel(mode, cb.b, cs.b));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
void main() {
|
|
148
|
+
vec4 layer = texture(u_texture0, v_texCoord);
|
|
149
|
+
// No backdrop registered: the blend has nothing to read, so pass the layer through unchanged.
|
|
150
|
+
if (u_hasBackdrop == 0) { o_color = layer; return; }
|
|
151
|
+
vec4 back = texture(u_texture1, v_texCoord);
|
|
152
|
+
|
|
153
|
+
// Un-premultiply to straight RGB for the blend math.
|
|
154
|
+
vec3 cs = layer.a > 0.0 ? layer.rgb / layer.a : vec3(0.0);
|
|
155
|
+
vec3 cb = back.a > 0.0 ? back.rgb / back.a : vec3(0.0);
|
|
156
|
+
float as = layer.a * u_opacity;
|
|
157
|
+
float ab = back.a;
|
|
158
|
+
|
|
159
|
+
// W3C blend mixing: the blended color contributes only where the backdrop is opaque; elsewhere the
|
|
160
|
+
// straight source shows through. cs' = (1 - ab) * cs + ab * B(cb, cs).
|
|
161
|
+
vec3 blended = blendRgb(u_mode, cb, cs);
|
|
162
|
+
vec3 mixed = (1.0 - ab) * cs + ab * blended;
|
|
163
|
+
|
|
164
|
+
// Porter-Duff source-over of the (mixed) layer onto the backdrop, output premultiplied.
|
|
165
|
+
float outA = as + ab * (1.0 - as);
|
|
166
|
+
vec3 outRgb = mixed * as + cb * ab * (1.0 - as);
|
|
167
|
+
o_color = vec4(outRgb, outA);
|
|
168
|
+
}`;
|
|
169
|
+
//# sourceMappingURL=glBlendEffect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glBlendEffect.js","sourceRoot":"","sources":["../src/glBlendEffect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CompositeEffect, CompositeOperator, GlRenderEffectRunner, GlRenderState, GlRenderTarget } from '@flighthq/types';
|
|
2
|
+
export declare function applyCompositeEffectToGl(state: GlRenderState, source: Readonly<GlRenderTarget>, dest: Readonly<GlRenderTarget>, effect: Readonly<CompositeEffect>): void;
|
|
3
|
+
export declare const defaultGlCompositeEffectRunner: GlRenderEffectRunner;
|
|
4
|
+
export declare function getCompositeEffectOperatorIndex(operator: CompositeOperator): number;
|
|
5
|
+
//# sourceMappingURL=glCompositeEffect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glCompositeEffect.d.ts","sourceRoot":"","sources":["../src/glCompositeEffect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,aAAa,EACb,cAAc,EACf,MAAM,iBAAiB,CAAC;AAiBzB,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC,EAChC,IAAI,EAAE,QAAQ,CAAC,cAAc,CAAC,EAC9B,MAAM,EAAE,QAAQ,CAAC,eAAe,CAAC,GAChC,IAAI,CAeN;AAED,eAAO,MAAM,8BAA8B,EAAE,oBAE5C,CAAC;AAIF,wBAAgB,+BAA+B,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,CAEnF"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { drawGlFullscreenPass } from '@flighthq/render-gl';
|
|
2
|
+
import { CompositeOperator as CompositeOperatorValues } from '@flighthq/types';
|
|
3
|
+
import { getGlBlendEffectBackdrop } from './glBlendEffect';
|
|
4
|
+
import { getGlEffectProgram, getGlEffectUniformLocation } from './glEffectProgramCache';
|
|
5
|
+
// Porter-Duff composite pass: sample the incoming layer (`u_texture0`, the effect's `source`) and a
|
|
6
|
+
// registered backdrop (`u_texture1`), combine them with the coverage factors of the effect's `operator`
|
|
7
|
+
// (`Fa*layer + Fb*backdrop` on premultiplied color), and write to `dest`. This is the GL realization of
|
|
8
|
+
// the CompositeEffect — the fixed-function-cost sibling of the shader-based BlendEffect. The GLSL factor
|
|
9
|
+
// formulas mirror @flighthq/effects compositeOperatorMath exactly, so the pass is verified against those
|
|
10
|
+
// plain-number tests.
|
|
11
|
+
//
|
|
12
|
+
// The backdrop is shared with BlendEffect: looked up by the effect's `backdropKey` in the per-state
|
|
13
|
+
// registry populated by registerGlBlendEffectBackdrop. A null/unregistered key composites over an implicit
|
|
14
|
+
// transparent backdrop (source-over reduces to passthrough; erase/mask reduce to clear) rather than
|
|
15
|
+
// erroring.
|
|
16
|
+
export function applyCompositeEffectToGl(state, source, dest, effect) {
|
|
17
|
+
const backdrop = getGlBlendEffectBackdrop(state, effect.backdropKey ?? null);
|
|
18
|
+
const program = getGlEffectProgram(state, 'composite.porterduff', COMPOSITE_FRAGMENT_SRC);
|
|
19
|
+
const operatorIndex = getCompositeEffectOperatorIndex(effect.operator);
|
|
20
|
+
const hasBackdrop = backdrop !== null;
|
|
21
|
+
// Bind the layer to unit 0 and the backdrop (or the layer itself as a harmless stand-in) to unit 1;
|
|
22
|
+
// `u_hasBackdrop` gates whether unit 1 is read, so a missing backdrop composites over transparent.
|
|
23
|
+
const inputs = [source.texture, hasBackdrop ? backdrop : source.texture];
|
|
24
|
+
drawGlFullscreenPass(state, program, inputs, dest, (gl, p) => {
|
|
25
|
+
const operatorLoc = getGlEffectUniformLocation(state, p, 'u_operator');
|
|
26
|
+
const hasBackdropLoc = getGlEffectUniformLocation(state, p, 'u_hasBackdrop');
|
|
27
|
+
if (operatorLoc !== null)
|
|
28
|
+
gl.uniform1i(operatorLoc, operatorIndex);
|
|
29
|
+
if (hasBackdropLoc !== null)
|
|
30
|
+
gl.uniform1i(hasBackdropLoc, hasBackdrop ? 1 : 0);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
export const defaultGlCompositeEffectRunner = (ctx, effect) => {
|
|
34
|
+
applyCompositeEffectToGl(ctx.state, ctx.source, ctx.dest, effect);
|
|
35
|
+
};
|
|
36
|
+
// Maps a CompositeOperator string to the integer the fragment shader switches on. Kept in lockstep with
|
|
37
|
+
// the COMPOSITE_FRAGMENT_SRC branch order; an unknown (vendor) operator maps to 0 (SourceOver).
|
|
38
|
+
export function getCompositeEffectOperatorIndex(operator) {
|
|
39
|
+
return COMPOSITE_OPERATOR_INDEX[operator] ?? 0;
|
|
40
|
+
}
|
|
41
|
+
// CompositeOperator → shader branch index. Kept in lockstep with the if-chain in COMPOSITE_FRAGMENT_SRC
|
|
42
|
+
// and with the factor formulas in @flighthq/effects compositeOperatorMath.
|
|
43
|
+
const COMPOSITE_OPERATOR_INDEX = {
|
|
44
|
+
[CompositeOperatorValues.SourceOver]: 0,
|
|
45
|
+
[CompositeOperatorValues.DestinationOver]: 1,
|
|
46
|
+
[CompositeOperatorValues.SourceIn]: 2,
|
|
47
|
+
[CompositeOperatorValues.DestinationIn]: 3,
|
|
48
|
+
[CompositeOperatorValues.SourceOut]: 4,
|
|
49
|
+
[CompositeOperatorValues.DestinationOut]: 5,
|
|
50
|
+
[CompositeOperatorValues.SourceAtop]: 6,
|
|
51
|
+
[CompositeOperatorValues.DestinationAtop]: 7,
|
|
52
|
+
[CompositeOperatorValues.Xor]: 8,
|
|
53
|
+
[CompositeOperatorValues.Copy]: 9,
|
|
54
|
+
[CompositeOperatorValues.Clear]: 10,
|
|
55
|
+
};
|
|
56
|
+
// Premultiplied Porter-Duff fragment shader. Layer = u_texture0, backdrop = u_texture1, both premultiplied.
|
|
57
|
+
// The composited pixel is `Fa*layer + Fb*backdrop`, where Fa/Fb depend on the operator and the coverage
|
|
58
|
+
// alphas (as = layer.a, ab = backdrop.a) — the same factors as compositeOperatorMath. Premultiplication is
|
|
59
|
+
// what lets one factor pair drive rgb and a alike, so no un-premultiply is needed (unlike BlendEffect).
|
|
60
|
+
const COMPOSITE_FRAGMENT_SRC = `#version 300 es
|
|
61
|
+
precision highp float;
|
|
62
|
+
in vec2 v_texCoord;
|
|
63
|
+
uniform sampler2D u_texture0;
|
|
64
|
+
uniform sampler2D u_texture1;
|
|
65
|
+
uniform int u_operator;
|
|
66
|
+
uniform int u_hasBackdrop;
|
|
67
|
+
out vec4 o_color;
|
|
68
|
+
|
|
69
|
+
void main() {
|
|
70
|
+
vec4 layer = texture(u_texture0, v_texCoord);
|
|
71
|
+
vec4 back = u_hasBackdrop == 1 ? texture(u_texture1, v_texCoord) : vec4(0.0);
|
|
72
|
+
float as = layer.a;
|
|
73
|
+
float ab = back.a;
|
|
74
|
+
|
|
75
|
+
float fa = 1.0;
|
|
76
|
+
float fb = 1.0 - as; // SourceOver (0, default)
|
|
77
|
+
if (u_operator == 1) { fa = 1.0 - ab; fb = 1.0; } // DestinationOver
|
|
78
|
+
else if (u_operator == 2) { fa = ab; fb = 0.0; } // SourceIn
|
|
79
|
+
else if (u_operator == 3) { fa = 0.0; fb = as; } // DestinationIn
|
|
80
|
+
else if (u_operator == 4) { fa = 1.0 - ab; fb = 0.0; } // SourceOut
|
|
81
|
+
else if (u_operator == 5) { fa = 0.0; fb = 1.0 - as; } // DestinationOut
|
|
82
|
+
else if (u_operator == 6) { fa = ab; fb = 1.0 - as; } // SourceAtop
|
|
83
|
+
else if (u_operator == 7) { fa = 1.0 - ab; fb = as; } // DestinationAtop
|
|
84
|
+
else if (u_operator == 8) { fa = 1.0 - ab; fb = 1.0 - as; } // Xor
|
|
85
|
+
else if (u_operator == 9) { fa = 1.0; fb = 0.0; } // Copy
|
|
86
|
+
else if (u_operator == 10) { fa = 0.0; fb = 0.0; } // Clear
|
|
87
|
+
|
|
88
|
+
o_color = fa * layer + fb * back;
|
|
89
|
+
}`;
|
|
90
|
+
//# sourceMappingURL=glCompositeEffect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glCompositeEffect.js","sourceRoot":"","sources":["../src/glCompositeEffect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAQ3D,OAAO,EAAE,iBAAiB,IAAI,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE/E,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAExF,oGAAoG;AACpG,wGAAwG;AACxG,wGAAwG;AACxG,yGAAyG;AACzG,yGAAyG;AACzG,sBAAsB;AACtB,EAAE;AACF,oGAAoG;AACpG,2GAA2G;AAC3G,oGAAoG;AACpG,YAAY;AACZ,MAAM,UAAU,wBAAwB,CACtC,KAAoB,EACpB,MAAgC,EAChC,IAA8B,EAC9B,MAAiC;IAEjC,MAAM,QAAQ,GAAG,wBAAwB,CAAC,KAAK,EAAE,MAAM,CAAC,WAAW,IAAI,IAAI,CAAC,CAAC;IAC7E,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,EAAE,sBAAsB,EAAE,sBAAsB,CAAC,CAAC;IAC1F,MAAM,aAAa,GAAG,+BAA+B,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACvE,MAAM,WAAW,GAAG,QAAQ,KAAK,IAAI,CAAC;IAEtC,oGAAoG;IACpG,mGAAmG;IACnG,MAAM,MAAM,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAE,QAAyB,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3F,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE;QAC3D,MAAM,WAAW,GAAG,0BAA0B,CAAC,KAAK,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC;QACvE,MAAM,cAAc,GAAG,0BAA0B,CAAC,KAAK,EAAE,CAAC,EAAE,eAAe,CAAC,CAAC;QAC7E,IAAI,WAAW,KAAK,IAAI;YAAE,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;QACnE,IAAI,cAAc,KAAK,IAAI;YAAE,EAAE,CAAC,SAAS,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,MAAM,8BAA8B,GAAyB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;IAClF,wBAAwB,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,MAAyB,CAAC,CAAC;AACvF,CAAC,CAAC;AAEF,wGAAwG;AACxG,gGAAgG;AAChG,MAAM,UAAU,+BAA+B,CAAC,QAA2B;IACzE,OAAO,wBAAwB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACjD,CAAC;AAED,wGAAwG;AACxG,2EAA2E;AAC3E,MAAM,wBAAwB,GAAqC;IACjE,CAAC,uBAAuB,CAAC,UAAU,CAAC,EAAE,CAAC;IACvC,CAAC,uBAAuB,CAAC,eAAe,CAAC,EAAE,CAAC;IAC5C,CAAC,uBAAuB,CAAC,QAAQ,CAAC,EAAE,CAAC;IACrC,CAAC,uBAAuB,CAAC,aAAa,CAAC,EAAE,CAAC;IAC1C,CAAC,uBAAuB,CAAC,SAAS,CAAC,EAAE,CAAC;IACtC,CAAC,uBAAuB,CAAC,cAAc,CAAC,EAAE,CAAC;IAC3C,CAAC,uBAAuB,CAAC,UAAU,CAAC,EAAE,CAAC;IACvC,CAAC,uBAAuB,CAAC,eAAe,CAAC,EAAE,CAAC;IAC5C,CAAC,uBAAuB,CAAC,GAAG,CAAC,EAAE,CAAC;IAChC,CAAC,uBAAuB,CAAC,IAAI,CAAC,EAAE,CAAC;IACjC,CAAC,uBAAuB,CAAC,KAAK,CAAC,EAAE,EAAE;CACpC,CAAC;AAEF,4GAA4G;AAC5G,wGAAwG;AACxG,2GAA2G;AAC3G,wGAAwG;AACxG,MAAM,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6B7B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glDropShadowEffect.d.ts","sourceRoot":"","sources":["../src/glDropShadowEffect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AAYzB,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC,EAChC,IAAI,EAAE,QAAQ,CAAC,cAAc,CAAC,EAC9B,IAAI,EAAE,kBAAkB,EACxB,MAAM,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GACjC,IAAI,
|
|
1
|
+
{"version":3,"file":"glDropShadowEffect.d.ts","sourceRoot":"","sources":["../src/glDropShadowEffect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AAYzB,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC,EAChC,IAAI,EAAE,QAAQ,CAAC,cAAc,CAAC,EAC9B,IAAI,EAAE,kBAAkB,EACxB,MAAM,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GACjC,IAAI,CA6CN;AAED,eAAO,MAAM,+BAA+B,EAAE,oBAE7C,CAAC"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { acquireGlRenderTarget, clearGlRenderTarget, releaseGlRenderTarget } from '@flighthq/render-gl';
|
|
2
|
-
import { applyGlEffectBlitOffsetPass, applyGlEffectBlitPass } from './glEffectBlitShader';
|
|
2
|
+
import { applyGlEffectBlitOffsetPass, applyGlEffectBlitPass, applyGlEffectErasePass } from './glEffectBlitShader';
|
|
3
3
|
import { applyGlEffectBoxBlur } from './glEffectBoxBlur';
|
|
4
4
|
import { applyGlEffectTintPass } from './glEffectTintShader';
|
|
5
5
|
// Drop-shadow composite effect: tint the scene silhouette, blur it, offset it by angle/distance, then composite the source over the shadow.
|
|
6
6
|
// Full-frame realization: acquires the recipe's three scratch targets from the effect pool, runs the
|
|
7
7
|
// inlined multi-pass recipe, then releases them.
|
|
8
8
|
//
|
|
9
|
-
// Compositing order
|
|
10
|
-
//
|
|
9
|
+
// Compositing order depends on `sourceMode`: 'draw' composites shadow → source, 'hide' composites
|
|
10
|
+
// shadow only, and 'knockout' composites shadow then erases the un-offset source silhouette.
|
|
11
11
|
export function applyDropShadowEffectToGl(state, source, dest, pool, effect) {
|
|
12
12
|
const descriptor = { width: source.width, height: source.height, format: source.format };
|
|
13
13
|
const s0 = acquireGlRenderTarget(state, pool, descriptor);
|
|
@@ -23,8 +23,7 @@ export function applyDropShadowEffectToGl(state, source, dest, pool, effect) {
|
|
|
23
23
|
const alpha = effect.alpha ?? 1;
|
|
24
24
|
const strength = effect.strength ?? 1;
|
|
25
25
|
const quality = Math.max(1, Math.round(effect.quality ?? 1));
|
|
26
|
-
const
|
|
27
|
-
const knockout = effect.knockout ?? false;
|
|
26
|
+
const sourceMode = effect.sourceMode ?? 'draw';
|
|
28
27
|
const tintStrength = Math.min(1, strength);
|
|
29
28
|
const shadowPasses = Math.max(1, Math.floor(strength));
|
|
30
29
|
const [mask, blurred, blurTemp] = [s0, s1, s2];
|
|
@@ -38,7 +37,10 @@ export function applyDropShadowEffectToGl(state, source, dest, pool, effect) {
|
|
|
38
37
|
for (let i = 0; i < shadowPasses; i++) {
|
|
39
38
|
applyGlEffectBlitOffsetPass(state, blurred, dst, dx, dy);
|
|
40
39
|
}
|
|
41
|
-
if (
|
|
40
|
+
if (sourceMode === 'knockout') {
|
|
41
|
+
applyGlEffectErasePass(state, src, dst);
|
|
42
|
+
}
|
|
43
|
+
else if (sourceMode === 'draw') {
|
|
42
44
|
applyGlEffectBlitPass(state, src, dst);
|
|
43
45
|
}
|
|
44
46
|
releaseGlRenderTarget(pool, s0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glDropShadowEffect.js","sourceRoot":"","sources":["../src/glDropShadowEffect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AASxG,OAAO,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"glDropShadowEffect.js","sourceRoot":"","sources":["../src/glDropShadowEffect.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,4 +7,6 @@ import type { GlRenderState } from '@flighthq/types';
|
|
|
7
7
|
export declare function applyGlEffectBlitOffsetPass(state: GlRenderState, source: GlRenderTarget, dest: GlRenderTarget, dx: number, dy: number): void;
|
|
8
8
|
/** Blits source directly into dest without modification. */
|
|
9
9
|
export declare function applyGlEffectBlitPass(state: GlRenderState, source: GlRenderTarget, dest: GlRenderTarget): void;
|
|
10
|
+
/** Erases dest by the source alpha mask, equivalent to destination-out compositing. */
|
|
11
|
+
export declare function applyGlEffectErasePass(state: GlRenderState, source: GlRenderTarget, dest: GlRenderTarget): void;
|
|
10
12
|
//# sourceMappingURL=glEffectBlitShader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glEffectBlitShader.d.ts","sourceRoot":"","sources":["../src/glEffectBlitShader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAuB,aAAa,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"glEffectBlitShader.d.ts","sourceRoot":"","sources":["../src/glEffectBlitShader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAuB,aAAa,EAAE,MAAM,iBAAiB,CAAC;AA+C1E;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,cAAc,EACpB,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,GACT,IAAI,CAKN;AAED,4DAA4D;AAC5D,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAG9G;AAED,uFAAuF;AACvF,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAK/G"}
|
|
@@ -23,8 +23,19 @@ out vec4 fragColor;
|
|
|
23
23
|
void main() {
|
|
24
24
|
fragColor = texture(u_texture, v_texCoord);
|
|
25
25
|
}`;
|
|
26
|
+
// Emits source alpha for a destination-out erase pass; blend state supplies the coverage operator.
|
|
27
|
+
const ERASE_FRAGMENT_SRC = `#version 300 es
|
|
28
|
+
precision mediump float;
|
|
29
|
+
in vec2 v_texCoord;
|
|
30
|
+
uniform sampler2D u_texture;
|
|
31
|
+
out vec4 fragColor;
|
|
32
|
+
void main() {
|
|
33
|
+
float a = texture(u_texture, v_texCoord).a;
|
|
34
|
+
fragColor = vec4(0.0, 0.0, 0.0, a);
|
|
35
|
+
}`;
|
|
26
36
|
const blitOffsetShaders = new WeakMap();
|
|
27
37
|
const blitShaders = new WeakMap();
|
|
38
|
+
const eraseShaders = new WeakMap();
|
|
28
39
|
/**
|
|
29
40
|
* Blits source into dest at a pixel offset (dx, dy in screen-space Y-down).
|
|
30
41
|
* Pixels sampling outside the source bounds produce transparent output.
|
|
@@ -40,6 +51,13 @@ export function applyGlEffectBlitPass(state, source, dest) {
|
|
|
40
51
|
const loc = getGlBlitShader(state);
|
|
41
52
|
drawGlFullscreenPass(state, loc, [source.texture], dest, () => { });
|
|
42
53
|
}
|
|
54
|
+
/** Erases dest by the source alpha mask, equivalent to destination-out compositing. */
|
|
55
|
+
export function applyGlEffectErasePass(state, source, dest) {
|
|
56
|
+
const loc = getGlEraseShader(state);
|
|
57
|
+
drawGlFullscreenPass(state, loc, [source.texture], dest, (gl) => {
|
|
58
|
+
gl.blendFunc(gl.ZERO, gl.ONE_MINUS_SRC_ALPHA);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
43
61
|
function getGlBlitOffsetShader(state) {
|
|
44
62
|
let loc = blitOffsetShaders.get(state);
|
|
45
63
|
if (loc === undefined) {
|
|
@@ -59,4 +77,13 @@ function getGlBlitShader(state) {
|
|
|
59
77
|
}
|
|
60
78
|
return loc;
|
|
61
79
|
}
|
|
80
|
+
function getGlEraseShader(state) {
|
|
81
|
+
let loc = eraseShaders.get(state);
|
|
82
|
+
if (loc === undefined) {
|
|
83
|
+
const gl = state.gl;
|
|
84
|
+
loc = compileGlFullscreenProgram(gl, ERASE_FRAGMENT_SRC);
|
|
85
|
+
eraseShaders.set(state, loc);
|
|
86
|
+
}
|
|
87
|
+
return loc;
|
|
88
|
+
}
|
|
62
89
|
//# sourceMappingURL=glEffectBlitShader.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glEffectBlitShader.js","sourceRoot":"","sources":["../src/glEffectBlitShader.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,0BAA0B,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAGvF,2FAA2F;AAC3F,MAAM,wBAAwB,GAAG;;;;;;;;;;;;;EAa/B,CAAC;AAEH,qBAAqB;AACrB,MAAM,iBAAiB,GAAG;;;;;;;EAOxB,CAAC;AAMH,MAAM,iBAAiB,GAAG,IAAI,OAAO,EAA4C,CAAC;AAClF,MAAM,WAAW,GAAG,IAAI,OAAO,EAAsC,CAAC;
|
|
1
|
+
{"version":3,"file":"glEffectBlitShader.js","sourceRoot":"","sources":["../src/glEffectBlitShader.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glEffectBoxBlur.d.ts","sourceRoot":"","sources":["../src/glEffectBoxBlur.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAuB,aAAa,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"glEffectBoxBlur.d.ts","sourceRoot":"","sources":["../src/glEffectBoxBlur.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAuB,aAAa,EAAE,MAAM,iBAAiB,CAAC;AA4C1E;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,cAAc,EACpB,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,QAAQ,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;CACvD,CAAC,GACD,IAAI,CA8BN"}
|
package/dist/glEffectBoxBlur.js
CHANGED
|
@@ -7,17 +7,25 @@ uniform sampler2D u_texture;
|
|
|
7
7
|
uniform vec2 u_texelSize;
|
|
8
8
|
uniform float u_radius;
|
|
9
9
|
uniform vec2 u_direction;
|
|
10
|
+
uniform vec4 u_edgeColor;
|
|
11
|
+
uniform float u_useEdgeColor;
|
|
10
12
|
out vec4 fragColor;
|
|
13
|
+
vec4 sampleBlur(vec2 uv) {
|
|
14
|
+
if (u_useEdgeColor > 0.5 && (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0)) {
|
|
15
|
+
return u_edgeColor;
|
|
16
|
+
}
|
|
17
|
+
return texture(u_texture, uv);
|
|
18
|
+
}
|
|
11
19
|
void main() {
|
|
12
20
|
int r = max(0, int(u_radius));
|
|
13
21
|
if (r == 0) {
|
|
14
|
-
fragColor =
|
|
22
|
+
fragColor = sampleBlur(v_texCoord);
|
|
15
23
|
return;
|
|
16
24
|
}
|
|
17
25
|
vec4 sum = vec4(0.0);
|
|
18
26
|
int count = 2 * r + 1;
|
|
19
27
|
for (int i = -r; i <= r; i++) {
|
|
20
|
-
sum +=
|
|
28
|
+
sum += sampleBlur(v_texCoord + float(i) * u_texelSize * u_direction);
|
|
21
29
|
}
|
|
22
30
|
fragColor = sum / float(count);
|
|
23
31
|
}`;
|
|
@@ -33,6 +41,7 @@ export function applyGlEffectBoxBlur(state, source, dest, temp, options) {
|
|
|
33
41
|
const passes = Math.max(1, Math.round(options.passes ?? 1));
|
|
34
42
|
const blurX = options.blurX ?? 4;
|
|
35
43
|
const blurY = options.blurY ?? 4;
|
|
44
|
+
const edgeColor = options.edgeColor;
|
|
36
45
|
const loc = getBoxBlurShader(state);
|
|
37
46
|
let read = source;
|
|
38
47
|
let write = temp;
|
|
@@ -41,13 +50,13 @@ export function applyGlEffectBoxBlur(state, source, dest, temp, options) {
|
|
|
41
50
|
for (let pass = 0; pass < passes; pass++) {
|
|
42
51
|
const radiusX = computeBoxBlurPassRadius(blurX, passes, pass);
|
|
43
52
|
if (radiusX > 0) {
|
|
44
|
-
applyBoxBlurPass(state, read, write, loc, radiusX, 1, 0);
|
|
53
|
+
applyBoxBlurPass(state, read, write, loc, radiusX, 1, 0, edgeColor);
|
|
45
54
|
read = write;
|
|
46
55
|
write = write === temp ? dest : temp;
|
|
47
56
|
}
|
|
48
57
|
const radiusY = computeBoxBlurPassRadius(blurY, passes, pass);
|
|
49
58
|
if (radiusY > 0) {
|
|
50
|
-
applyBoxBlurPass(state, read, write, loc, radiusY, 0, 1);
|
|
59
|
+
applyBoxBlurPass(state, read, write, loc, radiusY, 0, 1, edgeColor);
|
|
51
60
|
read = write;
|
|
52
61
|
write = write === temp ? dest : temp;
|
|
53
62
|
}
|
|
@@ -62,13 +71,25 @@ function applyBlurBlit(state, source, dest) {
|
|
|
62
71
|
gl.uniform2f(loc.locTexelSize, 0, 0);
|
|
63
72
|
gl.uniform1f(loc.locRadius, 0);
|
|
64
73
|
gl.uniform2f(loc.locDirection, 0, 0);
|
|
74
|
+
gl.uniform4f(loc.locEdgeColor, 0, 0, 0, 0);
|
|
75
|
+
gl.uniform1f(loc.locUseEdgeColor, 0);
|
|
76
|
+
gl.blendFunc(gl.ONE, gl.ZERO);
|
|
65
77
|
});
|
|
66
78
|
}
|
|
67
|
-
function applyBoxBlurPass(state, source, dest, loc, radius, dirX, dirY) {
|
|
79
|
+
function applyBoxBlurPass(state, source, dest, loc, radius, dirX, dirY, edgeColor) {
|
|
68
80
|
drawGlFullscreenPass(state, loc, [source.texture], dest, (gl) => {
|
|
69
81
|
gl.uniform2f(loc.locTexelSize, 1 / source.width, 1 / source.height);
|
|
70
82
|
gl.uniform1f(loc.locRadius, radius);
|
|
71
83
|
gl.uniform2f(loc.locDirection, dirX, dirY);
|
|
84
|
+
if (edgeColor === undefined) {
|
|
85
|
+
gl.uniform4f(loc.locEdgeColor, 0, 0, 0, 0);
|
|
86
|
+
gl.uniform1f(loc.locUseEdgeColor, 0);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
gl.uniform4f(loc.locEdgeColor, edgeColor[0], edgeColor[1], edgeColor[2], edgeColor[3]);
|
|
90
|
+
gl.uniform1f(loc.locUseEdgeColor, 1);
|
|
91
|
+
}
|
|
92
|
+
gl.blendFunc(gl.ONE, gl.ZERO);
|
|
72
93
|
});
|
|
73
94
|
}
|
|
74
95
|
function getBoxBlurShader(state) {
|
|
@@ -81,6 +102,8 @@ function getBoxBlurShader(state) {
|
|
|
81
102
|
locTexelSize: gl.getUniformLocation(base.program, 'u_texelSize'),
|
|
82
103
|
locRadius: gl.getUniformLocation(base.program, 'u_radius'),
|
|
83
104
|
locDirection: gl.getUniformLocation(base.program, 'u_direction'),
|
|
105
|
+
locEdgeColor: gl.getUniformLocation(base.program, 'u_edgeColor'),
|
|
106
|
+
locUseEdgeColor: gl.getUniformLocation(base.program, 'u_useEdgeColor'),
|
|
84
107
|
};
|
|
85
108
|
boxBlurShaders.set(state, loc);
|
|
86
109
|
}
|