@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,4 @@
|
|
|
1
|
+
import type { BevelEffect, GlRenderEffectRunner, GlRenderState, GlRenderTarget, GlRenderTargetPool } from '@flighthq/types';
|
|
2
|
+
export declare function applyBevelEffectToGl(state: GlRenderState, source: Readonly<GlRenderTarget>, dest: Readonly<GlRenderTarget>, pool: GlRenderTargetPool, effect: Readonly<BevelEffect>): void;
|
|
3
|
+
export declare const defaultGlBevelEffectRunner: GlRenderEffectRunner;
|
|
4
|
+
//# sourceMappingURL=glBevelEffect.d.ts.map
|
|
@@ -0,0 +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,CAsDN;AAED,eAAO,MAAM,0BAA0B,EAAE,oBAExC,CAAC"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { acquireGlRenderTarget, clearGlRenderTarget, compileGlFullscreenProgram, drawGlFullscreenPass, releaseGlRenderTarget, } from '@flighthq/render-gl';
|
|
2
|
+
import { applyGlEffectBlitPass, applyGlEffectErasePass } from './glEffectBlitShader';
|
|
3
|
+
import { applyGlEffectBoxBlur } from './glEffectBoxBlur';
|
|
4
|
+
import { applyGlEffectTintPass } from './glEffectTintShader';
|
|
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.
|
|
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
|
+
// The bevel is the directional gradient of the source's blurred alpha:
|
|
10
|
+
// `gradient = m(p − L) − m(p + L)` where `m` is the blurred alpha and
|
|
11
|
+
// `L = (cos angle, sin angle) · distance`. A positive gradient (the edge facing
|
|
12
|
+
// the light) draws the highlight color; a negative gradient draws the shadow
|
|
13
|
+
// color; `|gradient| · strength` is the band's alpha. The resulting tinted mask
|
|
14
|
+
// is composited over the source — matching `bevelSurface` (the CPU reference).
|
|
15
|
+
//
|
|
16
|
+
// `bevelType` clips the mask:
|
|
17
|
+
// - `'inner'` (default): keep the band inside the shape (× source alpha)
|
|
18
|
+
// - `'outer'`: keep it outside the shape (× 1 − source alpha)
|
|
19
|
+
// - `'full'`: no clip
|
|
20
|
+
export function applyBevelEffectToGl(state, source, dest, pool, effect) {
|
|
21
|
+
const descriptor = { width: source.width, height: source.height, format: source.format };
|
|
22
|
+
const s0 = acquireGlRenderTarget(state, pool, descriptor);
|
|
23
|
+
const s1 = acquireGlRenderTarget(state, pool, descriptor);
|
|
24
|
+
const s2 = acquireGlRenderTarget(state, pool, descriptor);
|
|
25
|
+
const src = source;
|
|
26
|
+
const dst = dest;
|
|
27
|
+
const angle = ((effect.angle ?? 45) * Math.PI) / 180;
|
|
28
|
+
const distance = effect.distance ?? 4;
|
|
29
|
+
// Match the surface reference, which snaps the light offset to whole pixels.
|
|
30
|
+
const offsetX = Math.round(Math.cos(angle) * distance);
|
|
31
|
+
const offsetY = Math.round(Math.sin(angle) * distance);
|
|
32
|
+
const shadowColor = effect.shadowColor ?? 0x000000;
|
|
33
|
+
const shadowAlpha = effect.shadowAlpha ?? 1;
|
|
34
|
+
const highlightColor = effect.highlightColor ?? 0xffffff;
|
|
35
|
+
const highlightAlpha = effect.highlightAlpha ?? 1;
|
|
36
|
+
const strength = effect.strength ?? 1;
|
|
37
|
+
const quality = Math.max(1, Math.round(effect.quality ?? 1));
|
|
38
|
+
const sourceMode = effect.sourceMode ?? 'draw';
|
|
39
|
+
const bevelType = effect.bevelType ?? 'inner';
|
|
40
|
+
const [tinted, blurred, blurTemp] = [s0, s1, s2];
|
|
41
|
+
// Blurred alpha field (neutral white tint, strength 1 — strength is the gradient
|
|
42
|
+
// intensity applied per-pixel in the composite, not baked into the field).
|
|
43
|
+
applyGlEffectTintPass(state, src, tinted, 0xffffff, 1, 1);
|
|
44
|
+
applyGlEffectBoxBlur(state, tinted, blurred, blurTemp, {
|
|
45
|
+
blurX: effect.blurX ?? 4,
|
|
46
|
+
blurY: effect.blurY ?? 4,
|
|
47
|
+
passes: quality,
|
|
48
|
+
});
|
|
49
|
+
clearGlRenderTarget(state, dst);
|
|
50
|
+
if (sourceMode === 'draw')
|
|
51
|
+
applyGlEffectBlitPass(state, src, dst);
|
|
52
|
+
applyGlBevelCompositePass(state, blurred, src, dst, {
|
|
53
|
+
offsetX: offsetX / src.width,
|
|
54
|
+
// Negate Y to match the screen-space-Y-down offset convention used by applyGlEffectBlitOffsetPass.
|
|
55
|
+
offsetY: -offsetY / src.height,
|
|
56
|
+
highlightColor,
|
|
57
|
+
highlightAlpha,
|
|
58
|
+
shadowColor,
|
|
59
|
+
shadowAlpha,
|
|
60
|
+
intensity: strength,
|
|
61
|
+
clipMode: bevelType === 'inner' ? 1 : bevelType === 'outer' ? 2 : 0,
|
|
62
|
+
});
|
|
63
|
+
if (sourceMode === 'knockout')
|
|
64
|
+
applyGlEffectErasePass(state, src, dst);
|
|
65
|
+
releaseGlRenderTarget(pool, s0);
|
|
66
|
+
releaseGlRenderTarget(pool, s1);
|
|
67
|
+
releaseGlRenderTarget(pool, s2);
|
|
68
|
+
}
|
|
69
|
+
export const defaultGlBevelEffectRunner = (ctx, effect) => {
|
|
70
|
+
applyBevelEffectToGl(ctx.state, ctx.source, ctx.dest, ctx.pool, effect);
|
|
71
|
+
};
|
|
72
|
+
// Reads the blurred alpha field (unit 0) and source (unit 1); writes the tinted, clipped bevel mask,
|
|
73
|
+
// premultiplied, blended over `dest` (which already holds the source when sourceMode is 'draw').
|
|
74
|
+
const BEVEL_COMPOSITE_FRAGMENT_SRC = `#version 300 es
|
|
75
|
+
precision mediump float;
|
|
76
|
+
in vec2 v_texCoord;
|
|
77
|
+
uniform sampler2D u_texture0;
|
|
78
|
+
uniform sampler2D u_texture1;
|
|
79
|
+
uniform vec4 u_highlight;
|
|
80
|
+
uniform vec4 u_shadow;
|
|
81
|
+
uniform vec2 u_offset;
|
|
82
|
+
uniform float u_intensity;
|
|
83
|
+
uniform float u_clipMode;
|
|
84
|
+
out vec4 fragColor;
|
|
85
|
+
|
|
86
|
+
float sampleField(vec2 uv) {
|
|
87
|
+
if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) return 0.0;
|
|
88
|
+
return texture(u_texture0, uv).a;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
void main() {
|
|
92
|
+
float lit = sampleField(v_texCoord - u_offset);
|
|
93
|
+
float shade = sampleField(v_texCoord + u_offset);
|
|
94
|
+
float gradient = lit - shade;
|
|
95
|
+
float srcA = texture(u_texture1, v_texCoord).a;
|
|
96
|
+
bool isHighlight = gradient >= 0.0;
|
|
97
|
+
vec3 color = isHighlight ? u_highlight.rgb : u_shadow.rgb;
|
|
98
|
+
float colorAlpha = isHighlight ? u_highlight.a : u_shadow.a;
|
|
99
|
+
float clip = 1.0;
|
|
100
|
+
if (u_clipMode == 1.0) { clip = srcA; }
|
|
101
|
+
else if (u_clipMode == 2.0) { clip = 1.0 - srcA; }
|
|
102
|
+
float edge = min(1.0, abs(gradient) * u_intensity);
|
|
103
|
+
float a = edge * colorAlpha * clip;
|
|
104
|
+
fragColor = vec4(color * a, a);
|
|
105
|
+
}`;
|
|
106
|
+
const bevelCompositeShaders = new WeakMap();
|
|
107
|
+
function applyGlBevelCompositePass(state, field, source, dest, params) {
|
|
108
|
+
const loc = getGlBevelCompositeShader(state);
|
|
109
|
+
drawGlFullscreenPass(state, loc, [field.texture, source.texture], dest, (gl) => {
|
|
110
|
+
gl.uniform4f(loc.locHighlight, ((params.highlightColor >> 16) & 0xff) / 255, ((params.highlightColor >> 8) & 0xff) / 255, (params.highlightColor & 0xff) / 255, params.highlightAlpha);
|
|
111
|
+
gl.uniform4f(loc.locShadow, ((params.shadowColor >> 16) & 0xff) / 255, ((params.shadowColor >> 8) & 0xff) / 255, (params.shadowColor & 0xff) / 255, params.shadowAlpha);
|
|
112
|
+
gl.uniform2f(loc.locOffset, params.offsetX, params.offsetY);
|
|
113
|
+
gl.uniform1f(loc.locIntensity, params.intensity);
|
|
114
|
+
gl.uniform1f(loc.locClipMode, params.clipMode);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
function getGlBevelCompositeShader(state) {
|
|
118
|
+
let loc = bevelCompositeShaders.get(state);
|
|
119
|
+
if (loc === undefined) {
|
|
120
|
+
const gl = state.gl;
|
|
121
|
+
const base = compileGlFullscreenProgram(gl, BEVEL_COMPOSITE_FRAGMENT_SRC);
|
|
122
|
+
loc = {
|
|
123
|
+
...base,
|
|
124
|
+
locHighlight: gl.getUniformLocation(base.program, 'u_highlight'),
|
|
125
|
+
locShadow: gl.getUniformLocation(base.program, 'u_shadow'),
|
|
126
|
+
locOffset: gl.getUniformLocation(base.program, 'u_offset'),
|
|
127
|
+
locIntensity: gl.getUniformLocation(base.program, 'u_intensity'),
|
|
128
|
+
locClipMode: gl.getUniformLocation(base.program, 'u_clipMode'),
|
|
129
|
+
};
|
|
130
|
+
bevelCompositeShaders.set(state, loc);
|
|
131
|
+
}
|
|
132
|
+
return loc;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=glBevelEffect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glBloomEffect.d.ts","sourceRoot":"","sources":["../src/glBloomEffect.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"glBloomEffect.d.ts","sourceRoot":"","sources":["../src/glBloomEffect.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,WAAW,EACX,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AAQzB,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,CAyBN;AAED,eAAO,MAAM,0BAA0B,EAAE,oBAExC,CAAC"}
|
package/dist/glBloomEffect.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { computeBloomBlurRadius, computeBloomIntensity, computeBloomThreshold } from '@flighthq/effects';
|
|
2
|
-
import { applyGaussianBlurFilterToGl } from '@flighthq/filters-gl';
|
|
3
2
|
import { acquireGlRenderTarget, drawGlFullscreenPass, releaseGlRenderTarget } from '@flighthq/render-gl';
|
|
3
|
+
import { applyGaussianBlurToGl } from './glBlurEffect';
|
|
4
4
|
import { getGlEffectProgram } from './glEffectProgramCache';
|
|
5
|
-
// Bloom: bright-pass → blur the bright branch (
|
|
6
|
-
// composite back. The multi-pass reference recipe — it acquires intermediate targets from
|
|
7
|
-
// and releases them, branches, and reuses
|
|
5
|
+
// Bloom: bright-pass → blur the bright branch (via the effects-owned separable gaussian blur) →
|
|
6
|
+
// additively composite back. The multi-pass reference recipe — it acquires intermediate targets from
|
|
7
|
+
// the pool and releases them, branches, and reuses the blur primitive, which is what makes it an effect.
|
|
8
8
|
export function applyBloomEffectToGl(state, source, dest, pool, effect) {
|
|
9
9
|
const threshold = computeBloomThreshold(effect);
|
|
10
10
|
const intensity = computeBloomIntensity(effect);
|
|
@@ -17,7 +17,7 @@ export function applyBloomEffectToGl(state, source, dest, pool, effect) {
|
|
|
17
17
|
drawGlFullscreenPass(state, brightProgram, [source.texture], bright, (gl, program) => {
|
|
18
18
|
gl.uniform1f(gl.getUniformLocation(program.program, 'u_threshold'), threshold);
|
|
19
19
|
});
|
|
20
|
-
|
|
20
|
+
applyGaussianBlurToGl(state, bright, blurred, temp, { blurX: radius, blurY: radius });
|
|
21
21
|
const compositeProgram = getGlEffectProgram(state, 'bloom.composite', BLOOM_COMPOSITE_FRAGMENT_SRC);
|
|
22
22
|
drawGlFullscreenPass(state, compositeProgram, [source.texture, blurred.texture], dest, (gl, program) => {
|
|
23
23
|
gl.uniform1f(gl.getUniformLocation(program.program, 'u_intensity'), intensity);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glBloomEffect.js","sourceRoot":"","sources":["../src/glBloomEffect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AACzG,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"glBloomEffect.js","sourceRoot":"","sources":["../src/glBloomEffect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AACzG,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AASzG,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,gGAAgG;AAChG,qGAAqG;AACrG,yGAAyG;AACzG,MAAM,UAAU,oBAAoB,CAClC,KAAoB,EACpB,MAAgC,EAChC,IAA8B,EAC9B,IAAwB,EACxB,MAA6B;IAE7B,MAAM,SAAS,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAChD,MAAM,SAAS,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IAEzF,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;IAC9D,MAAM,OAAO,GAAG,qBAAqB,CAAC,KAAK,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;IAC/D,MAAM,IAAI,GAAG,qBAAqB,CAAC,KAAK,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;IAE5D,MAAM,aAAa,GAAG,kBAAkB,CAAC,KAAK,EAAE,cAAc,EAAE,yBAAyB,CAAC,CAAC;IAC3F,oBAAoB,CAAC,KAAK,EAAE,aAAa,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE;QACnF,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,kBAAkB,CAAC,OAAO,CAAC,OAAO,EAAE,aAAa,CAAC,EAAE,SAAS,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAEtF,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,EAAE,4BAA4B,CAAC,CAAC;IACpG,oBAAoB,CAAC,KAAK,EAAE,gBAAgB,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE;QACrG,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,kBAAkB,CAAC,OAAO,CAAC,OAAO,EAAE,aAAa,CAAC,EAAE,SAAS,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACpC,qBAAqB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACrC,qBAAqB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,CAAC,MAAM,0BAA0B,GAAyB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;IAC9E,oBAAoB,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,MAAqB,CAAC,CAAC;AACzF,CAAC,CAAC;AAEF,MAAM,yBAAyB,GAAG;;;;;;;;;;;EAWhC,CAAC;AAEH,MAAM,4BAA4B,GAAG;;;;;;;;;;;EAWnC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BlurEffect, GlRenderEffectRunner, GlRenderState, GlRenderTarget } from '@flighthq/types';
|
|
2
|
+
export declare function applyBlurEffectToGl(state: GlRenderState, source: Readonly<GlRenderTarget>, dest: Readonly<GlRenderTarget>, temp: Readonly<GlRenderTarget>, effect: Readonly<BlurEffect>): void;
|
|
3
|
+
export declare function applyGaussianBlurToGl(state: GlRenderState, source: Readonly<GlRenderTarget>, dest: Readonly<GlRenderTarget>, temp: Readonly<GlRenderTarget>, options: Readonly<{
|
|
4
|
+
blurX?: number;
|
|
5
|
+
blurY?: number;
|
|
6
|
+
}>): void;
|
|
7
|
+
export declare const defaultGlBlurEffectRunner: GlRenderEffectRunner;
|
|
8
|
+
//# sourceMappingURL=glBlurEffect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glBlurEffect.d.ts","sourceRoot":"","sources":["../src/glBlurEffect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,oBAAoB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAYvG,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC,EAChC,IAAI,EAAE,QAAQ,CAAC,cAAc,CAAC,EAC9B,IAAI,EAAE,QAAQ,CAAC,cAAc,CAAC,EAC9B,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,GAC3B,IAAI,CAEN;AAMD,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC,EAChC,IAAI,EAAE,QAAQ,CAAC,cAAc,CAAC,EAC9B,IAAI,EAAE,QAAQ,CAAC,cAAc,CAAC,EAC9B,OAAO,EAAE,QAAQ,CAAC;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GACpD,IAAI,CAON;AAED,eAAO,MAAM,yBAAyB,EAAE,oBAKvC,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { acquireGlRenderTarget, drawGlFullscreenPass, releaseGlRenderTarget } from '@flighthq/render-gl';
|
|
2
|
+
import { getGlEffectProgram, getGlEffectUniformLocation } from './glEffectProgramCache';
|
|
3
|
+
// Plain separable Gaussian blur: two axis passes (source → temp horizontally, temp → dest vertically),
|
|
4
|
+
// each a single weighted fullscreen pass with radius ⌈3σ⌉. `blurX`/`blurY` are the Gaussian standard
|
|
5
|
+
// deviations (CSS `blur(Xpx)` uses sigma = X), so this matches the CSS and surface Gaussian references.
|
|
6
|
+
// The effects-owned blur primitive — the shared gaussian pass BloomEffect and the plain BlurEffect both
|
|
7
|
+
// use, so the effects backend owns its blur outright rather than delegating to a filters backend.
|
|
8
|
+
// Applies a `BlurEffect` descriptor to `source`, writing to `dest`. `temp` is a ping-pong scratch
|
|
9
|
+
// target distinct from both `source` and `dest`.
|
|
10
|
+
export function applyBlurEffectToGl(state, source, dest, temp, effect) {
|
|
11
|
+
applyGaussianBlurToGl(state, source, dest, temp, { blurX: effect.blurX, blurY: effect.blurY });
|
|
12
|
+
}
|
|
13
|
+
// Applies a faithful separable Gaussian blur to `source`, writing to `dest`. `blurX`/`blurY` are the
|
|
14
|
+
// Gaussian standard deviations in pixels (default 4). Runs two unconditional separable passes,
|
|
15
|
+
// source → temp (X) then temp → dest (Y); a zero-radius axis copies through unchanged, so the result
|
|
16
|
+
// always lands in `dest` without a separate blit. `temp` is a ping-pong scratch distinct from both.
|
|
17
|
+
export function applyGaussianBlurToGl(state, source, dest, temp, options) {
|
|
18
|
+
const sigmaX = options.blurX ?? 4;
|
|
19
|
+
const sigmaY = options.blurY ?? 4;
|
|
20
|
+
const radiusX = sigmaX > 0 ? Math.ceil(sigmaX * 3) : 0;
|
|
21
|
+
const radiusY = sigmaY > 0 ? Math.ceil(sigmaY * 3) : 0;
|
|
22
|
+
applyGlGaussianBlurPass(state, source, temp, sigmaX, radiusX, 1, 0);
|
|
23
|
+
applyGlGaussianBlurPass(state, temp, dest, sigmaY, radiusY, 0, 1);
|
|
24
|
+
}
|
|
25
|
+
export const defaultGlBlurEffectRunner = (ctx, effect) => {
|
|
26
|
+
const descriptor = { width: ctx.source.width, height: ctx.source.height, format: ctx.source.format };
|
|
27
|
+
const temp = acquireGlRenderTarget(ctx.state, ctx.pool, descriptor);
|
|
28
|
+
applyBlurEffectToGl(ctx.state, ctx.source, ctx.dest, temp, effect);
|
|
29
|
+
releaseGlRenderTarget(ctx.pool, temp);
|
|
30
|
+
};
|
|
31
|
+
function applyGlGaussianBlurPass(state, source, dest, sigma, radius, dirX, dirY) {
|
|
32
|
+
const program = getGlEffectProgram(state, 'blur.gaussian', GAUSSIAN_BLUR_FRAGMENT_SRC);
|
|
33
|
+
drawGlFullscreenPass(state, program, [source.texture], dest, (gl, p) => {
|
|
34
|
+
gl.uniform2f(getGlEffectUniformLocation(state, p, 'u_texelSize'), 1 / source.width, 1 / source.height);
|
|
35
|
+
gl.uniform1f(getGlEffectUniformLocation(state, p, 'u_sigma'), sigma);
|
|
36
|
+
gl.uniform1f(getGlEffectUniformLocation(state, p, 'u_radius'), radius);
|
|
37
|
+
gl.uniform2f(getGlEffectUniformLocation(state, p, 'u_direction'), dirX, dirY);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const GAUSSIAN_BLUR_FRAGMENT_SRC = `#version 300 es
|
|
41
|
+
precision mediump float;
|
|
42
|
+
in vec2 v_texCoord;
|
|
43
|
+
uniform sampler2D u_texture0;
|
|
44
|
+
uniform vec2 u_texelSize;
|
|
45
|
+
uniform float u_sigma;
|
|
46
|
+
uniform float u_radius;
|
|
47
|
+
uniform vec2 u_direction;
|
|
48
|
+
out vec4 o_color;
|
|
49
|
+
void main() {
|
|
50
|
+
int r = max(0, int(u_radius));
|
|
51
|
+
if (r == 0) {
|
|
52
|
+
o_color = texture(u_texture0, v_texCoord);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
float twoSigmaSq = 2.0 * u_sigma * u_sigma;
|
|
56
|
+
vec4 sum = vec4(0.0);
|
|
57
|
+
float weightSum = 0.0;
|
|
58
|
+
for (int i = -r; i <= r; i++) {
|
|
59
|
+
float w = exp(-float(i * i) / twoSigmaSq);
|
|
60
|
+
sum += w * texture(u_texture0, v_texCoord + float(i) * u_texelSize * u_direction);
|
|
61
|
+
weightSum += w;
|
|
62
|
+
}
|
|
63
|
+
o_color = sum / weightSum;
|
|
64
|
+
}`;
|
|
65
|
+
//# sourceMappingURL=glBlurEffect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glBlurEffect.js","sourceRoot":"","sources":["../src/glBlurEffect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ColorLut, GlColorLutTextureCache, GlRenderState, GlRenderTarget } from '@flighthq/types';
|
|
2
|
+
export declare function applyColorLutPassToGl(state: GlRenderState, source: Readonly<GlRenderTarget>, dest: Readonly<GlRenderTarget>, lut: Readonly<ColorLut>, cache: GlColorLutTextureCache): void;
|
|
3
|
+
//# sourceMappingURL=glColorLutPass.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glColorLutPass.d.ts","sourceRoot":"","sources":["../src/glColorLutPass.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,sBAAsB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAavG,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC,EAChC,IAAI,EAAE,QAAQ,CAAC,cAAc,CAAC,EAC9B,GAAG,EAAE,QAAQ,CAAC,QAAQ,CAAC,EACvB,KAAK,EAAE,sBAAsB,GAC5B,IAAI,CAYN"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { drawGlFullscreenPass } from '@flighthq/render-gl';
|
|
2
|
+
import { getGlEffectProgram } from './glEffectProgramCache';
|
|
3
|
+
// Generic pointwise color-LUT pass — the single fold-in realization for the whole LUT-tier Adjustment
|
|
4
|
+
// family on WebGL 2. A run of consecutive pointwise adjustments containing any nonlinear (LUT-tier)
|
|
5
|
+
// member bakes to ONE 3D `ColorLut` (matrices folded in) and runs through this one trilinear pass instead
|
|
6
|
+
// of one pass per op. The LUT is uploaded as a `size³` RGBA8 3D texture; hardware LINEAR filtering does
|
|
7
|
+
// the trilinear interpolation. Sampled color is treated as premultiplied and passed straight into the
|
|
8
|
+
// LUT (matching the per-op color passes this replaces); alpha is preserved. `cache` owns the uploaded 3D
|
|
9
|
+
// texture across frames; the LUT is re-uploaded only when it differs by identity from the last one baked
|
|
10
|
+
// into `cache` (bakeColorLutForRun returns a stable reference for an unchanged run), so a static grade
|
|
11
|
+
// uploads once. The caller owns `cache.texture` and destroys it on teardown.
|
|
12
|
+
export function applyColorLutPassToGl(state, source, dest, lut, cache) {
|
|
13
|
+
const gl = state.gl;
|
|
14
|
+
const size = lut.size;
|
|
15
|
+
const texture = uploadLutTexture(gl, lut, cache);
|
|
16
|
+
const program = getGlEffectProgram(state, 'adjustment.colorLut', COLOR_LUT_FRAGMENT_SRC);
|
|
17
|
+
drawGlFullscreenPass(state, program, [source.texture], dest, (glc, p) => {
|
|
18
|
+
glc.uniform1f(glc.getUniformLocation(p.program, 'u_lutSize'), size);
|
|
19
|
+
glc.activeTexture(glc.TEXTURE1);
|
|
20
|
+
glc.bindTexture(glc.TEXTURE_3D, texture);
|
|
21
|
+
glc.uniform1i(glc.getUniformLocation(p.program, 'u_lut'), 1);
|
|
22
|
+
glc.activeTexture(glc.TEXTURE0);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
// Uploads `lut` into the cache's reusable 3D texture (RGBA8, LINEAR, clamp-to-edge) and returns it. The
|
|
26
|
+
// upload is skipped entirely when `lut` is the same reference already baked into the texture — the common
|
|
27
|
+
// static-grade case — so an unchanged grade costs one texImage3D total, not one per frame.
|
|
28
|
+
function uploadLutTexture(gl, lut, cache) {
|
|
29
|
+
if (cache.texture !== null && cache.lut === lut)
|
|
30
|
+
return cache.texture;
|
|
31
|
+
const n = lut.size;
|
|
32
|
+
const samples = lut.samples;
|
|
33
|
+
const data = new Uint8Array(n * n * n * 4);
|
|
34
|
+
for (let i = 0, j = 0, o = 0; i < n * n * n; i++) {
|
|
35
|
+
data[o++] = Math.round(clamp01(samples[j++]) * 255);
|
|
36
|
+
data[o++] = Math.round(clamp01(samples[j++]) * 255);
|
|
37
|
+
data[o++] = Math.round(clamp01(samples[j++]) * 255);
|
|
38
|
+
data[o++] = 255;
|
|
39
|
+
}
|
|
40
|
+
let texture = cache.texture;
|
|
41
|
+
if (texture === null) {
|
|
42
|
+
texture = gl.createTexture();
|
|
43
|
+
cache.texture = texture;
|
|
44
|
+
}
|
|
45
|
+
gl.bindTexture(gl.TEXTURE_3D, texture);
|
|
46
|
+
gl.texImage3D(gl.TEXTURE_3D, 0, gl.RGBA8, n, n, n, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
|
|
47
|
+
gl.texParameteri(gl.TEXTURE_3D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
48
|
+
gl.texParameteri(gl.TEXTURE_3D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
49
|
+
gl.texParameteri(gl.TEXTURE_3D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
50
|
+
gl.texParameteri(gl.TEXTURE_3D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
51
|
+
gl.texParameteri(gl.TEXTURE_3D, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
|
|
52
|
+
gl.bindTexture(gl.TEXTURE_3D, null);
|
|
53
|
+
cache.lut = lut;
|
|
54
|
+
return texture;
|
|
55
|
+
}
|
|
56
|
+
function clamp01(v) {
|
|
57
|
+
return v < 0 ? 0 : v > 1 ? 1 : v;
|
|
58
|
+
}
|
|
59
|
+
// Half-texel scale/offset maps the [0,1] color to LUT cell centres, so v=0 hits cell 0 and v=1 the last.
|
|
60
|
+
const COLOR_LUT_FRAGMENT_SRC = `#version 300 es
|
|
61
|
+
precision highp float;
|
|
62
|
+
precision highp sampler3D;
|
|
63
|
+
in vec2 v_texCoord;
|
|
64
|
+
uniform sampler2D u_texture0;
|
|
65
|
+
uniform sampler3D u_lut;
|
|
66
|
+
uniform float u_lutSize;
|
|
67
|
+
out vec4 o_color;
|
|
68
|
+
void main() {
|
|
69
|
+
vec4 c = texture(u_texture0, v_texCoord);
|
|
70
|
+
float scale = (u_lutSize - 1.0) / u_lutSize;
|
|
71
|
+
float offset = 0.5 / u_lutSize;
|
|
72
|
+
vec3 lc = clamp(c.rgb, 0.0, 1.0) * scale + offset;
|
|
73
|
+
o_color = vec4(texture(u_lut, lc).rgb, c.a);
|
|
74
|
+
}`;
|
|
75
|
+
//# sourceMappingURL=glColorLutPass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glColorLutPass.js","sourceRoot":"","sources":["../src/glColorLutPass.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { GlRenderState, GlRenderTarget } from '@flighthq/types';
|
|
2
|
+
export declare function applyColorMatrixPassToGl(state: GlRenderState, source: Readonly<GlRenderTarget>, dest: Readonly<GlRenderTarget>, matrix: ReadonlyArray<number>): void;
|
|
3
|
+
//# sourceMappingURL=glColorMatrixPass.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glColorMatrixPass.d.ts","sourceRoot":"","sources":["../src/glColorMatrixPass.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AASrE,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC,EAChC,IAAI,EAAE,QAAQ,CAAC,cAAc,CAAC,EAC9B,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,GAC5B,IAAI,CAON"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { drawGlFullscreenPass } from '@flighthq/render-gl';
|
|
2
|
+
import { getGlEffectProgram } from './glEffectProgramCache';
|
|
3
|
+
// Generic pointwise color-matrix pass — the single fold-in realization for the whole matrix-tier
|
|
4
|
+
// Adjustment family. A run of consecutive matrix-tier adjustments fuses to ONE 4×5 matrix (in the
|
|
5
|
+
// adjustments colorMatrixMath convention: linear RGBA coefficients + a 0–255 offset column) and runs
|
|
6
|
+
// through this one pass instead of one pass per op. Sampled color is treated as premultiplied and the
|
|
7
|
+
// RGB result is clamped, matching the per-op color passes this replaces.
|
|
8
|
+
export function applyColorMatrixPassToGl(state, source, dest, matrix) {
|
|
9
|
+
const m = new Float32Array(20);
|
|
10
|
+
for (let i = 0; i < 20; i++)
|
|
11
|
+
m[i] = matrix[i] ?? 0;
|
|
12
|
+
const program = getGlEffectProgram(state, 'adjustment.colorMatrix', COLOR_MATRIX_FRAGMENT_SRC);
|
|
13
|
+
drawGlFullscreenPass(state, program, [source.texture], dest, (gl, p) => {
|
|
14
|
+
gl.uniform1fv(gl.getUniformLocation(p.program, 'u_colorMatrix'), m);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
// The offset column (indices 4, 9, 14, 19) is 0–255; normalized color needs it divided by 255.
|
|
18
|
+
const COLOR_MATRIX_FRAGMENT_SRC = `#version 300 es
|
|
19
|
+
precision highp float;
|
|
20
|
+
in vec2 v_texCoord;
|
|
21
|
+
uniform sampler2D u_texture0;
|
|
22
|
+
uniform float u_colorMatrix[20];
|
|
23
|
+
out vec4 o_color;
|
|
24
|
+
void main() {
|
|
25
|
+
vec4 c = texture(u_texture0, v_texCoord);
|
|
26
|
+
float r = c.r, g = c.g, b = c.b, a = c.a;
|
|
27
|
+
float nr = u_colorMatrix[0] * r + u_colorMatrix[1] * g + u_colorMatrix[2] * b + u_colorMatrix[3] * a + u_colorMatrix[4] / 255.0;
|
|
28
|
+
float ng = u_colorMatrix[5] * r + u_colorMatrix[6] * g + u_colorMatrix[7] * b + u_colorMatrix[8] * a + u_colorMatrix[9] / 255.0;
|
|
29
|
+
float nb = u_colorMatrix[10] * r + u_colorMatrix[11] * g + u_colorMatrix[12] * b + u_colorMatrix[13] * a + u_colorMatrix[14] / 255.0;
|
|
30
|
+
float na = u_colorMatrix[15] * r + u_colorMatrix[16] * g + u_colorMatrix[17] * b + u_colorMatrix[18] * a + u_colorMatrix[19] / 255.0;
|
|
31
|
+
o_color = vec4(clamp(vec3(nr, ng, nb), 0.0, 1.0), na);
|
|
32
|
+
}`;
|
|
33
|
+
//# sourceMappingURL=glColorMatrixPass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glColorMatrixPass.js","sourceRoot":"","sources":["../src/glColorMatrixPass.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAG3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,iGAAiG;AACjG,kGAAkG;AAClG,qGAAqG;AACrG,sGAAsG;AACtG,yEAAyE;AACzE,MAAM,UAAU,wBAAwB,CACtC,KAAoB,EACpB,MAAgC,EAChC,IAA8B,EAC9B,MAA6B;IAE7B,MAAM,CAAC,GAAG,IAAI,YAAY,CAAC,EAAE,CAAC,CAAC;IAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE;QAAE,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,EAAE,wBAAwB,EAAE,yBAAyB,CAAC,CAAC;IAC/F,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE;QACrE,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,OAAO,EAAE,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,+FAA+F;AAC/F,MAAM,yBAAyB,GAAG;;;;;;;;;;;;;;EAchC,CAAC"}
|