@zinejs/core 0.1.0 → 0.3.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/README.md +7 -2
- package/dist/cssRenderer-OzRRoEa4.js +127 -0
- package/dist/cssRenderer-OzRRoEa4.js.map +1 -0
- package/dist/engine/spread.d.ts +10 -5
- package/dist/geometry/curls/cone.d.ts +17 -0
- package/dist/geometry/curls/flick.d.ts +20 -0
- package/dist/geometry/curls/index.d.ts +5 -0
- package/dist/geometry/curls/leaf.d.ts +19 -0
- package/dist/geometry/curls/mesh.d.ts +20 -0
- package/dist/geometry/curls/roll.d.ts +8 -0
- package/dist/geometry/curls/simple.d.ts +7 -0
- package/dist/geometry/curls/types.d.ts +25 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +476 -315
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +47 -60
- package/dist/index.umd.cjs.map +1 -1
- package/dist/renderer/types.d.ts +22 -0
- package/dist/renderer/webglRenderer.d.ts +6 -5
- package/dist/source/compose.d.ts +16 -0
- package/dist/source/types.d.ts +6 -0
- package/dist/types-D-rEO00p.js +12 -0
- package/dist/types-D-rEO00p.js.map +1 -0
- package/dist/webglRenderer-Bg6VF4CW.js +558 -0
- package/dist/webglRenderer-Bg6VF4CW.js.map +1 -0
- package/dist/zine.d.ts +12 -3
- package/options.schema.json +27 -7
- package/package.json +1 -1
- package/dist/cssRenderer-BACNXO8M.js +0 -68
- package/dist/cssRenderer-BACNXO8M.js.map +0 -1
- package/dist/flipProgressToPose-DZWSuKoE.js +0 -13
- package/dist/flipProgressToPose-DZWSuKoE.js.map +0 -1
- package/dist/webglRenderer-D-1UyC-B.js +0 -306
- package/dist/webglRenderer-D-1UyC-B.js.map +0 -1
|
@@ -1,306 +0,0 @@
|
|
|
1
|
-
import { t as e } from "./flipProgressToPose-DZWSuKoE.js";
|
|
2
|
-
//#region src/renderer/gl/context.ts
|
|
3
|
-
function t(e) {
|
|
4
|
-
let t = e.getContext("webgl2", {
|
|
5
|
-
alpha: !0,
|
|
6
|
-
premultipliedAlpha: !0,
|
|
7
|
-
antialias: !0,
|
|
8
|
-
depth: !1,
|
|
9
|
-
stencil: !1,
|
|
10
|
-
preserveDrawingBuffer: !0
|
|
11
|
-
});
|
|
12
|
-
if (t === null) throw Error("WebglRenderer: could not create a WebGL2 context.");
|
|
13
|
-
return t;
|
|
14
|
-
}
|
|
15
|
-
//#endregion
|
|
16
|
-
//#region src/renderer/gl/program.ts
|
|
17
|
-
function n(e, t, n) {
|
|
18
|
-
let i = e.createProgram();
|
|
19
|
-
if (i === null) throw Error("WebglRenderer: could not create a program.");
|
|
20
|
-
let a = r(e, e.VERTEX_SHADER, t), o = r(e, e.FRAGMENT_SHADER, n);
|
|
21
|
-
if (e.attachShader(i, a), e.attachShader(i, o), e.linkProgram(i), e.deleteShader(a), e.deleteShader(o), !e.getProgramParameter(i, e.LINK_STATUS)) {
|
|
22
|
-
let t = e.getProgramInfoLog(i);
|
|
23
|
-
throw e.deleteProgram(i), Error(`WebglRenderer: program link failed: ${t ?? "unknown error"}`);
|
|
24
|
-
}
|
|
25
|
-
return i;
|
|
26
|
-
}
|
|
27
|
-
function r(e, t, n) {
|
|
28
|
-
let r = e.createShader(t);
|
|
29
|
-
if (r === null) throw Error("WebglRenderer: could not create a shader.");
|
|
30
|
-
if (e.shaderSource(r, n), e.compileShader(r), !e.getShaderParameter(r, e.COMPILE_STATUS)) {
|
|
31
|
-
let t = e.getShaderInfoLog(r);
|
|
32
|
-
throw e.deleteShader(r), Error(`WebglRenderer: shader compile failed: ${t ?? "unknown error"}`);
|
|
33
|
-
}
|
|
34
|
-
return r;
|
|
35
|
-
}
|
|
36
|
-
//#endregion
|
|
37
|
-
//#region src/renderer/gl/texture.ts
|
|
38
|
-
function i(e) {
|
|
39
|
-
let t = e.createTexture();
|
|
40
|
-
if (t === null) throw Error("WebglRenderer: could not create a texture.");
|
|
41
|
-
return e.bindTexture(e.TEXTURE_2D, t), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_S, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_T, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, e.LINEAR), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, e.LINEAR), t;
|
|
42
|
-
}
|
|
43
|
-
function a(e, t, n) {
|
|
44
|
-
e.bindTexture(e.TEXTURE_2D, t), e.pixelStorei(e.UNPACK_FLIP_Y_WEBGL, !1), e.pixelStorei(e.UNPACK_PREMULTIPLY_ALPHA_WEBGL, !0), e.texImage2D(e.TEXTURE_2D, 0, e.RGBA, e.RGBA, e.UNSIGNED_BYTE, n);
|
|
45
|
-
}
|
|
46
|
-
//#endregion
|
|
47
|
-
//#region src/renderer/webglRenderer.ts
|
|
48
|
-
var o = "#version 300 es\nin vec2 aUnit;\nuniform vec2 uViewport;\nuniform vec4 uRect;\nuniform vec3 uView;\nout vec2 vUv;\nvoid main() {\n vec2 px = uRect.xy + aUnit * uRect.zw;\n px = px * uView.x + uView.yz;\n vec2 clip = px / uViewport * 2.0 - 1.0;\n gl_Position = vec4(clip.x, -clip.y, 0.0, 1.0);\n vUv = aUnit;\n}", s = "#version 300 es\nprecision mediump float;\nin vec2 vUv;\nuniform sampler2D uTex;\nuniform float uGutterSide; // +1 = spine at the right edge, -1 = at the left edge, 0 = none\nout vec4 outColor;\nvoid main() {\n vec4 c = texture(uTex, vUv);\n if (uGutterSide != 0.0) {\n // Soft, permanent gutter shadow: darken toward the spine edge where the pages\n // meet, so the turning leaf's spine shadow lands into it instead of vanishing.\n float d = uGutterSide > 0.0 ? (1.0 - vUv.x) : vUv.x;\n c.rgb *= mix(0.72, 1.0, smoothstep(0.0, 0.10, d));\n }\n outColor = c;\n}", c = "#version 300 es\nin vec2 aUnit;\nuniform vec2 uViewport;\nuniform vec4 uLeaf; // spineX, y, width, height (device px)\nuniform vec3 uView; // scale, tx, ty\nuniform float uAngle; // spine rotation 0..PI\nuniform float uCurl; // 0..1 bend amount\nuniform float uDir; // +1 leaf sweeps from +x side, -1 from -x side\nout vec2 vUv;\nout float vU;\nout float vLight; // surface facing: +1 toward viewer, 0 edge-on, -1 away\nconst float CAM = 3.0; // perspective camera distance, in page widths (bigger = subtler)\nvoid main() {\n float u = aUnit.x;\n float W = uLeaf.z;\n // Cylinder wrap of the turning sheet, rotated about the spine (vertical y axis).\n float bend = uCurl * 1.5;\n float phi, xw, zw;\n if (bend > 0.001) {\n float R = W / bend;\n phi = u * bend;\n xw = R * sin(phi);\n zw = R * (1.0 - cos(phi));\n } else {\n phi = 0.0;\n xw = u * W;\n zw = 0.0;\n }\n float X = xw * cos(uAngle) - zw * sin(uAngle); // in-plane\n float Z = xw * sin(uAngle) + zw * cos(uAngle); // depth (+ toward viewer)\n float px = uLeaf.x + uDir * X;\n float py = uLeaf.y + aUnit.y * uLeaf.w;\n // Perspective by depth. X may bulge toward the viewer for 3D pop; Y only ever\n // SHRINKS (persp clamped <= 1) about the page's own vertical center, so the top\n // is never pushed past the frame (that was the hidden-top bug).\n float D = W * CAM;\n float persp = D / max(D - Z, 1.0);\n float cx = uViewport.x * 0.5;\n float cy = uLeaf.y + 0.5 * uLeaf.w;\n px = cx + (px - cx) * persp;\n py = cy + (py - cy) * min(persp, 1.0);\n vec2 p = vec2(px, py) * uView.x + uView.yz;\n vec2 clip = p / uViewport * 2.0 - 1.0;\n gl_Position = vec4(clip.x, -clip.y, 0.0, 1.0);\n vUv = aUnit;\n vU = u;\n vLight = cos(phi + uAngle);\n}", l = "#version 300 es\nprecision mediump float;\nin vec2 vUv;\nin float vU;\nin float vLight;\nuniform sampler2D uFront;\nuniform sampler2D uBack;\nuniform highp float uDir; // must match the vertex stage's default highp\nout vec4 outColor;\nvoid main() {\n // A backward flip (uDir < 0) mirrors the mesh horizontally, which flips both the\n // projected winding (gl_FrontFacing) and the page's u->x mapping; undo both here.\n float fx = uDir > 0.0 ? vUv.x : 1.0 - vUv.x;\n // Front/back from the sheet's smooth facing (vLight), NOT gl_FrontFacing: the\n // winding-based test flickers per-pixel at grazing angles as the curl overlaps.\n bool showFront = vLight > 0.0;\n vec4 c = showFront ? texture(uFront, vec2(fx, vUv.y)) : texture(uBack, vec2(1.0 - fx, vUv.y));\n\n // Diffuse curl shading from the (smooth) facing magnitude: face-on bright, edge-on dark.\n float diff = clamp(abs(vLight), 0.0, 1.0);\n float lit = mix(0.72, 1.0, diff); // ambient floor, never crushed\n float sheen = smoothstep(0.6, 0.95, diff) * (1.0 - diff) * 0.5; // soft crest highlight\n // Spine crease uses the SAME curve as the static gutter shadow, so when the leaf\n // lands the shadow is continuous instead of popping away.\n lit *= mix(0.72, 1.0, smoothstep(0.0, 0.10, vU));\n\n c.rgb = clamp(c.rgb * lit + sheen, 0.0, 1.0);\n outColor = c;\n}", u = 24, d = 4e3, f = 256 * 1024 * 1024, p = class {
|
|
49
|
-
#e = null;
|
|
50
|
-
#t = null;
|
|
51
|
-
#n = null;
|
|
52
|
-
#r = null;
|
|
53
|
-
#i = null;
|
|
54
|
-
#a = null;
|
|
55
|
-
#o = null;
|
|
56
|
-
#s = 0;
|
|
57
|
-
#c = /* @__PURE__ */ new Map();
|
|
58
|
-
#l = 0;
|
|
59
|
-
#u = null;
|
|
60
|
-
#d = {};
|
|
61
|
-
#f = {};
|
|
62
|
-
#p = {
|
|
63
|
-
scale: 1,
|
|
64
|
-
tx: 0,
|
|
65
|
-
ty: 0
|
|
66
|
-
};
|
|
67
|
-
#m = 1;
|
|
68
|
-
#h = null;
|
|
69
|
-
#g = !1;
|
|
70
|
-
#_ = null;
|
|
71
|
-
#v = 0;
|
|
72
|
-
#y = "forward";
|
|
73
|
-
#b = !1;
|
|
74
|
-
#x = !1;
|
|
75
|
-
#S = null;
|
|
76
|
-
#C = null;
|
|
77
|
-
mount(e) {
|
|
78
|
-
this.#e = e;
|
|
79
|
-
let n = e.ownerDocument, r = n.createElement("canvas");
|
|
80
|
-
return r.style.cssText = "display:block;width:100%;height:100%;", e.append(r), this.#t = r, r.addEventListener("webglcontextlost", this.#w), r.addEventListener("webglcontextrestored", this.#T), n.addEventListener("visibilitychange", this.#E), this.#n = t(r), this.#k(), Promise.resolve();
|
|
81
|
-
}
|
|
82
|
-
destroy() {
|
|
83
|
-
this.#O();
|
|
84
|
-
let e = this.#t;
|
|
85
|
-
e !== null && (e.removeEventListener("webglcontextlost", this.#w), e.removeEventListener("webglcontextrestored", this.#T), e.ownerDocument.removeEventListener("visibilitychange", this.#E));
|
|
86
|
-
let t = this.#n;
|
|
87
|
-
if (t !== null) {
|
|
88
|
-
for (let e of this.#c.values()) t.deleteTexture(e.tex);
|
|
89
|
-
this.#u !== null && t.deleteTexture(this.#u), this.#a !== null && t.deleteVertexArray(this.#a), this.#o !== null && t.deleteVertexArray(this.#o), this.#r !== null && t.deleteProgram(this.#r), this.#i !== null && t.deleteProgram(this.#i), t.getExtension("WEBGL_lose_context")?.loseContext();
|
|
90
|
-
}
|
|
91
|
-
e?.remove(), this.#c.clear(), this.#l = 0, this.#u = null, this.#e = null, this.#t = null, this.#n = null, this.#h = null, this.#_ = null;
|
|
92
|
-
}
|
|
93
|
-
onFatal(e) {
|
|
94
|
-
this.#C = e;
|
|
95
|
-
}
|
|
96
|
-
renderSpread(e, t, n) {
|
|
97
|
-
this.#h = t, this.#g = n?.fill ?? !1, this.#_ = null, this.#A();
|
|
98
|
-
}
|
|
99
|
-
beginFlip(e, t, n, r) {
|
|
100
|
-
let i = r?.fill ?? !1;
|
|
101
|
-
this.#y = n, this.#v = 0, i ? this.#_ = {
|
|
102
|
-
underLeft: null,
|
|
103
|
-
underRight: null,
|
|
104
|
-
underFull: t.right ?? t.left,
|
|
105
|
-
front: e.right ?? e.left,
|
|
106
|
-
back: t.right ?? t.left,
|
|
107
|
-
dir: n === "forward" ? 1 : -1,
|
|
108
|
-
spineAtStart: n === "forward" ? 0 : 1,
|
|
109
|
-
fill: !0
|
|
110
|
-
} : n === "forward" ? this.#_ = {
|
|
111
|
-
underLeft: e.left,
|
|
112
|
-
underRight: t.right,
|
|
113
|
-
underFull: null,
|
|
114
|
-
front: e.right,
|
|
115
|
-
back: t.left,
|
|
116
|
-
dir: 1,
|
|
117
|
-
spineAtStart: .5,
|
|
118
|
-
fill: !1
|
|
119
|
-
} : this.#_ = {
|
|
120
|
-
underLeft: t.left,
|
|
121
|
-
underRight: e.right,
|
|
122
|
-
underFull: null,
|
|
123
|
-
front: e.left,
|
|
124
|
-
back: t.right,
|
|
125
|
-
dir: -1,
|
|
126
|
-
spineAtStart: .5,
|
|
127
|
-
fill: !1
|
|
128
|
-
}, this.#A();
|
|
129
|
-
}
|
|
130
|
-
setFlipProgress(e, t) {
|
|
131
|
-
this.#v = e, this.#y = t, this.#A();
|
|
132
|
-
}
|
|
133
|
-
setViewTransform(e, t, n) {
|
|
134
|
-
this.#p = {
|
|
135
|
-
scale: e,
|
|
136
|
-
tx: t,
|
|
137
|
-
ty: n
|
|
138
|
-
}, this.#A();
|
|
139
|
-
}
|
|
140
|
-
measure() {
|
|
141
|
-
let e = this.#e, t = e?.clientWidth ?? 0, n = e?.clientHeight ?? 0;
|
|
142
|
-
return {
|
|
143
|
-
containerWidth: t,
|
|
144
|
-
containerHeight: n,
|
|
145
|
-
pageWidth: t / 2,
|
|
146
|
-
pageHeight: n
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
#w = (e) => {
|
|
150
|
-
e.preventDefault(), this.#b = !0, this.#S === null && (this.#S = setTimeout(() => this.#D(), d));
|
|
151
|
-
};
|
|
152
|
-
#T = () => {
|
|
153
|
-
this.#O(), this.#b = !1, this.#k(), this.#A();
|
|
154
|
-
};
|
|
155
|
-
#E = () => {
|
|
156
|
-
this.#t?.ownerDocument.visibilityState === "visible" && this.#A();
|
|
157
|
-
};
|
|
158
|
-
#D() {
|
|
159
|
-
this.#x || (this.#x = !0, this.#C?.());
|
|
160
|
-
}
|
|
161
|
-
#O() {
|
|
162
|
-
this.#S !== null && (clearTimeout(this.#S), this.#S = null);
|
|
163
|
-
}
|
|
164
|
-
#k() {
|
|
165
|
-
let e = this.#n;
|
|
166
|
-
if (e === null) return;
|
|
167
|
-
this.#r = n(e, o, s), this.#i = n(e, c, l);
|
|
168
|
-
for (let t of [
|
|
169
|
-
"uViewport",
|
|
170
|
-
"uRect",
|
|
171
|
-
"uView",
|
|
172
|
-
"uTex",
|
|
173
|
-
"uGutterSide"
|
|
174
|
-
]) this.#d[t] = e.getUniformLocation(this.#r, t);
|
|
175
|
-
for (let t of [
|
|
176
|
-
"uViewport",
|
|
177
|
-
"uLeaf",
|
|
178
|
-
"uView",
|
|
179
|
-
"uAngle",
|
|
180
|
-
"uCurl",
|
|
181
|
-
"uDir",
|
|
182
|
-
"uFront",
|
|
183
|
-
"uBack"
|
|
184
|
-
]) this.#f[t] = e.getUniformLocation(this.#i, t);
|
|
185
|
-
this.#a = this.#z(e, this.#r, new Float32Array([
|
|
186
|
-
0,
|
|
187
|
-
0,
|
|
188
|
-
1,
|
|
189
|
-
0,
|
|
190
|
-
0,
|
|
191
|
-
1,
|
|
192
|
-
1,
|
|
193
|
-
1
|
|
194
|
-
]));
|
|
195
|
-
let t = [];
|
|
196
|
-
for (let e = 0; e <= u; e++) {
|
|
197
|
-
let n = e / u;
|
|
198
|
-
t.push(n, 0, n, 1);
|
|
199
|
-
}
|
|
200
|
-
this.#s = 50, this.#o = this.#z(e, this.#i, new Float32Array(t)), this.#c.clear(), this.#l = 0, this.#u = this.#R(e), e.useProgram(this.#r), e.uniform1i(this.#d.uTex ?? null, 0), e.useProgram(this.#i), e.uniform1i(this.#f.uFront ?? null, 0), e.uniform1i(this.#f.uBack ?? null, 1), e.clearColor(0, 0, 0, 0), e.enable(e.BLEND), e.blendFunc(e.ONE, e.ONE_MINUS_SRC_ALPHA);
|
|
201
|
-
}
|
|
202
|
-
#A() {
|
|
203
|
-
let e = this.#n, t = this.#t;
|
|
204
|
-
e === null || t === null || this.#b || e.isContextLost() || (this.#B(), e.clear(e.COLOR_BUFFER_BIT), this.#_ === null ? this.#h !== null && this.#j() : this.#M());
|
|
205
|
-
}
|
|
206
|
-
#j() {
|
|
207
|
-
let e = this.#t, t = e.width, n = e.height;
|
|
208
|
-
this.#N();
|
|
209
|
-
let r = this.#h;
|
|
210
|
-
this.#g ? this.#P({
|
|
211
|
-
x: 0,
|
|
212
|
-
y: 0,
|
|
213
|
-
w: t,
|
|
214
|
-
h: n
|
|
215
|
-
}, r.right ?? r.left) : (this.#P({
|
|
216
|
-
x: 0,
|
|
217
|
-
y: 0,
|
|
218
|
-
w: t / 2,
|
|
219
|
-
h: n
|
|
220
|
-
}, r.left, 1), this.#P({
|
|
221
|
-
x: t / 2,
|
|
222
|
-
y: 0,
|
|
223
|
-
w: t / 2,
|
|
224
|
-
h: n
|
|
225
|
-
}, r.right, -1));
|
|
226
|
-
}
|
|
227
|
-
#M() {
|
|
228
|
-
let t = this.#n, n = this.#t, r = n.width, i = n.height, a = this.#_, o = e(this.#v);
|
|
229
|
-
if (this.#N(), a.fill ? this.#P({
|
|
230
|
-
x: 0,
|
|
231
|
-
y: 0,
|
|
232
|
-
w: r,
|
|
233
|
-
h: i
|
|
234
|
-
}, a.underFull) : (this.#P({
|
|
235
|
-
x: 0,
|
|
236
|
-
y: 0,
|
|
237
|
-
w: r / 2,
|
|
238
|
-
h: i
|
|
239
|
-
}, a.underLeft, 1), this.#P({
|
|
240
|
-
x: r / 2,
|
|
241
|
-
y: 0,
|
|
242
|
-
w: r / 2,
|
|
243
|
-
h: i
|
|
244
|
-
}, a.underRight, -1)), a.front === null && a.back === null) return;
|
|
245
|
-
this.#F(t.TEXTURE0, a.front), this.#F(t.TEXTURE1, a.back), t.activeTexture(t.TEXTURE0);
|
|
246
|
-
let s = a.fill ? r : r / 2, c = a.spineAtStart * r;
|
|
247
|
-
t.useProgram(this.#i), t.bindVertexArray(this.#o), t.uniform2f(this.#f.uViewport ?? null, r, i), t.uniform3f(this.#f.uView ?? null, this.#p.scale, this.#p.tx * this.#m, this.#p.ty * this.#m), t.uniform4f(this.#f.uLeaf ?? null, c, 0, s, i), t.uniform1f(this.#f.uAngle ?? null, o.angle), t.uniform1f(this.#f.uCurl ?? null, o.curl), t.uniform1f(this.#f.uDir ?? null, a.dir), t.drawArrays(t.TRIANGLE_STRIP, 0, this.#s);
|
|
248
|
-
}
|
|
249
|
-
#N() {
|
|
250
|
-
let e = this.#n, t = this.#t;
|
|
251
|
-
e.useProgram(this.#r), e.bindVertexArray(this.#a), e.activeTexture(e.TEXTURE0), e.uniform2f(this.#d.uViewport ?? null, t.width, t.height), e.uniform3f(this.#d.uView ?? null, this.#p.scale, this.#p.tx * this.#m, this.#p.ty * this.#m);
|
|
252
|
-
}
|
|
253
|
-
#P(e, t, n = 0) {
|
|
254
|
-
let r = this.#n;
|
|
255
|
-
t !== null && (this.#F(r.TEXTURE0, t), r.uniform4f(this.#d.uRect ?? null, e.x, e.y, e.w, e.h), r.uniform1f(this.#d.uGutterSide ?? null, n), r.drawArrays(r.TRIANGLE_STRIP, 0, 4));
|
|
256
|
-
}
|
|
257
|
-
#F(e, t) {
|
|
258
|
-
let n = this.#n;
|
|
259
|
-
n.activeTexture(e), n.bindTexture(n.TEXTURE_2D, t === null ? this.#u : this.#I(t));
|
|
260
|
-
}
|
|
261
|
-
#I(e) {
|
|
262
|
-
let t = this.#n, n = this.#c.get(e);
|
|
263
|
-
if (n !== void 0) return this.#c.delete(e), this.#c.set(e, n), n.tex;
|
|
264
|
-
let r = i(t);
|
|
265
|
-
a(t, r, e);
|
|
266
|
-
let o = e, s = o.width * o.height * 4;
|
|
267
|
-
return this.#c.set(e, {
|
|
268
|
-
tex: r,
|
|
269
|
-
bytes: s
|
|
270
|
-
}), this.#l += s, this.#L(), r;
|
|
271
|
-
}
|
|
272
|
-
#L() {
|
|
273
|
-
let e = this.#n;
|
|
274
|
-
for (let [t, n] of this.#c) {
|
|
275
|
-
if (this.#l <= f || this.#c.size <= 4) break;
|
|
276
|
-
this.#c.delete(t), this.#l -= n.bytes, e.deleteTexture(n.tex);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
#R(e) {
|
|
280
|
-
let t = i(e);
|
|
281
|
-
return e.bindTexture(e.TEXTURE_2D, t), e.texImage2D(e.TEXTURE_2D, 0, e.RGBA, 1, 1, 0, e.RGBA, e.UNSIGNED_BYTE, new Uint8Array([
|
|
282
|
-
0,
|
|
283
|
-
0,
|
|
284
|
-
0,
|
|
285
|
-
0
|
|
286
|
-
])), t;
|
|
287
|
-
}
|
|
288
|
-
#z(e, t, n) {
|
|
289
|
-
let r = e.createVertexArray(), i = e.createBuffer();
|
|
290
|
-
if (r === null || i === null) throw Error("WebglRenderer: could not create buffers.");
|
|
291
|
-
e.bindVertexArray(r), e.bindBuffer(e.ARRAY_BUFFER, i), e.bufferData(e.ARRAY_BUFFER, n, e.STATIC_DRAW);
|
|
292
|
-
let a = e.getAttribLocation(t, "aUnit");
|
|
293
|
-
return e.enableVertexAttribArray(a), e.vertexAttribPointer(a, 2, e.FLOAT, !1, 0, 0), e.bindVertexArray(null), r;
|
|
294
|
-
}
|
|
295
|
-
#B() {
|
|
296
|
-
let e = this.#n, t = this.#t, n = this.#e;
|
|
297
|
-
if (e === null || t === null || n === null) return;
|
|
298
|
-
this.#m = typeof devicePixelRatio == "number" ? devicePixelRatio : 1;
|
|
299
|
-
let r = Math.max(1, Math.round(n.clientWidth * this.#m)), i = Math.max(1, Math.round(n.clientHeight * this.#m));
|
|
300
|
-
(t.width !== r || t.height !== i) && (t.width = r, t.height = i, e.viewport(0, 0, r, i));
|
|
301
|
-
}
|
|
302
|
-
};
|
|
303
|
-
//#endregion
|
|
304
|
-
export { p as WebglRenderer };
|
|
305
|
-
|
|
306
|
-
//# sourceMappingURL=webglRenderer-D-1UyC-B.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"webglRenderer-D-1UyC-B.js","names":["#container","#canvas","#onContextLost","#onContextRestored","#onVisibilityChange","#gl","#buildGlResources","#clearRestoreTimer","#texCache","#blankTex","#quadVao","#gridVao","#flat","#curl","#cacheBytes","#content","#flip","#fatalHandler","#fill","#render","#flipDir","#flipT","#view","#contextLost","#restoreTimer","#fatal","#fatalFired","#flatU","#curlU","#makeVao","#gridCount","#makeBlankTexture","#resize","#drawFlip","#drawStatic","#useFlat","#drawQuad","#bindFace","#dpr","#textureFor","#evictTextures"],"sources":["../src/renderer/gl/context.ts","../src/renderer/gl/program.ts","../src/renderer/gl/texture.ts","../src/renderer/webglRenderer.ts"],"sourcesContent":["/** Create a WebGL2 context, or throw so the caller can fall back to CSS (§8.4). */\nexport function createGlContext(canvas: HTMLCanvasElement): WebGL2RenderingContext {\n const gl = canvas.getContext('webgl2', {\n alpha: true,\n premultipliedAlpha: true,\n antialias: true,\n depth: false,\n stencil: false,\n // We render on demand (not every frame), so the buffer must persist between\n // composites — otherwise the settled page flickers once the flip animation\n // stops and nothing is redrawing each frame.\n preserveDrawingBuffer: true,\n });\n if (gl === null) {\n throw new Error('WebglRenderer: could not create a WebGL2 context.');\n }\n return gl;\n}\n","/** Compile + link a shader program; throws with the driver log on failure. */\nexport function createProgram(\n gl: WebGL2RenderingContext,\n vertexSrc: string,\n fragmentSrc: string,\n): WebGLProgram {\n const program = gl.createProgram();\n if (program === null) throw new Error('WebglRenderer: could not create a program.');\n\n const vs = compileShader(gl, gl.VERTEX_SHADER, vertexSrc);\n const fs = compileShader(gl, gl.FRAGMENT_SHADER, fragmentSrc);\n gl.attachShader(program, vs);\n gl.attachShader(program, fs);\n gl.linkProgram(program);\n\n // Shaders can be detached/deleted once linked.\n gl.deleteShader(vs);\n gl.deleteShader(fs);\n\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n const log = gl.getProgramInfoLog(program);\n gl.deleteProgram(program);\n throw new Error(`WebglRenderer: program link failed: ${log ?? 'unknown error'}`);\n }\n return program;\n}\n\nfunction compileShader(gl: WebGL2RenderingContext, type: number, src: string): WebGLShader {\n const shader = gl.createShader(type);\n if (shader === null) throw new Error('WebglRenderer: could not create a shader.');\n gl.shaderSource(shader, src);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n const log = gl.getShaderInfoLog(shader);\n gl.deleteShader(shader);\n throw new Error(`WebglRenderer: shader compile failed: ${log ?? 'unknown error'}`);\n }\n return shader;\n}\n","/** Create a page texture with clamp + linear filtering (no mipmaps — §8.3). */\nexport function createTexture(gl: WebGL2RenderingContext): WebGLTexture {\n const tex = gl.createTexture();\n if (tex === null) throw new Error('WebglRenderer: could not create a texture.');\n gl.bindTexture(gl.TEXTURE_2D, tex);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n return tex;\n}\n\n/** Upload a decoded page raster (ImageBitmap or canvas) into `tex`. */\nexport function uploadTexture(\n gl: WebGL2RenderingContext,\n tex: WebGLTexture,\n source: TexImageSource,\n): void {\n gl.bindTexture(gl.TEXTURE_2D, tex);\n // No Y flip: the vertex shader maps aUnit.y=0 to the page top and samples the\n // source's top row there. UNPACK_FLIP_Y is honored for <canvas> sources but\n // IGNORED for ImageBitmap, so flipping would invert PDF (canvas) pages while\n // leaving image (ImageBitmap) pages upright. Off keeps both consistent.\n gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);\n gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source);\n}\n","import { flipProgressToPose } from '../geometry/flipProgressToPose';\nimport type { Spread } from '../engine/spread';\nimport type {\n FlipDirection,\n LayoutMetrics,\n Renderer,\n RenderOptions,\n SpreadContent,\n} from './types';\nimport { createGlContext } from './gl/context';\nimport { createProgram } from './gl/program';\nimport { createTexture, uploadTexture } from './gl/texture';\n\n// Flat program: maps a unit quad to a page rect (device px, top-left origin) with\n// zoom/pan. aUnit.y=0 is the page top and samples the source's top row (no flip).\nconst FLAT_VERT = `#version 300 es\nin vec2 aUnit;\nuniform vec2 uViewport;\nuniform vec4 uRect;\nuniform vec3 uView;\nout vec2 vUv;\nvoid main() {\n vec2 px = uRect.xy + aUnit * uRect.zw;\n px = px * uView.x + uView.yz;\n vec2 clip = px / uViewport * 2.0 - 1.0;\n gl_Position = vec4(clip.x, -clip.y, 0.0, 1.0);\n vUv = aUnit;\n}`;\n\nconst FLAT_FRAG = `#version 300 es\nprecision mediump float;\nin vec2 vUv;\nuniform sampler2D uTex;\nuniform float uGutterSide; // +1 = spine at the right edge, -1 = at the left edge, 0 = none\nout vec4 outColor;\nvoid main() {\n vec4 c = texture(uTex, vUv);\n if (uGutterSide != 0.0) {\n // Soft, permanent gutter shadow: darken toward the spine edge where the pages\n // meet, so the turning leaf's spine shadow lands into it instead of vanishing.\n float d = uGutterSide > 0.0 ? (1.0 - vUv.x) : vUv.x;\n c.rgb *= mix(0.72, 1.0, smoothstep(0.0, 0.10, d));\n }\n outColor = c;\n}`;\n\n// Curl program: the turning leaf. u runs from the spine (0) to the free edge (1).\n// The page wraps around a vertical cylinder (radius shrinks with uCurl) and rotates\n// about the spine by uAngle; orthographic (no perspective yet).\nconst CURL_VERT = `#version 300 es\nin vec2 aUnit;\nuniform vec2 uViewport;\nuniform vec4 uLeaf; // spineX, y, width, height (device px)\nuniform vec3 uView; // scale, tx, ty\nuniform float uAngle; // spine rotation 0..PI\nuniform float uCurl; // 0..1 bend amount\nuniform float uDir; // +1 leaf sweeps from +x side, -1 from -x side\nout vec2 vUv;\nout float vU;\nout float vLight; // surface facing: +1 toward viewer, 0 edge-on, -1 away\nconst float CAM = 3.0; // perspective camera distance, in page widths (bigger = subtler)\nvoid main() {\n float u = aUnit.x;\n float W = uLeaf.z;\n // Cylinder wrap of the turning sheet, rotated about the spine (vertical y axis).\n float bend = uCurl * 1.5;\n float phi, xw, zw;\n if (bend > 0.001) {\n float R = W / bend;\n phi = u * bend;\n xw = R * sin(phi);\n zw = R * (1.0 - cos(phi));\n } else {\n phi = 0.0;\n xw = u * W;\n zw = 0.0;\n }\n float X = xw * cos(uAngle) - zw * sin(uAngle); // in-plane\n float Z = xw * sin(uAngle) + zw * cos(uAngle); // depth (+ toward viewer)\n float px = uLeaf.x + uDir * X;\n float py = uLeaf.y + aUnit.y * uLeaf.w;\n // Perspective by depth. X may bulge toward the viewer for 3D pop; Y only ever\n // SHRINKS (persp clamped <= 1) about the page's own vertical center, so the top\n // is never pushed past the frame (that was the hidden-top bug).\n float D = W * CAM;\n float persp = D / max(D - Z, 1.0);\n float cx = uViewport.x * 0.5;\n float cy = uLeaf.y + 0.5 * uLeaf.w;\n px = cx + (px - cx) * persp;\n py = cy + (py - cy) * min(persp, 1.0);\n vec2 p = vec2(px, py) * uView.x + uView.yz;\n vec2 clip = p / uViewport * 2.0 - 1.0;\n gl_Position = vec4(clip.x, -clip.y, 0.0, 1.0);\n vUv = aUnit;\n vU = u;\n vLight = cos(phi + uAngle);\n}`;\n\n// Per-fragment facing: whichever side of the curling sheet faces the viewer shows\n// its own page, so mid-curl you see a sliver of the next page (continuous handoff).\nconst CURL_FRAG = `#version 300 es\nprecision mediump float;\nin vec2 vUv;\nin float vU;\nin float vLight;\nuniform sampler2D uFront;\nuniform sampler2D uBack;\nuniform highp float uDir; // must match the vertex stage's default highp\nout vec4 outColor;\nvoid main() {\n // A backward flip (uDir < 0) mirrors the mesh horizontally, which flips both the\n // projected winding (gl_FrontFacing) and the page's u->x mapping; undo both here.\n float fx = uDir > 0.0 ? vUv.x : 1.0 - vUv.x;\n // Front/back from the sheet's smooth facing (vLight), NOT gl_FrontFacing: the\n // winding-based test flickers per-pixel at grazing angles as the curl overlaps.\n bool showFront = vLight > 0.0;\n vec4 c = showFront ? texture(uFront, vec2(fx, vUv.y)) : texture(uBack, vec2(1.0 - fx, vUv.y));\n\n // Diffuse curl shading from the (smooth) facing magnitude: face-on bright, edge-on dark.\n float diff = clamp(abs(vLight), 0.0, 1.0);\n float lit = mix(0.72, 1.0, diff); // ambient floor, never crushed\n float sheen = smoothstep(0.6, 0.95, diff) * (1.0 - diff) * 0.5; // soft crest highlight\n // Spine crease uses the SAME curve as the static gutter shadow, so when the leaf\n // lands the shadow is continuous instead of popping away.\n lit *= mix(0.72, 1.0, smoothstep(0.0, 0.10, vU));\n\n c.rgb = clamp(c.rgb * lit + sheen, 0.0, 1.0);\n outColor = c;\n}`;\n\nconst GRID_COLS = 24;\n// If a lost context is not restored within this window, give up and let the engine\n// fall back to the CSS renderer (§8.4).\nconst RESTORE_TIMEOUT_MS = 4000;\n// GPU texture LRU ceiling (§9). Page textures are cached by content and evicted\n// least-recently-used beyond this, so flips/zooms don't re-upload every frame.\nconst MAX_TEXTURE_CACHE_BYTES = 256 * 1024 * 1024;\n\ninterface Rect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\ninterface FlipState {\n underLeft: TexImageSource | null;\n underRight: TexImageSource | null;\n underFull: TexImageSource | null; // fill mode\n front: TexImageSource | null;\n back: TexImageSource | null;\n dir: number; // +1 / -1 for the curl sweep\n spineAtStart: number; // 0 = spine at left edge, 0.5 = center, 1 = right edge\n fill: boolean;\n}\n\n/**\n * GPU renderer (WebGL2, hand-written, no third-party library). The turning leaf is\n * a grid mesh bent around a cylinder (driven by the shared flipProgressToPose), the\n * static pages are flat textured quads underneath. Restores its GL state in place on\n * context loss; if that fails it signals `onFatal` so the engine can fall back to CSS.\n */\nexport class WebglRenderer implements Renderer {\n #container: HTMLElement | null = null;\n #canvas: HTMLCanvasElement | null = null;\n #gl: WebGL2RenderingContext | null = null;\n\n #flat: WebGLProgram | null = null;\n #curl: WebGLProgram | null = null;\n #quadVao: WebGLVertexArrayObject | null = null;\n #gridVao: WebGLVertexArrayObject | null = null;\n #gridCount = 0;\n #texCache = new Map<TexImageSource, { tex: WebGLTexture; bytes: number }>();\n #cacheBytes = 0;\n #blankTex: WebGLTexture | null = null; // 1x1 transparent, for blank leaf faces\n\n #flatU: Record<string, WebGLUniformLocation | null> = {};\n #curlU: Record<string, WebGLUniformLocation | null> = {};\n\n #view = { scale: 1, tx: 0, ty: 0 };\n #dpr = 1;\n #content: SpreadContent | null = null;\n #fill = false;\n #flip: FlipState | null = null;\n #flipT = 0;\n #flipDir: FlipDirection = 'forward';\n\n #contextLost = false;\n #fatalFired = false;\n #restoreTimer: ReturnType<typeof setTimeout> | null = null;\n #fatalHandler: (() => void) | null = null;\n\n mount(container: HTMLElement): Promise<void> {\n this.#container = container;\n const doc = container.ownerDocument;\n const canvas = doc.createElement('canvas');\n // Fill the container as a plain block, so it doesn't depend on the container\n // being positioned (an absolute canvas would escape a static container).\n canvas.style.cssText = 'display:block;width:100%;height:100%;';\n container.append(canvas);\n this.#canvas = canvas;\n\n canvas.addEventListener('webglcontextlost', this.#onContextLost as EventListener);\n canvas.addEventListener('webglcontextrestored', this.#onContextRestored as EventListener);\n doc.addEventListener('visibilitychange', this.#onVisibilityChange);\n\n this.#gl = createGlContext(canvas); // throws if unavailable -> engine falls back (§8.4)\n this.#buildGlResources();\n\n return Promise.resolve();\n }\n\n destroy(): void {\n this.#clearRestoreTimer();\n const canvas = this.#canvas;\n if (canvas !== null) {\n canvas.removeEventListener('webglcontextlost', this.#onContextLost as EventListener);\n canvas.removeEventListener('webglcontextrestored', this.#onContextRestored as EventListener);\n canvas.ownerDocument.removeEventListener('visibilitychange', this.#onVisibilityChange);\n }\n const gl = this.#gl;\n if (gl !== null) {\n for (const cached of this.#texCache.values()) gl.deleteTexture(cached.tex);\n if (this.#blankTex !== null) gl.deleteTexture(this.#blankTex);\n if (this.#quadVao !== null) gl.deleteVertexArray(this.#quadVao);\n if (this.#gridVao !== null) gl.deleteVertexArray(this.#gridVao);\n if (this.#flat !== null) gl.deleteProgram(this.#flat);\n if (this.#curl !== null) gl.deleteProgram(this.#curl);\n gl.getExtension('WEBGL_lose_context')?.loseContext();\n }\n canvas?.remove();\n this.#texCache.clear();\n this.#cacheBytes = 0;\n this.#blankTex = null;\n this.#container = null;\n this.#canvas = null;\n this.#gl = null;\n this.#content = null;\n this.#flip = null;\n }\n\n onFatal(handler: () => void): void {\n this.#fatalHandler = handler;\n }\n\n renderSpread(_spread: Spread, content: SpreadContent, options?: RenderOptions): void {\n this.#content = content;\n this.#fill = options?.fill ?? false;\n this.#flip = null;\n this.#render();\n }\n\n beginFlip(\n from: SpreadContent,\n to: SpreadContent,\n direction: FlipDirection,\n options?: RenderOptions,\n ): void {\n const fill = options?.fill ?? false;\n this.#flipDir = direction;\n this.#flipT = 0;\n if (fill) {\n this.#flip = {\n underLeft: null,\n underRight: null,\n underFull: to.right ?? to.left,\n front: from.right ?? from.left,\n back: to.right ?? to.left,\n dir: direction === 'forward' ? 1 : -1,\n spineAtStart: direction === 'forward' ? 0 : 1,\n fill: true,\n };\n } else if (direction === 'forward') {\n // Right page lifts and swings left about the spine; left stays, right reveals `to`.\n this.#flip = {\n underLeft: from.left,\n underRight: to.right,\n underFull: null,\n front: from.right,\n back: to.left,\n dir: 1,\n spineAtStart: 0.5,\n fill: false,\n };\n } else {\n // Left page swings right about the spine; right stays, left reveals `to`.\n this.#flip = {\n underLeft: to.left,\n underRight: from.right,\n underFull: null,\n front: from.left,\n back: to.right,\n dir: -1,\n spineAtStart: 0.5,\n fill: false,\n };\n }\n this.#render();\n }\n\n setFlipProgress(t: number, direction: FlipDirection): void {\n this.#flipT = t;\n this.#flipDir = direction;\n this.#render();\n }\n\n setViewTransform(scale: number, x: number, y: number): void {\n this.#view = { scale, tx: x, ty: y };\n this.#render();\n }\n\n measure(): LayoutMetrics {\n const el = this.#container;\n const w = el?.clientWidth ?? 0;\n const h = el?.clientHeight ?? 0;\n return { containerWidth: w, containerHeight: h, pageWidth: w / 2, pageHeight: h };\n }\n\n // --- context loss / restore ---------------------------------------------------\n\n #onContextLost = (event: Event): void => {\n event.preventDefault(); // required, or the browser won't fire 'restored'\n this.#contextLost = true;\n if (this.#restoreTimer === null) {\n this.#restoreTimer = setTimeout(() => this.#fatal(), RESTORE_TIMEOUT_MS);\n }\n };\n\n #onContextRestored = (): void => {\n this.#clearRestoreTimer();\n this.#contextLost = false;\n this.#buildGlResources(); // old GL objects are gone; rebuild on the same context\n this.#render(); // CPU-side content/flip/view were retained, so re-upload + repaint\n };\n\n #onVisibilityChange = (): void => {\n if (this.#canvas?.ownerDocument.visibilityState === 'visible') this.#render();\n };\n\n #fatal(): void {\n if (this.#fatalFired) return;\n this.#fatalFired = true;\n this.#fatalHandler?.();\n }\n\n #clearRestoreTimer(): void {\n if (this.#restoreTimer !== null) {\n clearTimeout(this.#restoreTimer);\n this.#restoreTimer = null;\n }\n }\n\n #buildGlResources(): void {\n const gl = this.#gl;\n if (gl === null) return;\n\n this.#flat = createProgram(gl, FLAT_VERT, FLAT_FRAG);\n this.#curl = createProgram(gl, CURL_VERT, CURL_FRAG);\n for (const name of ['uViewport', 'uRect', 'uView', 'uTex', 'uGutterSide']) {\n this.#flatU[name] = gl.getUniformLocation(this.#flat, name);\n }\n for (const name of ['uViewport', 'uLeaf', 'uView', 'uAngle', 'uCurl', 'uDir', 'uFront', 'uBack']) {\n this.#curlU[name] = gl.getUniformLocation(this.#curl, name);\n }\n\n this.#quadVao = this.#makeVao(gl, this.#flat, new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]));\n\n // Grid strip across the width (columns subdivided, 2 rows) for a smooth bend.\n const grid: number[] = [];\n for (let c = 0; c <= GRID_COLS; c++) {\n const u = c / GRID_COLS;\n grid.push(u, 0, u, 1);\n }\n this.#gridCount = (GRID_COLS + 1) * 2;\n this.#gridVao = this.#makeVao(gl, this.#curl, new Float32Array(grid));\n\n // A (re)created context has no live textures; drop the cache and remake the blank.\n this.#texCache.clear();\n this.#cacheBytes = 0;\n this.#blankTex = this.#makeBlankTexture(gl);\n gl.useProgram(this.#flat);\n gl.uniform1i(this.#flatU.uTex ?? null, 0);\n gl.useProgram(this.#curl);\n gl.uniform1i(this.#curlU.uFront ?? null, 0);\n gl.uniform1i(this.#curlU.uBack ?? null, 1);\n gl.clearColor(0, 0, 0, 0);\n gl.enable(gl.BLEND);\n gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); // premultiplied alpha\n }\n\n // --- drawing ------------------------------------------------------------------\n\n #render(): void {\n const gl = this.#gl;\n const canvas = this.#canvas;\n if (gl === null || canvas === null || this.#contextLost || gl.isContextLost()) return;\n this.#resize();\n gl.clear(gl.COLOR_BUFFER_BIT);\n if (this.#flip !== null) this.#drawFlip();\n else if (this.#content !== null) this.#drawStatic();\n }\n\n #drawStatic(): void {\n const canvas = this.#canvas!;\n const w = canvas.width;\n const h = canvas.height;\n this.#useFlat();\n const content = this.#content!;\n if (this.#fill) {\n this.#drawQuad({ x: 0, y: 0, w, h }, content.right ?? content.left);\n } else {\n this.#drawQuad({ x: 0, y: 0, w: w / 2, h }, content.left, 1);\n this.#drawQuad({ x: w / 2, y: 0, w: w / 2, h }, content.right, -1);\n }\n }\n\n #drawFlip(): void {\n const gl = this.#gl!;\n const canvas = this.#canvas!;\n const w = canvas.width;\n const h = canvas.height;\n const flip = this.#flip!;\n const pose = flipProgressToPose(this.#flipT);\n\n // Static pages underneath.\n this.#useFlat();\n if (flip.fill) {\n this.#drawQuad({ x: 0, y: 0, w, h }, flip.underFull);\n } else {\n this.#drawQuad({ x: 0, y: 0, w: w / 2, h }, flip.underLeft, 1);\n this.#drawQuad({ x: w / 2, y: 0, w: w / 2, h }, flip.underRight, -1);\n }\n\n // Turning leaf: both faces uploaded, per-fragment facing picks front vs back.\n if (flip.front === null && flip.back === null) return;\n this.#bindFace(gl.TEXTURE0, flip.front);\n this.#bindFace(gl.TEXTURE1, flip.back);\n gl.activeTexture(gl.TEXTURE0);\n\n const leafW = flip.fill ? w : w / 2;\n const spineX = flip.spineAtStart * w;\n gl.useProgram(this.#curl);\n gl.bindVertexArray(this.#gridVao);\n gl.uniform2f(this.#curlU.uViewport ?? null, w, h);\n gl.uniform3f(this.#curlU.uView ?? null, this.#view.scale, this.#view.tx * this.#dpr, this.#view.ty * this.#dpr);\n gl.uniform4f(this.#curlU.uLeaf ?? null, spineX, 0, leafW, h);\n gl.uniform1f(this.#curlU.uAngle ?? null, pose.angle);\n gl.uniform1f(this.#curlU.uCurl ?? null, pose.curl);\n gl.uniform1f(this.#curlU.uDir ?? null, flip.dir);\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, this.#gridCount);\n }\n\n #useFlat(): void {\n const gl = this.#gl!;\n const canvas = this.#canvas!;\n gl.useProgram(this.#flat);\n gl.bindVertexArray(this.#quadVao);\n gl.activeTexture(gl.TEXTURE0);\n gl.uniform2f(this.#flatU.uViewport ?? null, canvas.width, canvas.height);\n gl.uniform3f(this.#flatU.uView ?? null, this.#view.scale, this.#view.tx * this.#dpr, this.#view.ty * this.#dpr);\n }\n\n #drawQuad(rect: Rect, source: TexImageSource | null, gutterSide = 0): void {\n const gl = this.#gl!;\n if (source === null) return;\n this.#bindFace(gl.TEXTURE0, source);\n gl.uniform4f(this.#flatU.uRect ?? null, rect.x, rect.y, rect.w, rect.h);\n gl.uniform1f(this.#flatU.uGutterSide ?? null, gutterSide);\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n }\n\n /** Bind the texture for `source` (a blank 1x1 when null) to a texture unit. */\n #bindFace(unit: number, source: TexImageSource | null): void {\n const gl = this.#gl!;\n gl.activeTexture(unit);\n gl.bindTexture(gl.TEXTURE_2D, source !== null ? this.#textureFor(source) : this.#blankTex);\n }\n\n /** Page texture cached by content: uploaded once, reused across frames, LRU-capped. */\n #textureFor(source: TexImageSource): WebGLTexture {\n const gl = this.#gl!;\n const existing = this.#texCache.get(source);\n if (existing !== undefined) {\n this.#texCache.delete(source); // move to most-recently-used\n this.#texCache.set(source, existing);\n return existing.tex;\n }\n const tex = createTexture(gl); // binds + uploads on the active unit set by the caller\n uploadTexture(gl, tex, source);\n const dims = source as unknown as { width: number; height: number }; // page rasters have both\n const bytes = dims.width * dims.height * 4;\n this.#texCache.set(source, { tex, bytes });\n this.#cacheBytes += bytes;\n this.#evictTextures();\n return tex;\n }\n\n /** Drop least-recently-used page textures past the byte ceiling (keep a small floor). */\n #evictTextures(): void {\n const gl = this.#gl!;\n for (const [src, cached] of this.#texCache) {\n if (this.#cacheBytes <= MAX_TEXTURE_CACHE_BYTES || this.#texCache.size <= 4) break;\n this.#texCache.delete(src);\n this.#cacheBytes -= cached.bytes;\n gl.deleteTexture(cached.tex);\n }\n }\n\n #makeBlankTexture(gl: WebGL2RenderingContext): WebGLTexture {\n const tex = createTexture(gl);\n gl.bindTexture(gl.TEXTURE_2D, tex);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 0, 0]));\n return tex;\n }\n\n #makeVao(gl: WebGL2RenderingContext, program: WebGLProgram, data: Float32Array): WebGLVertexArrayObject {\n const vao = gl.createVertexArray();\n const buffer = gl.createBuffer();\n if (vao === null || buffer === null) throw new Error('WebglRenderer: could not create buffers.');\n gl.bindVertexArray(vao);\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);\n const aUnit = gl.getAttribLocation(program, 'aUnit');\n gl.enableVertexAttribArray(aUnit);\n gl.vertexAttribPointer(aUnit, 2, gl.FLOAT, false, 0, 0);\n gl.bindVertexArray(null);\n return vao;\n }\n\n #resize(): void {\n const gl = this.#gl;\n const canvas = this.#canvas;\n const el = this.#container;\n if (gl === null || canvas === null || el === null) return;\n this.#dpr = typeof devicePixelRatio === 'number' ? devicePixelRatio : 1;\n const w = Math.max(1, Math.round(el.clientWidth * this.#dpr));\n const h = Math.max(1, Math.round(el.clientHeight * this.#dpr));\n if (canvas.width !== w || canvas.height !== h) {\n canvas.width = w;\n canvas.height = h;\n gl.viewport(0, 0, w, h);\n }\n }\n}\n"],"mappings":"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"}
|