@flighthq/effects-gl 0.1.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 +4 -0
- package/dist/glBevelEffect.d.ts.map +1 -0
- package/dist/glBevelEffect.js +134 -0
- package/dist/glBevelEffect.js.map +1 -0
- 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/glBloomEffect.d.ts.map +1 -1
- package/dist/glBloomEffect.js +5 -5
- package/dist/glBloomEffect.js.map +1 -1
- package/dist/glBlurEffect.d.ts +8 -0
- package/dist/glBlurEffect.d.ts.map +1 -0
- package/dist/glBlurEffect.js +65 -0
- package/dist/glBlurEffect.js.map +1 -0
- package/dist/glColorLutPass.d.ts +3 -0
- package/dist/glColorLutPass.d.ts.map +1 -0
- package/dist/glColorLutPass.js +75 -0
- package/dist/glColorLutPass.js.map +1 -0
- package/dist/glColorMatrixPass.d.ts +3 -0
- package/dist/glColorMatrixPass.d.ts.map +1 -0
- package/dist/glColorMatrixPass.js +33 -0
- package/dist/glColorMatrixPass.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/glConvolutionEffect.d.ts +5 -0
- package/dist/glConvolutionEffect.d.ts.map +1 -0
- package/dist/glConvolutionEffect.js +94 -0
- package/dist/glConvolutionEffect.js.map +1 -0
- package/dist/glDropShadowEffect.d.ts +4 -0
- package/dist/glDropShadowEffect.d.ts.map +1 -0
- package/dist/glDropShadowEffect.js +53 -0
- package/dist/glDropShadowEffect.js.map +1 -0
- package/dist/glEffectBlitShader.d.ts +12 -0
- package/dist/glEffectBlitShader.d.ts.map +1 -0
- package/dist/glEffectBlitShader.js +89 -0
- package/dist/glEffectBlitShader.js.map +1 -0
- package/dist/glEffectBoxBlur.d.ts +16 -0
- package/dist/glEffectBoxBlur.d.ts.map +1 -0
- package/dist/glEffectBoxBlur.js +112 -0
- package/dist/glEffectBoxBlur.js.map +1 -0
- package/dist/glEffectGradientRamp.d.ts +9 -0
- package/dist/glEffectGradientRamp.d.ts.map +1 -0
- package/dist/glEffectGradientRamp.js +64 -0
- package/dist/glEffectGradientRamp.js.map +1 -0
- package/dist/glEffectTintShader.d.ts +7 -0
- package/dist/glEffectTintShader.d.ts.map +1 -0
- package/dist/glEffectTintShader.js +82 -0
- package/dist/glEffectTintShader.js.map +1 -0
- package/dist/glGradientBevelEffect.d.ts +4 -0
- package/dist/glGradientBevelEffect.d.ts.map +1 -0
- package/dist/glGradientBevelEffect.js +127 -0
- package/dist/glGradientBevelEffect.js.map +1 -0
- package/dist/glGradientGlowEffect.d.ts +4 -0
- package/dist/glGradientGlowEffect.d.ts.map +1 -0
- package/dist/glGradientGlowEffect.js +78 -0
- package/dist/glGradientGlowEffect.js.map +1 -0
- package/dist/glInnerGlowEffect.d.ts +4 -0
- package/dist/glInnerGlowEffect.d.ts.map +1 -0
- package/dist/glInnerGlowEffect.js +96 -0
- package/dist/glInnerGlowEffect.js.map +1 -0
- package/dist/glInnerShadowEffect.d.ts +4 -0
- package/dist/glInnerShadowEffect.d.ts.map +1 -0
- package/dist/glInnerShadowEffect.js +103 -0
- package/dist/glInnerShadowEffect.js.map +1 -0
- package/dist/glMedianEffect.d.ts +5 -0
- package/dist/glMedianEffect.d.ts.map +1 -0
- package/dist/glMedianEffect.js +73 -0
- package/dist/glMedianEffect.js.map +1 -0
- package/dist/glOuterGlowEffect.d.ts +4 -0
- package/dist/glOuterGlowEffect.d.ts.map +1 -0
- package/dist/glOuterGlowEffect.js +49 -0
- package/dist/glOuterGlowEffect.js.map +1 -0
- package/dist/glRenderEffectPipeline.d.ts +2 -2
- package/dist/glRenderEffectPipeline.d.ts.map +1 -1
- package/dist/glRenderEffectPipeline.js +86 -14
- package/dist/glRenderEffectPipeline.js.map +1 -1
- package/dist/glRenderEffectRegistrar.d.ts +1 -0
- package/dist/glRenderEffectRegistrar.d.ts.map +1 -1
- package/dist/glRenderEffectRegistrar.js +62 -38
- package/dist/glRenderEffectRegistrar.js.map +1 -1
- package/dist/index.d.ts +18 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -10
- package/dist/index.js.map +1 -1
- package/package.json +11 -6
- package/src/glBevelEffect.test.ts +13 -0
- package/src/glBlendEffect.test.ts +111 -0
- package/src/glBlurEffect.test.ts +19 -0
- package/src/glColorLutPass.test.ts +7 -0
- package/src/glColorMatrixPass.test.ts +7 -0
- package/src/glCompositeEffect.test.ts +39 -0
- package/src/glConvolutionEffect.test.ts +13 -0
- package/src/glDropShadowEffect.test.ts +105 -0
- package/src/glEffectBlitShader.test.ts +19 -0
- package/src/glEffectBoxBlur.test.ts +57 -0
- package/src/glEffectGradientRamp.test.ts +7 -0
- package/src/glEffectTintShader.test.ts +13 -0
- package/src/glGradientBevelEffect.test.ts +13 -0
- package/src/glGradientGlowEffect.test.ts +13 -0
- package/src/glInnerGlowEffect.test.ts +145 -0
- package/src/glInnerShadowEffect.test.ts +145 -0
- package/src/glMedianEffect.test.ts +13 -0
- package/src/glOuterGlowEffect.test.ts +104 -0
- package/src/glRenderEffectRegistrar.test.ts +37 -6
- package/dist/glBrightnessContrastEffect.d.ts +0 -4
- package/dist/glBrightnessContrastEffect.d.ts.map +0 -1
- package/dist/glBrightnessContrastEffect.js +0 -28
- package/dist/glBrightnessContrastEffect.js.map +0 -1
- package/dist/glChannelMixerEffect.d.ts +0 -4
- package/dist/glChannelMixerEffect.d.ts.map +0 -1
- package/dist/glChannelMixerEffect.js +0 -30
- package/dist/glChannelMixerEffect.js.map +0 -1
- package/dist/glColorGradeEffect.d.ts +0 -4
- package/dist/glColorGradeEffect.d.ts.map +0 -1
- package/dist/glColorGradeEffect.js +0 -46
- package/dist/glColorGradeEffect.js.map +0 -1
- package/dist/glExposureEffect.d.ts +0 -4
- package/dist/glExposureEffect.d.ts.map +0 -1
- package/dist/glExposureEffect.js +0 -24
- package/dist/glExposureEffect.js.map +0 -1
- package/dist/glGrayscaleEffect.d.ts +0 -4
- package/dist/glGrayscaleEffect.d.ts.map +0 -1
- package/dist/glGrayscaleEffect.js +0 -25
- package/dist/glGrayscaleEffect.js.map +0 -1
- package/dist/glHueSaturationEffect.d.ts +0 -4
- package/dist/glHueSaturationEffect.d.ts.map +0 -1
- package/dist/glHueSaturationEffect.js +0 -67
- package/dist/glHueSaturationEffect.js.map +0 -1
- package/dist/glInvertEffect.d.ts +0 -4
- package/dist/glInvertEffect.d.ts.map +0 -1
- package/dist/glInvertEffect.js +0 -24
- package/dist/glInvertEffect.js.map +0 -1
- package/dist/glLiftGammaGainEffect.d.ts +0 -4
- package/dist/glLiftGammaGainEffect.d.ts.map +0 -1
- package/dist/glLiftGammaGainEffect.js +0 -44
- package/dist/glLiftGammaGainEffect.js.map +0 -1
- package/dist/glLookupTableGradeEffect.d.ts +0 -4
- package/dist/glLookupTableGradeEffect.d.ts.map +0 -1
- package/dist/glLookupTableGradeEffect.js +0 -28
- package/dist/glLookupTableGradeEffect.js.map +0 -1
- package/dist/glSepiaEffect.d.ts +0 -4
- package/dist/glSepiaEffect.d.ts.map +0 -1
- package/dist/glSepiaEffect.js +0 -29
- package/dist/glSepiaEffect.js.map +0 -1
- package/src/glBrightnessContrastEffect.test.ts +0 -16
- package/src/glChannelMixerEffect.test.ts +0 -13
- package/src/glColorGradeEffect.test.ts +0 -13
- package/src/glExposureEffect.test.ts +0 -13
- package/src/glGrayscaleEffect.test.ts +0 -13
- package/src/glHueSaturationEffect.test.ts +0 -13
- package/src/glInvertEffect.test.ts +0 -13
- package/src/glLiftGammaGainEffect.test.ts +0 -13
- package/src/glLookupTableGradeEffect.test.ts +0 -13
- package/src/glSepiaEffect.test.ts +0 -13
|
@@ -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":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ConvolutionEffect, GlRenderEffectRunner, GlRenderState, GlRenderTarget } from '@flighthq/types';
|
|
2
|
+
export declare const MAX_CONVOLUTION_EFFECT_GL_KERNEL_SIZE = 49;
|
|
3
|
+
export declare function applyConvolutionEffectToGl(state: GlRenderState, source: Readonly<GlRenderTarget>, dest: Readonly<GlRenderTarget>, effect: Readonly<ConvolutionEffect>): void;
|
|
4
|
+
export declare const defaultGlConvolutionEffectRunner: GlRenderEffectRunner;
|
|
5
|
+
//# sourceMappingURL=glConvolutionEffect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glConvolutionEffect.d.ts","sourceRoot":"","sources":["../src/glConvolutionEffect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAM9G,eAAO,MAAM,qCAAqC,KAAK,CAAC;AAIxD,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC,EAChC,IAAI,EAAE,QAAQ,CAAC,cAAc,CAAC,EAC9B,MAAM,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GAClC,IAAI,CAkCN;AAED,eAAO,MAAM,gCAAgC,EAAE,oBAE9C,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { drawGlFullscreenPass } from '@flighthq/render-gl';
|
|
2
|
+
import { getGlEffectProgram } from './glEffectProgramCache';
|
|
3
|
+
// Largest kernel the WebGL path supports (a 7×7). The cap is the fixed uniform-array size in the
|
|
4
|
+
// fragment shader; larger kernels are unsupported on this backend.
|
|
5
|
+
export const MAX_CONVOLUTION_EFFECT_GL_KERNEL_SIZE = 49;
|
|
6
|
+
// Generic matrix-kernel convolution: each output pixel is the weighted sum of its matrixX×matrixY
|
|
7
|
+
// neighborhood, normalized by `divisor` (defaults to the matrix sum) and offset by `bias`.
|
|
8
|
+
export function applyConvolutionEffectToGl(state, source, dest, effect) {
|
|
9
|
+
const { matrix, matrixX, matrixY } = effect;
|
|
10
|
+
if (matrixX <= 0 || matrixY <= 0)
|
|
11
|
+
throw new Error('Convolution matrix dimensions must be positive');
|
|
12
|
+
if (matrixX * matrixY > MAX_CONVOLUTION_EFFECT_GL_KERNEL_SIZE)
|
|
13
|
+
throw new Error(`Convolution kernel exceeds the WebGL maximum of 7×7 (${matrixX}×${matrixY} given)`);
|
|
14
|
+
if (matrix.length < matrixX * matrixY)
|
|
15
|
+
throw new Error('Convolution matrix does not match its declared dimensions');
|
|
16
|
+
const bias = effect.bias ?? 0;
|
|
17
|
+
const clampEdge = effect.clamp ?? true;
|
|
18
|
+
const preserveAlpha = effect.preserveAlpha ?? true;
|
|
19
|
+
const edgeColor = effect.color ?? 0;
|
|
20
|
+
const divisor = effect.divisor ?? getAutoDivisor(matrix, matrixX * matrixY);
|
|
21
|
+
const matrixData = new Float32Array(MAX_CONVOLUTION_EFFECT_GL_KERNEL_SIZE);
|
|
22
|
+
for (let i = 0; i < matrixX * matrixY; i++)
|
|
23
|
+
matrixData[i] = matrix[i];
|
|
24
|
+
const program = getGlEffectProgram(state, 'stylization.convolution', CONVOLUTION_FRAGMENT_SRC);
|
|
25
|
+
drawGlFullscreenPass(state, program, [source.texture], dest, (gl, p) => {
|
|
26
|
+
gl.uniform2f(gl.getUniformLocation(p.program, 'u_texelSize'), 1 / source.width, 1 / source.height);
|
|
27
|
+
gl.uniform1fv(gl.getUniformLocation(p.program, 'u_matrix[0]'), matrixData);
|
|
28
|
+
gl.uniform1i(gl.getUniformLocation(p.program, 'u_matrixX'), matrixX);
|
|
29
|
+
gl.uniform1i(gl.getUniformLocation(p.program, 'u_matrixY'), matrixY);
|
|
30
|
+
gl.uniform1f(gl.getUniformLocation(p.program, 'u_divisor'), divisor);
|
|
31
|
+
gl.uniform1f(gl.getUniformLocation(p.program, 'u_bias'), bias);
|
|
32
|
+
gl.uniform1i(gl.getUniformLocation(p.program, 'u_clamp'), clampEdge ? 1 : 0);
|
|
33
|
+
gl.uniform1i(gl.getUniformLocation(p.program, 'u_preserveAlpha'), preserveAlpha ? 1 : 0);
|
|
34
|
+
gl.uniform4f(gl.getUniformLocation(p.program, 'u_edgeColor'), ((edgeColor >> 16) & 0xff) / 255, ((edgeColor >> 8) & 0xff) / 255, (edgeColor & 0xff) / 255, ((edgeColor >>> 24) & 0xff) / 255);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
export const defaultGlConvolutionEffectRunner = (ctx, effect) => {
|
|
38
|
+
applyConvolutionEffectToGl(ctx.state, ctx.source, ctx.dest, effect);
|
|
39
|
+
};
|
|
40
|
+
// Sums the kernel weights; returns 1 when the sum is 0 (e.g. an edge-detect kernel) so the divide is safe.
|
|
41
|
+
function getAutoDivisor(matrix, length) {
|
|
42
|
+
let sum = 0;
|
|
43
|
+
for (let i = 0; i < length; i++)
|
|
44
|
+
sum += matrix[i];
|
|
45
|
+
return sum === 0 ? 1 : sum;
|
|
46
|
+
}
|
|
47
|
+
const CONVOLUTION_FRAGMENT_SRC = `#version 300 es
|
|
48
|
+
precision mediump float;
|
|
49
|
+
in vec2 v_texCoord;
|
|
50
|
+
uniform sampler2D u_texture0;
|
|
51
|
+
uniform vec2 u_texelSize;
|
|
52
|
+
uniform float u_matrix[${MAX_CONVOLUTION_EFFECT_GL_KERNEL_SIZE}];
|
|
53
|
+
uniform int u_matrixX;
|
|
54
|
+
uniform int u_matrixY;
|
|
55
|
+
uniform float u_divisor;
|
|
56
|
+
uniform float u_bias;
|
|
57
|
+
uniform bool u_clamp;
|
|
58
|
+
uniform bool u_preserveAlpha;
|
|
59
|
+
uniform vec4 u_edgeColor;
|
|
60
|
+
out vec4 fragColor;
|
|
61
|
+
|
|
62
|
+
vec4 sampleAt(vec2 uv) {
|
|
63
|
+
if (u_clamp) {
|
|
64
|
+
return texture(u_texture0, clamp(uv, vec2(0.0), vec2(1.0)));
|
|
65
|
+
}
|
|
66
|
+
if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {
|
|
67
|
+
return u_edgeColor;
|
|
68
|
+
}
|
|
69
|
+
return texture(u_texture0, uv);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
void main() {
|
|
73
|
+
int offsetX = u_matrixX / 2;
|
|
74
|
+
int offsetY = u_matrixY / 2;
|
|
75
|
+
vec4 sum = vec4(0.0);
|
|
76
|
+
for (int ky = 0; ky < u_matrixY; ky++) {
|
|
77
|
+
for (int kx = 0; kx < u_matrixX; kx++) {
|
|
78
|
+
float weight = u_matrix[ky * u_matrixX + kx];
|
|
79
|
+
vec2 off = vec2(float(kx - offsetX), float(ky - offsetY)) * u_texelSize;
|
|
80
|
+
sum += sampleAt(v_texCoord + off) * weight;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
sum /= u_divisor;
|
|
84
|
+
sum += u_bias / 255.0;
|
|
85
|
+
sum = clamp(sum, 0.0, 1.0);
|
|
86
|
+
if (u_preserveAlpha) {
|
|
87
|
+
// Keep the convolved color and restore the source alpha, matching the reference: a zero-sum
|
|
88
|
+
// kernel (e.g. edge-detect) drives the convolved alpha to 0, so overriding only .a leaves the
|
|
89
|
+
// color channels as the non-preserve branch produces them.
|
|
90
|
+
sum.a = texture(u_texture0, v_texCoord).a;
|
|
91
|
+
}
|
|
92
|
+
fragColor = sum;
|
|
93
|
+
}`;
|
|
94
|
+
//# sourceMappingURL=glConvolutionEffect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glConvolutionEffect.js","sourceRoot":"","sources":["../src/glConvolutionEffect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DropShadowEffect, GlRenderEffectRunner, GlRenderState, GlRenderTarget, GlRenderTargetPool } from '@flighthq/types';
|
|
2
|
+
export declare function applyDropShadowEffectToGl(state: GlRenderState, source: Readonly<GlRenderTarget>, dest: Readonly<GlRenderTarget>, pool: GlRenderTargetPool, effect: Readonly<DropShadowEffect>): void;
|
|
3
|
+
export declare const defaultGlDropShadowEffectRunner: GlRenderEffectRunner;
|
|
4
|
+
//# sourceMappingURL=glDropShadowEffect.d.ts.map
|
|
@@ -0,0 +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,CA6CN;AAED,eAAO,MAAM,+BAA+B,EAAE,oBAE7C,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { acquireGlRenderTarget, clearGlRenderTarget, releaseGlRenderTarget } from '@flighthq/render-gl';
|
|
2
|
+
import { applyGlEffectBlitOffsetPass, applyGlEffectBlitPass, applyGlEffectErasePass } from './glEffectBlitShader';
|
|
3
|
+
import { applyGlEffectBoxBlur } from './glEffectBoxBlur';
|
|
4
|
+
import { applyGlEffectTintPass } from './glEffectTintShader';
|
|
5
|
+
// Drop-shadow composite effect: tint the scene silhouette, blur it, offset it by angle/distance, then composite the source over the shadow.
|
|
6
|
+
// Full-frame realization: acquires the recipe's three scratch targets from the effect pool, runs the
|
|
7
|
+
// inlined multi-pass recipe, then releases them.
|
|
8
|
+
//
|
|
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
|
+
export function applyDropShadowEffectToGl(state, source, dest, pool, effect) {
|
|
12
|
+
const descriptor = { width: source.width, height: source.height, format: source.format };
|
|
13
|
+
const s0 = acquireGlRenderTarget(state, pool, descriptor);
|
|
14
|
+
const s1 = acquireGlRenderTarget(state, pool, descriptor);
|
|
15
|
+
const s2 = acquireGlRenderTarget(state, pool, descriptor);
|
|
16
|
+
const src = source;
|
|
17
|
+
const dst = dest;
|
|
18
|
+
const angle = ((effect.angle ?? 45) * Math.PI) / 180;
|
|
19
|
+
const distance = effect.distance ?? 4;
|
|
20
|
+
const dx = Math.cos(angle) * distance;
|
|
21
|
+
const dy = Math.sin(angle) * distance;
|
|
22
|
+
const color = effect.color ?? 0;
|
|
23
|
+
const alpha = effect.alpha ?? 1;
|
|
24
|
+
const strength = effect.strength ?? 1;
|
|
25
|
+
const quality = Math.max(1, Math.round(effect.quality ?? 1));
|
|
26
|
+
const sourceMode = effect.sourceMode ?? 'draw';
|
|
27
|
+
const tintStrength = Math.min(1, strength);
|
|
28
|
+
const shadowPasses = Math.max(1, Math.floor(strength));
|
|
29
|
+
const [mask, blurred, blurTemp] = [s0, s1, s2];
|
|
30
|
+
applyGlEffectTintPass(state, src, mask, color, alpha, tintStrength);
|
|
31
|
+
applyGlEffectBoxBlur(state, mask, blurred, blurTemp, {
|
|
32
|
+
blurX: effect.blurX ?? 4,
|
|
33
|
+
blurY: effect.blurY ?? 4,
|
|
34
|
+
passes: quality,
|
|
35
|
+
});
|
|
36
|
+
clearGlRenderTarget(state, dst);
|
|
37
|
+
for (let i = 0; i < shadowPasses; i++) {
|
|
38
|
+
applyGlEffectBlitOffsetPass(state, blurred, dst, dx, dy);
|
|
39
|
+
}
|
|
40
|
+
if (sourceMode === 'knockout') {
|
|
41
|
+
applyGlEffectErasePass(state, src, dst);
|
|
42
|
+
}
|
|
43
|
+
else if (sourceMode === 'draw') {
|
|
44
|
+
applyGlEffectBlitPass(state, src, dst);
|
|
45
|
+
}
|
|
46
|
+
releaseGlRenderTarget(pool, s0);
|
|
47
|
+
releaseGlRenderTarget(pool, s1);
|
|
48
|
+
releaseGlRenderTarget(pool, s2);
|
|
49
|
+
}
|
|
50
|
+
export const defaultGlDropShadowEffectRunner = (ctx, effect) => {
|
|
51
|
+
applyDropShadowEffectToGl(ctx.state, ctx.source, ctx.dest, ctx.pool, effect);
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=glDropShadowEffect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glDropShadowEffect.js","sourceRoot":"","sources":["../src/glDropShadowEffect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { GlRenderTarget } from '@flighthq/render-gl';
|
|
2
|
+
import type { GlRenderState } from '@flighthq/types';
|
|
3
|
+
/**
|
|
4
|
+
* Blits source into dest at a pixel offset (dx, dy in screen-space Y-down).
|
|
5
|
+
* Pixels sampling outside the source bounds produce transparent output.
|
|
6
|
+
*/
|
|
7
|
+
export declare function applyGlEffectBlitOffsetPass(state: GlRenderState, source: GlRenderTarget, dest: GlRenderTarget, dx: number, dy: number): void;
|
|
8
|
+
/** Blits source directly into dest without modification. */
|
|
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;
|
|
12
|
+
//# sourceMappingURL=glEffectBlitShader.d.ts.map
|
|
@@ -0,0 +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;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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { compileGlFullscreenProgram, drawGlFullscreenPass } from '@flighthq/render-gl';
|
|
2
|
+
// Blits a tinted texture at a UV offset. Out-of-bounds samples produce transparent output.
|
|
3
|
+
const BLIT_OFFSET_FRAGMENT_SRC = `#version 300 es
|
|
4
|
+
precision mediump float;
|
|
5
|
+
in vec2 v_texCoord;
|
|
6
|
+
uniform sampler2D u_texture;
|
|
7
|
+
uniform vec2 u_offset;
|
|
8
|
+
out vec4 fragColor;
|
|
9
|
+
void main() {
|
|
10
|
+
vec2 uv = v_texCoord + u_offset;
|
|
11
|
+
if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {
|
|
12
|
+
fragColor = vec4(0.0);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
fragColor = texture(u_texture, uv);
|
|
16
|
+
}`;
|
|
17
|
+
// Pass-through blit.
|
|
18
|
+
const BLIT_FRAGMENT_SRC = `#version 300 es
|
|
19
|
+
precision mediump float;
|
|
20
|
+
in vec2 v_texCoord;
|
|
21
|
+
uniform sampler2D u_texture;
|
|
22
|
+
out vec4 fragColor;
|
|
23
|
+
void main() {
|
|
24
|
+
fragColor = texture(u_texture, v_texCoord);
|
|
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
|
+
}`;
|
|
36
|
+
const blitOffsetShaders = new WeakMap();
|
|
37
|
+
const blitShaders = new WeakMap();
|
|
38
|
+
const eraseShaders = new WeakMap();
|
|
39
|
+
/**
|
|
40
|
+
* Blits source into dest at a pixel offset (dx, dy in screen-space Y-down).
|
|
41
|
+
* Pixels sampling outside the source bounds produce transparent output.
|
|
42
|
+
*/
|
|
43
|
+
export function applyGlEffectBlitOffsetPass(state, source, dest, dx, dy) {
|
|
44
|
+
const loc = getGlBlitOffsetShader(state);
|
|
45
|
+
drawGlFullscreenPass(state, loc, [source.texture], dest, (gl) => {
|
|
46
|
+
gl.uniform2f(loc.locOffset, -dx / source.width, dy / source.height);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/** Blits source directly into dest without modification. */
|
|
50
|
+
export function applyGlEffectBlitPass(state, source, dest) {
|
|
51
|
+
const loc = getGlBlitShader(state);
|
|
52
|
+
drawGlFullscreenPass(state, loc, [source.texture], dest, () => { });
|
|
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
|
+
}
|
|
61
|
+
function getGlBlitOffsetShader(state) {
|
|
62
|
+
let loc = blitOffsetShaders.get(state);
|
|
63
|
+
if (loc === undefined) {
|
|
64
|
+
const gl = state.gl;
|
|
65
|
+
const base = compileGlFullscreenProgram(gl, BLIT_OFFSET_FRAGMENT_SRC);
|
|
66
|
+
loc = { ...base, locOffset: gl.getUniformLocation(base.program, 'u_offset') };
|
|
67
|
+
blitOffsetShaders.set(state, loc);
|
|
68
|
+
}
|
|
69
|
+
return loc;
|
|
70
|
+
}
|
|
71
|
+
function getGlBlitShader(state) {
|
|
72
|
+
let loc = blitShaders.get(state);
|
|
73
|
+
if (loc === undefined) {
|
|
74
|
+
const gl = state.gl;
|
|
75
|
+
loc = compileGlFullscreenProgram(gl, BLIT_FRAGMENT_SRC);
|
|
76
|
+
blitShaders.set(state, loc);
|
|
77
|
+
}
|
|
78
|
+
return loc;
|
|
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
|
+
}
|
|
89
|
+
//# sourceMappingURL=glEffectBlitShader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glEffectBlitShader.js","sourceRoot":"","sources":["../src/glEffectBlitShader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { GlRenderTarget } from '@flighthq/render-gl';
|
|
2
|
+
import type { GlRenderState } from '@flighthq/types';
|
|
3
|
+
/**
|
|
4
|
+
* Applies a separable box blur to `source`, writing to `dest`. `blurX`/`blurY` are the target
|
|
5
|
+
* Gaussian standard deviations; `passes` is the number of box passes per axis (more passes
|
|
6
|
+
* converge on a Gaussian — see `computeBoxBlurPassRadius` — not a larger blur). A box blur is cheap
|
|
7
|
+
* and the right building block for soft spreads (glow, drop shadow). `temp` is a caller-provided
|
|
8
|
+
* ping-pong scratch target distinct from both `source` and `dest`.
|
|
9
|
+
*/
|
|
10
|
+
export declare function applyGlEffectBoxBlur(state: GlRenderState, source: GlRenderTarget, dest: GlRenderTarget, temp: GlRenderTarget, options: Readonly<{
|
|
11
|
+
blurX?: number;
|
|
12
|
+
blurY?: number;
|
|
13
|
+
passes?: number;
|
|
14
|
+
edgeColor?: readonly [number, number, number, number];
|
|
15
|
+
}>): void;
|
|
16
|
+
//# sourceMappingURL=glEffectBoxBlur.d.ts.map
|
|
@@ -0,0 +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;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"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { computeBoxBlurPassRadius } from '@flighthq/effects';
|
|
2
|
+
import { compileGlFullscreenProgram, drawGlFullscreenPass } from '@flighthq/render-gl';
|
|
3
|
+
const BOX_BLUR_FRAGMENT_SRC = `#version 300 es
|
|
4
|
+
precision mediump float;
|
|
5
|
+
in vec2 v_texCoord;
|
|
6
|
+
uniform sampler2D u_texture;
|
|
7
|
+
uniform vec2 u_texelSize;
|
|
8
|
+
uniform float u_radius;
|
|
9
|
+
uniform vec2 u_direction;
|
|
10
|
+
uniform vec4 u_edgeColor;
|
|
11
|
+
uniform float u_useEdgeColor;
|
|
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
|
+
}
|
|
19
|
+
void main() {
|
|
20
|
+
int r = max(0, int(u_radius));
|
|
21
|
+
if (r == 0) {
|
|
22
|
+
fragColor = sampleBlur(v_texCoord);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
vec4 sum = vec4(0.0);
|
|
26
|
+
int count = 2 * r + 1;
|
|
27
|
+
for (int i = -r; i <= r; i++) {
|
|
28
|
+
sum += sampleBlur(v_texCoord + float(i) * u_texelSize * u_direction);
|
|
29
|
+
}
|
|
30
|
+
fragColor = sum / float(count);
|
|
31
|
+
}`;
|
|
32
|
+
const boxBlurShaders = new WeakMap();
|
|
33
|
+
/**
|
|
34
|
+
* Applies a separable box blur to `source`, writing to `dest`. `blurX`/`blurY` are the target
|
|
35
|
+
* Gaussian standard deviations; `passes` is the number of box passes per axis (more passes
|
|
36
|
+
* converge on a Gaussian — see `computeBoxBlurPassRadius` — not a larger blur). A box blur is cheap
|
|
37
|
+
* and the right building block for soft spreads (glow, drop shadow). `temp` is a caller-provided
|
|
38
|
+
* ping-pong scratch target distinct from both `source` and `dest`.
|
|
39
|
+
*/
|
|
40
|
+
export function applyGlEffectBoxBlur(state, source, dest, temp, options) {
|
|
41
|
+
const passes = Math.max(1, Math.round(options.passes ?? 1));
|
|
42
|
+
const blurX = options.blurX ?? 4;
|
|
43
|
+
const blurY = options.blurY ?? 4;
|
|
44
|
+
const edgeColor = options.edgeColor;
|
|
45
|
+
const loc = getBoxBlurShader(state);
|
|
46
|
+
let read = source;
|
|
47
|
+
let write = temp;
|
|
48
|
+
// Each pass may use a different radius per axis so the box widths converge on the target sigma;
|
|
49
|
+
// zero-radius passes are skipped. If nothing is written, the tail blit copies source to dest.
|
|
50
|
+
for (let pass = 0; pass < passes; pass++) {
|
|
51
|
+
const radiusX = computeBoxBlurPassRadius(blurX, passes, pass);
|
|
52
|
+
if (radiusX > 0) {
|
|
53
|
+
applyBoxBlurPass(state, read, write, loc, radiusX, 1, 0, edgeColor);
|
|
54
|
+
read = write;
|
|
55
|
+
write = write === temp ? dest : temp;
|
|
56
|
+
}
|
|
57
|
+
const radiusY = computeBoxBlurPassRadius(blurY, passes, pass);
|
|
58
|
+
if (radiusY > 0) {
|
|
59
|
+
applyBoxBlurPass(state, read, write, loc, radiusY, 0, 1, edgeColor);
|
|
60
|
+
read = write;
|
|
61
|
+
write = write === temp ? dest : temp;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (read !== dest) {
|
|
65
|
+
applyBlurBlit(state, read, dest);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function applyBlurBlit(state, source, dest) {
|
|
69
|
+
const loc = getBoxBlurShader(state);
|
|
70
|
+
drawGlFullscreenPass(state, loc, [source.texture], dest, (gl) => {
|
|
71
|
+
gl.uniform2f(loc.locTexelSize, 0, 0);
|
|
72
|
+
gl.uniform1f(loc.locRadius, 0);
|
|
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);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function applyBoxBlurPass(state, source, dest, loc, radius, dirX, dirY, edgeColor) {
|
|
80
|
+
drawGlFullscreenPass(state, loc, [source.texture], dest, (gl) => {
|
|
81
|
+
gl.uniform2f(loc.locTexelSize, 1 / source.width, 1 / source.height);
|
|
82
|
+
gl.uniform1f(loc.locRadius, radius);
|
|
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);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function getBoxBlurShader(state) {
|
|
96
|
+
let loc = boxBlurShaders.get(state);
|
|
97
|
+
if (loc === undefined) {
|
|
98
|
+
const gl = state.gl;
|
|
99
|
+
const base = compileGlFullscreenProgram(gl, BOX_BLUR_FRAGMENT_SRC);
|
|
100
|
+
loc = {
|
|
101
|
+
...base,
|
|
102
|
+
locTexelSize: gl.getUniformLocation(base.program, 'u_texelSize'),
|
|
103
|
+
locRadius: gl.getUniformLocation(base.program, 'u_radius'),
|
|
104
|
+
locDirection: gl.getUniformLocation(base.program, 'u_direction'),
|
|
105
|
+
locEdgeColor: gl.getUniformLocation(base.program, 'u_edgeColor'),
|
|
106
|
+
locUseEdgeColor: gl.getUniformLocation(base.program, 'u_useEdgeColor'),
|
|
107
|
+
};
|
|
108
|
+
boxBlurShaders.set(state, loc);
|
|
109
|
+
}
|
|
110
|
+
return loc;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=glEffectBoxBlur.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glEffectBoxBlur.js","sourceRoot":"","sources":["../src/glEffectBoxBlur.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds a 256-entry RGBA gradient ramp on the GPU. The caller owns the
|
|
3
|
+
* returned texture and must delete it with `gl.deleteTexture` when done.
|
|
4
|
+
*
|
|
5
|
+
* `ratios` are in byte scale [0,255]. Colors are packed RGB integers.
|
|
6
|
+
* `alphas` are in [0,1].
|
|
7
|
+
*/
|
|
8
|
+
export declare function createGlEffectGradientRampTexture(gl: WebGL2RenderingContext, colors: ReadonlyArray<number>, alphas: ReadonlyArray<number>, ratios: ReadonlyArray<number>): WebGLTexture;
|
|
9
|
+
//# sourceMappingURL=glEffectGradientRamp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glEffectGradientRamp.d.ts","sourceRoot":"","sources":["../src/glEffectGradientRamp.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,iCAAiC,CAC/C,EAAE,EAAE,sBAAsB,EAC1B,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,EAC7B,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,EAC7B,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,GAC5B,YAAY,CAWd"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds a 256-entry RGBA gradient ramp on the GPU. The caller owns the
|
|
3
|
+
* returned texture and must delete it with `gl.deleteTexture` when done.
|
|
4
|
+
*
|
|
5
|
+
* `ratios` are in byte scale [0,255]. Colors are packed RGB integers.
|
|
6
|
+
* `alphas` are in [0,1].
|
|
7
|
+
*/
|
|
8
|
+
export function createGlEffectGradientRampTexture(gl, colors, alphas, ratios) {
|
|
9
|
+
const data = buildRampData(colors, alphas, ratios);
|
|
10
|
+
const texture = gl.createTexture();
|
|
11
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
12
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, 256, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
|
|
13
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
14
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
15
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
16
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
17
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
18
|
+
return texture;
|
|
19
|
+
}
|
|
20
|
+
function buildRampData(colors, alphas, ratios) {
|
|
21
|
+
const out = new Uint8ClampedArray(256 * 4);
|
|
22
|
+
if (colors.length === 0)
|
|
23
|
+
return out;
|
|
24
|
+
for (let i = 0; i < 256; i++) {
|
|
25
|
+
const t = i;
|
|
26
|
+
let r = 0, g = 0, b = 0, a = 0;
|
|
27
|
+
if (t <= ratios[0]) {
|
|
28
|
+
const c = colors[0];
|
|
29
|
+
r = (c >> 16) & 0xff;
|
|
30
|
+
g = (c >> 8) & 0xff;
|
|
31
|
+
b = c & 0xff;
|
|
32
|
+
a = Math.round(alphas[0] * 255);
|
|
33
|
+
}
|
|
34
|
+
else if (t >= ratios[ratios.length - 1]) {
|
|
35
|
+
const c = colors[colors.length - 1];
|
|
36
|
+
r = (c >> 16) & 0xff;
|
|
37
|
+
g = (c >> 8) & 0xff;
|
|
38
|
+
b = c & 0xff;
|
|
39
|
+
a = Math.round(alphas[alphas.length - 1] * 255);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
for (let j = 0; j < ratios.length - 1; j++) {
|
|
43
|
+
const r0 = ratios[j];
|
|
44
|
+
const r1 = ratios[j + 1];
|
|
45
|
+
if (t >= r0 && t <= r1) {
|
|
46
|
+
const blend = r1 > r0 ? (t - r0) / (r1 - r0) : 0;
|
|
47
|
+
const c0 = colors[j];
|
|
48
|
+
const c1 = colors[j + 1];
|
|
49
|
+
r = Math.round(((c0 >> 16) & 0xff) * (1 - blend) + ((c1 >> 16) & 0xff) * blend);
|
|
50
|
+
g = Math.round(((c0 >> 8) & 0xff) * (1 - blend) + ((c1 >> 8) & 0xff) * blend);
|
|
51
|
+
b = Math.round((c0 & 0xff) * (1 - blend) + (c1 & 0xff) * blend);
|
|
52
|
+
a = Math.round(alphas[j] * 255 * (1 - blend) + alphas[j + 1] * 255 * blend);
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
out[i * 4] = r;
|
|
58
|
+
out[i * 4 + 1] = g;
|
|
59
|
+
out[i * 4 + 2] = b;
|
|
60
|
+
out[i * 4 + 3] = a;
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=glEffectGradientRamp.js.map
|