@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,323 @@
|
|
|
1
|
+
// Pixel Bender kernels where Flash draws with them, as fragment shaders
|
|
2
|
+
// around a kernel's GLSL (the player's scene/pixel-bender-glsl.ts, which
|
|
3
|
+
// defines `vec4 pbKernel(vec2 outCoord)` and calls `pbNearest<t>` and
|
|
4
|
+
// `pbLinear<t>` for each texture `t` it samples). What is here is how
|
|
5
|
+
// each use reads its images and writes what the kernel gives, as adl
|
|
6
|
+
// does (docs/architecture/bitmaps.md, "Pixel Bender"): an image read as
|
|
7
|
+
// its premultiplied bytes times the float nearest 1/255, linearly in
|
|
8
|
+
// 256ths with each step's byte cut down; floats as they are, linearly in
|
|
9
|
+
// the same 256ths; as the CPU interpreter reads them. GLSL ES 3, each a
|
|
10
|
+
// whole fragment shader.
|
|
11
|
+
/** A byte's float as adl samples one: times the float nearest 1/255, not divided. */
|
|
12
|
+
const BYTE = "0.003921568859368563";
|
|
13
|
+
/** Each fragment shader's first lines, so that one is the whole source a program cache keys by. */
|
|
14
|
+
const HEADER = "#version 300 es\nprecision highp float;\n";
|
|
15
|
+
/** The most images a kernel's program binds besides its layer's: one with more is not drawn. */
|
|
16
|
+
export const KERNEL_IMAGES = 8;
|
|
17
|
+
/** Whether `images` bind no more textures of their own than a program takes (KERNEL_IMAGES). */
|
|
18
|
+
export function kernelImagesFit(images) {
|
|
19
|
+
let own = 0;
|
|
20
|
+
for (let k = 0; k < images.length; k++) {
|
|
21
|
+
if (!images[k].layer) {
|
|
22
|
+
own++;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return own <= KERNEL_IMAGES;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Precision, as ints default to mediump in a fragment shader; a texel
|
|
29
|
+
* coordinate as a texel's index, NaN as 0 and far past the edges kept in
|
|
30
|
+
* int's range; a texel's bytes from 0 to 255, read exactly from the 8-bit
|
|
31
|
+
* texture; and a kernel's output as adl writes it into a bitmap: clamped,
|
|
32
|
+
* NaN as 0, rounded to a byte a half to the even, each colour at most its
|
|
33
|
+
* alpha.
|
|
34
|
+
*/
|
|
35
|
+
const PRELUDE = `precision highp int;
|
|
36
|
+
precision highp sampler2D;
|
|
37
|
+
ivec2 pbFloor(vec2 x) {
|
|
38
|
+
x = mix(x, vec2(0.0), isnan(x));
|
|
39
|
+
return ivec2(clamp(floor(x), -1.0e9, 1.0e9));
|
|
40
|
+
}
|
|
41
|
+
vec4 pbBytes(vec4 v) {
|
|
42
|
+
return floor(v * 255.0 + 0.5);
|
|
43
|
+
}
|
|
44
|
+
vec4 pbOutput(vec4 c) {
|
|
45
|
+
c = mix(vec4(0.0), min(c, 1.0), greaterThan(c, vec4(0.0)));
|
|
46
|
+
c = roundEven(c * 255.0) / 255.0;
|
|
47
|
+
return vec4(min(c.rgb, c.a), c.a);
|
|
48
|
+
}
|
|
49
|
+
`;
|
|
50
|
+
/**
|
|
51
|
+
* Image `t`'s sampling from `pbTexel<t>`, its texel at an index (bytes from
|
|
52
|
+
* 0 to 255, or floats), at the texel coordinates `at` gives for a kernel's.
|
|
53
|
+
*/
|
|
54
|
+
function sampling(t, at, float) {
|
|
55
|
+
if (float) {
|
|
56
|
+
// The interpreter's floats: their texels as they are, linearly in 256ths, nothing cut.
|
|
57
|
+
return `vec4 pbNearest${t}(vec2 p) {
|
|
58
|
+
return pbTexel${t}(pbFloor(${at}));
|
|
59
|
+
}
|
|
60
|
+
vec4 pbLinear${t}(vec2 p) {
|
|
61
|
+
vec2 f = ${at} - 0.5;
|
|
62
|
+
vec2 below = floor(f);
|
|
63
|
+
vec2 w = floor((f - below) * 256.0 + 0.5) / 256.0;
|
|
64
|
+
w = mix(w, vec2(0.0), isnan(w));
|
|
65
|
+
ivec2 a = pbFloor(below);
|
|
66
|
+
vec4 row0 = pbTexel${t}(a) * (1.0 - w.x) + pbTexel${t}(a + ivec2(1, 0)) * w.x;
|
|
67
|
+
vec4 row1 = pbTexel${t}(a + ivec2(0, 1)) * (1.0 - w.x) + pbTexel${t}(a + 1) * w.x;
|
|
68
|
+
return row0 * (1.0 - w.y) + row1 * w.y;
|
|
69
|
+
}
|
|
70
|
+
`;
|
|
71
|
+
}
|
|
72
|
+
return `vec4 pbNearest${t}(vec2 p) {
|
|
73
|
+
return pbTexel${t}(pbFloor(${at})) * ${BYTE};
|
|
74
|
+
}
|
|
75
|
+
vec4 pbLinear${t}(vec2 p) {
|
|
76
|
+
vec2 f = ${at} - 0.5;
|
|
77
|
+
vec2 below = floor(f);
|
|
78
|
+
vec2 w = floor((f - below) * 256.0 + 0.5);
|
|
79
|
+
w = mix(w, vec2(0.0), isnan(w));
|
|
80
|
+
ivec2 a = pbFloor(below);
|
|
81
|
+
vec4 row0 = floor((pbTexel${t}(a) * (256.0 - w.x) + pbTexel${t}(a + ivec2(1, 0)) * w.x) / 256.0);
|
|
82
|
+
vec4 row1 = floor((pbTexel${t}(a + ivec2(0, 1)) * (256.0 - w.x) + pbTexel${t}(a + 1) * w.x) / 256.0);
|
|
83
|
+
return floor((row0 * (256.0 - w.y) + row1 * w.y) / 256.0) * ${BYTE};
|
|
84
|
+
}
|
|
85
|
+
`;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Image `t`, a texture of its own (`pbImage<t>`), clamped to its edges as
|
|
89
|
+
* adl clamps a kernel's input: its sampler, its texels and its sampling, in
|
|
90
|
+
* its own pixels.
|
|
91
|
+
*/
|
|
92
|
+
function ownImage(t, float) {
|
|
93
|
+
const texel = `texelFetch(pbImage${t}, clamp(at, ivec2(0), size - 1), 0)`;
|
|
94
|
+
return `uniform sampler2D pbImage${t};
|
|
95
|
+
vec4 pbTexel${t}(ivec2 at) {
|
|
96
|
+
ivec2 size = textureSize(pbImage${t}, 0);
|
|
97
|
+
return ${float ? texel : `pbBytes(${texel})`};
|
|
98
|
+
}
|
|
99
|
+
${sampling(t, "p", float)}`;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The kernel's GLSL with what every use puts round it: PRELUDE, then each
|
|
103
|
+
* image, by `layerTexel` for the layer's, its texel at an index, and
|
|
104
|
+
* ownImage for the others; `layerAt` takes a kernel's coordinate to the
|
|
105
|
+
* layer's texels.
|
|
106
|
+
*/
|
|
107
|
+
export function withImages(kernel, images, layerTexel, layerAt) {
|
|
108
|
+
const parts = [PRELUDE];
|
|
109
|
+
for (const { texture: t, layer, float, back } of images) {
|
|
110
|
+
parts.push(layer
|
|
111
|
+
? `${layerTexel(t, back ?? false)}\n${sampling(t, layerAt, false)}`
|
|
112
|
+
: ownImage(t, float));
|
|
113
|
+
}
|
|
114
|
+
parts.push(kernel);
|
|
115
|
+
return parts.join("\n");
|
|
116
|
+
}
|
|
117
|
+
/** The most kernels whose shaders a use keeps made (madeOnce), emptied when more come. */
|
|
118
|
+
const MADE = 64;
|
|
119
|
+
/** A kernel's shader for its images, made once: a frame asks for it again on each of its uses. */
|
|
120
|
+
export function madeOnce(made, kernel, images, make) {
|
|
121
|
+
let key = "";
|
|
122
|
+
for (let k = 0; k < images.length; k++) {
|
|
123
|
+
const i = images[k];
|
|
124
|
+
key += `${i.texture}${i.layer ? (i.back ? "B" : "L") : ""}${i.float ? "F" : ""},`;
|
|
125
|
+
}
|
|
126
|
+
let byImages = made.get(kernel);
|
|
127
|
+
if (!byImages) {
|
|
128
|
+
if (made.size >= MADE) {
|
|
129
|
+
made.clear();
|
|
130
|
+
}
|
|
131
|
+
byImages = new Map();
|
|
132
|
+
made.set(kernel, byImages);
|
|
133
|
+
}
|
|
134
|
+
let source = byImages.get(key);
|
|
135
|
+
if (source === undefined) {
|
|
136
|
+
source = make();
|
|
137
|
+
byImages.set(key, source);
|
|
138
|
+
}
|
|
139
|
+
return source;
|
|
140
|
+
}
|
|
141
|
+
const madeFilters = new Map();
|
|
142
|
+
/**
|
|
143
|
+
* A ShaderFilter's pass (filter-plan.ts, KERNEL_PASS), run as the
|
|
144
|
+
* filters' other passes are (webgl/filters.ts): the kernel's output over
|
|
145
|
+
* the input's frame, `outCoord` its pixel's centre in stage pixels from
|
|
146
|
+
* the corner of the bitmap the filter reads, `uKernelAt.xy` texels in from
|
|
147
|
+
* the frame's, which starts at `uOutputAt` in the target drawn into, at
|
|
148
|
+
* `uKernelAt.z` texels a stage pixel. The layer's image is the input
|
|
149
|
+
* (uTexture, within uTextureRect), transparent past the frame,
|
|
150
|
+
* `uKernelFrame` texels, as adl reads a filter's source; the others clamp
|
|
151
|
+
* to their edges. The output is as adl writes it (pbOutput), and
|
|
152
|
+
* transparent outside `uKernelRegion`, that bitmap grown by the filter's
|
|
153
|
+
* extensions, in stage pixels.
|
|
154
|
+
*/
|
|
155
|
+
export function filterKernel(kernel, images) {
|
|
156
|
+
return madeOnce(madeFilters, kernel, images, () => filterSource(kernel, images));
|
|
157
|
+
}
|
|
158
|
+
function filterSource(kernel, images) {
|
|
159
|
+
const layer = (t) => `vec4 pbTexel${t}(ivec2 at) {
|
|
160
|
+
if (any(lessThan(at, ivec2(0))) || any(greaterThanEqual(at, ivec2(uKernelFrame)))) {
|
|
161
|
+
return vec4(0.0);
|
|
162
|
+
}
|
|
163
|
+
return pbBytes(texelFetch(uTexture, ivec2(uTextureRect.xy) + at, 0));
|
|
164
|
+
}`;
|
|
165
|
+
return `${HEADER}in vec2 vTextureCoord;
|
|
166
|
+
out vec4 finalColor;
|
|
167
|
+
uniform sampler2D uTexture;
|
|
168
|
+
uniform highp vec4 uInputPixel;
|
|
169
|
+
uniform vec4 uTextureRect;
|
|
170
|
+
uniform vec3 uKernelAt;
|
|
171
|
+
uniform vec2 uKernelFrame;
|
|
172
|
+
uniform vec4 uKernelRegion;
|
|
173
|
+
uniform vec2 uOutputAt;
|
|
174
|
+
${withImages(kernel, images, layer, "p * uKernelAt.z + uKernelAt.xy")}
|
|
175
|
+
void main(void) {
|
|
176
|
+
// From the fragment's centre, exact, where an interpolated coordinate is a hair off a half.
|
|
177
|
+
vec2 outCoord = (gl_FragCoord.xy - uOutputAt - uKernelAt.xy) / uKernelAt.z;
|
|
178
|
+
if (any(lessThan(outCoord, uKernelRegion.xy)) || any(greaterThanEqual(outCoord, uKernelRegion.zw))) {
|
|
179
|
+
finalColor = vec4(0.0);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
finalColor = pbOutput(pbKernel(outCoord));
|
|
183
|
+
}
|
|
184
|
+
`;
|
|
185
|
+
}
|
|
186
|
+
const madeBlends = new Map();
|
|
187
|
+
/**
|
|
188
|
+
* A blend shader's composite (webgl/composite.ts), drawn as the composite
|
|
189
|
+
* program is (programs.ts, compositeFragment), its uniforms the same: as
|
|
190
|
+
* adl runs one, a pixel at a time, each where the layer covers anything
|
|
191
|
+
* and nothing where it does not, or over its whole rectangle (uWhole),
|
|
192
|
+
* the kernel's coordinate (0.5, 0.5) and its first two inputs that pixel
|
|
193
|
+
* of what is below and of the layer, coloured, whatever coordinate it
|
|
194
|
+
* samples them at; its result in place of what was below, as adl writes
|
|
195
|
+
* it (pbOutput). `rows` is the colour transform's reading of uRows
|
|
196
|
+
* (programs.ts, LAYER_COLOR).
|
|
197
|
+
*/
|
|
198
|
+
export function blendKernel(kernel, images, rows) {
|
|
199
|
+
return madeOnce(madeBlends, kernel, images, () => blendSource(kernel, images, rows));
|
|
200
|
+
}
|
|
201
|
+
function blendSource(kernel, images, rows) {
|
|
202
|
+
const pixel = (t, back) => `vec4 pbTexel${t}(ivec2 at) {
|
|
203
|
+
return pbBytes(${back ? "pbBack" : "pbFront"});
|
|
204
|
+
}`;
|
|
205
|
+
return `${HEADER}uniform sampler2D uLayer;
|
|
206
|
+
uniform sampler2D uBack;
|
|
207
|
+
uniform highp sampler2D uRows;
|
|
208
|
+
uniform int uRow;
|
|
209
|
+
uniform ivec2 uOffset;
|
|
210
|
+
uniform bool uFlip;
|
|
211
|
+
uniform ivec2 uBackOffset;
|
|
212
|
+
uniform bool uWhole;
|
|
213
|
+
out vec4 finalColor;
|
|
214
|
+
vec4 pbFront;
|
|
215
|
+
vec4 pbBack;
|
|
216
|
+
${withImages(kernel, images, pixel, "p")}
|
|
217
|
+
void main(void) {
|
|
218
|
+
ivec2 frag = ivec2(gl_FragCoord.xy);
|
|
219
|
+
ivec2 at = ivec2(frag.x - uOffset.x, uFlip ? uOffset.y - frag.y : frag.y - uOffset.y);
|
|
220
|
+
vec4 front = texelFetch(uLayer, at, 0);
|
|
221
|
+
${rows}
|
|
222
|
+
pbBack = texelFetch(uBack, frag - uBackOffset, 0);
|
|
223
|
+
if (!uWhole && pbBytes(front).a == 0.0) {
|
|
224
|
+
finalColor = pbBack;
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
pbFront = front;
|
|
228
|
+
finalColor = pbOutput(pbKernel(vec2(0.5)));
|
|
229
|
+
}
|
|
230
|
+
`;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* The layer shrunk to a texel a stage pixel for a kernel run once a pixel
|
|
234
|
+
* (filter-plan.ts): each output texel the mean of the `uDown.x` by
|
|
235
|
+
* `uDown.x` texels of the pixel it stands for, the grid from `uDown.yz`
|
|
236
|
+
* texels past the input's corner, which may be less than 0; the texels of
|
|
237
|
+
* a pixel past the frame, `uKernelFrame`, left out of the mean.
|
|
238
|
+
*/
|
|
239
|
+
export const PIXELS_DOWN = `${HEADER}precision highp int;
|
|
240
|
+
in vec2 vTextureCoord;
|
|
241
|
+
out vec4 finalColor;
|
|
242
|
+
uniform sampler2D uTexture;
|
|
243
|
+
uniform vec4 uTextureRect;
|
|
244
|
+
uniform vec3 uDown;
|
|
245
|
+
uniform vec2 uKernelFrame;
|
|
246
|
+
uniform vec2 uOutputAt;
|
|
247
|
+
void main(void) {
|
|
248
|
+
int n = int(uDown.x);
|
|
249
|
+
ivec2 from = ivec2(gl_FragCoord.xy - uOutputAt) * n + ivec2(uDown.yz);
|
|
250
|
+
ivec2 frame = ivec2(uKernelFrame);
|
|
251
|
+
vec4 sum = vec4(0.0);
|
|
252
|
+
float count = 0.0;
|
|
253
|
+
for (int j = 0; j < 16; j++) {
|
|
254
|
+
if (j >= n) { break; }
|
|
255
|
+
for (int i = 0; i < 16; i++) {
|
|
256
|
+
if (i >= n) { break; }
|
|
257
|
+
ivec2 at = from + ivec2(i, j);
|
|
258
|
+
if (all(greaterThanEqual(at, ivec2(0))) && all(lessThan(at, frame))) {
|
|
259
|
+
sum += texelFetch(uTexture, ivec2(uTextureRect.xy) + at, 0);
|
|
260
|
+
count += 1.0;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
finalColor = count > 0.0 ? sum / count : vec4(0.0);
|
|
265
|
+
}
|
|
266
|
+
`;
|
|
267
|
+
/**
|
|
268
|
+
* A kernel's output, run a texel a stage pixel, drawn back over the
|
|
269
|
+
* layer's frame: each texel its pixel's, the grid as PIXELS_DOWN had it.
|
|
270
|
+
*/
|
|
271
|
+
export const PIXELS_BACK = `${HEADER}precision highp int;
|
|
272
|
+
in vec2 vTextureCoord;
|
|
273
|
+
out vec4 finalColor;
|
|
274
|
+
uniform sampler2D uTexture;
|
|
275
|
+
uniform vec4 uTextureRect;
|
|
276
|
+
uniform vec3 uDown;
|
|
277
|
+
uniform vec2 uOutputAt;
|
|
278
|
+
void main(void) {
|
|
279
|
+
ivec2 at = (ivec2(gl_FragCoord.xy - uOutputAt) - ivec2(uDown.yz)) / int(uDown.x);
|
|
280
|
+
at = clamp(at, ivec2(0), ivec2(uTextureRect.zw) - 1);
|
|
281
|
+
finalColor = texelFetch(uTexture, ivec2(uTextureRect.xy) + at, 0);
|
|
282
|
+
}
|
|
283
|
+
`;
|
|
284
|
+
const madeFills = new Map();
|
|
285
|
+
/**
|
|
286
|
+
* A shader fill's program, after the mesh's vertex shader (programs.ts,
|
|
287
|
+
* meshVertex), which carries the kernel's coordinates in vUVT with a depth
|
|
288
|
+
* of 1: the kernel run once a pixel of Flash's, at its centre (uFrag as the
|
|
289
|
+
* mesh's has it), its images clamped to their edges; its colours left
|
|
290
|
+
* past its alpha, as adl composites them, but under a colour transform,
|
|
291
|
+
* which takes them straight.
|
|
292
|
+
*/
|
|
293
|
+
export function fillKernel(kernel, images) {
|
|
294
|
+
return madeOnce(madeFills, kernel, images, () => fillSource(kernel, images));
|
|
295
|
+
}
|
|
296
|
+
function fillSource(kernel, images) {
|
|
297
|
+
return `${HEADER}in vec3 vUVT;
|
|
298
|
+
flat in vec4 vMul;
|
|
299
|
+
flat in vec4 vAdd;
|
|
300
|
+
uniform vec4 uFrag;
|
|
301
|
+
out vec4 finalColor;
|
|
302
|
+
${withImages(kernel, images, () => "", "p")}
|
|
303
|
+
void main(void) {
|
|
304
|
+
float pixel = uFrag.w;
|
|
305
|
+
vec2 f = vec2(gl_FragCoord.x + uFrag.x, uFrag.y + uFrag.z * gl_FragCoord.y);
|
|
306
|
+
vec2 centre = (floor(f / pixel) + 0.5) * pixel;
|
|
307
|
+
vec3 at = vUVT + dFdx(vUVT) * (centre.x - f.x) + dFdy(vUVT) * ((centre.y - f.y) * uFrag.z);
|
|
308
|
+
vec4 c = pbKernel(at.xy / at.z);
|
|
309
|
+
c = mix(vec4(0.0), min(c, 1.0), greaterThan(c, vec4(0.0)));
|
|
310
|
+
if (vMul == vec4(1.0) && vAdd == vec4(0.0)) {
|
|
311
|
+
finalColor = c;
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
if (c.a == 0.0) {
|
|
315
|
+
finalColor = vec4(0.0);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
vec4 s = clamp(vec4(c.rgb / c.a, c.a) * vMul + vAdd, 0.0, 1.0);
|
|
319
|
+
finalColor = vec4(s.rgb * s.a, s.a);
|
|
320
|
+
}
|
|
321
|
+
`;
|
|
322
|
+
}
|
|
323
|
+
//# sourceMappingURL=kernel-shaders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kernel-shaders.js","sourceRoot":"","sources":["../src/kernel-shaders.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Geometries } from "./geometry.js";
|
|
2
|
+
import { type Rows } from "./rows.js";
|
|
3
|
+
import { type SceneList } from "./scene.js";
|
|
4
|
+
/**
|
|
5
|
+
* What measuring a frame's layers needs of its target: its size in pixels,
|
|
6
|
+
* its pixels a stage pixel, and its pixels a unit of its own (resolution),
|
|
7
|
+
* which a filtered layer is padded in.
|
|
8
|
+
*/
|
|
9
|
+
export interface MeasureTarget {
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
scale: number;
|
|
13
|
+
resolution: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Each layer's rectangle of the target (SceneList.layerRect), from what is
|
|
17
|
+
* drawn in it: its draws' geometries placed by their rows, a mask's own
|
|
18
|
+
* draws apart, what a mask clips cut to that mask's draws as it pops, and
|
|
19
|
+
* the rectangles of the layers in it; out to whole pixels and a pixel more
|
|
20
|
+
* each way, cut to the target. An alpha mask's layer is no part of the
|
|
21
|
+
* unfiltered layer it ends, which it cuts to its own rectangle instead, as
|
|
22
|
+
* nothing of that layer shows past it. What is drawn is what is measured,
|
|
23
|
+
* so a layer covers its draws however they came to be where they are. A
|
|
24
|
+
* filtered layer is measured as PixiJS's filter system measures it, which
|
|
25
|
+
* the filters' exactness rules were found with: cut to the target, out to
|
|
26
|
+
* whole pixels, then padded, not cut again; where nothing is drawn in it,
|
|
27
|
+
* it draws nothing.
|
|
28
|
+
*/
|
|
29
|
+
export declare function measureLayers(scene: SceneList, rows: Rows, geometries: Geometries, target: MeasureTarget): void;
|
|
30
|
+
/**
|
|
31
|
+
* The rectangle a filtered layer padded by `pad` units covers, from its
|
|
32
|
+
* area (least x and y, greatest x and y in target pixels, from `area[at]`)
|
|
33
|
+
* as PixiJS's filter system has it (FilterSystem's _calculateFilterArea): in
|
|
34
|
+
* units, the area cut to the target, out to whole pixels at the
|
|
35
|
+
* resolution, or to whole stage pixels as `whole` says (SceneList.wholes),
|
|
36
|
+
* padded; nothing where it has no size then; its edges snapped to the
|
|
37
|
+
* pixels they lie on. Into `out` from `to`: x, y, width, height, of no
|
|
38
|
+
* size for nothing. A whole layer's object, uncut, goes into `objects` at
|
|
39
|
+
* `to` too (SceneList.objects).
|
|
40
|
+
*/
|
|
41
|
+
export declare function filteredRect(area: ArrayLike<number>, at: number, pad: number, target: MeasureTarget, out: Int32Array, to: number, whole?: number, objects?: Float64Array | null): void;
|
|
42
|
+
/**
|
|
43
|
+
* Flash's bitmap of an object of bounds x0, y0 to x1, y1 in stage pixels:
|
|
44
|
+
* the bounds out to twips, then antialiased (WHOLE_SMOOTH) the pixels its
|
|
45
|
+
* edges touch and one more right and down where an edge lies on one,
|
|
46
|
+
* aliased (WHOLE_ALIASED) those whose centres it covers.
|
|
47
|
+
*/
|
|
48
|
+
export declare function wholeBitmap(x0: number, y0: number, x1: number, y1: number, whole: number): number[];
|
|
49
|
+
/**
|
|
50
|
+
* The area of the target the draws from entry `from` on cover, at `scale`
|
|
51
|
+
* target pixels a stage pixel, masks' own draws apart and nothing cut by
|
|
52
|
+
* the masks: into `out`, its least x and y, then its greatest, in target
|
|
53
|
+
* pixels; nothing drawn leaves the least past the greatest.
|
|
54
|
+
*/
|
|
55
|
+
export declare function drawnArea(scene: SceneList, rows: Rows, geometries: Geometries, from: number, scale: number, out: number[]): void;
|
|
56
|
+
//# sourceMappingURL=measure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"measure.d.ts","sourceRoot":"","sources":["../src/measure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAc,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,EAUL,KAAK,SAAS,EAEf,MAAM,YAAY,CAAC;AAEpB;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAYD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,SAAS,EAChB,IAAI,EAAE,IAAI,EACV,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,aAAa,GACpB,IAAI,CAqIN;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,EACvB,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,aAAa,EACrB,GAAG,EAAE,UAAU,EACf,EAAE,EAAE,MAAM,EACV,KAAK,SAAW,EAChB,OAAO,GAAE,YAAY,GAAG,IAAW,GAClC,IAAI,CA2DN;AAKD;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,GACZ,MAAM,EAAE,CAkBV;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,SAAS,EAChB,IAAI,EAAE,IAAI,EACV,UAAU,EAAE,UAAU,EACtB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EAAE,GACZ,IAAI,CAoBN"}
|
package/dist/measure.js
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { ROW_FLOATS } from "./rows.js";
|
|
2
|
+
import { ALPHA_MASK, DRAW, KEPT, LAYER_BEGIN, LAYER_END, MASK_BEGIN, MASK_POP, MASK_USE, NO_WHOLE, WHOLE_ALIASED, } from "./scene.js";
|
|
3
|
+
/** A hair, which keeps a padded edge on the pixel it lies on at any resolution. */
|
|
4
|
+
const TEXEL_SNAP = 1e-6;
|
|
5
|
+
// Scratch stacks, four numbers an open area: least x and y, greatest x and y, in target pixels.
|
|
6
|
+
const areas = [];
|
|
7
|
+
const clips = [];
|
|
8
|
+
const open = [];
|
|
9
|
+
// Each open layer's cut, four numbers as an area's: an alpha mask's rectangle in it (ALPHA_MASK).
|
|
10
|
+
const cuts = [];
|
|
11
|
+
/**
|
|
12
|
+
* Each layer's rectangle of the target (SceneList.layerRect), from what is
|
|
13
|
+
* drawn in it: its draws' geometries placed by their rows, a mask's own
|
|
14
|
+
* draws apart, what a mask clips cut to that mask's draws as it pops, and
|
|
15
|
+
* the rectangles of the layers in it; out to whole pixels and a pixel more
|
|
16
|
+
* each way, cut to the target. An alpha mask's layer is no part of the
|
|
17
|
+
* unfiltered layer it ends, which it cuts to its own rectangle instead, as
|
|
18
|
+
* nothing of that layer shows past it. What is drawn is what is measured,
|
|
19
|
+
* so a layer covers its draws however they came to be where they are. A
|
|
20
|
+
* filtered layer is measured as PixiJS's filter system measures it, which
|
|
21
|
+
* the filters' exactness rules were found with: cut to the target, out to
|
|
22
|
+
* whole pixels, then padded, not cut again; where nothing is drawn in it,
|
|
23
|
+
* it draws nothing.
|
|
24
|
+
*/
|
|
25
|
+
export function measureLayers(scene, rows, geometries, target) {
|
|
26
|
+
if (scene.layerCount === 0) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
areas.length = 0;
|
|
30
|
+
clips.length = 0;
|
|
31
|
+
open.length = 0;
|
|
32
|
+
cuts.length = 0;
|
|
33
|
+
pushEmpty(areas);
|
|
34
|
+
const k = target.scale;
|
|
35
|
+
const box = geometries.box;
|
|
36
|
+
const m = rows.data;
|
|
37
|
+
for (let i = 0; i < scene.length; i++) {
|
|
38
|
+
switch (scene.kind[i]) {
|
|
39
|
+
case DRAW:
|
|
40
|
+
placeDraw(scene, i, box, m, k, areas);
|
|
41
|
+
break;
|
|
42
|
+
case MASK_BEGIN:
|
|
43
|
+
// The mask's own draws, measured apart.
|
|
44
|
+
pushEmpty(areas);
|
|
45
|
+
break;
|
|
46
|
+
case LAYER_BEGIN:
|
|
47
|
+
open.push(scene.geometry[i]);
|
|
48
|
+
pushEmpty(areas);
|
|
49
|
+
cuts.push(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY);
|
|
50
|
+
break;
|
|
51
|
+
case MASK_USE:
|
|
52
|
+
// The mask's draws clip what follows, measured apart till it pops.
|
|
53
|
+
moveTop(areas, clips);
|
|
54
|
+
pushEmpty(areas);
|
|
55
|
+
break;
|
|
56
|
+
case MASK_POP: {
|
|
57
|
+
const n = areas.length;
|
|
58
|
+
const c = clips.length;
|
|
59
|
+
const left = Math.max(areas[n - 4], clips[c - 4]);
|
|
60
|
+
const top = Math.max(areas[n - 3], clips[c - 3]);
|
|
61
|
+
const right = Math.min(areas[n - 2], clips[c - 2]);
|
|
62
|
+
const bottom = Math.min(areas[n - 1], clips[c - 1]);
|
|
63
|
+
areas.length = n - 4;
|
|
64
|
+
clips.length = c - 4;
|
|
65
|
+
if (right > left && bottom > top) {
|
|
66
|
+
unionTop(left, top, right, bottom);
|
|
67
|
+
}
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
case LAYER_END: {
|
|
71
|
+
const n = areas.length;
|
|
72
|
+
const layer = open.pop();
|
|
73
|
+
const pad = scene.pads[layer];
|
|
74
|
+
const c = cuts.length - 4;
|
|
75
|
+
if (pad < 0) {
|
|
76
|
+
const left = Math.max(0, Math.floor(areas[n - 4]) - 1, cuts[c]);
|
|
77
|
+
const top = Math.max(0, Math.floor(areas[n - 3]) - 1, cuts[c + 1]);
|
|
78
|
+
const right = Math.min(target.width, Math.ceil(areas[n - 2]) + 1, cuts[c + 2]);
|
|
79
|
+
const bottom = Math.min(target.height, Math.ceil(areas[n - 1]) + 1, cuts[c + 3]);
|
|
80
|
+
areas.length = n - 4;
|
|
81
|
+
cuts.length = c;
|
|
82
|
+
if (scene.geometry[i] === ALPHA_MASK) {
|
|
83
|
+
// Not taken into the layer it ends, which it cuts to its rectangle: to nothing, where it
|
|
84
|
+
// has none.
|
|
85
|
+
if (right > left && bottom > top) {
|
|
86
|
+
scene.layerRect(layer, left, top, right - left, bottom - top);
|
|
87
|
+
}
|
|
88
|
+
const p = c - 4;
|
|
89
|
+
if (p >= 0) {
|
|
90
|
+
cuts[p] = Math.max(cuts[p], left);
|
|
91
|
+
cuts[p + 1] = Math.max(cuts[p + 1], top);
|
|
92
|
+
cuts[p + 2] = Math.min(cuts[p + 2], right);
|
|
93
|
+
cuts[p + 3] = Math.min(cuts[p + 3], bottom);
|
|
94
|
+
}
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
if (right > left && bottom > top) {
|
|
98
|
+
scene.layerRect(layer, left, top, right - left, bottom - top);
|
|
99
|
+
unionTop(left, top, right, bottom);
|
|
100
|
+
}
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
// The view puts no alpha mask straight in a filtered layer, which would run its filters on
|
|
104
|
+
// what the mask left (cuts).
|
|
105
|
+
cuts.length = c;
|
|
106
|
+
const kept = scene.areas;
|
|
107
|
+
for (let k = 0; k < 4; k++) {
|
|
108
|
+
kept[layer * 4 + k] = areas[n - 4 + k];
|
|
109
|
+
}
|
|
110
|
+
filteredRect(scene.areas, layer * 4, pad, target, scene.layers, layer * 4, scene.wholes[layer], scene.objects);
|
|
111
|
+
areas.length = n - 4;
|
|
112
|
+
const r = scene.layers;
|
|
113
|
+
const at = layer * 4;
|
|
114
|
+
if (r[at + 2] > 0) {
|
|
115
|
+
unionTop(r[at], r[at + 1], r[at] + r[at + 2], r[at + 1] + r[at + 3]);
|
|
116
|
+
}
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
case KEPT: {
|
|
120
|
+
// A kept output covers its rectangle, which its owner placed.
|
|
121
|
+
const r = scene.layers;
|
|
122
|
+
const at = scene.geometry[i] * 4;
|
|
123
|
+
if (r[at + 2] > 0 && r[at + 3] > 0) {
|
|
124
|
+
unionTop(r[at], r[at + 1], r[at] + r[at + 2], r[at + 1] + r[at + 3]);
|
|
125
|
+
}
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The rectangle a filtered layer padded by `pad` units covers, from its
|
|
133
|
+
* area (least x and y, greatest x and y in target pixels, from `area[at]`)
|
|
134
|
+
* as PixiJS's filter system has it (FilterSystem's _calculateFilterArea): in
|
|
135
|
+
* units, the area cut to the target, out to whole pixels at the
|
|
136
|
+
* resolution, or to whole stage pixels as `whole` says (SceneList.wholes),
|
|
137
|
+
* padded; nothing where it has no size then; its edges snapped to the
|
|
138
|
+
* pixels they lie on. Into `out` from `to`: x, y, width, height, of no
|
|
139
|
+
* size for nothing. A whole layer's object, uncut, goes into `objects` at
|
|
140
|
+
* `to` too (SceneList.objects).
|
|
141
|
+
*/
|
|
142
|
+
export function filteredRect(area, at, pad, target, out, to, whole = NO_WHOLE, objects = null) {
|
|
143
|
+
const res = target.resolution;
|
|
144
|
+
let x0 = area[at] / res;
|
|
145
|
+
let y0 = area[at + 1] / res;
|
|
146
|
+
let x1 = area[at + 2] / res;
|
|
147
|
+
let y1 = area[at + 3] / res;
|
|
148
|
+
out[to] = 0;
|
|
149
|
+
out[to + 1] = 0;
|
|
150
|
+
out[to + 2] = 0;
|
|
151
|
+
out[to + 3] = 0;
|
|
152
|
+
if (!(x1 > x0 && y1 > y0)) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (whole !== NO_WHOLE) {
|
|
156
|
+
// Flash's bitmap of the object, of whole stage pixels, whatever the stage's scale; cut to the
|
|
157
|
+
// target only after.
|
|
158
|
+
const k = target.scale;
|
|
159
|
+
const object = wholeBitmap(area[at] / k, area[at + 1] / k, area[at + 2] / k, area[at + 3] / k, whole);
|
|
160
|
+
const ox0 = object[0] * k;
|
|
161
|
+
const oy0 = object[1] * k;
|
|
162
|
+
const ox1 = object[2] * k;
|
|
163
|
+
const oy1 = object[3] * k;
|
|
164
|
+
if (objects) {
|
|
165
|
+
objects[to] = ox0;
|
|
166
|
+
objects[to + 1] = oy0;
|
|
167
|
+
objects[to + 2] = ox1 - ox0;
|
|
168
|
+
objects[to + 3] = oy1 - oy0;
|
|
169
|
+
}
|
|
170
|
+
x0 = Math.max(ox0, 0) / res - pad;
|
|
171
|
+
y0 = Math.max(oy0, 0) / res - pad;
|
|
172
|
+
x1 = Math.min(ox1, target.width) / res + pad;
|
|
173
|
+
y1 = Math.min(oy1, target.height) / res + pad;
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
// Each edge moved in alone, as Bounds.fitBounds does: an area off the target turns inside out,
|
|
177
|
+
// and its padding may yet give it a size.
|
|
178
|
+
x0 = Math.floor(Math.max(x0, 0) * res) / res - pad;
|
|
179
|
+
y0 = Math.floor(Math.max(y0, 0) * res) / res - pad;
|
|
180
|
+
x1 = Math.ceil(Math.min(x1, target.width / res) * res) / res + pad;
|
|
181
|
+
y1 = Math.ceil(Math.min(y1, target.height / res) * res) / res + pad;
|
|
182
|
+
}
|
|
183
|
+
if (!(x1 - x0 > 0 && y1 - y0 > 0)) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const left = Math.floor(x0 * res + TEXEL_SNAP);
|
|
187
|
+
const top = Math.floor(y0 * res + TEXEL_SNAP);
|
|
188
|
+
out[to] = left;
|
|
189
|
+
out[to + 1] = top;
|
|
190
|
+
out[to + 2] = Math.ceil(x1 * res - TEXEL_SNAP) - left;
|
|
191
|
+
out[to + 3] = Math.ceil(y1 * res - TEXEL_SNAP) - top;
|
|
192
|
+
}
|
|
193
|
+
/** What wholeBitmap gives, read before it is asked again. */
|
|
194
|
+
const bitmap = [0, 0, 0, 0];
|
|
195
|
+
/**
|
|
196
|
+
* Flash's bitmap of an object of bounds x0, y0 to x1, y1 in stage pixels:
|
|
197
|
+
* the bounds out to twips, then antialiased (WHOLE_SMOOTH) the pixels its
|
|
198
|
+
* edges touch and one more right and down where an edge lies on one,
|
|
199
|
+
* aliased (WHOLE_ALIASED) those whose centres it covers.
|
|
200
|
+
*/
|
|
201
|
+
export function wholeBitmap(x0, y0, x1, y1, whole) {
|
|
202
|
+
x0 = Math.floor(x0 * 20 + TEXEL_SNAP) / 20;
|
|
203
|
+
y0 = Math.floor(y0 * 20 + TEXEL_SNAP) / 20;
|
|
204
|
+
x1 = Math.ceil(x1 * 20 - TEXEL_SNAP) / 20;
|
|
205
|
+
y1 = Math.ceil(y1 * 20 - TEXEL_SNAP) / 20;
|
|
206
|
+
if (whole === WHOLE_ALIASED) {
|
|
207
|
+
bitmap[0] = Math.ceil(x0 - 0.5);
|
|
208
|
+
bitmap[1] = Math.ceil(y0 - 0.5);
|
|
209
|
+
bitmap[2] = Math.ceil(x1 - 0.5);
|
|
210
|
+
bitmap[3] = Math.ceil(y1 - 0.5);
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
bitmap[0] = Math.floor(x0);
|
|
214
|
+
bitmap[1] = Math.floor(y0);
|
|
215
|
+
bitmap[2] = Math.floor(x1) + 1;
|
|
216
|
+
bitmap[3] = Math.floor(y1) + 1;
|
|
217
|
+
}
|
|
218
|
+
return bitmap;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* The area of the target the draws from entry `from` on cover, at `scale`
|
|
222
|
+
* target pixels a stage pixel, masks' own draws apart and nothing cut by
|
|
223
|
+
* the masks: into `out`, its least x and y, then its greatest, in target
|
|
224
|
+
* pixels; nothing drawn leaves the least past the greatest.
|
|
225
|
+
*/
|
|
226
|
+
export function drawnArea(scene, rows, geometries, from, scale, out) {
|
|
227
|
+
out.length = 0;
|
|
228
|
+
pushEmpty(out);
|
|
229
|
+
let defining = 0;
|
|
230
|
+
for (let i = from; i < scene.length; i++) {
|
|
231
|
+
switch (scene.kind[i]) {
|
|
232
|
+
case DRAW:
|
|
233
|
+
if (defining === 0) {
|
|
234
|
+
placeDraw(scene, i, geometries.box, rows.data, scale, out);
|
|
235
|
+
}
|
|
236
|
+
break;
|
|
237
|
+
case MASK_BEGIN:
|
|
238
|
+
defining++;
|
|
239
|
+
break;
|
|
240
|
+
case MASK_USE:
|
|
241
|
+
defining--;
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/** Entry `i`'s geometry box placed by its row at `k` target pixels a stage pixel, taken into the area atop `stack`. */
|
|
247
|
+
function placeDraw(scene, i, box, m, k, stack) {
|
|
248
|
+
const g = scene.geometry[i] * 4;
|
|
249
|
+
const x0 = box[g];
|
|
250
|
+
const y0 = box[g + 1];
|
|
251
|
+
const x1 = box[g + 2];
|
|
252
|
+
const y1 = box[g + 3];
|
|
253
|
+
if (!(x1 >= x0 && y1 >= y0)) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const r = scene.row[i] * ROW_FLOATS;
|
|
257
|
+
const a = m[r] * k;
|
|
258
|
+
const b = m[r + 1] * k;
|
|
259
|
+
const c = m[r + 2] * k;
|
|
260
|
+
const d = m[r + 3] * k;
|
|
261
|
+
const tx = m[r + 4] * k;
|
|
262
|
+
const ty = m[r + 5] * k;
|
|
263
|
+
// The box's corners placed: each of the least and greatest a coordinate takes, by sign.
|
|
264
|
+
const n = stack.length;
|
|
265
|
+
stack[n - 4] = Math.min(stack[n - 4], tx + Math.min(a * x0, a * x1) + Math.min(c * y0, c * y1));
|
|
266
|
+
stack[n - 3] = Math.min(stack[n - 3], ty + Math.min(b * x0, b * x1) + Math.min(d * y0, d * y1));
|
|
267
|
+
stack[n - 2] = Math.max(stack[n - 2], tx + Math.max(a * x0, a * x1) + Math.max(c * y0, c * y1));
|
|
268
|
+
stack[n - 1] = Math.max(stack[n - 1], ty + Math.max(b * x0, b * x1) + Math.max(d * y0, d * y1));
|
|
269
|
+
}
|
|
270
|
+
function pushEmpty(stack) {
|
|
271
|
+
stack.push(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY);
|
|
272
|
+
}
|
|
273
|
+
/** The top area of `from` moved onto `to`. */
|
|
274
|
+
function moveTop(from, to) {
|
|
275
|
+
const n = from.length;
|
|
276
|
+
to.push(from[n - 4], from[n - 3], from[n - 2], from[n - 1]);
|
|
277
|
+
from.length = n - 4;
|
|
278
|
+
}
|
|
279
|
+
/** The open area on top grown to take in the rectangle. */
|
|
280
|
+
function unionTop(left, top, right, bottom) {
|
|
281
|
+
const n = areas.length;
|
|
282
|
+
areas[n - 4] = Math.min(areas[n - 4], left);
|
|
283
|
+
areas[n - 3] = Math.min(areas[n - 3], top);
|
|
284
|
+
areas[n - 2] = Math.max(areas[n - 2], right);
|
|
285
|
+
areas[n - 1] = Math.max(areas[n - 1], bottom);
|
|
286
|
+
}
|
|
287
|
+
//# sourceMappingURL=measure.js.map
|