@swf2es/render 0.0.0-stage → 0.1.0
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,714 @@
|
|
|
1
|
+
import { linkProgram } from "@swf2es/context3d/device";
|
|
2
|
+
import { RUN, STENCIL_POP, STENCIL_PUSH } from "../commands.js";
|
|
3
|
+
import { FILL_SHADER } from "../filters.js";
|
|
4
|
+
import { fillKernel, kernelImagesFit } from "../kernel-shaders.js";
|
|
5
|
+
import { CLAMP, DRAW, MESH, MIRROR, NORMAL, PLANE, REPEAT, SHADED, SMOOTH, SNAP, } from "../scene.js";
|
|
6
|
+
import { setModeBlend } from "./composite.js";
|
|
7
|
+
import { BACK_UNIT, blendFillFragment, FILL_SLOT, FILL_TEXTURES, FILL_UNIT, fillFragment, fillVertex, glyphsFragment, glyphsVertex, meshFragment, meshVertex, OUTLINE_UNIT, RUN_MOST, RUN_UNIT, SNAP_BIT, TEXTURE_UNIT, } from "./programs.js";
|
|
8
|
+
import { framebufferOf } from "./targets.js";
|
|
9
|
+
/** Last scene entry, table start, draw count, used units, then each unit's texture and sampling. */
|
|
10
|
+
const RUN_STRIDE = 4 + FILL_TEXTURES * 2;
|
|
11
|
+
/** The most masks the stencil's eight bits count. */
|
|
12
|
+
const STENCIL_MOST = 255;
|
|
13
|
+
/**
|
|
14
|
+
* The draws of a scene list's entries into the target bound: fills in runs,
|
|
15
|
+
* one multi-draw of the atlas's index ranges a run where WEBGL_multi_draw
|
|
16
|
+
* is, meshes and advanced text's glyphs each by a program of its own, and
|
|
17
|
+
* the masks' coverage into the stencil; and the view of the target drawn
|
|
18
|
+
* into, which each program is told.
|
|
19
|
+
*/
|
|
20
|
+
export class Draws {
|
|
21
|
+
host;
|
|
22
|
+
kernels;
|
|
23
|
+
gl;
|
|
24
|
+
state;
|
|
25
|
+
atlas;
|
|
26
|
+
gpu;
|
|
27
|
+
pool;
|
|
28
|
+
/** The fill program, and where it takes its row, view and Flash's pixels a stage pixel. */
|
|
29
|
+
program;
|
|
30
|
+
rowLocation = null;
|
|
31
|
+
viewLocation = null;
|
|
32
|
+
fillUnitLocation = null;
|
|
33
|
+
/**
|
|
34
|
+
* The fill program that blends a fill straight onto what is below it
|
|
35
|
+
* (drawBlended), a draw a call, and where it takes what the fill program
|
|
36
|
+
* does and the blend's mode, its layer's row and where the copy of what
|
|
37
|
+
* is below lies.
|
|
38
|
+
*/
|
|
39
|
+
blendProgram;
|
|
40
|
+
blendRowLocation = null;
|
|
41
|
+
blendViewLocation = null;
|
|
42
|
+
blendUnitLocation = null;
|
|
43
|
+
blendModeLocation = null;
|
|
44
|
+
blendLayerRowLocation = null;
|
|
45
|
+
blendBackLocation = null;
|
|
46
|
+
/** WEBGL_multi_draw, which draws a run of fills alike a call (drawEntries), where there is. */
|
|
47
|
+
multi = null;
|
|
48
|
+
/** Avoid the dynamically indexed uniform table used in the Intel GPU hang reproducer. */
|
|
49
|
+
runTable = null;
|
|
50
|
+
runBaseLocation = null;
|
|
51
|
+
runTableHeight = 0;
|
|
52
|
+
runTableMost = 0;
|
|
53
|
+
tableRows = new Int32Array(RUN_MOST);
|
|
54
|
+
tableCounts = new Int32Array(RUN_MOST);
|
|
55
|
+
tableOffsets = new Int32Array(RUN_MOST);
|
|
56
|
+
runs = new Int32Array(RUN_STRIDE * 256);
|
|
57
|
+
commandStarts = new Uint32Array(256);
|
|
58
|
+
prepared = false;
|
|
59
|
+
/** A run's draws: their index counts, their offsets in bytes, and their rows (FILL_SLOT). */
|
|
60
|
+
runCounts = new Int32Array(RUN_MOST);
|
|
61
|
+
runOffsets = new Int32Array(RUN_MOST);
|
|
62
|
+
runRows = new Int32Array(RUN_MOST);
|
|
63
|
+
/** Draws gathered by gatherRun, and the fill units they sample, a bit each. */
|
|
64
|
+
runCount = 0;
|
|
65
|
+
runUnits = 0;
|
|
66
|
+
/**
|
|
67
|
+
* The texture and sampling each fill unit was last given (runSlot), -1 for
|
|
68
|
+
* none, and the unit to take next when every one holds a texture.
|
|
69
|
+
*/
|
|
70
|
+
unitIds = new Int32Array(FILL_TEXTURES).fill(-1);
|
|
71
|
+
unitSampling = new Int32Array(FILL_TEXTURES);
|
|
72
|
+
unitNext = 0;
|
|
73
|
+
/** The meshes' program (MESH), and where it takes its row, view, fragments' place and mode. */
|
|
74
|
+
mesh;
|
|
75
|
+
meshRowLocation = null;
|
|
76
|
+
meshViewLocation = null;
|
|
77
|
+
meshFragLocation = null;
|
|
78
|
+
meshModeLocation = null;
|
|
79
|
+
/**
|
|
80
|
+
* The view the target drawn into gives the fill program, and where its
|
|
81
|
+
* fragments lie from the stage's origin (meshFragment's uFrag): told the
|
|
82
|
+
* mesh program as it next draws a mesh, once they change (meshStale).
|
|
83
|
+
*/
|
|
84
|
+
view = new Float32Array(4);
|
|
85
|
+
frag = new Float32Array(4);
|
|
86
|
+
meshStale = true;
|
|
87
|
+
/** The row and mode (REPEAT, SMOOTH) the mesh program was told last, -1 for none. */
|
|
88
|
+
meshRow = -1;
|
|
89
|
+
meshMode = -1;
|
|
90
|
+
/**
|
|
91
|
+
* Advanced text's program (GeometryData.glyphs), where it takes its row, view, Flash's
|
|
92
|
+
* pixels a stage pixel, mode and table; its vertices are in an atlas of their own.
|
|
93
|
+
*/
|
|
94
|
+
glyphProgram;
|
|
95
|
+
glyphRowLocation = null;
|
|
96
|
+
glyphViewLocation = null;
|
|
97
|
+
glyphUnitLocation = null;
|
|
98
|
+
glyphModeLocation = null;
|
|
99
|
+
glyphTableLocation = null;
|
|
100
|
+
glyphStale = true;
|
|
101
|
+
/** Flash's pixels a stage pixel: the target's pixels a stage pixel over those a pixel of Flash's. */
|
|
102
|
+
unit = 1;
|
|
103
|
+
/**
|
|
104
|
+
* The row a fill drawn alone (without WEBGL_multi_draw) last told the fill
|
|
105
|
+
* program, so that it is not told again; -1 for none (forgetRow).
|
|
106
|
+
*/
|
|
107
|
+
lastRow = -1;
|
|
108
|
+
/** Each shader fill's fragment shader by its entry in the frame's filters, for the generation it is of. */
|
|
109
|
+
fillShaders = new Map();
|
|
110
|
+
/** A shader fill's program as it is linked: its rows' unit. */
|
|
111
|
+
prepareFill = (program) => {
|
|
112
|
+
this.gl.uniform1i(this.gl.getUniformLocation(program, "uRows"), 0);
|
|
113
|
+
};
|
|
114
|
+
fillFilters = null;
|
|
115
|
+
fillGeneration = -1;
|
|
116
|
+
constructor(gl, state, atlas, gpu, pool,
|
|
117
|
+
/** Where shader fills find the frame's filters, whose chains their draws name (SHADED). */
|
|
118
|
+
host,
|
|
119
|
+
/** Shader fills' programs, the backend's one cache of kernels'. */
|
|
120
|
+
kernels) {
|
|
121
|
+
this.host = host;
|
|
122
|
+
this.kernels = kernels;
|
|
123
|
+
this.gl = gl;
|
|
124
|
+
this.state = state;
|
|
125
|
+
this.atlas = atlas;
|
|
126
|
+
this.gpu = gpu;
|
|
127
|
+
this.pool = pool;
|
|
128
|
+
}
|
|
129
|
+
/** The fill, mesh and glyph programs made, as the context comes or comes back. */
|
|
130
|
+
setUp(textureMost) {
|
|
131
|
+
const gl = this.gl;
|
|
132
|
+
this.multi = gl.getExtension("WEBGL_multi_draw");
|
|
133
|
+
try {
|
|
134
|
+
this.program = linkProgram(gl, fillVertex(this.multi !== null), fillFragment);
|
|
135
|
+
}
|
|
136
|
+
catch (e) {
|
|
137
|
+
if (!this.multi) {
|
|
138
|
+
throw e;
|
|
139
|
+
}
|
|
140
|
+
// An extension offered whose shader directive the compiler refuses: a call a draw.
|
|
141
|
+
this.multi = null;
|
|
142
|
+
this.program = linkProgram(gl, fillVertex(false), fillFragment);
|
|
143
|
+
}
|
|
144
|
+
this.unitIds.fill(-1);
|
|
145
|
+
this.rowLocation = gl.getUniformLocation(this.program, "uRow");
|
|
146
|
+
this.viewLocation = gl.getUniformLocation(this.program, "uView");
|
|
147
|
+
this.state.useProgram(this.program);
|
|
148
|
+
gl.uniform1i(gl.getUniformLocation(this.program, "uRows"), 0);
|
|
149
|
+
gl.uniform1iv(gl.getUniformLocation(this.program, "uTextures"), Array.from({ length: FILL_TEXTURES }, (_, k) => FILL_UNIT + k));
|
|
150
|
+
this.runTable = null;
|
|
151
|
+
this.runTableHeight = 0;
|
|
152
|
+
this.runTableMost = textureMost;
|
|
153
|
+
this.prepared = false;
|
|
154
|
+
this.runBaseLocation = gl.getUniformLocation(this.program, "uRunBase");
|
|
155
|
+
if (this.multi) {
|
|
156
|
+
this.sizeRunTable(1);
|
|
157
|
+
gl.uniform1i(gl.getUniformLocation(this.program, "uRunTable"), RUN_UNIT);
|
|
158
|
+
}
|
|
159
|
+
this.fillUnitLocation = gl.getUniformLocation(this.program, "uUnit");
|
|
160
|
+
this.blendProgram = linkProgram(gl, fillVertex(false), blendFillFragment);
|
|
161
|
+
this.blendRowLocation = gl.getUniformLocation(this.blendProgram, "uRow");
|
|
162
|
+
this.blendViewLocation = gl.getUniformLocation(this.blendProgram, "uView");
|
|
163
|
+
this.blendUnitLocation = gl.getUniformLocation(this.blendProgram, "uUnit");
|
|
164
|
+
this.blendModeLocation = gl.getUniformLocation(this.blendProgram, "uMode");
|
|
165
|
+
this.blendLayerRowLocation = gl.getUniformLocation(this.blendProgram, "uLayerRow");
|
|
166
|
+
this.blendBackLocation = gl.getUniformLocation(this.blendProgram, "uBackOffset");
|
|
167
|
+
this.state.useProgram(this.blendProgram);
|
|
168
|
+
gl.uniform1i(gl.getUniformLocation(this.blendProgram, "uRows"), 0);
|
|
169
|
+
gl.uniform1i(gl.getUniformLocation(this.blendProgram, "uBack"), BACK_UNIT);
|
|
170
|
+
gl.uniform1iv(gl.getUniformLocation(this.blendProgram, "uTextures"), Array.from({ length: FILL_TEXTURES }, (_, k) => FILL_UNIT + k));
|
|
171
|
+
this.mesh = linkProgram(gl, meshVertex, meshFragment);
|
|
172
|
+
this.meshRowLocation = gl.getUniformLocation(this.mesh, "uRow");
|
|
173
|
+
this.meshViewLocation = gl.getUniformLocation(this.mesh, "uView");
|
|
174
|
+
this.meshFragLocation = gl.getUniformLocation(this.mesh, "uFrag");
|
|
175
|
+
this.meshModeLocation = gl.getUniformLocation(this.mesh, "uMode");
|
|
176
|
+
this.state.useProgram(this.mesh);
|
|
177
|
+
gl.uniform1i(gl.getUniformLocation(this.mesh, "uRows"), 0);
|
|
178
|
+
gl.uniform1i(gl.getUniformLocation(this.mesh, "uTexture"), TEXTURE_UNIT);
|
|
179
|
+
this.meshStale = true;
|
|
180
|
+
this.meshRow = -1;
|
|
181
|
+
this.meshMode = -1;
|
|
182
|
+
this.glyphProgram = linkProgram(gl, glyphsVertex, glyphsFragment);
|
|
183
|
+
this.glyphRowLocation = gl.getUniformLocation(this.glyphProgram, "uRow");
|
|
184
|
+
this.glyphViewLocation = gl.getUniformLocation(this.glyphProgram, "uView");
|
|
185
|
+
this.glyphUnitLocation = gl.getUniformLocation(this.glyphProgram, "uUnit");
|
|
186
|
+
this.glyphModeLocation = gl.getUniformLocation(this.glyphProgram, "uMode");
|
|
187
|
+
this.glyphTableLocation = gl.getUniformLocation(this.glyphProgram, "uTable");
|
|
188
|
+
this.state.useProgram(this.glyphProgram);
|
|
189
|
+
gl.uniform1i(gl.getUniformLocation(this.glyphProgram, "uRows"), 0);
|
|
190
|
+
gl.uniform1i(gl.getUniformLocation(this.glyphProgram, "uSegments"), OUTLINE_UNIT);
|
|
191
|
+
this.glyphStale = true;
|
|
192
|
+
this.lastRow = -1;
|
|
193
|
+
}
|
|
194
|
+
/** Upload before any draws, so that updating a run cannot stall earlier draws reading it. */
|
|
195
|
+
prepare(commands, scene) {
|
|
196
|
+
this.prepared = false;
|
|
197
|
+
if (!this.multi) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (commands.length > this.commandStarts.length) {
|
|
201
|
+
this.commandStarts = new Uint32Array(commands.ops.length / 4);
|
|
202
|
+
}
|
|
203
|
+
let count = 0;
|
|
204
|
+
let run = 0;
|
|
205
|
+
const ops = commands.ops;
|
|
206
|
+
for (let k = 0; k < commands.length; k++) {
|
|
207
|
+
const at = k * 4;
|
|
208
|
+
const op = ops[at];
|
|
209
|
+
if (op !== RUN && op !== STENCIL_PUSH && op !== STENCIL_POP) {
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
const stencil = op !== RUN;
|
|
213
|
+
const end = ops[at + 1] + ops[at + 2];
|
|
214
|
+
this.commandStarts[k] = run;
|
|
215
|
+
// Held layers execute in a different order. Save each run's bindings independently
|
|
216
|
+
// of the commands executed before it.
|
|
217
|
+
this.unitIds.fill(-1);
|
|
218
|
+
this.unitNext = 0;
|
|
219
|
+
for (let i = ops[at + 1]; i < end; i++) {
|
|
220
|
+
if (scene.kind[i] !== DRAW) {
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
const place = this.atlas.places[scene.geometry[i]];
|
|
224
|
+
if (!place || place.glyphs || (!stencil && scene.sampler[i] & (MESH | PLANE | SHADED))) {
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
i = this.gatherRun(scene, i, end, stencil);
|
|
228
|
+
const needed = count + this.runCount;
|
|
229
|
+
if (needed > RUN_MOST * this.runTableMost) {
|
|
230
|
+
// An unusually large frame still draws by updating the first row a run at a time.
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (needed > this.tableRows.length) {
|
|
234
|
+
const size = Math.min(RUN_MOST * this.runTableMost, Math.max(needed, this.tableRows.length * 2));
|
|
235
|
+
const rows = new Int32Array(size);
|
|
236
|
+
rows.set(this.tableRows);
|
|
237
|
+
this.tableRows = rows;
|
|
238
|
+
const counts = new Int32Array(size);
|
|
239
|
+
counts.set(this.tableCounts);
|
|
240
|
+
this.tableCounts = counts;
|
|
241
|
+
const offsets = new Int32Array(size);
|
|
242
|
+
offsets.set(this.tableOffsets);
|
|
243
|
+
this.tableOffsets = offsets;
|
|
244
|
+
}
|
|
245
|
+
if (run + RUN_STRIDE > this.runs.length) {
|
|
246
|
+
const runs = new Int32Array(this.runs.length * 2);
|
|
247
|
+
runs.set(this.runs);
|
|
248
|
+
this.runs = runs;
|
|
249
|
+
}
|
|
250
|
+
this.runs[run] = i;
|
|
251
|
+
this.runs[run + 1] = count;
|
|
252
|
+
this.runs[run + 2] = this.runCount;
|
|
253
|
+
this.runs[run + 3] = this.runUnits;
|
|
254
|
+
for (let j = 0; j < FILL_TEXTURES; j++) {
|
|
255
|
+
if (this.runUnits & (1 << j)) {
|
|
256
|
+
this.runs[run + 4 + j * 2] = this.unitIds[j];
|
|
257
|
+
this.runs[run + 5 + j * 2] = this.unitSampling[j];
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
run += RUN_STRIDE;
|
|
261
|
+
for (let j = 0; j < this.runCount; j++) {
|
|
262
|
+
this.tableRows[count] = this.runRows[j];
|
|
263
|
+
this.tableCounts[count] = this.runCounts[j];
|
|
264
|
+
this.tableOffsets[count++] = this.runOffsets[j];
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
const height = Math.ceil(count / RUN_MOST);
|
|
269
|
+
if (height > 0) {
|
|
270
|
+
this.sizeRunTable(height);
|
|
271
|
+
const gl = this.gl;
|
|
272
|
+
this.state.bindTexture(RUN_UNIT, this.runTable);
|
|
273
|
+
this.state.activeTexture(RUN_UNIT);
|
|
274
|
+
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, RUN_MOST, height, gl.RED_INTEGER, gl.INT, this.tableRows);
|
|
275
|
+
}
|
|
276
|
+
this.prepared = true;
|
|
277
|
+
}
|
|
278
|
+
sizeRunTable(height) {
|
|
279
|
+
if (height <= this.runTableHeight) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const gl = this.gl;
|
|
283
|
+
if (this.runTable) {
|
|
284
|
+
this.state.dropTexture(this.runTable);
|
|
285
|
+
gl.deleteTexture(this.runTable);
|
|
286
|
+
}
|
|
287
|
+
this.runTableHeight = Math.min(this.runTableMost, Math.max(height, this.runTableHeight * 2));
|
|
288
|
+
this.runTable = gl.createTexture();
|
|
289
|
+
this.state.bindTexture(RUN_UNIT, this.runTable);
|
|
290
|
+
this.state.activeTexture(RUN_UNIT);
|
|
291
|
+
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.R32I, RUN_MOST, this.runTableHeight);
|
|
292
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
293
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Draw into `open` from here on: its framebuffer bound, its viewport its
|
|
297
|
+
* rectangle's size, and the stage placed on it as on the canvas, its
|
|
298
|
+
* rectangle's corner the origin, its rows running up on the canvas and
|
|
299
|
+
* down in a layer. The fill program takes the view.
|
|
300
|
+
*/
|
|
301
|
+
drawInto(open, target) {
|
|
302
|
+
const gl = this.gl;
|
|
303
|
+
const state = this.state;
|
|
304
|
+
const ox = open.ox ?? 0;
|
|
305
|
+
const oy = open.oy ?? 0;
|
|
306
|
+
state.bindFramebuffer(framebufferOf(open));
|
|
307
|
+
state.viewport(ox, oy, open.width, open.height);
|
|
308
|
+
state.useProgram(this.program);
|
|
309
|
+
const down = open.layer ? 1 : -1;
|
|
310
|
+
const view = this.view;
|
|
311
|
+
view[0] = (2 * target.scale) / open.width;
|
|
312
|
+
view[1] = (down * 2 * target.scale) / open.height;
|
|
313
|
+
view[2] = -1 + (2 * (target.x - open.x)) / open.width;
|
|
314
|
+
view[3] = -down * (1 - (2 * (target.y - open.y)) / open.height);
|
|
315
|
+
gl.uniform4fv(this.viewLocation, view);
|
|
316
|
+
// A layer's rows run down from its corner; the canvas' up from its bottom.
|
|
317
|
+
const frag = this.frag;
|
|
318
|
+
frag[0] = open.x - target.x - ox;
|
|
319
|
+
frag[1] = (open.layer ? open.y : open.y + open.height) - target.y - oy;
|
|
320
|
+
frag[2] = down;
|
|
321
|
+
frag[3] = target.pixel;
|
|
322
|
+
this.unit = target.scale / target.pixel;
|
|
323
|
+
gl.uniform1f(this.fillUnitLocation, this.unit);
|
|
324
|
+
this.meshStale = true;
|
|
325
|
+
this.glyphStale = true;
|
|
326
|
+
}
|
|
327
|
+
/** The row the fill program was told forgotten, so that the next fill tells it again. */
|
|
328
|
+
forgetRow() {
|
|
329
|
+
this.lastRow = -1;
|
|
330
|
+
}
|
|
331
|
+
/** The fill program, its vertex array and rows bound, as runs and masks draw with them. */
|
|
332
|
+
useFill() {
|
|
333
|
+
this.state.useProgram(this.program);
|
|
334
|
+
this.state.bindVertexArray(this.atlas.vertexArray);
|
|
335
|
+
this.state.bindTexture(0, this.gpu.rowsTexture);
|
|
336
|
+
}
|
|
337
|
+
/** Entries `first` up to `end` drawn as fills, where the masks pushed pass. */
|
|
338
|
+
drawRun(scene, first, end, command) {
|
|
339
|
+
const gl = this.gl;
|
|
340
|
+
// Premultiplied, as every blend mode will be.
|
|
341
|
+
this.useFill();
|
|
342
|
+
this.state.setBlend(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
343
|
+
this.drawEntries(scene, first, end, false, command);
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Whether entry `i` is a flat fill (GeometryData.flat), a bitmap's quad or
|
|
347
|
+
* one fill of a shape, of no mesh, shader fill or text, whose texture, if
|
|
348
|
+
* it samples one, is there. Drawn straight onto what is below in a blend
|
|
349
|
+
* mode, it is as its layer would be composited, as no part of it is over
|
|
350
|
+
* another.
|
|
351
|
+
*/
|
|
352
|
+
blendable(scene, i) {
|
|
353
|
+
if (scene.kind[i] !== DRAW || scene.sampler[i] & (MESH | PLANE | SHADED)) {
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
const place = this.atlas.places[scene.geometry[i]];
|
|
357
|
+
const id = scene.texture[i];
|
|
358
|
+
return !!place && place.flat && !place.glyphs && (id < 0 || !!this.gpu.textures[id]);
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Entry `i`, blendable, drawn onto the target bound in blend mode `mode`,
|
|
362
|
+
* coloured by its layer's row `layerRow` (or -1), where the masks pushed
|
|
363
|
+
* pass: GL's blending computing add, screen and, where it does not
|
|
364
|
+
* `reads` below, multiply, the program the rest from the copy of what is
|
|
365
|
+
* below (Compositor.copyBelow), whose texel at a fragment is (`backX`,
|
|
366
|
+
* `backY`) short of it.
|
|
367
|
+
*/
|
|
368
|
+
drawBlended(scene, i, mode, reads, layerRow, backX, backY) {
|
|
369
|
+
const gl = this.gl;
|
|
370
|
+
const state = this.state;
|
|
371
|
+
state.useProgram(this.blendProgram);
|
|
372
|
+
state.bindVertexArray(this.atlas.vertexArray);
|
|
373
|
+
state.bindTexture(0, this.gpu.rowsTexture);
|
|
374
|
+
gl.uniform4fv(this.blendViewLocation, this.view);
|
|
375
|
+
gl.uniform1f(this.blendUnitLocation, this.unit);
|
|
376
|
+
// Its pixel alone where GL's blending computes the mode (readsBelow).
|
|
377
|
+
gl.uniform1i(this.blendModeLocation, reads ? mode : NORMAL);
|
|
378
|
+
gl.uniform1i(this.blendLayerRowLocation, layerRow);
|
|
379
|
+
gl.uniform2i(this.blendBackLocation, backX, backY);
|
|
380
|
+
this.gatherRun(scene, i, i + 1, false);
|
|
381
|
+
if (this.runCount === 0) {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
for (let k = 0; k < FILL_TEXTURES; k++) {
|
|
385
|
+
if (this.runUnits & (1 << k)) {
|
|
386
|
+
state.bindTexture(FILL_UNIT + k, this.gpu.textures[this.unitIds[k]]);
|
|
387
|
+
state.bindSampler(FILL_UNIT + k, this.gpu.sampler(this.unitSampling[k]));
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
gl.uniform1i(this.blendRowLocation, this.runRows[0]);
|
|
391
|
+
setModeBlend(gl, state, reads ? -1 : mode);
|
|
392
|
+
gl.drawElements(gl.TRIANGLES, this.runCounts[0], gl.UNSIGNED_INT, this.runOffsets[0]);
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Entries `first` up to `end`, a mask, pushed onto `masks` (STENCIL_PUSH)
|
|
396
|
+
* or popped off them (STENCIL_POP), left out past STENCIL_MOST: its
|
|
397
|
+
* coverage, once a pixel however its fills overlap, counted up into the
|
|
398
|
+
* stencil where the masks pushed before it pass, and back down where it
|
|
399
|
+
* and they did.
|
|
400
|
+
*/
|
|
401
|
+
drawMask(scene, first, end, push, masks, command) {
|
|
402
|
+
if (push ? masks.depth >= STENCIL_MOST || masks.past > 0 : masks.past > 0) {
|
|
403
|
+
masks.past += push ? 1 : -1;
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
const gl = this.gl;
|
|
407
|
+
const state = this.state;
|
|
408
|
+
this.useFill();
|
|
409
|
+
state.colorMask(0);
|
|
410
|
+
state.stencil(gl.EQUAL, masks.depth, push ? gl.INCR : gl.DECR);
|
|
411
|
+
this.drawEntries(scene, first, end, true, command);
|
|
412
|
+
masks.depth += push ? 1 : -1;
|
|
413
|
+
state.colorMask(15);
|
|
414
|
+
this.maskBy(masks);
|
|
415
|
+
}
|
|
416
|
+
/** What is drawn from here on kept to where `masks` pass, by the stencil. */
|
|
417
|
+
maskBy(masks) {
|
|
418
|
+
const gl = this.gl;
|
|
419
|
+
this.state.stencil(masks.depth > 0 ? gl.EQUAL : null, masks.depth, gl.KEEP);
|
|
420
|
+
}
|
|
421
|
+
/** The draws at `scene`'s entries from `first` up to `end`; for the stencil alone, untextured. */
|
|
422
|
+
drawEntries(scene, first, end, stencil, command) {
|
|
423
|
+
const gl = this.gl;
|
|
424
|
+
const state = this.state;
|
|
425
|
+
const places = this.atlas.places;
|
|
426
|
+
let run = this.prepared ? this.commandStarts[command] : 0;
|
|
427
|
+
// Whether the mesh or the glyph program is in use, till the next entry of neither.
|
|
428
|
+
let other = false;
|
|
429
|
+
for (let i = first; i < end; i++) {
|
|
430
|
+
if (scene.kind[i] !== DRAW) {
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
const place = places[scene.geometry[i]];
|
|
434
|
+
if (!place) {
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
// A mesh by the mesh program; in a mask, its triangles' coverage as a fill's. Glyphs by the
|
|
438
|
+
// glyph program, in a mask too, which covers their shapes alone.
|
|
439
|
+
if (place.glyphs) {
|
|
440
|
+
this.drawGlyphs(scene, i, place);
|
|
441
|
+
other = true;
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
if (!stencil && scene.sampler[i] & (MESH | PLANE)) {
|
|
445
|
+
other = this.drawMesh(scene, i, place) || other;
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
448
|
+
if (!stencil && scene.sampler[i] & SHADED) {
|
|
449
|
+
other = this.drawShaded(scene, i, place) || other;
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
if (other) {
|
|
453
|
+
this.useFill();
|
|
454
|
+
other = false;
|
|
455
|
+
}
|
|
456
|
+
let base = 0;
|
|
457
|
+
let draws;
|
|
458
|
+
let units;
|
|
459
|
+
const bindings = run + 4;
|
|
460
|
+
if (this.prepared) {
|
|
461
|
+
i = this.runs[run];
|
|
462
|
+
base = this.runs[run + 1];
|
|
463
|
+
draws = this.runs[run + 2];
|
|
464
|
+
units = this.runs[run + 3];
|
|
465
|
+
run += RUN_STRIDE;
|
|
466
|
+
}
|
|
467
|
+
else {
|
|
468
|
+
i = this.gatherRun(scene, i, end, stencil);
|
|
469
|
+
draws = this.runCount;
|
|
470
|
+
units = this.runUnits;
|
|
471
|
+
}
|
|
472
|
+
if (draws === 0) {
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
for (let k = 0; k < FILL_TEXTURES; k++) {
|
|
476
|
+
if (units & (1 << k)) {
|
|
477
|
+
const id = this.prepared ? this.runs[bindings + k * 2] : this.unitIds[k];
|
|
478
|
+
const sampling = this.prepared ? this.runs[bindings + k * 2 + 1] : this.unitSampling[k];
|
|
479
|
+
state.bindTexture(FILL_UNIT + k, this.gpu.textures[id]);
|
|
480
|
+
state.bindSampler(FILL_UNIT + k, this.gpu.sampler(sampling));
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (!this.multi) {
|
|
484
|
+
if (this.runRows[0] !== this.lastRow) {
|
|
485
|
+
this.lastRow = this.runRows[0];
|
|
486
|
+
gl.uniform1i(this.rowLocation, this.lastRow);
|
|
487
|
+
}
|
|
488
|
+
gl.drawElements(gl.TRIANGLES, this.runCounts[0], gl.UNSIGNED_INT, this.runOffsets[0]);
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
state.bindTexture(RUN_UNIT, this.runTable);
|
|
492
|
+
state.bindSampler(RUN_UNIT, null);
|
|
493
|
+
if (!this.prepared) {
|
|
494
|
+
state.activeTexture(RUN_UNIT);
|
|
495
|
+
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, draws, 1, gl.RED_INTEGER, gl.INT, this.runRows);
|
|
496
|
+
}
|
|
497
|
+
gl.uniform1i(this.runBaseLocation, base);
|
|
498
|
+
this.multi.multiDrawElementsWEBGL(gl.TRIANGLES, this.prepared ? this.tableCounts : this.runCounts, base, gl.UNSIGNED_INT, this.prepared ? this.tableOffsets : this.runOffsets, base, draws);
|
|
499
|
+
}
|
|
500
|
+
if (other) {
|
|
501
|
+
this.useFill();
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* The fills from entry `i` on that one call draws, as many as fit its
|
|
506
|
+
* textures (FILL_TEXTURES, each with its sampling) and, without
|
|
507
|
+
* WEBGL_multi_draw, one: their runCounts, runOffsets and runRows (FILL_SLOT),
|
|
508
|
+
* and the units their textures take in runUnits. The last entry gathered,
|
|
509
|
+
* past those whose texture is gone, which draw nothing.
|
|
510
|
+
*/
|
|
511
|
+
gatherRun(scene, i, end, stencil) {
|
|
512
|
+
const places = this.atlas.places;
|
|
513
|
+
const textures = this.gpu.textures;
|
|
514
|
+
const most = this.multi ? RUN_MOST : 1;
|
|
515
|
+
let draws = 0;
|
|
516
|
+
let last = i;
|
|
517
|
+
this.runUnits = 0;
|
|
518
|
+
for (let j = i; j < end && draws < most; j++) {
|
|
519
|
+
if (scene.kind[j] !== DRAW) {
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
const place = places[scene.geometry[j]];
|
|
523
|
+
if (!place) {
|
|
524
|
+
continue;
|
|
525
|
+
}
|
|
526
|
+
if (place.glyphs || (!stencil && scene.sampler[j] & (MESH | PLANE | SHADED))) {
|
|
527
|
+
break;
|
|
528
|
+
}
|
|
529
|
+
const id = stencil ? -1 : scene.texture[j];
|
|
530
|
+
let slot = 0;
|
|
531
|
+
if (id >= 0) {
|
|
532
|
+
if (!textures[id]) {
|
|
533
|
+
last = j;
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
const sampling = scene.sampler[j] & (SMOOTH | REPEAT | MIRROR);
|
|
537
|
+
slot = this.runSlot(id, sampling);
|
|
538
|
+
if (slot === 0) {
|
|
539
|
+
break;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
this.runCounts[draws] = place.indices;
|
|
543
|
+
this.runOffsets[draws] = place.indexStart * 4;
|
|
544
|
+
this.runRows[draws] =
|
|
545
|
+
scene.row[j] | (slot << FILL_SLOT) | (scene.sampler[j] & SNAP ? SNAP_BIT : 0);
|
|
546
|
+
draws++;
|
|
547
|
+
last = j;
|
|
548
|
+
}
|
|
549
|
+
this.runCount = draws;
|
|
550
|
+
return last;
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* The slot (FILL_SLOT) of the unit texture `id` is sampled from so in the
|
|
554
|
+
* run: the one it was left on, else one the run has not taken, an empty
|
|
555
|
+
* one first, so that a texture stays where it is from run to run; 0 when
|
|
556
|
+
* the run has taken all.
|
|
557
|
+
*/
|
|
558
|
+
runSlot(id, sampling) {
|
|
559
|
+
for (let k = 0; k < FILL_TEXTURES; k++) {
|
|
560
|
+
if (this.unitIds[k] === id && this.unitSampling[k] === sampling) {
|
|
561
|
+
this.runUnits |= 1 << k;
|
|
562
|
+
return k + 1;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
let free = -1;
|
|
566
|
+
for (let n = 0; n < FILL_TEXTURES; n++) {
|
|
567
|
+
const k = (this.unitNext + n) % FILL_TEXTURES;
|
|
568
|
+
if (!(this.runUnits & (1 << k)) && (free < 0 || this.unitIds[k] < 0)) {
|
|
569
|
+
free = k;
|
|
570
|
+
if (this.unitIds[k] < 0) {
|
|
571
|
+
break;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
if (free < 0) {
|
|
576
|
+
return 0;
|
|
577
|
+
}
|
|
578
|
+
this.unitIds[free] = id;
|
|
579
|
+
this.unitSampling[free] = sampling;
|
|
580
|
+
this.unitNext = (free + 1) % FILL_TEXTURES;
|
|
581
|
+
this.runUnits |= 1 << free;
|
|
582
|
+
return free + 1;
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Entry `i`, advanced text's glyph quads (GeometryData.glyphs), drawn by the glyph
|
|
586
|
+
* program from its atlas, which is told the view as it changed, and its
|
|
587
|
+
* text's mode and table; the glyph program left in use.
|
|
588
|
+
*/
|
|
589
|
+
drawGlyphs(scene, i, place) {
|
|
590
|
+
const gl = this.gl;
|
|
591
|
+
const state = this.state;
|
|
592
|
+
const glyphs = place.glyphs;
|
|
593
|
+
state.useProgram(this.glyphProgram);
|
|
594
|
+
state.bindVertexArray(this.atlas.glyphArray);
|
|
595
|
+
if (this.glyphStale) {
|
|
596
|
+
gl.uniform4fv(this.glyphViewLocation, this.view);
|
|
597
|
+
gl.uniform1f(this.glyphUnitLocation, this.unit);
|
|
598
|
+
this.glyphStale = false;
|
|
599
|
+
}
|
|
600
|
+
gl.uniform1i(this.glyphRowLocation, scene.row[i]);
|
|
601
|
+
gl.uniform4fv(this.glyphModeLocation, glyphs.mode);
|
|
602
|
+
gl.uniform4fv(this.glyphTableLocation, glyphs.table);
|
|
603
|
+
state.bindTexture(OUTLINE_UNIT, this.gpu.outlines);
|
|
604
|
+
state.bindSampler(OUTLINE_UNIT, null);
|
|
605
|
+
gl.drawElements(gl.TRIANGLES, place.indices, gl.UNSIGNED_INT, place.indexStart * 4);
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Entry `i`, a mesh (MESH), drawn by the mesh program, which is told the
|
|
609
|
+
* view as it changed, and its row and mode as they change; whether it
|
|
610
|
+
* was drawn, the mesh program left in use.
|
|
611
|
+
*/
|
|
612
|
+
drawMesh(scene, i, place) {
|
|
613
|
+
const id = scene.texture[i];
|
|
614
|
+
const plane = (scene.sampler[i] & PLANE) !== 0;
|
|
615
|
+
const texture = id < 0
|
|
616
|
+
? null
|
|
617
|
+
: plane
|
|
618
|
+
? (this.pool.keptLayer(id)?.texture ?? null)
|
|
619
|
+
: (this.gpu.textures[id] ?? null);
|
|
620
|
+
if (!texture) {
|
|
621
|
+
return false;
|
|
622
|
+
}
|
|
623
|
+
const gl = this.gl;
|
|
624
|
+
const state = this.state;
|
|
625
|
+
state.useProgram(this.mesh);
|
|
626
|
+
// The atlas' vertices, which a glyph draw before may have left bound for its own.
|
|
627
|
+
state.bindVertexArray(this.atlas.vertexArray);
|
|
628
|
+
if (this.meshStale) {
|
|
629
|
+
gl.uniform4fv(this.meshViewLocation, this.view);
|
|
630
|
+
gl.uniform4fv(this.meshFragLocation, this.frag);
|
|
631
|
+
this.meshStale = false;
|
|
632
|
+
}
|
|
633
|
+
const row = scene.row[i];
|
|
634
|
+
if (row !== this.meshRow) {
|
|
635
|
+
this.meshRow = row;
|
|
636
|
+
gl.uniform1i(this.meshRowLocation, row);
|
|
637
|
+
}
|
|
638
|
+
const mode = scene.sampler[i] & (REPEAT | SMOOTH | PLANE);
|
|
639
|
+
if (mode !== this.meshMode) {
|
|
640
|
+
this.meshMode = mode;
|
|
641
|
+
gl.uniform3i(this.meshModeLocation, mode & REPEAT ? 1 : 0, mode & SMOOTH ? 1 : 0, mode & PLANE ? 1 : 0);
|
|
642
|
+
}
|
|
643
|
+
state.bindTexture(TEXTURE_UNIT, texture);
|
|
644
|
+
// A plane's bitmap smoothed; a mesh's read texel by texel, but through a sampler without
|
|
645
|
+
// mipmaps, as a texture with none needs.
|
|
646
|
+
state.bindSampler(TEXTURE_UNIT, this.gpu.sampler(plane ? SMOOTH | CLAMP : CLAMP));
|
|
647
|
+
gl.drawElements(gl.TRIANGLES, place.indices, gl.UNSIGNED_INT, place.indexStart * 4);
|
|
648
|
+
return true;
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Entry `i`, a shader fill (SHADED), drawn by its kernel's program, after
|
|
652
|
+
* the mesh's vertex shader, told the view, its row and its kernel's
|
|
653
|
+
* uniforms; whether it was drawn, its program left in use.
|
|
654
|
+
*/
|
|
655
|
+
drawShaded(scene, i, place) {
|
|
656
|
+
const filters = this.host.filters();
|
|
657
|
+
const chain = scene.texture[i];
|
|
658
|
+
if (!filters || chain < 0 || chain >= filters.chainCount) {
|
|
659
|
+
return false;
|
|
660
|
+
}
|
|
661
|
+
// A kernel the GPU will not link, of more images than a program binds, or with an image
|
|
662
|
+
// gone, fills nothing. Its shader is found once a frame for its entry; its program is the
|
|
663
|
+
// cache's, linked again where another took its place.
|
|
664
|
+
const entry = filters.chains[chain];
|
|
665
|
+
const fragment = this.fillShader(filters, entry);
|
|
666
|
+
const kernel = fragment ? this.kernels.use(meshVertex, fragment, this.prepareFill) : null;
|
|
667
|
+
if (!kernel) {
|
|
668
|
+
return false;
|
|
669
|
+
}
|
|
670
|
+
const gl = this.gl;
|
|
671
|
+
this.state.bindVertexArray(this.atlas.vertexArray);
|
|
672
|
+
gl.uniform4fv(kernel.at("uView"), this.view);
|
|
673
|
+
gl.uniform4fv(kernel.at("uFrag"), this.frag);
|
|
674
|
+
gl.uniform1i(kernel.at("uRow"), scene.row[i]);
|
|
675
|
+
this.kernels.setUniforms(kernel, filters, entry, this.host);
|
|
676
|
+
// The mesh program is told its uniforms again after another program drew.
|
|
677
|
+
this.meshStale = true;
|
|
678
|
+
this.meshRow = -1;
|
|
679
|
+
this.meshMode = -1;
|
|
680
|
+
gl.drawElements(gl.TRIANGLES, place.indices, gl.UNSIGNED_INT, place.indexStart * 4);
|
|
681
|
+
return true;
|
|
682
|
+
}
|
|
683
|
+
/** The fragment shader of the shader fill at entry `i` of `filters`, made once a frame; null for none. */
|
|
684
|
+
fillShader(filters, i) {
|
|
685
|
+
if (this.fillFilters !== filters || this.fillGeneration !== filters.generation) {
|
|
686
|
+
this.fillShaders.clear();
|
|
687
|
+
this.fillFilters = filters;
|
|
688
|
+
this.fillGeneration = filters.generation;
|
|
689
|
+
}
|
|
690
|
+
let fragment = this.fillShaders.get(i);
|
|
691
|
+
if (fragment === undefined) {
|
|
692
|
+
const source = filters.kernels[i];
|
|
693
|
+
const images = source && filters.kind[i] === FILL_SHADER
|
|
694
|
+
? this.kernels.readImages(filters, i, this.host)
|
|
695
|
+
: null;
|
|
696
|
+
fragment = source && images && kernelImagesFit(images) ? fillKernel(source, images) : null;
|
|
697
|
+
this.fillShaders.set(i, fragment);
|
|
698
|
+
}
|
|
699
|
+
return fragment;
|
|
700
|
+
}
|
|
701
|
+
/** The programs and draw table made on the context, deleted. */
|
|
702
|
+
destroy() {
|
|
703
|
+
if (this.runTable) {
|
|
704
|
+
this.state.dropTexture(this.runTable);
|
|
705
|
+
this.gl.deleteTexture(this.runTable);
|
|
706
|
+
this.runTable = null;
|
|
707
|
+
}
|
|
708
|
+
const gl = this.gl;
|
|
709
|
+
gl.deleteProgram(this.program);
|
|
710
|
+
gl.deleteProgram(this.mesh);
|
|
711
|
+
gl.deleteProgram(this.glyphProgram);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
//# sourceMappingURL=draws.js.map
|