@swf2es/render 0.0.0-stage → 0.1.1
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/LICENSE +202 -0
- package/README.md +17 -2
- package/dist/commands.d.ts +67 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +93 -0
- package/dist/commands.js.map +1 -0
- package/dist/filter-plan.d.ts +110 -0
- package/dist/filter-plan.d.ts.map +1 -0
- package/dist/filter-plan.js +480 -0
- package/dist/filter-plan.js.map +1 -0
- package/dist/filter-shaders.d.ts +63 -0
- package/dist/filter-shaders.d.ts.map +1 -0
- package/dist/filter-shaders.js +350 -0
- package/dist/filter-shaders.js.map +1 -0
- package/dist/filters.d.ts +107 -0
- package/dist/filters.d.ts.map +1 -0
- package/dist/filters.js +187 -0
- package/dist/filters.js.map +1 -0
- package/dist/geometry.d.ts +83 -0
- package/dist/geometry.d.ts.map +1 -0
- package/dist/geometry.js +93 -0
- package/dist/geometry.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/keeps.d.ts +17 -0
- package/dist/keeps.d.ts.map +1 -0
- package/dist/keeps.js +17 -0
- package/dist/keeps.js.map +1 -0
- package/dist/kernel-shaders.d.ts +74 -0
- package/dist/kernel-shaders.d.ts.map +1 -0
- package/dist/kernel-shaders.js +323 -0
- package/dist/kernel-shaders.js.map +1 -0
- package/dist/measure.d.ts +56 -0
- package/dist/measure.d.ts.map +1 -0
- package/dist/measure.js +287 -0
- package/dist/measure.js.map +1 -0
- package/dist/plan.d.ts +14 -0
- package/dist/plan.d.ts.map +1 -0
- package/dist/plan.js +247 -0
- package/dist/plan.js.map +1 -0
- package/dist/registry.d.ts +49 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +87 -0
- package/dist/registry.js.map +1 -0
- package/dist/rows.d.ts +39 -0
- package/dist/rows.d.ts.map +1 -0
- package/dist/rows.js +60 -0
- package/dist/rows.js.map +1 -0
- package/dist/scene.d.ts +179 -0
- package/dist/scene.d.ts.map +1 -0
- package/dist/scene.js +265 -0
- package/dist/scene.js.map +1 -0
- package/dist/shelves.d.ts +23 -0
- package/dist/shelves.d.ts.map +1 -0
- package/dist/shelves.js +63 -0
- package/dist/shelves.js.map +1 -0
- package/dist/textures.d.ts +72 -0
- package/dist/textures.d.ts.map +1 -0
- package/dist/textures.js +160 -0
- package/dist/textures.js.map +1 -0
- package/dist/webgl/atlas.d.ts +63 -0
- package/dist/webgl/atlas.d.ts.map +1 -0
- package/dist/webgl/atlas.js +328 -0
- package/dist/webgl/atlas.js.map +1 -0
- package/dist/webgl/backend.d.ts +141 -0
- package/dist/webgl/backend.d.ts.map +1 -0
- package/dist/webgl/backend.js +659 -0
- package/dist/webgl/backend.js.map +1 -0
- package/dist/webgl/composite.d.ts +101 -0
- package/dist/webgl/composite.d.ts.map +1 -0
- package/dist/webgl/composite.js +293 -0
- package/dist/webgl/composite.js.map +1 -0
- package/dist/webgl/draws.d.ts +213 -0
- package/dist/webgl/draws.d.ts.map +1 -0
- package/dist/webgl/draws.js +714 -0
- package/dist/webgl/draws.js.map +1 -0
- package/dist/webgl/filters.d.ts +107 -0
- package/dist/webgl/filters.d.ts.map +1 -0
- package/dist/webgl/filters.js +351 -0
- package/dist/webgl/filters.js.map +1 -0
- package/dist/webgl/gpu-textures.d.ts +44 -0
- package/dist/webgl/gpu-textures.d.ts.map +1 -0
- package/dist/webgl/gpu-textures.js +178 -0
- package/dist/webgl/gpu-textures.js.map +1 -0
- package/dist/webgl/holds.d.ts +97 -0
- package/dist/webgl/holds.d.ts.map +1 -0
- package/dist/webgl/holds.js +453 -0
- package/dist/webgl/holds.js.map +1 -0
- package/dist/webgl/index.d.ts +2 -0
- package/dist/webgl/index.d.ts.map +1 -0
- package/dist/webgl/index.js +4 -0
- package/dist/webgl/index.js.map +1 -0
- package/dist/webgl/kernels.d.ts +64 -0
- package/dist/webgl/kernels.d.ts.map +1 -0
- package/dist/webgl/kernels.js +160 -0
- package/dist/webgl/kernels.js.map +1 -0
- package/dist/webgl/pool.d.ts +71 -0
- package/dist/webgl/pool.d.ts.map +1 -0
- package/dist/webgl/pool.js +192 -0
- package/dist/webgl/pool.js.map +1 -0
- package/dist/webgl/programs.d.ts +130 -0
- package/dist/webgl/programs.d.ts.map +1 -0
- package/dist/webgl/programs.js +582 -0
- package/dist/webgl/programs.js.map +1 -0
- package/dist/webgl/stage.d.ts +67 -0
- package/dist/webgl/stage.d.ts.map +1 -0
- package/dist/webgl/stage.js +173 -0
- package/dist/webgl/stage.js.map +1 -0
- package/dist/webgl/targets.d.ts +172 -0
- package/dist/webgl/targets.d.ts.map +1 -0
- package/dist/webgl/targets.js +323 -0
- package/dist/webgl/targets.js.map +1 -0
- package/package.json +35 -3
- package/src/commands.ts +98 -0
- package/src/filter-plan.ts +755 -0
- package/src/filter-shaders.ts +360 -0
- package/src/filters.ts +220 -0
- package/src/geometry.ts +143 -0
- package/src/index.ts +87 -0
- package/src/keeps.ts +21 -0
- package/src/kernel-shaders.ts +375 -0
- package/src/measure.ts +400 -0
- package/src/plan.ts +331 -0
- package/src/registry.ts +105 -0
- package/src/rows.ts +93 -0
- package/src/scene.ts +297 -0
- package/src/shelves.ts +70 -0
- package/src/textures.ts +198 -0
- package/src/webgl/atlas.ts +370 -0
- package/src/webgl/backend.ts +973 -0
- package/src/webgl/composite.ts +372 -0
- package/src/webgl/draws.ts +902 -0
- package/src/webgl/filters.ts +502 -0
- package/src/webgl/gpu-textures.ts +253 -0
- package/src/webgl/holds.ts +624 -0
- package/src/webgl/index.ts +3 -0
- package/src/webgl/kernels.ts +205 -0
- package/src/webgl/pool.ts +245 -0
- package/src/webgl/programs.ts +620 -0
- package/src/webgl/stage.ts +214 -0
- package/src/webgl/targets.ts +464 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import { type GlState, linkProgram } from "@swf2es/context3d/device";
|
|
2
|
+
import { BLEND, type Filters } from "../filters.js";
|
|
3
|
+
import { blendKernel, kernelImagesFit } from "../kernel-shaders.js";
|
|
4
|
+
import { ADD, ALPHA_MASK, KERNEL, LAYER, MULTIPLY, NORMAL, SCREEN } from "../scene.js";
|
|
5
|
+
import type { KernelHost, KernelProgram, KernelPrograms } from "./kernels.js";
|
|
6
|
+
import {
|
|
7
|
+
BACK_UNIT,
|
|
8
|
+
compositeFragment,
|
|
9
|
+
compositeVertex,
|
|
10
|
+
LAYER_COLOR,
|
|
11
|
+
LAYER_UNIT,
|
|
12
|
+
} from "./programs.js";
|
|
13
|
+
import { framebufferOf, LAYER_STEP, type Layer, type Open } from "./targets.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Whether blend mode `mode` reads what is below, which GL's blending does
|
|
17
|
+
* not compute, onto a target `opaque` throughout or not. Over an opaque
|
|
18
|
+
* one, multiply's src × (1 − da) term is none, and premultiplied it is
|
|
19
|
+
* s × d + d × (1 − sa), alpha as normal's: GL's blending (setModeBlend).
|
|
20
|
+
* An alpha mask's is d × sa (ALPHA_MASK).
|
|
21
|
+
*/
|
|
22
|
+
export function readsBelow(mode: number, opaque = false): boolean {
|
|
23
|
+
return !(
|
|
24
|
+
mode === NORMAL ||
|
|
25
|
+
mode === ALPHA_MASK ||
|
|
26
|
+
mode === LAYER ||
|
|
27
|
+
mode === ADD ||
|
|
28
|
+
mode === SCREEN ||
|
|
29
|
+
(mode === MULTIPLY && opaque)
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* GL's blending set for `mode` where it computes it (readsBelow false),
|
|
35
|
+
* the fragment then its pixel alone (BLEND_FRONT's normal); else off, the
|
|
36
|
+
* fragment the blend itself.
|
|
37
|
+
*/
|
|
38
|
+
export function setModeBlend(gl: WebGL2RenderingContext, state: GlState, mode: number): void {
|
|
39
|
+
switch (mode) {
|
|
40
|
+
case ADD:
|
|
41
|
+
state.setBlend(gl.ONE, gl.ONE);
|
|
42
|
+
break;
|
|
43
|
+
case SCREEN:
|
|
44
|
+
state.setBlend(gl.ONE, gl.ONE_MINUS_SRC_COLOR);
|
|
45
|
+
break;
|
|
46
|
+
case NORMAL:
|
|
47
|
+
case LAYER:
|
|
48
|
+
state.setBlend(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
49
|
+
break;
|
|
50
|
+
case MULTIPLY:
|
|
51
|
+
state.setBlend(gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
52
|
+
break;
|
|
53
|
+
case ALPHA_MASK:
|
|
54
|
+
state.setBlend(gl.ZERO, gl.SRC_ALPHA);
|
|
55
|
+
break;
|
|
56
|
+
default:
|
|
57
|
+
state.setBlend(null);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Where a compositor finds the frame's blend shaders and the textures they read. */
|
|
62
|
+
export interface CompositeHost extends KernelHost {
|
|
63
|
+
filters(): Filters | null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Layers composited onto what they are drawn over, in Flash's blend modes:
|
|
68
|
+
* through GL's blending where it computes the blend, else by the composite
|
|
69
|
+
* program from a copy of what is below, or by a blend shader's program
|
|
70
|
+
* (KERNEL).
|
|
71
|
+
*/
|
|
72
|
+
export class Compositor {
|
|
73
|
+
private readonly gl: WebGL2RenderingContext;
|
|
74
|
+
private readonly state: GlState;
|
|
75
|
+
/** The layers' composite program and where it takes its mode and row. */
|
|
76
|
+
private composite!: WebGLProgram;
|
|
77
|
+
private modeLocation: WebGLUniformLocation | null = null;
|
|
78
|
+
private compositeRowLocation: WebGLUniformLocation | null = null;
|
|
79
|
+
private offsetLocation: WebGLUniformLocation | null = null;
|
|
80
|
+
private flipLocation: WebGLUniformLocation | null = null;
|
|
81
|
+
private backOffsetLocation: WebGLUniformLocation | null = null;
|
|
82
|
+
private rectLocation: WebGLUniformLocation | null = null;
|
|
83
|
+
/** A copy of what is below a layer whose mode reads it, the target's size. */
|
|
84
|
+
private back: WebGLTexture | null = null;
|
|
85
|
+
private backFramebuffer: WebGLFramebuffer | null = null;
|
|
86
|
+
private backWidth = 0;
|
|
87
|
+
private backHeight = 0;
|
|
88
|
+
constructor(
|
|
89
|
+
gl: WebGL2RenderingContext,
|
|
90
|
+
state: GlState,
|
|
91
|
+
private readonly host: CompositeHost,
|
|
92
|
+
/** Blend shaders' programs, the backend's one cache of kernels'. */
|
|
93
|
+
private readonly kernels: KernelPrograms,
|
|
94
|
+
) {
|
|
95
|
+
this.gl = gl;
|
|
96
|
+
this.state = state;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** The composite program made, and no copy yet, as the context comes or comes back. */
|
|
100
|
+
setUp(): void {
|
|
101
|
+
const gl = this.gl;
|
|
102
|
+
this.composite = linkProgram(gl, compositeVertex, compositeFragment);
|
|
103
|
+
this.state.useProgram(this.composite);
|
|
104
|
+
gl.uniform1i(gl.getUniformLocation(this.composite, "uLayer"), LAYER_UNIT);
|
|
105
|
+
gl.uniform1i(gl.getUniformLocation(this.composite, "uBack"), BACK_UNIT);
|
|
106
|
+
gl.uniform1i(gl.getUniformLocation(this.composite, "uRows"), 0);
|
|
107
|
+
this.modeLocation = gl.getUniformLocation(this.composite, "uMode");
|
|
108
|
+
this.compositeRowLocation = gl.getUniformLocation(this.composite, "uRow");
|
|
109
|
+
this.offsetLocation = gl.getUniformLocation(this.composite, "uOffset");
|
|
110
|
+
this.flipLocation = gl.getUniformLocation(this.composite, "uFlip");
|
|
111
|
+
this.backOffsetLocation = gl.getUniformLocation(this.composite, "uBackOffset");
|
|
112
|
+
this.rectLocation = gl.getUniformLocation(this.composite, "uRect");
|
|
113
|
+
this.back = null;
|
|
114
|
+
this.backFramebuffer = null;
|
|
115
|
+
this.backWidth = 0;
|
|
116
|
+
this.backHeight = 0;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* `open` composited onto `under`, bound, in blend mode `mode`, coloured by
|
|
121
|
+
* row `row` (or -1), over its rectangle alone: through GL's blending where
|
|
122
|
+
* it computes Flash's blend, else from a copy of what is below there, the
|
|
123
|
+
* result replacing it. Its rectangle is cut to `under`'s, as a filtered
|
|
124
|
+
* one may reach past the canvas; in `under`'s framebuffer its rows run
|
|
125
|
+
* up on the canvas and down in a layer.
|
|
126
|
+
*/
|
|
127
|
+
compositeLayer(open: Open, under: Open, given: number, row: number): void {
|
|
128
|
+
const gl = this.gl;
|
|
129
|
+
// A blend shader that will not link, of too many images, or with an image gone, composites as
|
|
130
|
+
// normal.
|
|
131
|
+
const kernel = given >= KERNEL ? this.useKernel(given - KERNEL) : null;
|
|
132
|
+
const mode = given >= KERNEL && !kernel ? NORMAL : given;
|
|
133
|
+
const state = this.state;
|
|
134
|
+
const reads = readsBelow(mode, under.opaque);
|
|
135
|
+
if (!this.cover(open, under) || (reads && !this.copyBelow(under))) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const { dx, dy, x0, y0, width, height, fx, fy, backX, backY } = this.place;
|
|
140
|
+
const flip = !under.layer;
|
|
141
|
+
state.bindTexture(LAYER_UNIT, (open.layer as Layer).texture);
|
|
142
|
+
state.bindSampler(LAYER_UNIT, null);
|
|
143
|
+
state.bindSampler(BACK_UNIT, null);
|
|
144
|
+
state.bindVertexArray(null);
|
|
145
|
+
// Less its corner on its page, where it is a held layer's rectangle of one (HELD), and past
|
|
146
|
+
// the target's, where that is one.
|
|
147
|
+
const ox = (under.ox ?? 0) - (open.ox ?? 0);
|
|
148
|
+
const oy = (under.oy ?? 0) - (open.oy ?? 0);
|
|
149
|
+
const offsetY = flip ? under.height - 1 - dy - oy : dy + oy;
|
|
150
|
+
if (kernel) {
|
|
151
|
+
const filters = this.host.filters() as Filters;
|
|
152
|
+
const entry = filters.chains[mode - KERNEL];
|
|
153
|
+
state.useProgram(kernel.program);
|
|
154
|
+
gl.uniform1i(kernel.at("uRow"), row);
|
|
155
|
+
gl.uniform2i(kernel.at("uOffset"), dx + ox, offsetY);
|
|
156
|
+
gl.uniform1i(kernel.at("uFlip"), flip ? 1 : 0);
|
|
157
|
+
gl.uniform2i(kernel.at("uBackOffset"), backX, backY);
|
|
158
|
+
gl.uniform1i(kernel.at("uWhole"), filters.values[filters.start[entry]]);
|
|
159
|
+
this.kernels.setUniforms(kernel, filters, entry, this.host);
|
|
160
|
+
} else {
|
|
161
|
+
state.useProgram(this.composite);
|
|
162
|
+
// Its pixel alone where GL's blending computes the mode (MULTIPLY over an opaque target).
|
|
163
|
+
gl.uniform1i(this.modeLocation, reads ? mode : NORMAL);
|
|
164
|
+
gl.uniform1i(this.compositeRowLocation, row);
|
|
165
|
+
gl.uniform2i(this.offsetLocation, dx + ox, offsetY);
|
|
166
|
+
gl.uniform1i(this.flipLocation, flip ? 1 : 0);
|
|
167
|
+
gl.uniform2i(this.backOffsetLocation, backX, backY);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
setModeBlend(gl, state, reads ? -1 : mode);
|
|
171
|
+
// Over the rectangle alone, in the target's clip space; the scissor keeps it to whole pixels.
|
|
172
|
+
const tw = under.width;
|
|
173
|
+
const th = under.height;
|
|
174
|
+
gl.uniform4f(
|
|
175
|
+
kernel ? kernel.at("uRect") : this.rectLocation,
|
|
176
|
+
(2 * x0) / tw - 1,
|
|
177
|
+
(2 * y0) / th - 1,
|
|
178
|
+
(2 * (x0 + width)) / tw - 1,
|
|
179
|
+
(2 * (y0 + height)) / th - 1,
|
|
180
|
+
);
|
|
181
|
+
state.scissor([fx, fy, width, height]);
|
|
182
|
+
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
183
|
+
state.scissor(null);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** Where cover last found a rectangle on its target, and where copyBelow copied what is below it. */
|
|
187
|
+
readonly place = {
|
|
188
|
+
dx: 0,
|
|
189
|
+
dy: 0,
|
|
190
|
+
x0: 0,
|
|
191
|
+
y0: 0,
|
|
192
|
+
width: 0,
|
|
193
|
+
height: 0,
|
|
194
|
+
fx: 0,
|
|
195
|
+
fy: 0,
|
|
196
|
+
backX: 0,
|
|
197
|
+
backY: 0,
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Where `rect` lies on `under`, into place: cut to `under`'s, as a
|
|
202
|
+
* filtered layer may reach past the canvas; in `under`'s framebuffer its
|
|
203
|
+
* rows run up on the canvas and down in a layer. Whether any of it does.
|
|
204
|
+
*/
|
|
205
|
+
cover(rect: { x: number; y: number; width: number; height: number }, under: Open): boolean {
|
|
206
|
+
const place = this.place;
|
|
207
|
+
const dx = rect.x - under.x;
|
|
208
|
+
const dy = rect.y - under.y;
|
|
209
|
+
const y = under.layer ? dy : under.height - dy - rect.height;
|
|
210
|
+
place.dx = dx;
|
|
211
|
+
place.dy = dy;
|
|
212
|
+
place.x0 = Math.max(0, dx);
|
|
213
|
+
place.y0 = Math.max(0, y);
|
|
214
|
+
place.width = Math.min(under.width, dx + rect.width) - place.x0;
|
|
215
|
+
place.height = Math.min(under.height, y + rect.height) - place.y0;
|
|
216
|
+
// The rectangle's corner in the target's framebuffer, where the target is a held layer's
|
|
217
|
+
// rectangle of a page (HOLD_PUSH).
|
|
218
|
+
place.fx = place.x0 + (under.ox ?? 0);
|
|
219
|
+
place.fy = place.y0 + (under.oy ?? 0);
|
|
220
|
+
// Where the copy of what is below has the rectangle's corner, less where the target has it.
|
|
221
|
+
place.backX = 0;
|
|
222
|
+
place.backY = 0;
|
|
223
|
+
return place.width > 0 && place.height > 0;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* What is below the rectangle cover found copied, for a blend that reads
|
|
228
|
+
* it: bound to BACK_UNIT, where the copy has the rectangle's corner, less
|
|
229
|
+
* where the target has it, into place, and `under`'s framebuffer bound again.
|
|
230
|
+
*/
|
|
231
|
+
copyBelow(under: Open): boolean {
|
|
232
|
+
const gl = this.gl;
|
|
233
|
+
const state = this.state;
|
|
234
|
+
const { fx, fy, width, height } = this.place;
|
|
235
|
+
// Out of a multisampled page, its rectangle resolved into the page's own texture first, which
|
|
236
|
+
// a blit may then copy anywhere: copied where it lies, the copy would stay as large as the
|
|
237
|
+
// page's far corner.
|
|
238
|
+
let from = framebufferOf(under);
|
|
239
|
+
const paged = under.msaa !== null && under.layer !== null && under.ox !== undefined;
|
|
240
|
+
if (paged) {
|
|
241
|
+
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, from);
|
|
242
|
+
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, (under.layer as Layer).framebuffer);
|
|
243
|
+
gl.blitFramebuffer(
|
|
244
|
+
fx,
|
|
245
|
+
fy,
|
|
246
|
+
fx + width,
|
|
247
|
+
fy + height,
|
|
248
|
+
fx,
|
|
249
|
+
fy,
|
|
250
|
+
fx + width,
|
|
251
|
+
fy + height,
|
|
252
|
+
gl.COLOR_BUFFER_BIT,
|
|
253
|
+
gl.NEAREST,
|
|
254
|
+
);
|
|
255
|
+
from = (under.layer as Layer).framebuffer;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Copied from its corner, or out of a multisampled target to where it lies, as a blit
|
|
259
|
+
// resolving must keep its rectangle: then as large as the rectangle's far corner.
|
|
260
|
+
const bx = under.msaa && !paged ? fx : 0;
|
|
261
|
+
const by = under.msaa && !paged ? fy : 0;
|
|
262
|
+
this.place.backX = fx - bx;
|
|
263
|
+
this.place.backY = fy - by;
|
|
264
|
+
const right = bx + width;
|
|
265
|
+
const top = by + height;
|
|
266
|
+
if (!this.back || this.backWidth < right || this.backHeight < top) {
|
|
267
|
+
if (this.back) {
|
|
268
|
+
state.dropTexture(this.back);
|
|
269
|
+
gl.deleteTexture(this.back);
|
|
270
|
+
gl.deleteFramebuffer(this.backFramebuffer);
|
|
271
|
+
this.backFramebuffer = null;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
this.back = gl.createTexture() as WebGLTexture;
|
|
275
|
+
this.backWidth = Math.max(this.backWidth, Math.ceil(right / LAYER_STEP) * LAYER_STEP);
|
|
276
|
+
this.backHeight = Math.max(this.backHeight, Math.ceil(top / LAYER_STEP) * LAYER_STEP);
|
|
277
|
+
state.bindTexture(BACK_UNIT, this.back);
|
|
278
|
+
state.activeTexture(BACK_UNIT);
|
|
279
|
+
gl.texImage2D(
|
|
280
|
+
gl.TEXTURE_2D,
|
|
281
|
+
0,
|
|
282
|
+
gl.RGBA8,
|
|
283
|
+
this.backWidth,
|
|
284
|
+
this.backHeight,
|
|
285
|
+
0,
|
|
286
|
+
gl.RGBA,
|
|
287
|
+
gl.UNSIGNED_BYTE,
|
|
288
|
+
null,
|
|
289
|
+
);
|
|
290
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
291
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Blitted, not copied: the canvas' colour may have no alpha, which copyTexSubImage2D into an
|
|
295
|
+
// RGBA texture refuses, where a blit fills it in.
|
|
296
|
+
// Out of a multisampled target the blit resolves the rectangle alone.
|
|
297
|
+
if (!this.backFramebuffer) {
|
|
298
|
+
this.backFramebuffer = gl.createFramebuffer() as WebGLFramebuffer;
|
|
299
|
+
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.backFramebuffer);
|
|
300
|
+
gl.framebufferTexture2D(
|
|
301
|
+
gl.DRAW_FRAMEBUFFER,
|
|
302
|
+
gl.COLOR_ATTACHMENT0,
|
|
303
|
+
gl.TEXTURE_2D,
|
|
304
|
+
this.back,
|
|
305
|
+
0,
|
|
306
|
+
);
|
|
307
|
+
} else {
|
|
308
|
+
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.backFramebuffer);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, from);
|
|
312
|
+
gl.blitFramebuffer(
|
|
313
|
+
fx,
|
|
314
|
+
fy,
|
|
315
|
+
fx + width,
|
|
316
|
+
fy + height,
|
|
317
|
+
bx,
|
|
318
|
+
by,
|
|
319
|
+
right,
|
|
320
|
+
top,
|
|
321
|
+
gl.COLOR_BUFFER_BIT,
|
|
322
|
+
gl.NEAREST,
|
|
323
|
+
);
|
|
324
|
+
// Both bindings back as the state cache has them.
|
|
325
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, framebufferOf(under));
|
|
326
|
+
state.bindTexture(BACK_UNIT, this.back);
|
|
327
|
+
state.bindSampler(BACK_UNIT, null);
|
|
328
|
+
return true;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* The program of the blend shader of chain `chain` of the frame's
|
|
333
|
+
* filters (KernelPrograms), in use; null for none, one that would not
|
|
334
|
+
* link, one of more images than a program binds, or one whose image is gone.
|
|
335
|
+
*/
|
|
336
|
+
private useKernel(chain: number): KernelProgram | null {
|
|
337
|
+
const filters = this.host.filters();
|
|
338
|
+
if (!filters || chain >= filters.chainCount) {
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const i = filters.chains[chain];
|
|
343
|
+
const source = filters.kernels[i];
|
|
344
|
+
const images =
|
|
345
|
+
source && filters.kind[i] === BLEND ? this.kernels.readImages(filters, i, this.host) : null;
|
|
346
|
+
if (!source || !images || !kernelImagesFit(images)) {
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return this.kernels.use(
|
|
351
|
+
compositeVertex,
|
|
352
|
+
blendKernel(source, images, LAYER_COLOR),
|
|
353
|
+
(program) => {
|
|
354
|
+
const gl = this.gl;
|
|
355
|
+
gl.uniform1i(gl.getUniformLocation(program, "uLayer"), LAYER_UNIT);
|
|
356
|
+
gl.uniform1i(gl.getUniformLocation(program, "uBack"), BACK_UNIT);
|
|
357
|
+
gl.uniform1i(gl.getUniformLocation(program, "uRows"), 0);
|
|
358
|
+
},
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/** The program and the copy made on the context, deleted. */
|
|
363
|
+
destroy(): void {
|
|
364
|
+
const gl = this.gl;
|
|
365
|
+
gl.deleteProgram(this.composite);
|
|
366
|
+
|
|
367
|
+
if (this.back) {
|
|
368
|
+
gl.deleteTexture(this.back);
|
|
369
|
+
gl.deleteFramebuffer(this.backFramebuffer);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|