summaryrefslogtreecommitdiff
path: root/apps/web/src/services/renderer/mask-feather.ts
blob: 39ad80a837494dbfe9761dd3213c8152a470b69a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import jfaDistanceShader from "@/lib/masks/shaders/jfa-distance.frag.glsl";
import { getWebGLContext, readResult } from "./webgl/webgl-context";
import { computeSignedDistanceField, runPass } from "./webgl/jfa";
import { compileProgram, createTexture } from "./webgl/webgl-utils";

export function applyMaskFeather({
	maskCanvas,
	width,
	height,
	feather,
}: {
	maskCanvas: CanvasImageSource;
	width: number;
	height: number;
	feather: number;
}): OffscreenCanvas | HTMLCanvasElement {
	const { context, programCache } = getWebGLContext({ width, height });
	const sourceTexture = createTexture({ context, source: maskCanvas });

	const sdf = computeSignedDistanceField({
		context,
		programCache,
		sourceTexture,
		width,
		height,
	});

	const distanceProgram = compileProgram({
		context,
		fragmentShaderSource: jfaDistanceShader,
		programCache,
	});

	runPass({
		context,
		program: distanceProgram,
		inputTexture: sdf.insideTexture,
		target: null,
		width,
		height,
		uniforms: { u_feather_half: feather / 2.0 },
		extraBindings: [
			{ unit: 1, texture: sdf.outsideTexture, name: "u_jfa_outside" },
		],
	});

	context.deleteTexture(sourceTexture);
	sdf.cleanup();

	context.bindTexture(context.TEXTURE_2D, null);
	context.bindFramebuffer(context.FRAMEBUFFER, null);

	return readResult({ width, height });
}