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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
import type { CanvasRenderer } from "../canvas-renderer";
import { createOffscreenCanvas } from "../canvas-utils";
import { getEffect } from "@/lib/effects";
import type { EffectParamValues } from "@/types/effects";
import { BaseNode } from "./base-node";
import { webglEffectRenderer } from "../webgl-effect-renderer";
export type CompositeEffectNodeParams = {
contentNodes: BaseNode[];
effectType: string;
effectParams: EffectParamValues;
scale: number;
};
export class CompositeEffectNode extends BaseNode<CompositeEffectNodeParams> {
async render({
renderer,
time,
}: {
renderer: CanvasRenderer;
time: number;
}): Promise<void> {
const offscreen = createOffscreenCanvas({
width: renderer.width,
height: renderer.height,
});
const offscreenCtx = offscreen.getContext("2d") as OffscreenCanvasRenderingContext2D | null;
if (!offscreenCtx) {
throw new Error("failed to get offscreen canvas context");
}
const originalContext = renderer.context;
renderer.context = offscreenCtx;
for (const node of this.params.contentNodes) {
await node.render({ renderer, time });
}
renderer.context = originalContext;
const effectDefinition = getEffect({ effectType: this.params.effectType });
const scale = this.params.scale;
const scaledWidth = renderer.width * scale;
const scaledHeight = renderer.height * scale;
const offsetX = (renderer.width - scaledWidth) / 2;
const offsetY = (renderer.height - scaledHeight) / 2;
const passes = effectDefinition.renderer.passes.map((pass) => ({
fragmentShader: pass.fragmentShader,
uniforms: pass.uniforms({
effectParams: this.params.effectParams,
width: renderer.width,
height: renderer.height,
}),
}));
const effectResult = webglEffectRenderer.applyEffect({
source: offscreen as CanvasImageSource,
width: renderer.width,
height: renderer.height,
passes,
});
renderer.context.save();
renderer.context.drawImage(
effectResult,
0,
0,
renderer.width,
renderer.height,
offsetX,
offsetY,
scaledWidth,
scaledHeight,
);
renderer.context.restore();
}
}
|