@swf2es/player 0.1.0 → 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/package.json +7 -7
- package/dist/audio.d.ts +0 -22
- package/dist/audio.d.ts.map +0 -1
- package/dist/audio.js +0 -106
- package/dist/audio.js.map +0 -1
- package/dist/bitmap-filters.d.ts +0 -29
- package/dist/bitmap-filters.d.ts.map +0 -1
- package/dist/bitmap-filters.js +0 -906
- package/dist/bitmap-filters.js.map +0 -1
- package/dist/bitmap-ops.d.ts +0 -113
- package/dist/bitmap-ops.d.ts.map +0 -1
- package/dist/bitmap-ops.js +0 -725
- package/dist/bitmap-ops.js.map +0 -1
- package/dist/bitmap.d.ts +0 -98
- package/dist/bitmap.d.ts.map +0 -1
- package/dist/bitmap.js +0 -314
- package/dist/bitmap.js.map +0 -1
- package/dist/bounds.d.ts +0 -26
- package/dist/bounds.d.ts.map +0 -1
- package/dist/bounds.js +0 -300
- package/dist/bounds.js.map +0 -1
- package/dist/color.d.ts +0 -7
- package/dist/color.d.ts.map +0 -1
- package/dist/color.js +0 -42
- package/dist/color.js.map +0 -1
- package/dist/display.d.ts +0 -425
- package/dist/display.d.ts.map +0 -1
- package/dist/display.js +0 -1274
- package/dist/display.js.map +0 -1
- package/dist/drawing.d.ts +0 -52
- package/dist/drawing.d.ts.map +0 -1
- package/dist/drawing.js +0 -204
- package/dist/drawing.js.map +0 -1
- package/dist/filters.d.ts +0 -54
- package/dist/filters.d.ts.map +0 -1
- package/dist/filters.js +0 -155
- package/dist/filters.js.map +0 -1
- package/dist/fonts.d.ts +0 -23
- package/dist/fonts.d.ts.map +0 -1
- package/dist/fonts.js +0 -91
- package/dist/fonts.js.map +0 -1
- package/dist/geometry.d.ts +0 -21
- package/dist/geometry.d.ts.map +0 -1
- package/dist/geometry.js +0 -76
- package/dist/geometry.js.map +0 -1
- package/dist/gradients.d.ts +0 -29
- package/dist/gradients.d.ts.map +0 -1
- package/dist/gradients.js +0 -116
- package/dist/gradients.js.map +0 -1
- package/dist/images.d.ts +0 -22
- package/dist/images.d.ts.map +0 -1
- package/dist/images.js +0 -147
- package/dist/images.js.map +0 -1
- package/dist/input.d.ts +0 -79
- package/dist/input.d.ts.map +0 -1
- package/dist/input.js +0 -366
- package/dist/input.js.map +0 -1
- package/dist/keyboard.d.ts +0 -97
- package/dist/keyboard.d.ts.map +0 -1
- package/dist/keyboard.js +0 -583
- package/dist/keyboard.js.map +0 -1
- package/dist/morph.d.ts +0 -17
- package/dist/morph.d.ts.map +0 -1
- package/dist/morph.js +0 -218
- package/dist/morph.js.map +0 -1
- package/dist/pixi-blend.d.ts +0 -7
- package/dist/pixi-blend.d.ts.map +0 -1
- package/dist/pixi-blend.js +0 -253
- package/dist/pixi-blend.js.map +0 -1
- package/dist/pixi-color.d.ts +0 -54
- package/dist/pixi-color.d.ts.map +0 -1
- package/dist/pixi-color.js +0 -336
- package/dist/pixi-color.js.map +0 -1
- package/dist/pixi-filters.d.ts +0 -40
- package/dist/pixi-filters.d.ts.map +0 -1
- package/dist/pixi-filters.js +0 -953
- package/dist/pixi-filters.js.map +0 -1
- package/dist/pixi-resolve.d.ts +0 -4
- package/dist/pixi-resolve.d.ts.map +0 -1
- package/dist/pixi-resolve.js +0 -76
- package/dist/pixi-resolve.js.map +0 -1
- package/dist/pixi.d.ts +0 -219
- package/dist/pixi.d.ts.map +0 -1
- package/dist/pixi.js +0 -2169
- package/dist/pixi.js.map +0 -1
- package/dist/playerglobal/flash/filters/filters.d.ts +0 -26
- package/dist/playerglobal/flash/filters/filters.d.ts.map +0 -1
- package/dist/playerglobal/flash/filters/filters.js +0 -287
- package/dist/playerglobal/flash/filters/filters.js.map +0 -1
- package/dist/playerglobal/flash/system/FSCommand.d.ts +0 -4
- package/dist/playerglobal/flash/system/FSCommand.d.ts.map +0 -1
- package/dist/playerglobal/flash/system/FSCommand.js +0 -18
- package/dist/playerglobal/flash/system/FSCommand.js.map +0 -1
- package/dist/playerglobal/natives.d.ts +0 -10
- package/dist/playerglobal/natives.d.ts.map +0 -1
- package/dist/playerglobal/natives.js +0 -53
- package/dist/playerglobal/natives.js.map +0 -1
- package/dist/png.d.ts +0 -4
- package/dist/png.d.ts.map +0 -1
- package/dist/png.js +0 -140
- package/dist/png.js.map +0 -1
- package/dist/render/art.d.ts +0 -148
- package/dist/render/art.d.ts.map +0 -1
- package/dist/render/art.js +0 -575
- package/dist/render/art.js.map +0 -1
- package/dist/render/batchers.d.ts +0 -23
- package/dist/render/batchers.d.ts.map +0 -1
- package/dist/render/batchers.js +0 -52
- package/dist/render/batchers.js.map +0 -1
- package/dist/render/bitmaps.d.ts +0 -117
- package/dist/render/bitmaps.d.ts.map +0 -1
- package/dist/render/bitmaps.js +0 -422
- package/dist/render/bitmaps.js.map +0 -1
- package/dist/render/blend.d.ts +0 -37
- package/dist/render/blend.d.ts.map +0 -1
- package/dist/render/blend.js +0 -195
- package/dist/render/blend.js.map +0 -1
- package/dist/render/color.d.ts +0 -111
- package/dist/render/color.d.ts.map +0 -1
- package/dist/render/color.js +0 -533
- package/dist/render/color.js.map +0 -1
- package/dist/render/compositing.d.ts +0 -77
- package/dist/render/compositing.d.ts.map +0 -1
- package/dist/render/compositing.js +0 -188
- package/dist/render/compositing.js.map +0 -1
- package/dist/render/filters.d.ts +0 -98
- package/dist/render/filters.d.ts.map +0 -1
- package/dist/render/filters.js +0 -1326
- package/dist/render/filters.js.map +0 -1
- package/dist/render/hooks.d.ts +0 -4
- package/dist/render/hooks.d.ts.map +0 -1
- package/dist/render/hooks.js +0 -48
- package/dist/render/hooks.js.map +0 -1
- package/dist/render/node.d.ts +0 -139
- package/dist/render/node.d.ts.map +0 -1
- package/dist/render/node.js +0 -59
- package/dist/render/node.js.map +0 -1
- package/dist/render/patches.d.ts +0 -54
- package/dist/render/patches.d.ts.map +0 -1
- package/dist/render/patches.js +0 -154
- package/dist/render/patches.js.map +0 -1
- package/dist/render/planes.d.ts +0 -74
- package/dist/render/planes.d.ts.map +0 -1
- package/dist/render/planes.js +0 -267
- package/dist/render/planes.js.map +0 -1
- package/dist/render/pointer.d.ts +0 -5
- package/dist/render/pointer.d.ts.map +0 -1
- package/dist/render/pointer.js +0 -279
- package/dist/render/pointer.js.map +0 -1
- package/dist/render/pools.d.ts +0 -122
- package/dist/render/pools.d.ts.map +0 -1
- package/dist/render/pools.js +0 -238
- package/dist/render/pools.js.map +0 -1
- package/dist/render/resolve.d.ts +0 -4
- package/dist/render/resolve.d.ts.map +0 -1
- package/dist/render/resolve.js +0 -76
- package/dist/render/resolve.js.map +0 -1
- package/dist/render/saffron.d.ts +0 -135
- package/dist/render/saffron.d.ts.map +0 -1
- package/dist/render/saffron.js +0 -725
- package/dist/render/saffron.js.map +0 -1
- package/dist/render/settle.d.ts +0 -60
- package/dist/render/settle.d.ts.map +0 -1
- package/dist/render/settle.js +0 -128
- package/dist/render/settle.js.map +0 -1
- package/dist/render/shared.d.ts +0 -25
- package/dist/render/shared.d.ts.map +0 -1
- package/dist/render/shared.js +0 -33
- package/dist/render/shared.js.map +0 -1
- package/dist/render/snapshot.d.ts +0 -21
- package/dist/render/snapshot.d.ts.map +0 -1
- package/dist/render/snapshot.js +0 -91
- package/dist/render/snapshot.js.map +0 -1
- package/dist/render/spares.d.ts +0 -56
- package/dist/render/spares.d.ts.map +0 -1
- package/dist/render/spares.js +0 -160
- package/dist/render/spares.js.map +0 -1
- package/dist/render/strokes.d.ts +0 -107
- package/dist/render/strokes.d.ts.map +0 -1
- package/dist/render/strokes.js +0 -448
- package/dist/render/strokes.js.map +0 -1
- package/dist/render/table.d.ts +0 -213
- package/dist/render/table.d.ts.map +0 -1
- package/dist/render/table.js +0 -795
- package/dist/render/table.js.map +0 -1
- package/dist/render/tessellate.d.ts +0 -89
- package/dist/render/tessellate.d.ts.map +0 -1
- package/dist/render/tessellate.js +0 -386
- package/dist/render/tessellate.js.map +0 -1
- package/dist/render/text.d.ts +0 -40
- package/dist/render/text.d.ts.map +0 -1
- package/dist/render/text.js +0 -309
- package/dist/render/text.js.map +0 -1
- package/dist/render/three.d.ts +0 -83
- package/dist/render/three.d.ts.map +0 -1
- package/dist/render/three.js +0 -511
- package/dist/render/three.js.map +0 -1
- package/dist/render/triangles.d.ts +0 -28
- package/dist/render/triangles.d.ts.map +0 -1
- package/dist/render/triangles.js +0 -189
- package/dist/render/triangles.js.map +0 -1
- package/dist/render/view.d.ts +0 -238
- package/dist/render/view.d.ts.map +0 -1
- package/dist/render/view.js +0 -1173
- package/dist/render/view.js.map +0 -1
- package/dist/render/worker/bitmaps.d.ts +0 -43
- package/dist/render/worker/bitmaps.d.ts.map +0 -1
- package/dist/render/worker/bitmaps.js +0 -151
- package/dist/render/worker/bitmaps.js.map +0 -1
- package/dist/render/worker/drawing.d.ts +0 -21
- package/dist/render/worker/drawing.d.ts.map +0 -1
- package/dist/render/worker/drawing.js +0 -356
- package/dist/render/worker/drawing.js.map +0 -1
- package/dist/render/worker/filters.d.ts +0 -7
- package/dist/render/worker/filters.d.ts.map +0 -1
- package/dist/render/worker/filters.js +0 -125
- package/dist/render/worker/filters.js.map +0 -1
- package/dist/render/worker/frames.d.ts +0 -32
- package/dist/render/worker/frames.d.ts.map +0 -1
- package/dist/render/worker/frames.js +0 -124
- package/dist/render/worker/frames.js.map +0 -1
- package/dist/render/worker/host.d.ts +0 -60
- package/dist/render/worker/host.d.ts.map +0 -1
- package/dist/render/worker/host.js +0 -297
- package/dist/render/worker/host.js.map +0 -1
- package/dist/render/worker/libraries.d.ts +0 -36
- package/dist/render/worker/libraries.d.ts.map +0 -1
- package/dist/render/worker/libraries.js +0 -153
- package/dist/render/worker/libraries.js.map +0 -1
- package/dist/render/worker/presentation.d.ts +0 -18
- package/dist/render/worker/presentation.d.ts.map +0 -1
- package/dist/render/worker/presentation.js +0 -47
- package/dist/render/worker/presentation.js.map +0 -1
- package/dist/render/worker/renderer.d.ts +0 -4
- package/dist/render/worker/renderer.d.ts.map +0 -1
- package/dist/render/worker/renderer.js +0 -21
- package/dist/render/worker/renderer.js.map +0 -1
- package/dist/render/worker/scene.d.ts +0 -32
- package/dist/render/worker/scene.d.ts.map +0 -1
- package/dist/render/worker/scene.js +0 -611
- package/dist/render/worker/scene.js.map +0 -1
- package/dist/render/worker/text.d.ts +0 -47
- package/dist/render/worker/text.d.ts.map +0 -1
- package/dist/render/worker/text.js +0 -261
- package/dist/render/worker/text.js.map +0 -1
- package/dist/render/worker/thread.d.ts +0 -23
- package/dist/render/worker/thread.d.ts.map +0 -1
- package/dist/render/worker/thread.js +0 -107
- package/dist/render/worker/thread.js.map +0 -1
- package/dist/render/worker/values.d.ts +0 -18
- package/dist/render/worker/values.d.ts.map +0 -1
- package/dist/render/worker/values.js +0 -64
- package/dist/render/worker/values.js.map +0 -1
- package/dist/sha256.d.ts +0 -5
- package/dist/sha256.d.ts.map +0 -1
- package/dist/sha256.js +0 -96
- package/dist/sha256.js.map +0 -1
- package/dist/shapes.d.ts +0 -71
- package/dist/shapes.d.ts.map +0 -1
- package/dist/shapes.js +0 -340
- package/dist/shapes.js.map +0 -1
- package/dist/static-text.d.ts +0 -33
- package/dist/static-text.d.ts.map +0 -1
- package/dist/static-text.js +0 -105
- package/dist/static-text.js.map +0 -1
- package/dist/text-layout.d.ts +0 -66
- package/dist/text-layout.d.ts.map +0 -1
- package/dist/text-layout.js +0 -315
- package/dist/text-layout.js.map +0 -1
- package/dist/text.d.ts +0 -67
- package/dist/text.d.ts.map +0 -1
- package/dist/text.js +0 -383
- package/dist/text.js.map +0 -1
- package/dist/timeline.d.ts +0 -150
- package/dist/timeline.d.ts.map +0 -1
- package/dist/timeline.js +0 -266
- package/dist/timeline.js.map +0 -1
package/dist/render/saffron.js
DELETED
|
@@ -1,725 +0,0 @@
|
|
|
1
|
-
import { Buffer, BufferImageSource, BufferUsage, Geometry, GlProgram, Mesh, RendererType, Shader, UniformGroup, } from "pixi.js";
|
|
2
|
-
import { CURVE, LINE, MOVE, shapeLayers } from "../display/shapes.js";
|
|
3
|
-
/** Most table entries a text's uniforms hold. */
|
|
4
|
-
const ENTRIES = 48;
|
|
5
|
-
/**
|
|
6
|
-
* Chords a curve is cut into stray from it by this fraction of the em at
|
|
7
|
-
* most: a 2048th, a hundredth of a pixel at 20 pixels, and few chords.
|
|
8
|
-
*/
|
|
9
|
-
const TOLERANCE = 2048;
|
|
10
|
-
// uView.x: Flash's pixels to a unit of the world, on whose grid they lie, whatever the target.
|
|
11
|
-
// uMode: gridFitType (0 none, 1 pixel, 2 subpixel), thickness, sharpness, and whether a Flash
|
|
12
|
-
// colour transform (uMul, uAdd) replaces Pixi's colour. uWorldOffset (the Pixi fork's): what a
|
|
13
|
-
// filter's input took off the world's translation. uTable: the tables' entries, size, inside,
|
|
14
|
-
// outside. A glyph's aOrigin is its pen and its light and dark tables, each its first entry plus
|
|
15
|
-
// 64 times its entries; aGlyph a corner of its outline's bounds and the way out from it; aRun its
|
|
16
|
-
// segments, first and count, the pixels of a unit of its outline, and its size.
|
|
17
|
-
const vertex = `#version 300 es
|
|
18
|
-
in vec2 aPosition;
|
|
19
|
-
in vec4 aOrigin;
|
|
20
|
-
in vec4 aGlyph;
|
|
21
|
-
in vec4 aRun;
|
|
22
|
-
in vec4 aColor;
|
|
23
|
-
out vec2 vPixel;
|
|
24
|
-
flat out vec2 vPen;
|
|
25
|
-
flat out vec4 vToGlyph;
|
|
26
|
-
flat out vec4 vToPixel;
|
|
27
|
-
flat out vec4 vCut;
|
|
28
|
-
flat out vec4 vShown;
|
|
29
|
-
uniform mat3 uProjectionMatrix;
|
|
30
|
-
uniform mat3 uWorldTransformMatrix;
|
|
31
|
-
uniform vec4 uWorldColorAlpha;
|
|
32
|
-
uniform mat3 uTransformMatrix;
|
|
33
|
-
uniform vec4 uColor;
|
|
34
|
-
uniform vec2 uWorldOffset;
|
|
35
|
-
uniform vec4 uView;
|
|
36
|
-
uniform vec4 uMode;
|
|
37
|
-
uniform vec4 uMul;
|
|
38
|
-
uniform vec4 uAdd;
|
|
39
|
-
uniform vec4 uTable[${ENTRIES}];
|
|
40
|
-
|
|
41
|
-
// The cutoffs at ppem by the table of entries start to start + count, as text/csm.ts' cutoffs.
|
|
42
|
-
vec2 cutoffs(int start, int count, float ppem) {
|
|
43
|
-
vec4 first = uTable[start];
|
|
44
|
-
vec4 last = uTable[start + count - 1];
|
|
45
|
-
vec2 c = first.yz;
|
|
46
|
-
if (ppem >= last.x) {
|
|
47
|
-
c = last.yz;
|
|
48
|
-
} else if (ppem > first.x) {
|
|
49
|
-
for (int i = 1; i < ${ENTRIES}; i++) {
|
|
50
|
-
if (i >= count) {
|
|
51
|
-
break;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
vec4 b = uTable[start + i];
|
|
55
|
-
if (ppem <= b.x) {
|
|
56
|
-
vec4 a = uTable[start + i - 1];
|
|
57
|
-
c = mix(a.yz, b.yz, (ppem - a.x) / (b.x - a.x));
|
|
58
|
-
break;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
float unit = 0.0001 * ppem;
|
|
64
|
-
float t = clamp(uMode.y, -200.0, 200.0);
|
|
65
|
-
float s = clamp(uMode.z, -400.0, 400.0);
|
|
66
|
-
c -= unit * vec2(t + s * 0.5, t - s * 0.5);
|
|
67
|
-
if (c.x < c.y) {
|
|
68
|
-
c = vec2((c.x + c.y) * 0.5);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return c;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
void main(void) {
|
|
75
|
-
// The local space to Flash's pixels, in the world's space: their grid is the stage's (or a
|
|
76
|
-
// BitmapData's) wherever the target lies on it, as a filter's does.
|
|
77
|
-
float unit = uView.x;
|
|
78
|
-
mat3 m = mat3(unit, 0.0, 0.0, 0.0, unit, 0.0, uWorldOffset * unit, 1.0)
|
|
79
|
-
* uWorldTransformMatrix * uTransformMatrix;
|
|
80
|
-
mat2 linear = mat2(m[0].xy, m[1].xy);
|
|
81
|
-
vec2 origin = m[2].xy;
|
|
82
|
-
vec2 pen = (m * vec3(aOrigin.xy, 1.0)).xy + roundEven(origin) - origin;
|
|
83
|
-
float across = max(abs(linear[0][1]), abs(linear[1][0]));
|
|
84
|
-
if (across > max(abs(linear[0][0]), abs(linear[1][1])) / 65536.0) {
|
|
85
|
-
// Turned or skewed: no grid.
|
|
86
|
-
} else if (uMode.x == 1.0) {
|
|
87
|
-
pen = vec2(roundEven(pen.x * 8.0) / 8.0 + 0.5, roundEven(pen.y));
|
|
88
|
-
} else if (uMode.x == 2.0) {
|
|
89
|
-
pen = vec2(roundEven(pen.x * 4.0) / 4.0 + 0.5, roundEven(pen.y));
|
|
90
|
-
} else {
|
|
91
|
-
pen = roundEven(pen * 4.0) / 4.0 + vec2(0.5, 0.0);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
float ppem = aRun.w * sqrt(abs(determinant(linear)));
|
|
95
|
-
// The colour as drawn, straight: light or dark by it, as adl chooses.
|
|
96
|
-
vec4 tint = uColor * uWorldColorAlpha;
|
|
97
|
-
vec4 shown = uMode.w < 0.5
|
|
98
|
-
? vec4(aColor.rgb * (tint.a > 0.0 ? tint.rgb / tint.a : vec3(0.0)), aColor.a * tint.a)
|
|
99
|
-
: clamp(aColor * uMul + uAdd, 0.0, 1.0);
|
|
100
|
-
bool light = dot(floor(shown.rgb * 255.0 + 0.5), vec3(30.0, 59.0, 11.0)) > 20000.0;
|
|
101
|
-
int table = int(light ? aOrigin.z : aOrigin.w);
|
|
102
|
-
vec2 cut = cutoffs(table & 63, table >> 6, ppem);
|
|
103
|
-
mat2 toPixel = linear * aRun.z;
|
|
104
|
-
float margin = max(abs(cut.x), abs(cut.y)) + 1.0;
|
|
105
|
-
float det = determinant(toPixel);
|
|
106
|
-
mat2 inverse = det != 0.0
|
|
107
|
-
? mat2(toPixel[1][1], -toPixel[0][1], -toPixel[1][0], toPixel[0][0]) / det
|
|
108
|
-
: mat2(0.0);
|
|
109
|
-
// Expand in glyph space so the margin stays outside under reflections and rotations.
|
|
110
|
-
// Each inverse row gives the glyph units needed for a pixel perpendicular to that edge.
|
|
111
|
-
vec2 reach = vec2(length(vec2(inverse[0][0], inverse[1][0])),
|
|
112
|
-
length(vec2(inverse[0][1], inverse[1][1]))) * margin;
|
|
113
|
-
vec2 p = pen + toPixel * (aGlyph.xy + aGlyph.zw * reach);
|
|
114
|
-
vPixel = p;
|
|
115
|
-
vPen = pen;
|
|
116
|
-
vToGlyph = vec4(inverse[0], inverse[1]);
|
|
117
|
-
vToPixel = vec4(toPixel[0], toPixel[1]);
|
|
118
|
-
vCut = vec4(cut, aRun.xy);
|
|
119
|
-
vShown = shown;
|
|
120
|
-
gl_Position = vec4((uProjectionMatrix * vec3(p / unit - uWorldOffset, 1.0)).xy, 0.0, 1.0);
|
|
121
|
-
}
|
|
122
|
-
`;
|
|
123
|
-
const fragment = `#version 300 es
|
|
124
|
-
precision highp float;
|
|
125
|
-
precision highp int;
|
|
126
|
-
in vec2 vPixel;
|
|
127
|
-
flat in vec2 vPen;
|
|
128
|
-
flat in vec4 vToGlyph;
|
|
129
|
-
flat in vec4 vToPixel;
|
|
130
|
-
flat in vec4 vCut;
|
|
131
|
-
flat in vec4 vShown;
|
|
132
|
-
out vec4 finalColor;
|
|
133
|
-
uniform highp sampler2D uSegments;
|
|
134
|
-
|
|
135
|
-
void main(void) {
|
|
136
|
-
vec2 centre = floor(vPixel) + 0.5;
|
|
137
|
-
mat2 toGlyph = mat2(vToGlyph.xy, vToGlyph.zw);
|
|
138
|
-
mat2 toPixel = mat2(vToPixel.xy, vToPixel.zw);
|
|
139
|
-
vec2 g = toGlyph * (centre - vPen);
|
|
140
|
-
int start = int(vCut.z);
|
|
141
|
-
int count = int(vCut.w);
|
|
142
|
-
float nearest = 3.4e38;
|
|
143
|
-
vec2 along = vec2(1.0, 0.0);
|
|
144
|
-
bool inside = false;
|
|
145
|
-
for (int i = 0; i < count; i++) {
|
|
146
|
-
int k = start + i;
|
|
147
|
-
vec4 s = texelFetch(uSegments, ivec2(k & 1023, k >> 10), 0);
|
|
148
|
-
vec2 a = s.xy;
|
|
149
|
-
vec2 e = s.zw - a;
|
|
150
|
-
vec2 w = g - a;
|
|
151
|
-
float t = clamp(dot(w, e) / max(dot(e, e), 1e-20), 0.0, 1.0);
|
|
152
|
-
vec2 off = w - e * t;
|
|
153
|
-
float d = dot(off, off);
|
|
154
|
-
if (d < nearest) {
|
|
155
|
-
nearest = d;
|
|
156
|
-
along = e;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if ((a.y > g.y) != (s.w > g.y) && a.x + (g.y - a.y) * e.x / e.y > g.x) {
|
|
160
|
-
inside = !inside;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// In Flash's pixels, across the nearest edge as the transform stretches it.
|
|
165
|
-
float stretch = length(toPixel * along);
|
|
166
|
-
float d = stretch > 0.0
|
|
167
|
-
? sqrt(nearest) * abs(determinant(toPixel)) * length(along) / stretch
|
|
168
|
-
: 0.0;
|
|
169
|
-
d = inside ? d : -d;
|
|
170
|
-
float coverage = vCut.x > vCut.y
|
|
171
|
-
? clamp((d - vCut.y) / (vCut.x - vCut.y), 0.0, 1.0)
|
|
172
|
-
: step(vCut.x, d);
|
|
173
|
-
// Nothing outside: as a mask, which writes the stencil wherever it draws, a glyph is its shape.
|
|
174
|
-
if (coverage <= 0.0) {
|
|
175
|
-
discard;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
finalColor = vec4(vShown.rgb * vShown.a, vShown.a) * coverage;
|
|
179
|
-
}
|
|
180
|
-
`;
|
|
181
|
-
let program = null;
|
|
182
|
-
/** Segments to a row of the texture. */
|
|
183
|
-
const ROW = 1024;
|
|
184
|
-
/** The most segments kept: 16 bytes each, 16 MB. Past it the store starts again. */
|
|
185
|
-
export const MOST = ROW * 1024;
|
|
186
|
-
/**
|
|
187
|
-
* The most segments a glyph may have: every pixel of its quad goes through
|
|
188
|
-
* them all, so a glyph past this is drawn as normal text is.
|
|
189
|
-
*/
|
|
190
|
-
export const GLYPH_MOST = 2048;
|
|
191
|
-
/**
|
|
192
|
-
* The most a field may ask of the shader, its glyphs' segments times the
|
|
193
|
-
* pixels of their quads: past it, the field is drawn as normal text, so
|
|
194
|
-
* that no SWF has the GPU go through millions of segments a pixel.
|
|
195
|
-
*/
|
|
196
|
-
export const FIELD_BUDGET = 2 ** 25;
|
|
197
|
-
/**
|
|
198
|
-
* The glyphs' outlines as segments, x0 y0 x1 y1 a texel, in the font's
|
|
199
|
-
* units over 20 (as shapeLayers reads them), each glyph's a run of its
|
|
200
|
-
* own: added as a glyph is first drawn, kept until the store is full, when
|
|
201
|
-
* it starts again and the texts drawn from it are drawn again, or until the
|
|
202
|
-
* last view that draws them goes.
|
|
203
|
-
*/
|
|
204
|
-
let data = new Float32Array(ROW * 4 * 16);
|
|
205
|
-
let used = 0;
|
|
206
|
-
let source = null;
|
|
207
|
-
/** Bumped as the store starts again, grows or goes: each renderer then uploads it whole. */
|
|
208
|
-
let epoch = 0;
|
|
209
|
-
/** Each renderer's upload of the store: of which epoch, and how many segments of it. */
|
|
210
|
-
const uploads = new WeakMap();
|
|
211
|
-
/** What a glyph of more segments than GLYPH_MOST is known by, so that it is not cut again. */
|
|
212
|
-
const TOO_MANY = { start: 0, count: 0, xMin: 0, yMin: 0, xMax: 0, yMax: 0 };
|
|
213
|
-
/** Each glyph's outline in the store as it now is; null for an empty one. */
|
|
214
|
-
let outlines = new WeakMap();
|
|
215
|
-
/** The texts drawn from the store, each with what draws it again. */
|
|
216
|
-
const live = new Map();
|
|
217
|
-
/** The segments' texture, made on first use; its contents go up as renderers draw (uploadSegments). */
|
|
218
|
-
function segments() {
|
|
219
|
-
source ??= new BufferImageSource({
|
|
220
|
-
resource: data,
|
|
221
|
-
width: ROW,
|
|
222
|
-
height: data.length / 4 / ROW,
|
|
223
|
-
format: "rgba32float",
|
|
224
|
-
scaleMode: "nearest",
|
|
225
|
-
alphaMode: "no-premultiply-alpha",
|
|
226
|
-
autoGenerateMipmaps: false,
|
|
227
|
-
});
|
|
228
|
-
return source;
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* Upload what `renderer` has not of the store: the rows added since it last
|
|
232
|
-
* did, or the whole after the store started again or grew. A view calls it
|
|
233
|
-
* after it syncs, before it draws.
|
|
234
|
-
*/
|
|
235
|
-
export function uploadSegments(renderer) {
|
|
236
|
-
if (!source || renderer.type !== RendererType.WEBGL) {
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
let upload = uploads.get(renderer);
|
|
240
|
-
if (!upload) {
|
|
241
|
-
// Its first bind uploads the texture whole.
|
|
242
|
-
upload = { epoch, segments: used };
|
|
243
|
-
uploads.set(renderer, upload);
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
const from = upload.epoch === epoch ? upload.segments : 0;
|
|
247
|
-
if (from >= used) {
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
const gl = renderer.gl;
|
|
251
|
-
const first = Math.floor(from / ROW);
|
|
252
|
-
const rows = Math.ceil(used / ROW) - first;
|
|
253
|
-
renderer.texture.bindForUpload(source);
|
|
254
|
-
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, first, ROW, rows, gl.RGBA, gl.FLOAT, data, first * ROW * 4);
|
|
255
|
-
upload.epoch = epoch;
|
|
256
|
-
upload.segments = used;
|
|
257
|
-
}
|
|
258
|
-
/**
|
|
259
|
-
* Start the store again: every outline is cut again on its next draw, and
|
|
260
|
-
* every text drawn from the store hidden till it is drawn again.
|
|
261
|
-
*/
|
|
262
|
-
export function resetSegments() {
|
|
263
|
-
used = 0;
|
|
264
|
-
epoch++;
|
|
265
|
-
outlines = new WeakMap();
|
|
266
|
-
for (const [text, again] of live) {
|
|
267
|
-
text.visible = false;
|
|
268
|
-
again();
|
|
269
|
-
}
|
|
270
|
-
live.clear();
|
|
271
|
-
}
|
|
272
|
-
/** How many segments the store holds, for tests. */
|
|
273
|
-
export function segmentsUsed() {
|
|
274
|
-
return used;
|
|
275
|
-
}
|
|
276
|
-
/** Room for `count` more segments, the store grown to hold them: false past MOST. */
|
|
277
|
-
function room(count) {
|
|
278
|
-
if (used + count > MOST) {
|
|
279
|
-
return false;
|
|
280
|
-
}
|
|
281
|
-
if ((used + count) * 4 > data.length) {
|
|
282
|
-
let length = data.length;
|
|
283
|
-
while ((used + count) * 4 > length) {
|
|
284
|
-
length *= 2;
|
|
285
|
-
}
|
|
286
|
-
const grown = new Float32Array(length);
|
|
287
|
-
grown.set(data.subarray(0, used * 4));
|
|
288
|
-
data = grown;
|
|
289
|
-
if (source) {
|
|
290
|
-
source.resource = data;
|
|
291
|
-
source.resize(ROW, length / 4 / ROW, 1);
|
|
292
|
-
}
|
|
293
|
-
epoch++;
|
|
294
|
-
}
|
|
295
|
-
return true;
|
|
296
|
-
}
|
|
297
|
-
/**
|
|
298
|
-
* A glyph's outline cut into segments, its curves into chords that stray
|
|
299
|
-
* from them by `tolerance` at most, as x0 y0 x1 y1 each.
|
|
300
|
-
*/
|
|
301
|
-
export function chordsOf(glyph, tolerance) {
|
|
302
|
-
const shape = {
|
|
303
|
-
id: 0,
|
|
304
|
-
bounds: { xMin: 0, xMax: 0, yMin: 0, yMax: 0 },
|
|
305
|
-
edgeBounds: null,
|
|
306
|
-
fills: [{ type: "solid", color: 0xffffffff }],
|
|
307
|
-
lines: [],
|
|
308
|
-
records: glyph.records,
|
|
309
|
-
truncated: false,
|
|
310
|
-
};
|
|
311
|
-
const layers = shapeLayers(shape);
|
|
312
|
-
const points = [];
|
|
313
|
-
const contours = layers.length > 0 ? layers[0].fills.flatMap((f) => f.contours) : [];
|
|
314
|
-
for (const path of contours) {
|
|
315
|
-
let x = 0;
|
|
316
|
-
let y = 0;
|
|
317
|
-
let startX = 0;
|
|
318
|
-
let startY = 0;
|
|
319
|
-
for (let i = 0; i < path.length;) {
|
|
320
|
-
switch (path[i]) {
|
|
321
|
-
case MOVE:
|
|
322
|
-
if (x !== startX || y !== startY) {
|
|
323
|
-
points.push(x, y, startX, startY);
|
|
324
|
-
}
|
|
325
|
-
x = startX = path[i + 1];
|
|
326
|
-
y = startY = path[i + 2];
|
|
327
|
-
i += 3;
|
|
328
|
-
break;
|
|
329
|
-
case LINE:
|
|
330
|
-
points.push(x, y, path[i + 1], path[i + 2]);
|
|
331
|
-
x = path[i + 1];
|
|
332
|
-
y = path[i + 2];
|
|
333
|
-
i += 3;
|
|
334
|
-
break;
|
|
335
|
-
case CURVE: {
|
|
336
|
-
const cx = path[i + 1];
|
|
337
|
-
const cy = path[i + 2];
|
|
338
|
-
const ax = path[i + 3];
|
|
339
|
-
const ay = path[i + 4];
|
|
340
|
-
// A quadratic strays from its chords of a nth of it by |p0 - 2c + p1| / 4n² at most.
|
|
341
|
-
const bend = Math.hypot(x - 2 * cx + ax, y - 2 * cy + ay);
|
|
342
|
-
const n = Math.max(1, Math.min(64, Math.ceil(Math.sqrt(bend / (4 * tolerance)))));
|
|
343
|
-
let px = x;
|
|
344
|
-
let py = y;
|
|
345
|
-
for (let k = 1; k <= n; k++) {
|
|
346
|
-
const t = k / n;
|
|
347
|
-
const u = 1 - t;
|
|
348
|
-
const qx = u * u * x + 2 * u * t * cx + t * t * ax;
|
|
349
|
-
const qy = u * u * y + 2 * u * t * cy + t * t * ay;
|
|
350
|
-
points.push(px, py, qx, qy);
|
|
351
|
-
px = qx;
|
|
352
|
-
py = qy;
|
|
353
|
-
}
|
|
354
|
-
x = ax;
|
|
355
|
-
y = ay;
|
|
356
|
-
i += 5;
|
|
357
|
-
break;
|
|
358
|
-
}
|
|
359
|
-
default:
|
|
360
|
-
// A cubic, which no glyph has.
|
|
361
|
-
i += 7;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
if (x !== startX || y !== startY) {
|
|
365
|
-
points.push(x, y, startX, startY);
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
return points;
|
|
369
|
-
}
|
|
370
|
-
/**
|
|
371
|
-
* A glyph's outline in the store, cut on its first draw: null for an empty
|
|
372
|
-
* glyph, undefined for one of more segments than GLYPH_MOST or past the
|
|
373
|
-
* store's room.
|
|
374
|
-
*/
|
|
375
|
-
function outlineOf(glyph, tolerance) {
|
|
376
|
-
const known = outlines.get(glyph);
|
|
377
|
-
if (known !== undefined) {
|
|
378
|
-
return known === TOO_MANY ? undefined : known;
|
|
379
|
-
}
|
|
380
|
-
const points = chordsOf(glyph, tolerance);
|
|
381
|
-
const count = points.length / 4;
|
|
382
|
-
if (count === 0) {
|
|
383
|
-
outlines.set(glyph, null);
|
|
384
|
-
return null;
|
|
385
|
-
}
|
|
386
|
-
if (count > GLYPH_MOST) {
|
|
387
|
-
outlines.set(glyph, TOO_MANY);
|
|
388
|
-
return undefined;
|
|
389
|
-
}
|
|
390
|
-
if (!room(count)) {
|
|
391
|
-
return undefined;
|
|
392
|
-
}
|
|
393
|
-
const outline = {
|
|
394
|
-
start: used,
|
|
395
|
-
count,
|
|
396
|
-
xMin: Number.POSITIVE_INFINITY,
|
|
397
|
-
yMin: Number.POSITIVE_INFINITY,
|
|
398
|
-
xMax: Number.NEGATIVE_INFINITY,
|
|
399
|
-
yMax: Number.NEGATIVE_INFINITY,
|
|
400
|
-
};
|
|
401
|
-
for (let i = 0; i < points.length; i += 2) {
|
|
402
|
-
outline.xMin = Math.min(outline.xMin, points[i]);
|
|
403
|
-
outline.xMax = Math.max(outline.xMax, points[i]);
|
|
404
|
-
outline.yMin = Math.min(outline.yMin, points[i + 1]);
|
|
405
|
-
outline.yMax = Math.max(outline.yMax, points[i + 1]);
|
|
406
|
-
}
|
|
407
|
-
data.set(points, used * 4);
|
|
408
|
-
used += count;
|
|
409
|
-
outlines.set(glyph, outline);
|
|
410
|
-
return outline;
|
|
411
|
-
}
|
|
412
|
-
/** The views that draw on the stage, by which the store is kept: it goes with the last. */
|
|
413
|
-
let views = 0;
|
|
414
|
-
const viewsGone = new FinalizationRegistry(() => {
|
|
415
|
-
views--;
|
|
416
|
-
if (views === 0) {
|
|
417
|
-
resetSegments();
|
|
418
|
-
source?.destroy();
|
|
419
|
-
source = null;
|
|
420
|
-
data = new Float32Array(ROW * 4 * 16);
|
|
421
|
-
}
|
|
422
|
-
});
|
|
423
|
-
/**
|
|
424
|
-
* What every advanced text a view draws shares: Flash's pixels to a unit
|
|
425
|
-
* of its world, and whether its renderer draws them at all (WebGL 2, as
|
|
426
|
-
* the shader is GLSL ES 3.0; elsewhere text is drawn as normal text).
|
|
427
|
-
*/
|
|
428
|
-
export class SaffronView {
|
|
429
|
-
uniforms = new UniformGroup({
|
|
430
|
-
uView: { value: new Float32Array([1, 0, 0, 0]), type: "vec4<f32>" },
|
|
431
|
-
});
|
|
432
|
-
enabled;
|
|
433
|
-
constructor(renderer, keeps) {
|
|
434
|
-
this.enabled =
|
|
435
|
-
renderer.type === RendererType.WEBGL &&
|
|
436
|
-
renderer.context?.webGLVersion === 2;
|
|
437
|
-
if (keeps) {
|
|
438
|
-
views++;
|
|
439
|
-
viewsGone.register(this, null);
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
get unit() {
|
|
443
|
-
return this.uniforms.uniforms.uView[0];
|
|
444
|
-
}
|
|
445
|
-
set unit(unit) {
|
|
446
|
-
const view = this.uniforms.uniforms.uView;
|
|
447
|
-
if (view[0] !== unit) {
|
|
448
|
-
view[0] = unit;
|
|
449
|
-
this.uniforms.update();
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
/** The corners of a glyph's quad, as signs: the margin goes out from it so. */
|
|
454
|
-
const CORNERS = [-1, -1, 1, -1, 1, 1, -1, 1];
|
|
455
|
-
/** Floats a vertex: aPosition 2, then aOrigin, aGlyph, aRun and aColor 4 each. */
|
|
456
|
-
const STRIDE = 18;
|
|
457
|
-
/** The vertices a builder writes, reused by the next: builders build one at a time. */
|
|
458
|
-
let scratch = new Float32Array(STRIDE * 4 * 64);
|
|
459
|
-
/** Indices of quads in order, two triangles each: views of one array, which only grows. */
|
|
460
|
-
let quads = new Uint32Array(0);
|
|
461
|
-
function quadIndices(count) {
|
|
462
|
-
if (quads.length < count * 6) {
|
|
463
|
-
const n = Math.max(count, quads.length / 3);
|
|
464
|
-
quads = new Uint32Array(n * 6);
|
|
465
|
-
for (let i = 0; i < n; i++) {
|
|
466
|
-
const v = i * 4;
|
|
467
|
-
const at = i * 6;
|
|
468
|
-
quads[at] = v;
|
|
469
|
-
quads[at + 1] = v + 1;
|
|
470
|
-
quads[at + 2] = v + 2;
|
|
471
|
-
quads[at + 3] = v;
|
|
472
|
-
quads[at + 4] = v + 2;
|
|
473
|
-
quads[at + 5] = v + 3;
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
return quads.subarray(0, count * 6);
|
|
477
|
-
}
|
|
478
|
-
/** The finite value of `v`, 0 for NaN or an infinity, as a field's settings reach the shader. */
|
|
479
|
-
const finite = (v) => (Number.isFinite(v) ? v : 0);
|
|
480
|
-
/** The table's furthest cutoff from the outline, in pixels. */
|
|
481
|
-
function reachOf(table) {
|
|
482
|
-
let reach = 0;
|
|
483
|
-
for (let i = 0; i < table.length; i += 3) {
|
|
484
|
-
reach = Math.max(reach, Math.abs(table[i + 1]), Math.abs(table[i + 2]));
|
|
485
|
-
}
|
|
486
|
-
return reach;
|
|
487
|
-
}
|
|
488
|
-
/**
|
|
489
|
-
* The glyphs of a text drawn with advanced anti-aliasing: each glyph first
|
|
490
|
-
* reserved (reserve), which cuts its outline and counts what it asks of
|
|
491
|
-
* the shader, then, if all fit, added (add) and made into one mesh
|
|
492
|
-
* (done). One builds at a time: they share the vertices they write.
|
|
493
|
-
*/
|
|
494
|
-
export class SaffronBuilder {
|
|
495
|
-
view;
|
|
496
|
-
grid;
|
|
497
|
-
scale;
|
|
498
|
-
again;
|
|
499
|
-
glyphs = 0;
|
|
500
|
-
tables = [];
|
|
501
|
-
starts = [];
|
|
502
|
-
entries = 0;
|
|
503
|
-
cost = 0;
|
|
504
|
-
thickness;
|
|
505
|
-
sharpness;
|
|
506
|
-
/** The epoch the reserved glyphs' outlines are of. */
|
|
507
|
-
reserved = epoch;
|
|
508
|
-
constructor(view,
|
|
509
|
-
/** 0 none, 1 pixel, 2 subpixel. */
|
|
510
|
-
grid, thickness, sharpness,
|
|
511
|
-
/** Flash's pixels to a pixel of the text, as it is placed now, for the quads' reach and cost. */
|
|
512
|
-
scale,
|
|
513
|
-
/** Draws the text again, when the store it is drawn from starts again. */
|
|
514
|
-
again) {
|
|
515
|
-
this.view = view;
|
|
516
|
-
this.grid = grid;
|
|
517
|
-
this.scale = scale;
|
|
518
|
-
this.again = again;
|
|
519
|
-
this.thickness = finite(thickness);
|
|
520
|
-
this.sharpness = finite(sharpness);
|
|
521
|
-
}
|
|
522
|
-
/** Flash's pixels the shader may reach past the outline, at `size` pixels to the em, by `tables`. */
|
|
523
|
-
reach(size, tables) {
|
|
524
|
-
const ppem = size * this.scale;
|
|
525
|
-
const moved = 0.0001 * ppem * (Math.abs(this.thickness) + Math.abs(this.sharpness) / 2);
|
|
526
|
-
// And a pixel round, and two for the pen's snapping.
|
|
527
|
-
return Math.max(reachOf(tables[0]), reachOf(tables[1])) + moved + 3;
|
|
528
|
-
}
|
|
529
|
-
/**
|
|
530
|
-
* Cut a glyph of a font of `em` units and count it at `size` pixels to the
|
|
531
|
-
* em: false where the text cannot be drawn so, a glyph past GLYPH_MOST
|
|
532
|
-
* or the field past FIELD_BUDGET, for the whole text to be drawn as
|
|
533
|
-
* normal text. The store may start again here: reserving every glyph
|
|
534
|
-
* then goes again (reserveAll).
|
|
535
|
-
*/
|
|
536
|
-
reserve(glyph, em, size, tables) {
|
|
537
|
-
const units = em / 20;
|
|
538
|
-
let outline = outlineOf(glyph, units / TOLERANCE);
|
|
539
|
-
if (outline === undefined && outlines.get(glyph) !== TOO_MANY) {
|
|
540
|
-
resetSegments();
|
|
541
|
-
outline = outlineOf(glyph, units / TOLERANCE);
|
|
542
|
-
}
|
|
543
|
-
if (outline === undefined) {
|
|
544
|
-
return false;
|
|
545
|
-
}
|
|
546
|
-
if (outline === null) {
|
|
547
|
-
return true;
|
|
548
|
-
}
|
|
549
|
-
const s = (size / units) * this.scale;
|
|
550
|
-
const margin = 2 * this.reach(size, tables);
|
|
551
|
-
const area = ((outline.xMax - outline.xMin) * s + margin) * ((outline.yMax - outline.yMin) * s + margin);
|
|
552
|
-
this.cost += outline.count * area;
|
|
553
|
-
return this.cost <= FIELD_BUDGET;
|
|
554
|
-
}
|
|
555
|
-
/**
|
|
556
|
-
* Whether every glyph reserved since restart is still in the store as it
|
|
557
|
-
* was: false where the store started again while they were reserved.
|
|
558
|
-
*/
|
|
559
|
-
intact() {
|
|
560
|
-
return this.reserved === epoch;
|
|
561
|
-
}
|
|
562
|
-
/** Reserve afresh, the store's epoch now. */
|
|
563
|
-
restart() {
|
|
564
|
-
this.cost = 0;
|
|
565
|
-
this.reserved = epoch;
|
|
566
|
-
}
|
|
567
|
-
/**
|
|
568
|
-
* Add a reserved glyph, its pen at (x, y) in the text's pixels, `size`
|
|
569
|
-
* pixels to the em, in 0xRRGGBB and `alpha`, by the light or the dark of
|
|
570
|
-
* `tables` as its colour is drawn: false where the tables' room is full,
|
|
571
|
-
* which leaves the text to be drawn as normal text.
|
|
572
|
-
*/
|
|
573
|
-
add(glyph, em, x, y, size, color, alpha, tables) {
|
|
574
|
-
const units = em / 20;
|
|
575
|
-
const outline = outlineOf(glyph, units / TOLERANCE);
|
|
576
|
-
if (outline === null) {
|
|
577
|
-
return true;
|
|
578
|
-
}
|
|
579
|
-
if (outline === undefined) {
|
|
580
|
-
return false;
|
|
581
|
-
}
|
|
582
|
-
const light = this.code(tables[0]);
|
|
583
|
-
const dark = this.code(tables[1]);
|
|
584
|
-
if (light < 0 || dark < 0) {
|
|
585
|
-
return false;
|
|
586
|
-
}
|
|
587
|
-
if ((this.glyphs + 1) * 4 * STRIDE > scratch.length) {
|
|
588
|
-
const grown = new Float32Array(scratch.length * 2);
|
|
589
|
-
grown.set(scratch.subarray(0, this.glyphs * 4 * STRIDE));
|
|
590
|
-
scratch = grown;
|
|
591
|
-
}
|
|
592
|
-
const scale = size / units;
|
|
593
|
-
// Where the quad reaches in the text's pixels, for Pixi's bounds (filters, culling): the
|
|
594
|
-
// shader moves it out by the cutoffs from where the pen snaps.
|
|
595
|
-
const out = this.reach(size, tables) / Math.max(this.scale, 1 / 64);
|
|
596
|
-
const r = ((color >> 16) & 0xff) / 255;
|
|
597
|
-
const g = ((color >> 8) & 0xff) / 255;
|
|
598
|
-
const b = (color & 0xff) / 255;
|
|
599
|
-
let at = this.glyphs * 4 * STRIDE;
|
|
600
|
-
for (let k = 0; k < 8; k += 2) {
|
|
601
|
-
const sx = CORNERS[k];
|
|
602
|
-
const sy = CORNERS[k + 1];
|
|
603
|
-
const gx = sx < 0 ? outline.xMin : outline.xMax;
|
|
604
|
-
const gy = sy < 0 ? outline.yMin : outline.yMax;
|
|
605
|
-
scratch[at] = x + gx * scale + sx * out;
|
|
606
|
-
scratch[at + 1] = y + gy * scale + sy * out;
|
|
607
|
-
scratch[at + 2] = x;
|
|
608
|
-
scratch[at + 3] = y;
|
|
609
|
-
scratch[at + 4] = light;
|
|
610
|
-
scratch[at + 5] = dark;
|
|
611
|
-
scratch[at + 6] = gx;
|
|
612
|
-
scratch[at + 7] = gy;
|
|
613
|
-
scratch[at + 8] = sx;
|
|
614
|
-
scratch[at + 9] = sy;
|
|
615
|
-
scratch[at + 10] = outline.start;
|
|
616
|
-
scratch[at + 11] = outline.count;
|
|
617
|
-
scratch[at + 12] = scale;
|
|
618
|
-
scratch[at + 13] = size;
|
|
619
|
-
scratch[at + 14] = r;
|
|
620
|
-
scratch[at + 15] = g;
|
|
621
|
-
scratch[at + 16] = b;
|
|
622
|
-
scratch[at + 17] = alpha;
|
|
623
|
-
at += STRIDE;
|
|
624
|
-
}
|
|
625
|
-
this.glyphs++;
|
|
626
|
-
return true;
|
|
627
|
-
}
|
|
628
|
-
/** A table's place in the uniforms, its first entry plus 64 times its entries, added where new; -1 past their room. */
|
|
629
|
-
code(table) {
|
|
630
|
-
let t = this.tables.indexOf(table);
|
|
631
|
-
if (t < 0) {
|
|
632
|
-
if (this.entries + table.length / 3 > ENTRIES) {
|
|
633
|
-
return -1;
|
|
634
|
-
}
|
|
635
|
-
t = this.tables.length;
|
|
636
|
-
this.tables.push(table);
|
|
637
|
-
this.starts.push(this.entries);
|
|
638
|
-
this.entries += table.length / 3;
|
|
639
|
-
}
|
|
640
|
-
return this.starts[t] + (table.length / 3) * 64;
|
|
641
|
-
}
|
|
642
|
-
/** The mesh of the glyphs added, null for none. */
|
|
643
|
-
done() {
|
|
644
|
-
if (this.glyphs === 0) {
|
|
645
|
-
return null;
|
|
646
|
-
}
|
|
647
|
-
const buffer = new Buffer({
|
|
648
|
-
data: scratch.slice(0, this.glyphs * 4 * STRIDE),
|
|
649
|
-
usage: BufferUsage.VERTEX | BufferUsage.COPY_DST,
|
|
650
|
-
});
|
|
651
|
-
const bytes = STRIDE * 4;
|
|
652
|
-
const geometry = new Geometry({
|
|
653
|
-
attributes: {
|
|
654
|
-
aPosition: { buffer, format: "float32x2", stride: bytes, offset: 0 },
|
|
655
|
-
aOrigin: { buffer, format: "float32x4", stride: bytes, offset: 8 },
|
|
656
|
-
aGlyph: { buffer, format: "float32x4", stride: bytes, offset: 24 },
|
|
657
|
-
aRun: { buffer, format: "float32x4", stride: bytes, offset: 40 },
|
|
658
|
-
aColor: { buffer, format: "float32x4", stride: bytes, offset: 56 },
|
|
659
|
-
},
|
|
660
|
-
indexBuffer: quadIndices(this.glyphs),
|
|
661
|
-
});
|
|
662
|
-
const table = new Float32Array(ENTRIES * 4);
|
|
663
|
-
for (let t = 0; t < this.tables.length; t++) {
|
|
664
|
-
const entries = this.tables[t];
|
|
665
|
-
for (let i = 0; i < entries.length; i += 3) {
|
|
666
|
-
const at = (this.starts[t] + i / 3) * 4;
|
|
667
|
-
table[at] = entries[i];
|
|
668
|
-
table[at + 1] = entries[i + 1];
|
|
669
|
-
table[at + 2] = entries[i + 2];
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
const text = new SaffronText(geometry, this.view, new Float32Array([this.grid, this.thickness, this.sharpness, 0]), table);
|
|
673
|
-
live.set(text, this.again);
|
|
674
|
-
return text;
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
/**
|
|
678
|
-
* A text's glyphs drawn with advanced anti-aliasing: a mesh of their
|
|
679
|
-
* quads under its own shader, one draw. It destroys its geometry and its
|
|
680
|
-
* shader with itself, and leaves the segments' texture, which every one
|
|
681
|
-
* shares.
|
|
682
|
-
*/
|
|
683
|
-
export class SaffronText extends Mesh {
|
|
684
|
-
uniforms;
|
|
685
|
-
flash = null;
|
|
686
|
-
constructor(geometry, view, mode, table) {
|
|
687
|
-
program ??= new GlProgram({ vertex, fragment, name: "flash-saffron" });
|
|
688
|
-
const uniforms = new UniformGroup({
|
|
689
|
-
uMode: { value: mode, type: "vec4<f32>" },
|
|
690
|
-
uMul: { value: new Float32Array([1, 1, 1, 1]), type: "vec4<f32>" },
|
|
691
|
-
uAdd: { value: new Float32Array(4), type: "vec4<f32>" },
|
|
692
|
-
uTable: { value: table, type: "vec4<f32>", size: ENTRIES },
|
|
693
|
-
});
|
|
694
|
-
const shader = new Shader({
|
|
695
|
-
glProgram: program,
|
|
696
|
-
resources: { uSegments: segments(), saffronView: view.uniforms, saffronText: uniforms },
|
|
697
|
-
});
|
|
698
|
-
super({ geometry, shader });
|
|
699
|
-
this.uniforms = uniforms;
|
|
700
|
-
}
|
|
701
|
-
/** The Flash colour transform it draws under, in place of Pixi's colour (render/color.ts). */
|
|
702
|
-
get flashColor() {
|
|
703
|
-
return this.flash;
|
|
704
|
-
}
|
|
705
|
-
set flashColor(ct) {
|
|
706
|
-
this.flash = ct;
|
|
707
|
-
const { uMode, uMul, uAdd } = this.uniforms.uniforms;
|
|
708
|
-
uMode[3] = ct ? 1 : 0;
|
|
709
|
-
if (ct) {
|
|
710
|
-
uMul.set([ct.rMul, ct.gMul, ct.bMul, ct.aMul]);
|
|
711
|
-
uAdd.set([ct.rAdd / 255, ct.gAdd / 255, ct.bAdd / 255, ct.aAdd / 255]);
|
|
712
|
-
}
|
|
713
|
-
this.uniforms.update();
|
|
714
|
-
}
|
|
715
|
-
destroy() {
|
|
716
|
-
const geometry = this.geometry;
|
|
717
|
-
const shader = this.shader;
|
|
718
|
-
live.delete(this);
|
|
719
|
-
super.destroy();
|
|
720
|
-
// Its buffers too: the renderer holds a buffer, and its data, till the buffer goes.
|
|
721
|
-
geometry.destroy(true);
|
|
722
|
-
shader.destroy();
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
//# sourceMappingURL=saffron.js.map
|