nanovgjs 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/nanovg.js ADDED
@@ -0,0 +1,3205 @@
1
+ const NVG_CCW = 1;
2
+ const NVG_CW = 2;
3
+
4
+ const NVG_INIT_COMMANDS_SIZE = 256;
5
+ const NVG_INIT_POINTS_SIZE = 128;
6
+ const NVG_INIT_PATHS_SIZE = 16;
7
+ const NVG_INIT_VERTS_SIZE = 256;
8
+
9
+ const NVG_VERTEX_SIZEOF = 16;
10
+
11
+ const NVG_SOLID = 1;
12
+ const NVG_HOLE = 2;
13
+
14
+ const NVG_BUTT = 0;
15
+ const NVG_ROUND = 1;
16
+ const NVG_SQUARE = 2;
17
+ const NVG_BEVEL = 3;
18
+ const NVG_MITER = 4;
19
+
20
+ const NVG_ALIGN_LEFT = 1 << 0;
21
+ const NVG_ALIGN_CENTER = 1 << 1;
22
+ const NVG_ALIGN_RIGHT = 1 << 2;
23
+ const NVG_ALIGN_TOP = 1 << 3;
24
+ const NVG_ALIGN_MIDDLE = 1 << 4;
25
+ const NVG_ALIGN_BOTTOM = 1 << 5;
26
+ const NVG_ALIGN_BASELINE = 1 << 6;
27
+
28
+ const NVG_ZERO = 1 << 0;
29
+ const NVG_ONE = 1 << 1;
30
+ const NVG_SRC_COLOR = 1 << 2;
31
+ const NVG_ONE_MINUS_SRC_COLOR = 1 << 3;
32
+ const NVG_DST_COLOR = 1 << 4;
33
+ const NVG_ONE_MINUS_DST_COLOR = 1 << 5;
34
+ const NVG_SRC_ALPHA = 1 << 6;
35
+ const NVG_ONE_MINUS_SRC_ALPHA = 1 << 7;
36
+ const NVG_DST_ALPHA = 1 << 8;
37
+ const NVG_ONE_MINUS_DST_ALPHA = 1 << 9;
38
+ const NVG_SRC_ALPHA_SATURATE = 1 << 10;
39
+
40
+ const NVG_SOURCE_OVER = 0;
41
+ const NVG_SOURCE_IN = 1;
42
+ const NVG_SOURCE_OUT = 2;
43
+ const NVG_ATOP = 3;
44
+ const NVG_DESTINATION_OVER = 4;
45
+ const NVG_DESTINATION_IN = 5;
46
+ const NVG_DESTINATION_OUT = 6;
47
+ const NVG_DESTINATION_ATOP = 7;
48
+ const NVG_LIGHTER = 8;
49
+ const NVG_COPY = 9;
50
+ const NVG_XOR = 10;
51
+
52
+ const NVG_IMAGE_GENERATE_MIPMAPS = 1 << 0;
53
+ const NVG_IMAGE_REPEATX = 1 << 1;
54
+ const NVG_IMAGE_REPEATY = 1 << 2;
55
+ const NVG_IMAGE_FLIPY = 1 << 3;
56
+ const NVG_IMAGE_PREMULTIPLIED = 1 << 4;
57
+ const NVG_IMAGE_NEAREST = 1 << 5;
58
+
59
+ const NVG_MAX_STATES = 32;
60
+
61
+ const NVG_TEXTURE_ALPHA = 1;
62
+ const NVG_TEXTURE_RGBA = 2;
63
+
64
+ const NVG_PT_CORNER = 1;
65
+ const NVG_PT_LEFT = 2;
66
+ const NVG_PT_BEVEL = 4;
67
+ const NVG_PR_INNERBEVEL = 8;
68
+
69
+ const NVG_MOVETO = 0;
70
+ const NVG_LINETO = 1;
71
+ const NVG_BEZIERTO = 2;
72
+ const NVG_CLOSE = 3;
73
+ const NVG_WINDING = 4;
74
+
75
+ const NVG_INIT_FONTIMAGE_SIZE = 512;
76
+ const NVG_MAX_FONTIMAGE_SIZE = 2048;
77
+ const NVG_MAX_FONTIMAGES = 4;
78
+
79
+ const FONS_ZERO_TOPLEFT = 1;
80
+ const FONS_ZERO_BOTTOMLEFT = 2;
81
+
82
+ const NVG_PI = Math.PI;
83
+
84
+ const NVG_KAPPA90 = 0.5522847493;
85
+
86
+ function NVG_NOTUSED(v) {
87
+ for (;;) {
88
+ console.log(v)
89
+ console.log(1 ? 0 : ((v)))
90
+ if (1 ? 0 : ((v))) {
91
+ break;
92
+ }
93
+ }
94
+ }
95
+
96
+ class NVGvertex {
97
+ constructor(buffer, byteOffset) {
98
+ this.buffer = buffer;
99
+ this.byteOffset = byteOffset;
100
+ this.float32Array = new Float32Array(buffer, byteOffset*NVG_VERTEX_SIZEOF, 4);
101
+ }
102
+
103
+ set x(value) { this.float32Array[0] = value; }
104
+ get x() { return this.float32Array[0]; }
105
+ set y(value) { this.float32Array[1] = value; }
106
+ get y() { return this.float32Array[1]; }
107
+ set u(value) { this.float32Array[2] = value; }
108
+ get u() { return this.float32Array[2]; }
109
+ set v(value) { this.float32Array[3] = value; }
110
+ get v() { return this.float32Array[3]; }
111
+ }
112
+
113
+ class NVGcolor {
114
+ constructor(r = 0, g = 0, b = 0, a = 0) {
115
+ this.rgba = new Float32Array(4);
116
+
117
+ this.r = r;
118
+ this.g = g;
119
+ this.b = b;
120
+ this.a = a;
121
+ }
122
+
123
+ get r() { return this.rgba[0]; }
124
+ get g() { return this.rgba[1]; }
125
+ get b() { return this.rgba[2]; }
126
+ get a() { return this.rgba[3]; }
127
+
128
+ set r(value) { this.rgba[0] = value; }
129
+ set g(value) { this.rgba[1] = value; }
130
+ set b(value) { this.rgba[2] = value; }
131
+ set a(value) { this.rgba[3] = value; }
132
+
133
+ static nvgRGB(r, g, b) {
134
+ return this.nvgRGBA(r, g, b, 255);
135
+ }
136
+
137
+ static nvgRGBf(r, g, b) {
138
+ return this.nvgRGBAf(r, g, b, 1.0);
139
+ }
140
+
141
+ static nvgRGBA(r, g, b, a) {
142
+ return new NVGcolor(parseFloat(r) / 255.0, parseFloat(g) / 255.0, parseFloat(b) / 255.0, parseFloat(a) / 255.0);
143
+ }
144
+
145
+ static nvgRGBAf(r, g, b, a) {
146
+ return new NVGcolor(r, g, b, a);
147
+ }
148
+
149
+ static nvgHSLA(h, s, l, a) {
150
+ let m1, m2;
151
+ const col = new NVGcolor();
152
+ h = nvg__modf(h, 1.0);
153
+ if (h < 0.0) h += 1.0;
154
+ s = nvg__clampf(s, 0.0, 1.0);
155
+ l = nvg__clampf(l, 0.0, 1.0);
156
+ m2 = l <= 0.5 ? l * (1 + s) : l + s - l * s;
157
+ m1 = 2 * l - m2;
158
+ col.r = nvg__clampf(nvg__hue(h + 1.0 / 3.0, m1, m2), 0.0, 1.0);
159
+ col.g = nvg__clampf(nvg__hue(h, m1, m2), 0.0, 1.0);
160
+ col.b = nvg__clampf(nvg__hue(h - 1.0 / 3.0, m1, m2), 0.0, 1.0);
161
+ col.a = a / 255.0;
162
+ return col;
163
+ }
164
+
165
+ static nvgTransRGBA(c, a) {
166
+ c.a = a / 255.0;
167
+ return c;
168
+ }
169
+
170
+ static nvgTransRGBAf(c, a) {
171
+ c.a = a;
172
+ return c;
173
+ }
174
+
175
+ static nvgLerpRGBA(c0, c1, u) {
176
+ const cint = new NVGcolor();
177
+ u = nvg__clampf(u, 0.0, 1.0);
178
+ const oneminu = 1.0 - u;
179
+ for (let i = 0; i < 4; i++) {
180
+ cint.rgba[i] = c0.rgba[i] * oneminu + c1.rgba[i] * u;
181
+ }
182
+ return cint;
183
+ }
184
+
185
+ static nvgHSL(h, s, l) {
186
+ return this.nvgHSLA(h, s, l, 255);
187
+ }
188
+ }
189
+
190
+ class NVGpaint {
191
+ constructor(_array = new Float32Array(18)) {
192
+ this.image = 0;
193
+ this.xform = new Float32Array(_array.subarray(0, 6));
194
+ this.extent = new Float32Array(_array.subarray(6, 8));
195
+ this._radius = new Float32Array(_array.subarray(8, 9));
196
+ this._feather = new Float32Array(_array.subarray(9, 10));
197
+ this.innerColor = new NVGcolor(new Float32Array(_array.subarray(10, 14)));
198
+ this.outerColor = new NVGcolor(new Float32Array(_array.subarray(14, 18)));
199
+ }
200
+ get radius() { return this._radius[0]; }
201
+ set radius(value) { this._radius[0] = value; }
202
+ get feather() { return this._feather[0]; }
203
+ set feather(value) { this._feather[0] = value; }
204
+ }
205
+
206
+ class NVGpoint {
207
+ constructor() {
208
+ this.x = 0;
209
+ this.y = 0;
210
+ this.dx = 0;
211
+ this.dy = 0;
212
+ this.len = 0;
213
+ this.dmx = 0;
214
+ this.dmy = 0;
215
+ this.flags = 0;
216
+ }
217
+ }
218
+
219
+ class NVGscissor {
220
+ constructor() {
221
+ this.xform = new Array(6).fill(0);
222
+ this.extent = new Array(2).fill(0);
223
+ this.enabled = false;
224
+ }
225
+ }
226
+
227
+ class NVGstate {
228
+ constructor() {
229
+ this.compositeOperation = new NVGcompositeOperationState();
230
+ this.shapeAntiAlias = 0;
231
+ this.fill = new NVGpaint();
232
+ this.stroke = new NVGpaint();
233
+ this.strokeWidth = 0;
234
+ this.miterLimit = 0;
235
+ this.lineJoin = 0;
236
+ this.lineCap = 0;
237
+ this.alpha = 0;
238
+ this.xform = new Array(6).fill(0);
239
+ this.scissor = new NVGscissor();
240
+ this.fontSize = 0;
241
+ this.letterSpacing = 0;
242
+ this.lineHeight = 0;
243
+ this.fontBlur = 0;
244
+ this.textAlign = 0;
245
+ this.fontId = 0;
246
+ }
247
+ }
248
+
249
+ class NVGcompositeOperationState {
250
+ constructor(srcRGB, dstRGB, srcAlpha, dstAlpha) {
251
+ this.srcRGB = srcRGB;
252
+ this.dstRGB = dstRGB;
253
+ this.srcAlpha = srcAlpha;
254
+ this.dstAlpha = dstAlpha;
255
+ }
256
+ }
257
+
258
+ class NVGglyphPosition {
259
+ constructor(str, x, minx, maxx) {
260
+ this.str = str;
261
+ this.x = x;
262
+ this.minx = minx;
263
+ this.maxx = maxx;
264
+ }
265
+ }
266
+
267
+ class NVGtextRow {
268
+ constructor(start, end, next, width, minx, maxx) {
269
+ this.start = start;
270
+ this.end = end;
271
+ this.next = next;
272
+ this.width = width;
273
+ this.minx = minx;
274
+ this.maxx = maxx;
275
+ }
276
+ }
277
+
278
+ class NVGpath {
279
+ constructor() {
280
+ this.first = 0;
281
+ this.count = 0;
282
+ this.closed = false;
283
+ this.nbevel = 0;
284
+ this.fill = [];
285
+ this.nfill = 0;
286
+ this.stroke = [];
287
+ this.nstroke = 0;
288
+ this.winding = 0;
289
+ this.convex = 0;
290
+ }
291
+ }
292
+
293
+ class NVGparams {
294
+ constructor() {
295
+ this.userPtr = null;
296
+ this.edgeAntiAlias = 0;
297
+ this.renderCreate = null;
298
+ this.renderCreateTexture = null;
299
+ this.renderDeleteTexture = null;
300
+ this.renderUpdateTexture = null;
301
+ this.renderGetTextureSize = null;
302
+ this.renderViewport = null;
303
+ this.renderCancel = null;
304
+ this.renderFlush = null;
305
+ this.renderFill = null;
306
+ this.renderStroke = null;
307
+ this.renderTriangles = null;
308
+ this.renderDelete = null;
309
+ }
310
+ }
311
+
312
+ class NVGpathCache {
313
+ constructor() {
314
+ this.points = [];
315
+ this.npoints = 0;
316
+ this.cpoints = 0;
317
+ this.paths = [];
318
+ this.npaths = 0;
319
+ this.cpaths = 0;
320
+ this.verts = new ArrayBuffer();
321
+ this.nverts = 0;
322
+ this.cverts = 0;
323
+ this.bounds = new Array(4);
324
+ this.pverts = [];
325
+ }
326
+ }
327
+
328
+ class FONScontext {
329
+ constructor(params = {}) {
330
+ this.width = params.width || NVG_INIT_FONTIMAGE_SIZE;
331
+ this.height = params.height || NVG_INIT_FONTIMAGE_SIZE;
332
+ this.flags = params.flags || FONS_ZERO_TOPLEFT;
333
+ this.fonts = [];
334
+ this.fontsByName = new Map();
335
+ this.state = {
336
+ size: 16,
337
+ spacing: 0,
338
+ blur: 0,
339
+ align: FONS_ALIGN_LEFT | FONS_ALIGN_BASELINE,
340
+ font: FONS_INVALID,
341
+ };
342
+ this.cursorX = 1;
343
+ this.cursorY = 1;
344
+ this.rowH = 0;
345
+ this.dirty = true;
346
+ this.textureData = new Uint8Array(this.width * this.height);
347
+ this.canvas = null;
348
+ this.ctx2d = null;
349
+ this.scratchCanvas = null;
350
+ this.scratchCtx = null;
351
+ this._initCanvases();
352
+ }
353
+
354
+ _initCanvases() {
355
+ if (typeof document === "undefined") return;
356
+ this.canvas = document.createElement("canvas");
357
+ this.canvas.width = this.width;
358
+ this.canvas.height = this.height;
359
+ this.ctx2d = this.canvas.getContext("2d", { willReadFrequently: true });
360
+ this.scratchCanvas = document.createElement("canvas");
361
+ this.scratchCanvas.width = 256;
362
+ this.scratchCanvas.height = 256;
363
+ this.scratchCtx = this.scratchCanvas.getContext("2d", { willReadFrequently: true });
364
+ }
365
+
366
+ resize(width, height) {
367
+ this.width = width;
368
+ this.height = height;
369
+ this.cursorX = 1;
370
+ this.cursorY = 1;
371
+ this.rowH = 0;
372
+ this.textureData = new Uint8Array(width * height);
373
+ this.dirty = true;
374
+ if (this.canvas) {
375
+ this.canvas.width = width;
376
+ this.canvas.height = height;
377
+ }
378
+ for (const font of this.fonts) {
379
+ font.glyphs.clear();
380
+ }
381
+ }
382
+
383
+ addFont(name, source) {
384
+ const id = this.fonts.length;
385
+ const family = `NVGFont_${id}_${String(name || "font").replace(/[^A-Za-z0-9_]/g, "_")}`;
386
+ const font = {
387
+ id,
388
+ name,
389
+ family,
390
+ glyphs: new Map(),
391
+ loaded: false,
392
+ loading: null,
393
+ };
394
+
395
+ if (typeof FontFace !== "undefined") {
396
+ try {
397
+ const face = source instanceof ArrayBuffer
398
+ ? new FontFace(family, source)
399
+ : new FontFace(family, `url("${source}")`);
400
+ font.face = face;
401
+ font.loading = face.load()
402
+ .then((loadedFace) => {
403
+ if (typeof document !== "undefined" && document.fonts) {
404
+ document.fonts.add(loadedFace);
405
+ }
406
+ font.loaded = true;
407
+ font.glyphs.clear();
408
+ return loadedFace;
409
+ })
410
+ .catch(() => {
411
+ font.loaded = false;
412
+ return null;
413
+ });
414
+ } catch (err) {
415
+ font.loaded = false;
416
+ }
417
+ } else {
418
+ font.loaded = true;
419
+ }
420
+
421
+ this.fonts.push(font);
422
+ if (name != null) {
423
+ this.fontsByName.set(name, id);
424
+ }
425
+ return id;
426
+ }
427
+
428
+ findFont(name) {
429
+ if (name == null) return FONS_INVALID;
430
+ return this.fontsByName.has(name) ? this.fontsByName.get(name) : FONS_INVALID;
431
+ }
432
+
433
+ allocRect(w, h) {
434
+ if (w + 2 > this.width || h + 2 > this.height) return null;
435
+ if (this.cursorX + w + 1 > this.width) {
436
+ this.cursorX = 1;
437
+ this.cursorY += this.rowH + 1;
438
+ this.rowH = 0;
439
+ }
440
+ if (this.cursorY + h + 1 > this.height) return null;
441
+ const rect = { x: this.cursorX, y: this.cursorY, w, h };
442
+ this.cursorX += w + 1;
443
+ this.rowH = Math.max(this.rowH, h);
444
+ return rect;
445
+ }
446
+ }
447
+
448
+ const FONS_INVALID = -1;
449
+ const FONS_ALIGN_LEFT = 1 << 0;
450
+ const FONS_ALIGN_CENTER = 1 << 1;
451
+ const FONS_ALIGN_RIGHT = 1 << 2;
452
+ const FONS_ALIGN_TOP = 1 << 3;
453
+ const FONS_ALIGN_MIDDLE = 1 << 4;
454
+ const FONS_ALIGN_BOTTOM = 1 << 5;
455
+ const FONS_ALIGN_BASELINE = 1 << 6;
456
+
457
+ function nvg__buildFontCSS(font, size) {
458
+ const family = font && font.family ? font.family : "sans-serif";
459
+ return `${Math.max(1, size)}px "${family}"`;
460
+ }
461
+
462
+ function nvg__ensureScratchCanvas(fs, w, h) {
463
+ if (!fs.scratchCanvas || !fs.scratchCtx) return false;
464
+ if (fs.scratchCanvas.width < w) fs.scratchCanvas.width = nvg__maxi(w, fs.scratchCanvas.width * 2);
465
+ if (fs.scratchCanvas.height < h) fs.scratchCanvas.height = nvg__maxi(h, fs.scratchCanvas.height * 2);
466
+ return true;
467
+ }
468
+
469
+ function nvg__resolveTextEnd(string, end) {
470
+ if (typeof string !== "string") return "";
471
+ if (typeof end === "number") return string.substring(0, end);
472
+ if (typeof end === "string") {
473
+ const idx = string.indexOf(end);
474
+ return idx >= 0 ? string.substring(0, idx) : string;
475
+ }
476
+ return string;
477
+ }
478
+
479
+ function nvg__getJsFont(ctx, fontId) {
480
+ if (!ctx.fs || fontId == null || fontId < 0 || fontId >= ctx.fs.fonts.length) return null;
481
+ return ctx.fs.fonts[fontId];
482
+ }
483
+
484
+ function nvg__measureTextWidth(ctx2d, text) {
485
+ if (!ctx2d || text.length === 0) return 0;
486
+ return ctx2d.measureText(text).width;
487
+ }
488
+
489
+ function nvg__computeTextStartX(align, x, width) {
490
+ if (align & NVG_ALIGN_RIGHT) return x - width;
491
+ if (align & NVG_ALIGN_CENTER) return x - width * 0.5;
492
+ return x;
493
+ }
494
+
495
+ function nvg__computeTextBaselineY(align, y, metrics) {
496
+ if (align & NVG_ALIGN_TOP) return y + metrics.ascender;
497
+ if (align & NVG_ALIGN_MIDDLE) return y + (metrics.ascender + metrics.descender) * 0.5;
498
+ if (align & NVG_ALIGN_BOTTOM) return y + metrics.descender;
499
+ return y;
500
+ }
501
+
502
+ function nvg__getFontVerticalMetrics(ctx2d, size) {
503
+ const metrics = ctx2d ? ctx2d.measureText("Mg") : null;
504
+ const ascender = metrics && metrics.actualBoundingBoxAscent ? metrics.actualBoundingBoxAscent : size * 0.8;
505
+ const descender = metrics && metrics.actualBoundingBoxDescent ? -metrics.actualBoundingBoxDescent : -size * 0.2;
506
+ const lineh = ascender - descender;
507
+ return { ascender, descender, lineh };
508
+ }
509
+
510
+ function nvg__ensureGlyph(ctx, font, size, blur, codepoint) {
511
+ const fs = ctx.fs;
512
+ if (!fs || !font || !fs.scratchCtx) return null;
513
+ if (!font.loaded) return null;
514
+
515
+ const key = `${size}:${blur}:${codepoint}`;
516
+ if (font.glyphs.has(key)) {
517
+ return font.glyphs.get(key);
518
+ }
519
+
520
+ const ch = String.fromCodePoint(codepoint);
521
+ const measureCtx = fs.scratchCtx;
522
+ measureCtx.setTransform(1, 0, 0, 1, 0, 0);
523
+ measureCtx.font = nvg__buildFontCSS(font, size);
524
+ measureCtx.textAlign = "left";
525
+ measureCtx.textBaseline = "alphabetic";
526
+
527
+ const metrics = measureCtx.measureText(ch);
528
+ const left = metrics.actualBoundingBoxLeft ?? 0;
529
+ const right = metrics.actualBoundingBoxRight ?? metrics.width;
530
+ const ascent = metrics.actualBoundingBoxAscent ?? size * 0.8;
531
+ const descent = metrics.actualBoundingBoxDescent ?? size * 0.2;
532
+ const glyphW = Math.max(1, Math.ceil(left + right));
533
+ const glyphH = Math.max(1, Math.ceil(ascent + descent));
534
+ const pad = Math.max(2, Math.ceil(blur) + 2);
535
+ const drawW = glyphW + pad * 2;
536
+ const drawH = glyphH + pad * 2;
537
+
538
+ nvg__ensureScratchCanvas(fs, drawW, drawH);
539
+ const scratch = fs.scratchCtx;
540
+ scratch.setTransform(1, 0, 0, 1, 0, 0);
541
+ scratch.clearRect(0, 0, fs.scratchCanvas.width, fs.scratchCanvas.height);
542
+ scratch.font = nvg__buildFontCSS(font, size);
543
+ scratch.textAlign = "left";
544
+ scratch.textBaseline = "alphabetic";
545
+ scratch.fillStyle = "#fff";
546
+ scratch.fillText(ch, pad + left, pad + ascent);
547
+
548
+ let rect = fs.allocRect(drawW, drawH);
549
+ if (!rect) {
550
+ if (!nvg__allocTextAtlas(ctx)) return null;
551
+ rect = fs.allocRect(drawW, drawH);
552
+ if (!rect) return null;
553
+ }
554
+
555
+ const imageData = scratch.getImageData(0, 0, drawW, drawH).data;
556
+ for (let sy = 0; sy < drawH; sy++) {
557
+ for (let sx = 0; sx < drawW; sx++) {
558
+ const srcIndex = (sy * drawW + sx) * 4 + 3;
559
+ const dstIndex = (rect.y + sy) * fs.width + (rect.x + sx);
560
+ fs.textureData[dstIndex] = imageData[srcIndex];
561
+ }
562
+ }
563
+ fs.dirty = true;
564
+
565
+ const glyph = {
566
+ advance: metrics.width,
567
+ left: -left - pad + 1,
568
+ top: -ascent - pad + 1,
569
+ right: glyphW - left + pad - 1,
570
+ bottom: descent + pad - 1,
571
+ x: rect.x,
572
+ y: rect.y,
573
+ w: drawW,
574
+ h: drawH,
575
+ s0: (rect.x + 1) / fs.width,
576
+ t0: (rect.y + 1) / fs.height,
577
+ s1: (rect.x + drawW - 1) / fs.width,
578
+ t1: (rect.y + drawH - 1) / fs.height,
579
+ };
580
+ font.glyphs.set(key, glyph);
581
+ return glyph;
582
+ }
583
+
584
+ function nvg__flushTextTexture(ctx) {
585
+ const fs = ctx.fs;
586
+ if (!fs || !fs.dirty) return;
587
+ const fontImage = ctx.fontImages[ctx.fontImageIdx];
588
+ if (fontImage === 0) return;
589
+ ctx.params.renderUpdateTexture(ctx.params.userPtr, fontImage, 0, 0, fs.width, fs.height, fs.textureData);
590
+ fs.dirty = false;
591
+ }
592
+
593
+ function nvg__allocTextAtlas(ctx) {
594
+ let iw = 0;
595
+ let ih = 0;
596
+ nvg__flushTextTexture(ctx);
597
+ if (ctx.fontImageIdx >= NVG_MAX_FONTIMAGES - 1) return 0;
598
+ if (ctx.fontImages[ctx.fontImageIdx + 1] !== 0) {
599
+ [iw, ih] = ctx.nvgImageSize(ctx.fontImages[ctx.fontImageIdx + 1]);
600
+ } else {
601
+ [iw, ih] = ctx.nvgImageSize(ctx.fontImages[ctx.fontImageIdx]);
602
+ if (iw > ih) ih *= 2;
603
+ else iw *= 2;
604
+ if (iw > NVG_MAX_FONTIMAGE_SIZE || ih > NVG_MAX_FONTIMAGE_SIZE) {
605
+ iw = ih = NVG_MAX_FONTIMAGE_SIZE;
606
+ }
607
+ ctx.fontImages[ctx.fontImageIdx + 1] = ctx.params.renderCreateTexture(ctx.params.userPtr, NVG_TEXTURE_ALPHA, iw, ih, 0, null);
608
+ }
609
+ ctx.fontImageIdx++;
610
+ if (ctx.fs) {
611
+ ctx.fs.resize(iw, ih);
612
+ }
613
+ return 1;
614
+ }
615
+
616
+ function nvg__renderText(ctx, verts, nverts) {
617
+ if (nverts <= 0) return;
618
+ const state = nvg__getState(ctx);
619
+ const paint = nvg__clonePaint(state.fill);
620
+ paint.image = ctx.fontImages[ctx.fontImageIdx];
621
+ paint.innerColor.a *= state.alpha;
622
+ paint.outerColor.a *= state.alpha;
623
+ ctx.params.renderTriangles(ctx.params.userPtr, paint, state.compositeOperation, state.scissor, verts, nverts, ctx.fringeWidth);
624
+ ctx.drawCallCount++;
625
+ ctx.textTriCount += nverts / 3;
626
+ }
627
+
628
+ function fonsDeleteInternal(fs) {
629
+ if (!fs) return;
630
+ fs.fonts = [];
631
+ fs.fontsByName = new Map();
632
+ fs.canvas = null;
633
+ fs.ctx2d = null;
634
+ fs.scratchCanvas = null;
635
+ fs.scratchCtx = null;
636
+ }
637
+
638
+ class NVGcontext {
639
+ constructor() {
640
+ this.params = new NVGparams();
641
+ this.commands = null;
642
+ this.ccommands = 0;
643
+ this.ncommands = 0;
644
+ this.commandx = 0;
645
+ this.commandy = 0;
646
+ this.states = Array.from({ length: NVG_MAX_STATES }, () => new NVGstate());
647
+ this.nstates = 0;
648
+ this.cache = new NVGpathCache();
649
+ this.tessTol = 0;
650
+ this.distTol = 0;
651
+ this.fringeWidth = 0;
652
+ this.devicePxRatio = 0;
653
+ this.fs = null;
654
+ this.fontImages = new Array(NVG_MAX_FONTIMAGES).fill(0);
655
+ this.fontImageIdx = 0;
656
+ this.drawCallCount = 0;
657
+ this.fillTriCount = 0;
658
+ this.strokeTriCount = 0;
659
+ this.textTriCount = 0;
660
+ }
661
+
662
+ nvgBeginFrame(windowWidth, windowHeight, devicePixelRatio) {
663
+ this.nstates = 0;
664
+ this.nvgSave();
665
+ this.nvgReset();
666
+
667
+ nvg__setDevicePixelRatio(this, devicePixelRatio);
668
+
669
+ this.params.renderViewport(this.params.userPtr, windowWidth, windowHeight, devicePixelRatio);
670
+
671
+ this.drawCallCount = 0;
672
+ this.fillTriCount = 0;
673
+ this.strokeTriCount = 0;
674
+ this.textTriCount = 0;
675
+ }
676
+
677
+ nvgCancelFrame() {
678
+ this.params.renderCancel(this.params.userPtr);
679
+ }
680
+
681
+ nvgEndFrame() {
682
+ this.params.renderFlush(this);
683
+ if (this.fontImageIdx != 0) {
684
+ let fontImage = this.fontImages[this.fontImageIdx];
685
+ this.fontImages[this.fontImageIdx] = 0;
686
+ let i, j, iw, ih;
687
+ if (fontImage == 0)
688
+ return;
689
+ [iw, ih] = this.nvgImageSize(fontImage);
690
+ for (i = j = 0; i < this.fontImageIdx; i++) {
691
+ if (this.fontImages[i] != 0) {
692
+ let nw, nh;
693
+ let image = this.fontImages[i];
694
+ this.fontImages[i] = 0;
695
+ [nw, nh] = this.nvgImageSize(image);
696
+ if (nw < iw || nh < ih)
697
+ this.nvgDeleteImage(image);
698
+ else
699
+ this.fontImages[j++] = image;
700
+ }
701
+ }
702
+ this.fontImages[j] = this.fontImages[0];
703
+ this.fontImages[0] = fontImage;
704
+ this.fontImageIdx = 0;
705
+ }
706
+ }
707
+
708
+ nvgSave() {
709
+ const ctx = this;
710
+ if (ctx.nstates >= NVG_MAX_STATES)
711
+ return;
712
+ if (ctx.nstates > 0)
713
+ ctx.states[ctx.nstates] = nvg__cloneState(ctx.states[ctx.nstates - 1]);
714
+ ctx.nstates++;
715
+ }
716
+
717
+ nvgRestore() {
718
+ if (this.nstates <= 1)
719
+ return;
720
+ this.nstates--;
721
+ }
722
+
723
+ nvgReset() {
724
+ const ctx = this;
725
+ const state = new NVGstate();
726
+ ctx.states[ctx.nstates - 1] = state;
727
+
728
+ nvg__setPaintColor(state.fill, NVGcolor.nvgRGBA(255,255,255,255));
729
+ nvg__setPaintColor(state.stroke, NVGcolor.nvgRGBA(0,0,0,255));
730
+ state.compositeOperation = nvg__compositeOperationState(NVG_SOURCE_OVER);
731
+ state.shapeAntiAlias = 1;
732
+ state.strokeWidth = 1.0;
733
+ state.miterLimit = 10.0;
734
+ state.lineCap = NVG_BUTT;
735
+ state.lineJoin = NVG_MITER;
736
+ state.alpha = 1.0;
737
+ nvgTransformIdentity(state.xform);
738
+
739
+ state.scissor.extent[0] = -1.0;
740
+ state.scissor.extent[1] = -1.0;
741
+
742
+ state.fontSize = 16.0;
743
+ state.letterSpacing = 0.0;
744
+ state.lineHeight = 1.0;
745
+ state.fontBlur = 0.0;
746
+ state.textAlign = NVG_ALIGN_LEFT | NVG_ALIGN_BASELINE;
747
+ state.fontId = 0;
748
+ }
749
+
750
+ nvgShapeAntiAlias(enabled)
751
+ {
752
+ const state = nvg__getState(this);
753
+ state.shapeAntiAlias = enabled;
754
+ }
755
+
756
+ nvgStrokeWidth(width) {
757
+ const state = nvg__getState(this);
758
+ state.strokeWidth = width;
759
+ }
760
+
761
+ nvgMiterLimit(limit)
762
+ {
763
+ const state = nvg__getState(this);
764
+ state.miterLimit = limit;
765
+ }
766
+
767
+ nvgLineCap(cap)
768
+ {
769
+ const state = nvg__getState(this);
770
+ state.lineCap = cap;
771
+ }
772
+
773
+ nvgLineJoin(join)
774
+ {
775
+ const state = nvg__getState(this);
776
+ state.lineJoin = join;
777
+ }
778
+
779
+ nvgGlobalAlpha(alpha)
780
+ {
781
+ const state = nvg__getState(this);
782
+ state.alpha = alpha;
783
+ }
784
+
785
+ nvgTransform(a, b, c, d, e, f)
786
+ {
787
+ const state = nvg__getState(this);
788
+ let t = [ a, b, c, d, e, f ];
789
+ nvgTransformPremultiply(state.xform, t);
790
+ }
791
+
792
+ nvgResetTransform()
793
+ {
794
+ const state = nvg__getState(this);
795
+ nvgTransformIdentity(state.xform);
796
+ }
797
+
798
+ nvgTranslate(x, y)
799
+ {
800
+ const state = nvg__getState(this);
801
+ let t = [];
802
+ nvgTransformTranslate(t, x,y);
803
+ nvgTransformPremultiply(state.xform, t);
804
+ }
805
+
806
+ nvgRotate(angle)
807
+ {
808
+ const state = nvg__getState(this);
809
+ let t = [];
810
+ nvgTransformRotate(t, angle);
811
+ nvgTransformPremultiply(state.xform, t);
812
+ }
813
+
814
+ nvgSkewX(angle)
815
+ {
816
+ const state = nvg__getState(this);
817
+ let t = [];
818
+ nvgTransformSkewX(t, angle);
819
+ nvgTransformPremultiply(state.xform, t);
820
+ }
821
+
822
+ nvgBeginPath()
823
+ {
824
+ this.ncommands = 0;
825
+ nvg__clearPathCache(this);
826
+ }
827
+
828
+ nvgMoveTo(x, y) {
829
+ let vals = [ NVG_MOVETO, x, y ];
830
+ nvg__appendCommands(this, vals, NVG_COUNTOF(vals));
831
+ }
832
+
833
+ nvgLineTo(x, y) {
834
+ let vals = [ NVG_LINETO, x, y ];
835
+ nvg__appendCommands(this, vals, NVG_COUNTOF(vals));
836
+ }
837
+
838
+ nvgBezierTo(c1x, c1y, c2x, c2y, x, y) {
839
+ let vals = [ NVG_BEZIERTO, c1x, c1y, c2x, c2y, x, y ];
840
+ nvg__appendCommands(this, vals, NVG_COUNTOF(vals));
841
+ }
842
+
843
+ nvgQuadTo(cx, cy, x, y) {
844
+ let x0 = this.commandx;
845
+ let y0 = this.commandy;
846
+ let vals = [ NVG_BEZIERTO,
847
+ x0 + 2.0/3.0*(cx - x0), y0 + 2.0/3.0*(cy - y0),
848
+ x + 2.0/3.0*(cx - x), y + 2.0/3.0*(cy - y),
849
+ x, y ];
850
+ nvg__appendCommands(this, vals, NVG_COUNTOF(vals));
851
+ }
852
+
853
+ nvgArcTo(x1, y1, x2, y2, radius) {
854
+ let x0 = this.commandx;
855
+ let y0 = this.commandy;
856
+ let dx0, dy0, dx1, dy1, a, d, cx, cy, a0, a1;
857
+ let dir;
858
+
859
+ if (this.ncommands === 0) {
860
+ return;
861
+ }
862
+
863
+ if (
864
+ nvg__ptEquals(x0, y0, x1, y1, this.distTol) ||
865
+ nvg__ptEquals(x1, y1, x2, y2, this.distTol) ||
866
+ nvg__distPtSeg(x1, y1, x0, y0, x2, y2) < this.distTol * this.distTol ||
867
+ radius < this.distTol
868
+ ) {
869
+ this.nvgLineTo(x1, y1);
870
+ return;
871
+ }
872
+
873
+ dx0 = x0 - x1;
874
+ dy0 = y0 - y1;
875
+ dx1 = x2 - x1;
876
+ dy1 = y2 - y1;
877
+ [dx0, dy0] = nvg__normalizeXY(dx0, dy0);
878
+ [dx1, dy1] = nvg__normalizeXY(dx1, dy1);
879
+ a = nvg__acosf(dx0 * dx1 + dy0 * dy1);
880
+ d = radius / Math.tan(a / 2.0);
881
+
882
+ if (d > 10000.0) {
883
+ this.nvgLineTo(x1, y1);
884
+ return;
885
+ }
886
+
887
+ if (nvg__cross(dx0, dy0, dx1, dy1) > 0.0) {
888
+ cx = x1 + dx0 * d + dy0 * radius;
889
+ cy = y1 + dy0 * d + -dx0 * radius;
890
+ a0 = nvg__atan2f(dx0, -dy0);
891
+ a1 = nvg__atan2f(-dx1, dy1);
892
+ dir = NVG_CW;
893
+ } else {
894
+ cx = x1 + dx0 * d + -dy0 * radius;
895
+ cy = y1 + dy0 * d + dx0 * radius;
896
+ a0 = nvg__atan2f(-dx0, dy0);
897
+ a1 = nvg__atan2f(dx1, -dy1);
898
+ dir = NVG_CCW;
899
+ }
900
+
901
+ this.nvgArc(cx, cy, radius, a0, a1, dir);
902
+ }
903
+
904
+ nvgClosePath() {
905
+ let vals = [ NVG_CLOSE ];
906
+ nvg__appendCommands(this, vals, NVG_COUNTOF(vals));
907
+ }
908
+
909
+ nvgPathWinding(dir) {
910
+ let vals = [ NVG_WINDING, dir ];
911
+ nvg__appendCommands(this, vals, NVG_COUNTOF(vals));
912
+ }
913
+
914
+ nvgArc(cx, cy, r, a0, a1, dir) {
915
+ let a = 0, da = 0, hda = 0, kappa = 0;
916
+ let dx = 0, dy = 0, x = 0, y = 0, tanx = 0, tany = 0;
917
+ let px = 0, py = 0, ptanx = 0, ptany = 0;
918
+ let vals = [];
919
+ let ndivs, nvals;
920
+ let move = this.ncommands > 0 ? NVG_LINETO : NVG_MOVETO;
921
+
922
+ da = a1 - a0;
923
+ if (dir === NVG_CW) {
924
+ if (Math.abs(da) >= Math.PI * 2) {
925
+ da = Math.PI * 2;
926
+ } else {
927
+ while (da < 0.0) da += Math.PI * 2;
928
+ }
929
+ } else {
930
+ if (Math.abs(da) >= Math.PI * 2) {
931
+ da = -Math.PI * 2;
932
+ } else {
933
+ while (da > 0.0) da -= Math.PI * 2;
934
+ }
935
+ }
936
+
937
+ ndivs = Math.max(1, Math.min(Math.floor(Math.abs(da) / (Math.PI * 0.5) + 0.5), 5));
938
+ hda = (da / ndivs) / 2.0;
939
+ kappa = Math.abs(4.0 / 3.0 * (1.0 - Math.cos(hda)) / Math.sin(hda));
940
+
941
+ if (dir === NVG_CCW)
942
+ kappa = -kappa;
943
+
944
+ nvals = 0;
945
+ for (let i = 0; i <= ndivs; i++) {
946
+ a = a0 + da * (i / ndivs);
947
+ dx = Math.cos(a);
948
+ dy = Math.sin(a);
949
+ x = cx + dx * r;
950
+ y = cy + dy * r;
951
+ tanx = -dy * r * kappa;
952
+ tany = dx * r * kappa;
953
+
954
+ if (i === 0) {
955
+ vals[nvals++] = move;
956
+ vals[nvals++] = x;
957
+ vals[nvals++] = y;
958
+ } else {
959
+ vals[nvals++] = NVG_BEZIERTO;
960
+ vals[nvals++] = px + ptanx;
961
+ vals[nvals++] = py + ptany;
962
+ vals[nvals++] = x - tanx;
963
+ vals[nvals++] = y - tany;
964
+ vals[nvals++] = x;
965
+ vals[nvals++] = y;
966
+ }
967
+ px = x;
968
+ py = y;
969
+ ptanx = tanx;
970
+ ptany = tany;
971
+ }
972
+
973
+ nvg__appendCommands(this, vals, nvals);
974
+ }
975
+
976
+ nvgRect(x, y, w, h) {
977
+ let vals = [
978
+ NVG_MOVETO, x,y,
979
+ NVG_LINETO, x,y+h,
980
+ NVG_LINETO, x+w,y+h,
981
+ NVG_LINETO, x+w,y,
982
+ NVG_CLOSE
983
+ ];
984
+ nvg__appendCommands(this, vals, NVG_COUNTOF(vals));
985
+ }
986
+
987
+ nvgRoundedRect(x, y, w, h, r) {
988
+ this.nvgRoundedRectVarying(x, y, w, h, r, r, r, r);
989
+ }
990
+
991
+ nvgRoundedRectVarying(x, y, w, h, radTopLeft, radTopRight, radBottomRight, radBottomLeft) {
992
+ if (radTopLeft < 0.1 && radTopRight < 0.1 && radBottomRight < 0.1 && radBottomLeft < 0.1) {
993
+ this.nvgRect(x, y, w, h);
994
+ return;
995
+ } else {
996
+ let halfw = Math.abs(w) * 0.5;
997
+ let halfh = Math.abs(h) * 0.5;
998
+ let rxBL = Math.min(radBottomLeft, halfw) * Math.sign(w);
999
+ let ryBL = Math.min(radBottomLeft, halfh) * Math.sign(h);
1000
+ let rxBR = Math.min(radBottomRight, halfw) * Math.sign(w);
1001
+ let ryBR = Math.min(radBottomRight, halfh) * Math.sign(h);
1002
+ let rxTR = Math.min(radTopRight, halfw) * Math.sign(w);
1003
+ let ryTR = Math.min(radTopRight, halfh) * Math.sign(h);
1004
+ let rxTL = Math.min(radTopLeft, halfw) * Math.sign(w);
1005
+ let ryTL = Math.min(radTopLeft, halfh) * Math.sign(h);
1006
+ let vals = [
1007
+ NVG_MOVETO, x, y + ryTL,
1008
+ NVG_LINETO, x, y + h - ryBL,
1009
+ NVG_BEZIERTO, x, y + h - ryBL * (1 - NVG_KAPPA90), x + rxBL * (1 - NVG_KAPPA90), y + h, x + rxBL, y + h,
1010
+ NVG_LINETO, x + w - rxBR, y + h,
1011
+ NVG_BEZIERTO, x + w - rxBR * (1 - NVG_KAPPA90), y + h, x + w, y + h - ryBR * (1 - NVG_KAPPA90), x + w, y + h - ryBR,
1012
+ NVG_LINETO, x + w, y + ryTR,
1013
+ NVG_BEZIERTO, x + w, y + ryTR * (1 - NVG_KAPPA90), x + w - rxTR * (1 - NVG_KAPPA90), y, x + w - rxTR, y,
1014
+ NVG_LINETO, x + rxTL, y,
1015
+ NVG_BEZIERTO, x + rxTL * (1 - NVG_KAPPA90), y, x, y + ryTL * (1 - NVG_KAPPA90), x, y + ryTL,
1016
+ NVG_CLOSE
1017
+ ];
1018
+ nvg__appendCommands(this, vals, vals.length);
1019
+ }
1020
+ }
1021
+
1022
+ nvgEllipse(cx, cy, rx, ry) {
1023
+ let vals = [
1024
+ NVG_MOVETO, cx-rx, cy,
1025
+ NVG_BEZIERTO, cx-rx, cy+ry*NVG_KAPPA90, cx-rx*NVG_KAPPA90, cy+ry, cx, cy+ry,
1026
+ NVG_BEZIERTO, cx+rx*NVG_KAPPA90, cy+ry, cx+rx, cy+ry*NVG_KAPPA90, cx+rx, cy,
1027
+ NVG_BEZIERTO, cx+rx, cy-ry*NVG_KAPPA90, cx+rx*NVG_KAPPA90, cy-ry, cx, cy-ry,
1028
+ NVG_BEZIERTO, cx-rx*NVG_KAPPA90, cy-ry, cx-rx, cy-ry*NVG_KAPPA90, cx-rx, cy,
1029
+ NVG_CLOSE
1030
+ ];
1031
+ nvg__appendCommands(this, vals, NVG_COUNTOF(vals));
1032
+ }
1033
+
1034
+ nvgCircle(cx, cy, r) {
1035
+ this.nvgEllipse(cx, cy, r, r);
1036
+ }
1037
+
1038
+ //nvgDebugDumpPathCache() {
1039
+ // let path, i, j;
1040
+ // console.log("Dumping %d cached paths\n", this.cache.npaths);
1041
+ // for (i = 0; i < this.cache.npaths; i++) {
1042
+ // path = this.cache.paths[i];
1043
+ // console.log(" - Path %d\n", i);
1044
+ // if (path.nfill) {
1045
+ // console.log(" - fill: %d\n", path.nfill);
1046
+ // for (j = 0; j < path.nfill; j++)
1047
+ // console.log("%f\t%f\n", path.fill[j].x, path.fill[j].y);
1048
+ // }
1049
+ // if (path.nstroke > 0) {
1050
+ // console.log(" - stroke: %d\n", path.nstroke);
1051
+ // for (j = 0; j < path.nstroke; j++)
1052
+ // console.log("%f\t%f\n", path.stroke[j].x, path.stroke[j].y);
1053
+ // }
1054
+ // }
1055
+ //}
1056
+
1057
+ nvgDebugDumpPathCache() {
1058
+ let path, i, j;
1059
+ console.log("Dumping %d cached paths\n", this.cache.npaths);
1060
+ for (i = 0; i < this.cache.npaths; i++) {
1061
+ path = this.cache.paths[i];
1062
+ console.log(" - Path %d\n", i);
1063
+ if (path.nfill) {
1064
+ console.log(" - fill: %d\n", path.nfill);
1065
+ for (j = 0; j < path.nfill; j=j+4)
1066
+ console.log("%f\t%f\n", path.fill[j], path.fill[j+1]);
1067
+ }
1068
+ if (path.nstroke > 0) {
1069
+ console.log(" - stroke: %d\n", path.nstroke);
1070
+ for (j = 0; j < path.nstroke; j=j+4)
1071
+ console.log("%f\t%f\n", path.stroke[j], path.stroke[j+1]);
1072
+ }
1073
+ }
1074
+ }
1075
+
1076
+ nvgFill() {
1077
+ const state = nvg__getState(this);
1078
+ let path;
1079
+ let fillPaint = nvg__clonePaint(state.fill);
1080
+ let i;
1081
+
1082
+ nvg__flattenPaths(this);
1083
+ if (this.params.edgeAntiAlias && state.shapeAntiAlias)
1084
+ nvg__expandFill(this, this.fringeWidth, NVG_MITER, 2.4);
1085
+ else
1086
+ nvg__expandFill(this, 0.0, NVG_MITER, 2.4);
1087
+
1088
+ fillPaint.innerColor.a *= state.alpha;
1089
+ fillPaint.outerColor.a *= state.alpha;
1090
+
1091
+ this.params.renderFill(
1092
+ this.params.userPtr,
1093
+ fillPaint,
1094
+ state.compositeOperation,
1095
+ state.scissor,
1096
+ this.fringeWidth,
1097
+ this.cache.bounds,
1098
+ this.cache.paths,
1099
+ this.cache.npaths
1100
+ );
1101
+
1102
+ for (i = 0; i < this.cache.npaths; i++) {
1103
+ path = this.cache.paths[i];
1104
+ this.fillTriCount += path.nfill - 2;
1105
+ this.fillTriCount += path.nstroke - 2;
1106
+ this.drawCallCount += 2;
1107
+ }
1108
+ }
1109
+
1110
+ nvgStroke() {
1111
+ const state = nvg__getState(this);
1112
+ const cache = this.cache;
1113
+
1114
+ this.drawCallCount++;
1115
+ this.strokeTriCount = 0;
1116
+
1117
+ let scale = nvg__getAverageScale(state.xform);
1118
+ let strokeWidth = nvg__clampf(state.strokeWidth * scale, 0.0, 200.0);
1119
+
1120
+ let strokePaint = new NVGpaint();
1121
+
1122
+ strokePaint.xform.set(state.stroke.xform);
1123
+ strokePaint.extent.set(state.stroke.extent);
1124
+ strokePaint.radius = state.stroke.radius;
1125
+ strokePaint.feather = state.stroke.feather;
1126
+ strokePaint.image = state.stroke.image;
1127
+
1128
+ strokePaint.innerColor = NVGcolor.nvgRGBAf(
1129
+ state.stroke.innerColor.r,
1130
+ state.stroke.innerColor.g,
1131
+ state.stroke.innerColor.b,
1132
+ state.stroke.innerColor.a
1133
+ );
1134
+ strokePaint.outerColor = NVGcolor.nvgRGBAf(
1135
+ state.stroke.outerColor.r,
1136
+ state.stroke.outerColor.g,
1137
+ state.stroke.outerColor.b,
1138
+ state.stroke.outerColor.a
1139
+ );
1140
+
1141
+ if (strokeWidth < this.fringeWidth) {
1142
+ let alpha = nvg__clampf(strokeWidth / this.fringeWidth, 0.0, 1.0);
1143
+ strokePaint.innerColor.a *= alpha * alpha;
1144
+ strokePaint.outerColor.a *= alpha * alpha;
1145
+ strokeWidth = this.fringeWidth;
1146
+ }
1147
+
1148
+ strokePaint.innerColor.a *= state.alpha;
1149
+ strokePaint.outerColor.a *= state.alpha;
1150
+
1151
+ nvg__flattenPaths(this);
1152
+ if (cache.npaths === 0) return;
1153
+
1154
+ const fringe = this.params.edgeAntiAlias && state.shapeAntiAlias ? this.fringeWidth : 0.0;
1155
+
1156
+ nvg__expandStroke(
1157
+ this,
1158
+ strokeWidth * 0.5,
1159
+ fringe,
1160
+ state.lineCap,
1161
+ state.lineJoin,
1162
+ state.miterLimit
1163
+ );
1164
+
1165
+ this.params.renderStroke(
1166
+ this.params.userPtr,
1167
+ strokePaint,
1168
+ state.compositeOperation,
1169
+ state.scissor,
1170
+ this.fringeWidth,
1171
+ strokeWidth,
1172
+ cache.paths,
1173
+ cache.npaths
1174
+ );
1175
+
1176
+ for (let i = 0; i < cache.npaths; i++) {
1177
+ const path = cache.paths[i];
1178
+ if (path.nstroke >= 3) {
1179
+ this.strokeTriCount += path.nstroke;
1180
+ }
1181
+ }
1182
+ }
1183
+
1184
+ nvgCreateFont(name, filename) {
1185
+ if (!this.fs || name == null || filename == null) return FONS_INVALID;
1186
+ return this.fs.addFont(name, filename);
1187
+ }
1188
+
1189
+ nvgCreateFontAtIndex(name, filename, fontIndex) {
1190
+ NVG_NOTUSED(fontIndex);
1191
+ return this.nvgCreateFont(name, filename);
1192
+ }
1193
+
1194
+ nvgCreateFontMem(name, data, ndata, freeData) {
1195
+ NVG_NOTUSED(ndata);
1196
+ NVG_NOTUSED(freeData);
1197
+ if (!this.fs || name == null || data == null) return FONS_INVALID;
1198
+ let buffer = data;
1199
+ if (ArrayBuffer.isView(data)) {
1200
+ buffer = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
1201
+ }
1202
+ return this.fs.addFont(name, buffer);
1203
+ }
1204
+
1205
+ nvgCreateFontMemAtIndex(name, data, ndata, freeData, fontIndex) {
1206
+ NVG_NOTUSED(fontIndex);
1207
+ return this.nvgCreateFontMem(name, data, ndata, freeData);
1208
+ }
1209
+
1210
+ nvgFindFont(name) {
1211
+ if (name == null) return -1;
1212
+ return this.fs ? this.fs.findFont(name) : FONS_INVALID;
1213
+ }
1214
+
1215
+ nvgAddFallbackFontId(baseFont, fallbackFont)
1216
+ {
1217
+ NVG_NOTUSED(baseFont);
1218
+ NVG_NOTUSED(fallbackFont);
1219
+ return 1;
1220
+ }
1221
+
1222
+ nvgAddFallbackFont(baseFont, fallbackFont)
1223
+ {
1224
+ return this.nvgAddFallbackFontId(this.nvgFindFont(baseFont), this.nvgFindFont(fallbackFont));
1225
+ }
1226
+
1227
+ nvgResetFallbackFontsId(baseFont)
1228
+ {
1229
+ NVG_NOTUSED(baseFont);
1230
+ }
1231
+
1232
+ nvgResetFallbackFonts(baseFont)
1233
+ {
1234
+ this.nvgResetFallbackFontsId(this.nvgFindFont(baseFont));
1235
+ }
1236
+
1237
+ nvgFontSize(size) {
1238
+ const state = nvg__getState(this);
1239
+ state.fontSize = size;
1240
+ }
1241
+
1242
+ nvgFontBlur(size) {
1243
+ const state = nvg__getState(this);
1244
+ state.fontBlur = size;
1245
+ }
1246
+
1247
+ nvgTextLetterSpacing(spacing) {
1248
+ const state = nvg__getState(this);
1249
+ state.letterSpacing = spacing;
1250
+ }
1251
+
1252
+ nvgTextLineHeight(lineHeight) {
1253
+ const state = nvg__getState(this);
1254
+ state.lineHeight = lineHeight;
1255
+ }
1256
+
1257
+ nvgTextAlign(align) {
1258
+ const state = nvg__getState(this);
1259
+ state.textAlign = align;
1260
+ }
1261
+
1262
+ nvgFontFaceId(font) {
1263
+ const state = nvg__getState(this);
1264
+ state.fontId = font;
1265
+ }
1266
+
1267
+ nvgFontFace(font) {
1268
+ const state = nvg__getState(this);
1269
+ state.fontId = this.nvgFindFont(font);
1270
+ }
1271
+
1272
+ nvgText(x, y, string, end) {
1273
+ const state = nvg__getState(this);
1274
+ const text = nvg__resolveTextEnd(string, end);
1275
+ const font = nvg__getJsFont(this, state.fontId);
1276
+ if (!font || text.length === 0 || !this.fs || !this.fs.scratchCtx) return x;
1277
+
1278
+ const scale = nvg__getFontScale(state) * this.devicePxRatio;
1279
+ const invscale = 1.0 / scale;
1280
+ const drawSize = state.fontSize * scale;
1281
+ const measureCtx = this.fs.scratchCtx;
1282
+ measureCtx.font = nvg__buildFontCSS(font, drawSize);
1283
+
1284
+ let width = 0;
1285
+ for (const ch of text) {
1286
+ width += nvg__measureTextWidth(measureCtx, ch) + state.letterSpacing * scale;
1287
+ }
1288
+ if (text.length > 0) width -= state.letterSpacing * scale;
1289
+
1290
+ const verticalMetrics = nvg__getFontVerticalMetrics(measureCtx, drawSize);
1291
+ let penX = nvg__computeTextStartX(state.textAlign, x * scale, width);
1292
+ const penY = nvg__computeTextBaselineY(state.textAlign, y * scale, verticalMetrics);
1293
+ const verts = nvg__allocTempVerts(this, Math.max(2, text.length) * 6);
1294
+ if (verts == null) return x;
1295
+ let nverts = 0;
1296
+
1297
+ for (const ch of text) {
1298
+ const glyph = nvg__ensureGlyph(this, font, drawSize, state.fontBlur * scale, ch.codePointAt(0));
1299
+ if (!glyph) {
1300
+ penX += nvg__measureTextWidth(measureCtx, ch) + state.letterSpacing * scale;
1301
+ continue;
1302
+ }
1303
+
1304
+ const x0 = penX + glyph.left;
1305
+ const y0 = penY + glyph.top;
1306
+ const x1 = penX + glyph.right;
1307
+ const y1 = penY + glyph.bottom;
1308
+ const c0 = nvgTransformPoint(state.xform, x0 * invscale, y0 * invscale);
1309
+ const c1 = nvgTransformPoint(state.xform, x1 * invscale, y0 * invscale);
1310
+ const c2 = nvgTransformPoint(state.xform, x1 * invscale, y1 * invscale);
1311
+ const c3 = nvgTransformPoint(state.xform, x0 * invscale, y1 * invscale);
1312
+
1313
+ const base = nverts * 4;
1314
+ const view = new Float32Array(verts, nverts * NVG_VERTEX_SIZEOF, 24);
1315
+ view.set([
1316
+ c0[0], c0[1], glyph.s0, glyph.t0,
1317
+ c2[0], c2[1], glyph.s1, glyph.t1,
1318
+ c1[0], c1[1], glyph.s1, glyph.t0,
1319
+ c0[0], c0[1], glyph.s0, glyph.t0,
1320
+ c3[0], c3[1], glyph.s0, glyph.t1,
1321
+ c2[0], c2[1], glyph.s1, glyph.t1,
1322
+ ]);
1323
+ nverts += 6;
1324
+ penX += glyph.advance + state.letterSpacing * scale;
1325
+ }
1326
+
1327
+ nvg__flushTextTexture(this);
1328
+ nvg__renderText(this, verts, nverts);
1329
+ return penX * invscale;
1330
+ }
1331
+
1332
+ nvgTextBox(x, y, breakRowWidth, string, end) {
1333
+ const state = nvg__getState(this);
1334
+ const text = nvg__resolveTextEnd(string, end);
1335
+ if (text.length === 0) return;
1336
+
1337
+ const widthInfo = { value: 0 };
1338
+ const ascInfo = { value: 0 };
1339
+ const descInfo = { value: 0 };
1340
+ const lineInfo = { value: 0 };
1341
+ const oldAlign = state.textAlign;
1342
+ const halign = state.textAlign & (NVG_ALIGN_LEFT | NVG_ALIGN_CENTER | NVG_ALIGN_RIGHT);
1343
+ const valign = state.textAlign & (NVG_ALIGN_TOP | NVG_ALIGN_MIDDLE | NVG_ALIGN_BOTTOM | NVG_ALIGN_BASELINE);
1344
+ this.nvgTextMetrics(ascInfo, descInfo, lineInfo);
1345
+ state.textAlign = NVG_ALIGN_LEFT | valign;
1346
+
1347
+ const words = text.split(/\s+/);
1348
+ let line = "";
1349
+ for (const word of words) {
1350
+ const candidate = line.length === 0 ? word : `${line} ${word}`;
1351
+ widthInfo.value = this.nvgTextBounds(0, 0, candidate, null, null);
1352
+ if (line.length > 0 && widthInfo.value > breakRowWidth) {
1353
+ let dx = 0;
1354
+ const lineWidth = this.nvgTextBounds(0, 0, line, null, null);
1355
+ if (halign & NVG_ALIGN_CENTER) dx = breakRowWidth * 0.5 - lineWidth * 0.5;
1356
+ else if (halign & NVG_ALIGN_RIGHT) dx = breakRowWidth - lineWidth;
1357
+ this.nvgText(x + dx, y, line, null);
1358
+ y += lineInfo.value * state.lineHeight;
1359
+ line = word;
1360
+ } else {
1361
+ line = candidate;
1362
+ }
1363
+ }
1364
+ if (line.length > 0) {
1365
+ let dx = 0;
1366
+ const lineWidth = this.nvgTextBounds(0, 0, line, null, null);
1367
+ if (halign & NVG_ALIGN_CENTER) dx = breakRowWidth * 0.5 - lineWidth * 0.5;
1368
+ else if (halign & NVG_ALIGN_RIGHT) dx = breakRowWidth - lineWidth;
1369
+ this.nvgText(x + dx, y, line, null);
1370
+ }
1371
+ state.textAlign = oldAlign;
1372
+ }
1373
+
1374
+ nvgTextMetrics(ascender, descender, lineh) {
1375
+ const state = nvg__getState(this);
1376
+ const scale = nvg__getFontScale(state) * this.devicePxRatio;
1377
+ const invscale = 1.0 / scale;
1378
+
1379
+ const font = nvg__getJsFont(this, state.fontId);
1380
+ if (!font || !this.fs || !this.fs.scratchCtx) return;
1381
+
1382
+ const measureCtx = this.fs.scratchCtx;
1383
+ measureCtx.font = nvg__buildFontCSS(font, state.fontSize * scale);
1384
+ const metrics = nvg__getFontVerticalMetrics(measureCtx, state.fontSize * scale);
1385
+ if (typeof ascender === "object" && ascender) ascender.value = metrics.ascender * invscale;
1386
+ if (typeof descender === "object" && descender) descender.value = metrics.descender * invscale;
1387
+ if (typeof lineh === "object" && lineh) lineh.value = metrics.lineh * invscale;
1388
+ }
1389
+
1390
+ nvgTextBounds(x, y, string, end, bounds) {
1391
+ const state = nvg__getState(this);
1392
+ const text = nvg__resolveTextEnd(string, end);
1393
+ const font = nvg__getJsFont(this, state.fontId);
1394
+ if (!font || !this.fs || !this.fs.scratchCtx) {
1395
+ if (bounds) bounds.splice(0, bounds.length, 0, 0, 0, 0);
1396
+ return 0;
1397
+ }
1398
+ const scale = nvg__getFontScale(state) * this.devicePxRatio;
1399
+ const invscale = 1.0 / scale;
1400
+ const measureCtx = this.fs.scratchCtx;
1401
+ measureCtx.font = nvg__buildFontCSS(font, state.fontSize * scale);
1402
+
1403
+ let width = 0;
1404
+ for (const ch of text) {
1405
+ width += nvg__measureTextWidth(measureCtx, ch) + state.letterSpacing * scale;
1406
+ }
1407
+ if (text.length > 0) width -= state.letterSpacing * scale;
1408
+ const metrics = nvg__getFontVerticalMetrics(measureCtx, state.fontSize * scale);
1409
+ const baselineY = nvg__computeTextBaselineY(state.textAlign, y * scale, metrics);
1410
+ const startX = nvg__computeTextStartX(state.textAlign, x * scale, width) * invscale;
1411
+ if (bounds) {
1412
+ bounds[0] = startX;
1413
+ bounds[1] = (baselineY - metrics.ascender) * invscale;
1414
+ bounds[2] = startX + width * invscale;
1415
+ bounds[3] = (baselineY - metrics.descender) * invscale;
1416
+ }
1417
+ return width * invscale;
1418
+ }
1419
+
1420
+ nvgTextGlyphPositions(x, y, string, end, positions, maxPositions) {
1421
+ const state = nvg__getState(this);
1422
+ const text = nvg__resolveTextEnd(string, end);
1423
+ const font = nvg__getJsFont(this, state.fontId);
1424
+ if (!font || !this.fs || !this.fs.scratchCtx || !positions || maxPositions <= 0) return 0;
1425
+
1426
+ const scale = nvg__getFontScale(state) * this.devicePxRatio;
1427
+ const invscale = 1.0 / scale;
1428
+ const measureCtx = this.fs.scratchCtx;
1429
+ measureCtx.font = nvg__buildFontCSS(font, state.fontSize * scale);
1430
+
1431
+ let penX = nvg__computeTextStartX(state.textAlign, x * scale, 0);
1432
+ let n = 0;
1433
+ for (const ch of text) {
1434
+ if (n >= maxPositions) break;
1435
+ const glyphWidth = nvg__measureTextWidth(measureCtx, ch);
1436
+ positions[n] = {
1437
+ str: ch,
1438
+ x: penX * invscale,
1439
+ minx: penX * invscale,
1440
+ maxx: (penX + glyphWidth) * invscale
1441
+ };
1442
+ penX += glyphWidth + state.letterSpacing * scale;
1443
+ n++;
1444
+ }
1445
+ return n;
1446
+ }
1447
+
1448
+ nvgTextBreakLines(string, end, breakRowWidth, rows, maxRows) {
1449
+ const state = nvg__getState(this);
1450
+ const text = nvg__resolveTextEnd(string, end);
1451
+ const font = nvg__getJsFont(this, state.fontId);
1452
+ if (!font || !this.fs || !this.fs.scratchCtx || !rows || maxRows <= 0) return 0;
1453
+
1454
+ const scale = nvg__getFontScale(state) * this.devicePxRatio;
1455
+ const invscale = 1.0 / scale;
1456
+ const measureCtx = this.fs.scratchCtx;
1457
+ measureCtx.font = nvg__buildFontCSS(font, state.fontSize * scale);
1458
+
1459
+ const pushRow = (segment, nextIndex, outIndex) => {
1460
+ const width = this.nvgTextBounds(0, 0, segment, null, null);
1461
+ const rowText = segment.replace(/\s+$/g, "");
1462
+ const rowWidth = this.nvgTextBounds(0, 0, rowText, null, null);
1463
+ rows[outIndex] = {
1464
+ start: rowText,
1465
+ end: rowText,
1466
+ next: nextIndex,
1467
+ width: rowWidth,
1468
+ minx: 0,
1469
+ maxx: rowWidth
1470
+ };
1471
+ return width;
1472
+ };
1473
+
1474
+ let count = 0;
1475
+ let i = 0;
1476
+ while (i < text.length && count < maxRows) {
1477
+ if (text[i] === "\n") {
1478
+ rows[count++] = { start: "", end: "", next: i + 1, width: 0, minx: 0, maxx: 0 };
1479
+ i++;
1480
+ continue;
1481
+ }
1482
+
1483
+ let lineStart = i;
1484
+ let lastBreak = -1;
1485
+ let j = i;
1486
+ let lineWidth = 0;
1487
+
1488
+ while (j < text.length) {
1489
+ const ch = text[j];
1490
+ if (ch === "\n") break;
1491
+ const advance = (nvg__measureTextWidth(measureCtx, ch) + state.letterSpacing * scale) * invscale;
1492
+ if (/\s/.test(ch)) lastBreak = j;
1493
+ if (j > lineStart && lineWidth + advance > breakRowWidth) {
1494
+ if (lastBreak >= lineStart) {
1495
+ j = lastBreak + 1;
1496
+ }
1497
+ break;
1498
+ }
1499
+ lineWidth += advance;
1500
+ j++;
1501
+ }
1502
+
1503
+ const segment = text.slice(lineStart, j);
1504
+ pushRow(segment, j < text.length && text[j] === "\n" ? j + 1 : j, count);
1505
+ count++;
1506
+
1507
+ i = j;
1508
+ while (i < text.length && text[i] === "\n") break;
1509
+ while (i < text.length && i > lineStart && /\s/.test(text[i]) && text[i] !== "\n") i++;
1510
+ if (j < text.length && text[j] === "\n") i = j + 1;
1511
+ }
1512
+ return count;
1513
+ }
1514
+
1515
+ nvgTextBoxBounds(x, y, breakRowWidth, string, end, bounds) {
1516
+ const state = nvg__getState(this);
1517
+ const text = nvg__resolveTextEnd(string, end);
1518
+ const asc = { value: 0 };
1519
+ const desc = { value: 0 };
1520
+ const lineh = { value: 0 };
1521
+ this.nvgTextMetrics(asc, desc, lineh);
1522
+
1523
+ const lines = text.split("\n");
1524
+ let maxWidth = 0;
1525
+ let yy = y;
1526
+ const oldAlign = state.textAlign;
1527
+ state.textAlign = (state.textAlign & (NVG_ALIGN_LEFT | NVG_ALIGN_CENTER | NVG_ALIGN_RIGHT)) | NVG_ALIGN_TOP;
1528
+
1529
+ for (const rawLine of lines) {
1530
+ const words = rawLine.length ? rawLine.split(/\s+/) : [""];
1531
+ let line = "";
1532
+ if (rawLine.trim().length === 0) {
1533
+ yy += lineh.value * state.lineHeight;
1534
+ continue;
1535
+ }
1536
+ for (const word of words) {
1537
+ const candidate = line.length === 0 ? word : `${line} ${word}`;
1538
+ const candidateWidth = this.nvgTextBounds(x, yy, candidate, null, null);
1539
+ if (line.length > 0 && candidateWidth > breakRowWidth) {
1540
+ maxWidth = Math.max(maxWidth, this.nvgTextBounds(x, yy, line, null, null));
1541
+ yy += lineh.value * state.lineHeight;
1542
+ line = word;
1543
+ } else {
1544
+ line = candidate;
1545
+ }
1546
+ }
1547
+ maxWidth = Math.max(maxWidth, this.nvgTextBounds(x, yy, line, null, null));
1548
+ yy += lineh.value * state.lineHeight;
1549
+ }
1550
+
1551
+ state.textAlign = oldAlign;
1552
+ if (bounds) {
1553
+ bounds[0] = x;
1554
+ bounds[1] = y;
1555
+ bounds[2] = x + Math.max(maxWidth, breakRowWidth > 0 ? Math.min(maxWidth, breakRowWidth) : maxWidth);
1556
+ bounds[3] = yy;
1557
+ }
1558
+ return maxWidth;
1559
+ }
1560
+
1561
+ nvgCreateImage(filename, imageFlags) {
1562
+ let w, h, n, image;
1563
+ let img;
1564
+ stbi_set_unpremultiply_on_load(1); // TODO: stbi_set_unpremultiply_on_load
1565
+ stbi_convert_iphone_png_to_rgb(1); // TODO: stbi_convert_iphone_png_to_rgb
1566
+ img = stbi_load(filename, w, h, n, 4);
1567
+ if (img == null) {
1568
+ // console.log(`Failed to load ${filename} - ${stbi_failure_reason()}\n`);
1569
+ return 0;
1570
+ }
1571
+ image = this.nvgCreateImageRGBA(w, h, imageFlags, img);
1572
+ stbi_image_free(img); // TODO: stbi_image_free
1573
+ return image;
1574
+ }
1575
+
1576
+ nvgCreateImageMem(imageFlags, data, ndata)
1577
+ {
1578
+ let w, h, n, image;
1579
+ let img = stbi_load_from_memory(data, ndata, w, h, n, 4); // TODO: stbi_load_from_memory
1580
+ if (img == null) {
1581
+ // console.log(`Failed to load ${filename} - ${stbi_failure_reason()}\n`);
1582
+ return 0;
1583
+ }
1584
+ image = this.nvgCreateImageRGBA(w, h, imageFlags, img);
1585
+ stbi_image_free(img); // TODO: stbi_image_free
1586
+ return image;
1587
+ }
1588
+
1589
+ nvgCreateImageRGBA(w, h, imageFlags, data) {
1590
+ return this.params.renderCreateTexture(this.params.userPtr, NVG_TEXTURE_RGBA, w, h, imageFlags, data);
1591
+ }
1592
+
1593
+ nvgUpdateImage(image, data) {
1594
+ const [w, h] = this.nvgImageSize(image);
1595
+ this.params.renderUpdateTexture(this.params.userPtr, image, 0,0, w,h, data);
1596
+ }
1597
+
1598
+ nvgImageSize(image) {
1599
+ const size = this.params.renderGetTextureSize(this.params.userPtr, image);
1600
+ if (Array.isArray(size))
1601
+ return size;
1602
+ if (size && typeof size === "object")
1603
+ return [size.width ?? 0, size.height ?? 0];
1604
+ return [0, 0];
1605
+ }
1606
+
1607
+ nvgDeleteImage(image) {
1608
+ this.params.renderDeleteTexture(this.params.userPtr, image);
1609
+ }
1610
+
1611
+ nvgLinearGradient(sx, sy, ex, ey, icol, ocol) {
1612
+ var p = {
1613
+ xform: new Array(6),
1614
+ extent: new Array(2),
1615
+ radius: 0.0,
1616
+ feather: 0.0,
1617
+ innerColor: icol,
1618
+ outerColor: ocol
1619
+ };
1620
+ var dx, dy, d;
1621
+ var large = 1e5;
1622
+
1623
+ dx = ex - sx;
1624
+ dy = ey - sy;
1625
+ d = Math.sqrt(dx * dx + dy * dy);
1626
+ if (d > 0.0001) {
1627
+ dx /= d;
1628
+ dy /= d;
1629
+ } else {
1630
+ dx = 0;
1631
+ dy = 1;
1632
+ }
1633
+
1634
+ p.xform[0] = dy;
1635
+ p.xform[1] = -dx;
1636
+ p.xform[2] = dx;
1637
+ p.xform[3] = dy;
1638
+ p.xform[4] = sx - dx * large;
1639
+ p.xform[5] = sy - dy * large;
1640
+
1641
+ p.extent[0] = large;
1642
+ p.extent[1] = large + d * 0.5;
1643
+
1644
+ p.feather = Math.max(1.0, d);
1645
+
1646
+ return p;
1647
+ }
1648
+
1649
+ nvgRadialGradient(cx, cy, inr, outr, icol, ocol) {
1650
+ var p = {
1651
+ xform: new Array(6),
1652
+ extent: new Array(2),
1653
+ radius: (inr + outr) * 0.5,
1654
+ feather: 0.0,
1655
+ innerColor: icol,
1656
+ outerColor: ocol
1657
+ };
1658
+ var f = outr - inr;
1659
+
1660
+ p.xform[0] = 1.0;
1661
+ p.xform[1] = 0.0;
1662
+ p.xform[2] = 0.0;
1663
+ p.xform[3] = 1.0;
1664
+
1665
+ p.xform[4] = cx;
1666
+ p.xform[5] = cy;
1667
+
1668
+ p.extent[0] = p.radius;
1669
+ p.extent[1] = p.radius;
1670
+
1671
+ p.feather = Math.max(1.0, f);
1672
+
1673
+ return p;
1674
+ }
1675
+
1676
+ nvgBoxGradient(x, y, w, h, r, f, icol, ocol) {
1677
+ var p = {
1678
+ xform: new Array(6),
1679
+ extent: new Array(2),
1680
+ radius: r,
1681
+ feather: 0.0,
1682
+ innerColor: icol,
1683
+ outerColor: ocol
1684
+ };
1685
+
1686
+ p.xform[0] = 1.0;
1687
+ p.xform[1] = 0.0;
1688
+ p.xform[2] = 0.0;
1689
+ p.xform[3] = 1.0;
1690
+ p.xform[4] = x + w * 0.5;
1691
+ p.xform[5] = y + h * 0.5;
1692
+
1693
+ p.extent[0] = w * 0.5;
1694
+ p.extent[1] = h * 0.5;
1695
+
1696
+ p.feather = Math.max(1.0, f);
1697
+
1698
+ return p;
1699
+ }
1700
+
1701
+ nvgImagePattern(cx, cy, w, h, angle, image, alpha) {
1702
+ const p = new NVGpaint();
1703
+ nvgTransformRotate(p.xform, angle);
1704
+ p.xform[4] = cx;
1705
+ p.xform[5] = cy;
1706
+
1707
+ p.extent[0] = w;
1708
+ p.extent[1] = h;
1709
+ p.image = image;
1710
+ p.innerColor = NVGcolor.nvgRGBAf(1.0, 1.0, 1.0, alpha);
1711
+ p.outerColor = NVGcolor.nvgRGBAf(1.0, 1.0, 1.0, alpha);
1712
+
1713
+ return p;
1714
+ }
1715
+
1716
+ nvgScissor(x, y, w, h) {
1717
+ const state = nvg__getState(this);
1718
+
1719
+ w = Math.max(0.0, w);
1720
+ h = Math.max(0.0, h);
1721
+
1722
+ nvgTransformIdentity(state.scissor.xform);
1723
+ state.scissor.xform[4] = x + w * 0.5;
1724
+ state.scissor.xform[5] = y + h * 0.5;
1725
+ nvgTransformMultiply(state.scissor.xform, state.xform);
1726
+
1727
+ state.scissor.extent[0] = w * 0.5;
1728
+ state.scissor.extent[1] = h * 0.5;
1729
+ }
1730
+
1731
+ nvgIntersectScissor(x, y, w, h) {
1732
+ const state = nvg__getState(this);
1733
+ let pxform = new Array(6);
1734
+ let invxorm = new Array(6);
1735
+ let rect = new Array(4);
1736
+ let ex, ey, tex, tey;
1737
+
1738
+ if (state.scissor.extent[0] < 0) {
1739
+ this.nvgScissor(x, y, w, h);
1740
+ return;
1741
+ }
1742
+
1743
+ pxform = state.scissor.xform.slice();
1744
+ ex = state.scissor.extent[0];
1745
+ ey = state.scissor.extent[1];
1746
+ nvgTransformInverse(invxorm, state.xform);
1747
+ nvgTransformMultiply(pxform, invxorm);
1748
+ tex = ex * Math.abs(pxform[0]) + ey * Math.abs(pxform[2]);
1749
+ tey = ex * Math.abs(pxform[1]) + ey * Math.abs(pxform[3]);
1750
+
1751
+ nvg__isectRects(rect, pxform[4] - tex, pxform[5] - tey, tex * 2, tey * 2, x, y, w, h);
1752
+
1753
+ this.nvgScissor(rect[0], rect[1], rect[2], rect[3]);
1754
+ }
1755
+
1756
+ nvgResetScissor() {
1757
+ const state = nvg__getState(this);
1758
+ state.scissor.xform.fill(0);
1759
+ state.scissor.extent[0] = -1.0;
1760
+ state.scissor.extent[1] = -1.0;
1761
+ }
1762
+
1763
+ nvgGlobalCompositeOperation(op)
1764
+ {
1765
+ const state = nvg__getState(this);
1766
+ state.compositeOperation = nvg__compositeOperationState(op);
1767
+ }
1768
+
1769
+ nvgGlobalCompositeBlendFunc(sfactor, dfactor)
1770
+ {
1771
+ this.nvgGlobalCompositeBlendFuncSeparate(sfactor, dfactor, sfactor, dfactor);
1772
+ }
1773
+
1774
+ nvgGlobalCompositeBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha)
1775
+ {
1776
+ const op = new NVGcompositeOperationState(srcRGB, dstRGB, srcAlpha, dstAlpha);
1777
+ op.srcRGB = srcRGB;
1778
+ op.dstRGB = dstRGB;
1779
+ op.srcAlpha = srcAlpha;
1780
+ op.dstAlpha = dstAlpha;
1781
+
1782
+ const state = nvg__getState(this);
1783
+ state.compositeOperation = op;
1784
+ }
1785
+
1786
+ nvgSkewY(angle)
1787
+ {
1788
+ const state = nvg__getState(this);
1789
+ let t = [];
1790
+ nvgTransformSkewY(t, angle);
1791
+ nvgTransformPremultiply(state.xform, t);
1792
+ }
1793
+
1794
+ nvgScale(x, y)
1795
+ {
1796
+ const state = nvg__getState(this);
1797
+ let t = [];
1798
+ nvgTransformScale(t, x,y);
1799
+ nvgTransformPremultiply(state.xform, t);
1800
+ }
1801
+
1802
+ nvgCurrentTransform(xform) {
1803
+ const state = nvg__getState(this);
1804
+ if (xform == null) return;
1805
+ xform.set(state.xform);
1806
+ }
1807
+
1808
+ nvgStrokeColor(color) {
1809
+ const state = nvg__getState(this);
1810
+ nvg__setPaintColor(state.stroke, color);
1811
+ }
1812
+
1813
+ nvgStrokePaint(paint) {
1814
+ const state = nvg__getState(this);
1815
+ state.stroke = paint;
1816
+ nvgTransformMultiply(state.stroke.xform, state.xform);
1817
+ }
1818
+
1819
+ nvgFillColor(color) {
1820
+ const state = nvg__getState(this);
1821
+ nvg__setPaintColor(state.fill, color);
1822
+ }
1823
+
1824
+ nvgFillPaint(paint) {
1825
+ const state = nvg__getState(this);
1826
+ state.fill = paint;
1827
+ nvgTransformMultiply(state.fill.xform, state.xform);
1828
+ }
1829
+
1830
+ }
1831
+
1832
+ // TODO:
1833
+
1834
+ function nvg__getState(ctx) {
1835
+ return ctx.states[ctx.nstates - 1];
1836
+ }
1837
+
1838
+ function nvg__cloneColor(color) {
1839
+ const clone = new NVGcolor();
1840
+ clone.rgba.set(color.rgba);
1841
+ return clone;
1842
+ }
1843
+
1844
+ function nvg__clonePaint(paint) {
1845
+ const clone = new NVGpaint();
1846
+ clone.image = paint.image;
1847
+ clone.xform.set(paint.xform);
1848
+ clone.extent.set(paint.extent);
1849
+ clone.radius = paint.radius;
1850
+ clone.feather = paint.feather;
1851
+ clone.innerColor = nvg__cloneColor(paint.innerColor);
1852
+ clone.outerColor = nvg__cloneColor(paint.outerColor);
1853
+ return clone;
1854
+ }
1855
+
1856
+ function nvg__cloneScissor(scissor) {
1857
+ const clone = new NVGscissor();
1858
+ clone.xform = scissor.xform.slice();
1859
+ clone.extent = scissor.extent.slice();
1860
+ clone.enabled = scissor.enabled;
1861
+ return clone;
1862
+ }
1863
+
1864
+ function nvg__cloneCompositeOperation(op) {
1865
+ return new NVGcompositeOperationState(op.srcRGB, op.dstRGB, op.srcAlpha, op.dstAlpha);
1866
+ }
1867
+
1868
+ function nvg__cloneState(state) {
1869
+ const clone = new NVGstate();
1870
+ clone.compositeOperation = nvg__cloneCompositeOperation(state.compositeOperation);
1871
+ clone.shapeAntiAlias = state.shapeAntiAlias;
1872
+ clone.fill = nvg__clonePaint(state.fill);
1873
+ clone.stroke = nvg__clonePaint(state.stroke);
1874
+ clone.strokeWidth = state.strokeWidth;
1875
+ clone.miterLimit = state.miterLimit;
1876
+ clone.lineJoin = state.lineJoin;
1877
+ clone.lineCap = state.lineCap;
1878
+ clone.alpha = state.alpha;
1879
+ clone.xform = state.xform.slice();
1880
+ clone.scissor = nvg__cloneScissor(state.scissor);
1881
+ clone.fontSize = state.fontSize;
1882
+ clone.letterSpacing = state.letterSpacing;
1883
+ clone.lineHeight = state.lineHeight;
1884
+ clone.fontBlur = state.fontBlur;
1885
+ clone.textAlign = state.textAlign;
1886
+ clone.fontId = state.fontId;
1887
+ return clone;
1888
+ }
1889
+
1890
+ function nvgCreateInternal(params) {
1891
+ const fontParams = {};
1892
+ let ctx = new NVGcontext();
1893
+ ctx.params = params;
1894
+ ctx.fontImages = [];
1895
+ ctx.commands = new Float32Array(NVG_INIT_COMMANDS_SIZE);
1896
+ ctx.ncommands = 0;
1897
+ ctx.ccommands = NVG_INIT_COMMANDS_SIZE;
1898
+ ctx.cache = null;
1899
+ ctx.fs = null;
1900
+ ctx.fontImageIdx = 0;
1901
+
1902
+ if (ctx.params == null) return null;
1903
+
1904
+ for (let i = 0; i < NVG_MAX_FONTIMAGES; i++) {
1905
+ ctx.fontImages[i] = 0;
1906
+ }
1907
+
1908
+ ctx.cache = nvg__allocPathCache();
1909
+ if (ctx.cache == null) return null;
1910
+
1911
+ ctx.nvgSave();
1912
+ ctx.nvgReset();
1913
+
1914
+ nvg__setDevicePixelRatio(ctx, 1.0);
1915
+
1916
+ if (ctx.params.renderCreate(ctx.params.userPtr) === 0) return null;
1917
+
1918
+ Object.assign(fontParams, {
1919
+ width: NVG_INIT_FONTIMAGE_SIZE,
1920
+ height: NVG_INIT_FONTIMAGE_SIZE,
1921
+ flags: FONS_ZERO_TOPLEFT,
1922
+ renderCreate: null,
1923
+ renderUpdate: null,
1924
+ renderDraw: null,
1925
+ renderDelete: null,
1926
+ userPtr: null
1927
+ });
1928
+ ctx.fs = new FONScontext(fontParams);
1929
+ if (ctx.fs == null) return null;
1930
+
1931
+ ctx.fontImages[0] = ctx.params.renderCreateTexture(ctx.params.userPtr, NVG_TEXTURE_ALPHA, fontParams.width, fontParams.height, 0, null);
1932
+ if (ctx.fontImages[0] === 0) return null;
1933
+ ctx.fontImageIdx = 0;
1934
+
1935
+ return ctx;
1936
+ }
1937
+
1938
+ function nvgInternalParams(ctx) {
1939
+ return ctx.params;
1940
+ }
1941
+
1942
+ function nvgDeleteInternal(ctx) {
1943
+ if (ctx == null) return;
1944
+
1945
+ if (ctx.commands != null) {
1946
+ ctx.commands = null;
1947
+ }
1948
+
1949
+ if (ctx.cache != null) {
1950
+ nvg__deletePathCache(ctx.cache);
1951
+ }
1952
+
1953
+ if (ctx.fs != null) {
1954
+ fonsDeleteInternal(ctx.fs);
1955
+ }
1956
+
1957
+ for (let i = 0; i < NVG_MAX_FONTIMAGES; i++) {
1958
+ if (ctx.fontImages[i] != 0) {
1959
+ ctx.nvgDeleteImage(ctx.fontImages[i]);
1960
+ ctx.fontImages[i] = 0;
1961
+ }
1962
+ }
1963
+
1964
+ if (ctx.params.renderDelete != null) {
1965
+ ctx.params.renderDelete(ctx.params.userPtr);
1966
+ }
1967
+
1968
+ ctx = null;
1969
+ }
1970
+
1971
+ function nvg__setDevicePixelRatio(ctx, ratio)
1972
+ {
1973
+ ratio = Number(ratio.toFixed(2));
1974
+ ctx.tessTol = 0.25 / ratio;
1975
+ ctx.distTol = 0.01 / ratio;
1976
+ ctx.fringeWidth = 1.0 / ratio;
1977
+ ctx.devicePxRatio = ratio;
1978
+ }
1979
+
1980
+ function nvgRGB(r, g, b) { return NVGcolor.nvgRGB(r, g, b); }
1981
+ function nvgRGBf(r, g, b) { return NVGcolor.nvgRGBf(r, g, b); }
1982
+ function nvgRGBA(r, g, b, a) { return NVGcolor.nvgRGBA(r, g, b, a); }
1983
+ function nvgRGBAf(r, g, b, a) { return NVGcolor.nvgRGBAf(r, g, b, a); }
1984
+ function nvgTransRGBA(c, a) { return NVGcolor.nvgTransRGBA(c, a); }
1985
+ function nvgTransRGBAf(c, a) { return NVGcolor.nvgTransRGBAf(c, a); }
1986
+ function nvgLerpRGBA(c0, c1, u) { return NVGcolor.nvgLerpRGBA(c0, c1, u); }
1987
+ function nvgHSL(h, s, l) { return NVGcolor.nvgHSL(h, s, l); }
1988
+ function nvgHSLA(h, s, l, a) { return NVGcolor.nvgHSLA(h, s, l, a); }
1989
+
1990
+ function nvg__compositeOperationState(op) {
1991
+ let sfactor, dfactor;
1992
+
1993
+ switch(op)
1994
+ {
1995
+ case NVG_SOURCE_OVER:{
1996
+ sfactor = NVG_ONE;
1997
+ dfactor = NVG_ONE_MINUS_SRC_ALPHA;
1998
+ break;
1999
+ }
2000
+ case NVG_SOURCE_IN: {
2001
+ sfactor = NVG_DST_ALPHA;
2002
+ dfactor = NVG_ZERO;
2003
+ break;
2004
+ }
2005
+ case NVG_SOURCE_OUT: {
2006
+ sfactor = NVG_ONE_MINUS_DST_ALPHA;
2007
+ dfactor = NVG_ZERO;
2008
+ break;
2009
+ }
2010
+ case NVG_ATOP: {
2011
+ sfactor = NVG_DST_ALPHA;
2012
+ dfactor = NVG_ONE_MINUS_SRC_ALPHA;
2013
+ break;
2014
+ }
2015
+ case NVG_DESTINATION_OVER: {
2016
+ sfactor = NVG_ONE_MINUS_DST_ALPHA;
2017
+ dfactor = NVG_ONE;
2018
+ break;
2019
+ }
2020
+ case NVG_DESTINATION_IN: {
2021
+ sfactor = NVG_ZERO;
2022
+ dfactor = NVG_SRC_ALPHA;
2023
+ break;
2024
+ }
2025
+ case NVG_DESTINATION_OUT: {
2026
+ sfactor = NVG_ZERO;
2027
+ dfactor = NVG_ONE_MINUS_SRC_ALPHA;
2028
+ break;
2029
+ }
2030
+ case NVG_DESTINATION_ATOP: {
2031
+ sfactor = NVG_ONE_MINUS_DST_ALPHA;
2032
+ dfactor = NVG_SRC_ALPHA;
2033
+ break;
2034
+ }
2035
+ case NVG_LIGHTER: {
2036
+ sfactor = NVG_ONE;
2037
+ dfactor = NVG_ONE;
2038
+ break;
2039
+ }
2040
+ case NVG_COPY: {
2041
+ sfactor = NVG_ONE;
2042
+ dfactor = NVG_ZERO;
2043
+ break;
2044
+ }
2045
+ case NVG_XOR: {
2046
+ sfactor = NVG_ONE_MINUS_DST_ALPHA;
2047
+ dfactor = NVG_ONE_MINUS_SRC_ALPHA;
2048
+ break;
2049
+ }
2050
+ default: {
2051
+ sfactor = NVG_ONE;
2052
+ dfactor = NVG_ZERO;
2053
+ break;
2054
+ }
2055
+ }
2056
+
2057
+ const state = new NVGcompositeOperationState(sfactor, dfactor, sfactor, dfactor);
2058
+ return state;
2059
+ }
2060
+
2061
+ function nvg__hue(h, m1, m2)
2062
+ {
2063
+ if (h < 0) h += 1;
2064
+ if (h > 1) h -= 1;
2065
+ if (h < 1.0/6.0)
2066
+ return m1 + (m2 - m1) * h * 6.0;
2067
+ else if (h < 3.0/6.0)
2068
+ return m2;
2069
+ else if (h < 4.0/6.0)
2070
+ return m1 + (m2 - m1) * (2.0/3.0 - h) * 6.0;
2071
+ return m1;
2072
+ }
2073
+
2074
+ function fmodf(a, b) {
2075
+ return ((a % b) + b) % b;
2076
+ }
2077
+
2078
+ function nvg__modf(a, b) {
2079
+ return fmodf(a, b);
2080
+ }
2081
+
2082
+ function nvg__clampf(a, mn, mx) {
2083
+ return a < mn ? mn : (a > mx ? mx : a);
2084
+ }
2085
+
2086
+ function nvg__sqrtf(a) { return Math.sqrt(a); }
2087
+ function nvg__sinf(a) { return Math.sin(a); }
2088
+ function nvg__cosf(a) { return Math.cos(a); }
2089
+ function nvg__tanf(a) { return Math.tan(a); }
2090
+ function nvg__atan2f(a, b) { return Math.atan2(a, b); }
2091
+ function nvg__acosf(a) { return Math.acos(a); }
2092
+ function nvg__mini(a, b) { return a < b ? a : b; }
2093
+ function nvg__maxi(a, b) { return a > b ? a : b; }
2094
+ function nvg__clampi(a, mn, mx) { return a < mn ? mn : (a > mx ? mx : a); }
2095
+ function nvg__absf(a) { return a >= 0.0 ? a : -a; }
2096
+ function nvg__signf(a) { return a >= 0.0 ? 1.0 : -1.0; }
2097
+ function nvg__cross(dx0, dy0, dx1, dy1) { return dx1 * dy0 - dx0 * dy1; }
2098
+
2099
+ function nvg__isectRects(dst, ax, ay, aw, ah, bx, by, bw, bh) {
2100
+ let minx = Math.max(ax, bx);
2101
+ let miny = Math.max(ay, by);
2102
+ let maxx = Math.min(ax + aw, bx + bw);
2103
+ let maxy = Math.min(ay + ah, by + bh);
2104
+ dst[0] = minx;
2105
+ dst[1] = miny;
2106
+ dst[2] = Math.max(0.0, maxx - minx);
2107
+ dst[3] = Math.max(0.0, maxy - miny);
2108
+ }
2109
+
2110
+ function nvgTransformInverse(inv, t) {
2111
+ let invdet, det = t[0] * t[3] - t[2] * t[1];
2112
+ if (det > -1e-6 && det < 1e-6) {
2113
+ nvgTransformIdentity(inv);
2114
+ return 0;
2115
+ }
2116
+ invdet = 1.0 / det;
2117
+ inv[0] = t[3] * invdet;
2118
+ inv[2] = -t[2] * invdet;
2119
+ inv[4] = (t[2] * t[5] - t[3] * t[4]) * invdet;
2120
+ inv[1] = -t[1] * invdet;
2121
+ inv[3] = t[0] * invdet;
2122
+ inv[5] = (t[1] * t[4] - t[0] * t[5]) * invdet;
2123
+ return 1;
2124
+ }
2125
+
2126
+ function nvgTransformIdentity(t) {
2127
+ t[0] = 1.0; t[1] = 0.0;
2128
+ t[2] = 0.0; t[3] = 1.0;
2129
+ t[4] = 0.0; t[5] = 0.0;
2130
+ }
2131
+
2132
+ function nvgTransformTranslate(t, tx, ty) {
2133
+ t[0] = 1.0; t[1] = 0.0;
2134
+ t[2] = 0.0; t[3] = 1.0;
2135
+ t[4] = tx; t[5] = ty;
2136
+ }
2137
+
2138
+ function nvgTransformScale(t, sx, sy) {
2139
+ t[0] = sx; t[1] = 0.0;
2140
+ t[2] = 0.0; t[3] = sy;
2141
+ t[4] = 0.0; t[5] = 0.0;
2142
+ }
2143
+
2144
+ function nvgTransformRotate(t, a) {
2145
+ var cs = Math.cos(a), sn = Math.sin(a);
2146
+ t[0] = cs; t[1] = sn;
2147
+ t[2] = -sn; t[3] = cs;
2148
+ t[4] = 0.0; t[5] = 0.0;
2149
+ }
2150
+
2151
+ function nvgTransformSkewX(t, a) {
2152
+ t[0] = 1.0; t[1] = 0.0;
2153
+ t[2] = Math.tan(a); t[3] = 1.0;
2154
+ t[4] = 0.0; t[5] = 0.0;
2155
+ }
2156
+
2157
+ function nvgTransformSkewY(t, a) {
2158
+ t[0] = 1.0; t[1] = Math.tan(a);
2159
+ t[2] = 0.0; t[3] = 1.0;
2160
+ t[4] = 0.0; t[5] = 0.0;
2161
+ }
2162
+
2163
+ function nvgTransformMultiply(t, s) {
2164
+ var t0 = t[0] * s[0] + t[1] * s[2];
2165
+ var t2 = t[2] * s[0] + t[3] * s[2];
2166
+ var t4 = t[4] * s[0] + t[5] * s[2] + s[4];
2167
+ t[1] = t[0] * s[1] + t[1] * s[3];
2168
+ t[3] = t[2] * s[1] + t[3] * s[3];
2169
+ t[5] = t[4] * s[1] + t[5] * s[3] + s[5];
2170
+ t[0] = t0;
2171
+ t[2] = t2;
2172
+ t[4] = t4;
2173
+ }
2174
+
2175
+ function nvgTransformPremultiply(t, s) {
2176
+ const s2 = s.slice(0);
2177
+ nvgTransformMultiply(s2, t);
2178
+ if (typeof t.set === "function")
2179
+ t.set(s2);
2180
+ else
2181
+ for (let i = 0; i < 6; i++) t[i] = s2[i];
2182
+ }
2183
+
2184
+ function nvg__setPaintColor(p, color) {
2185
+ p.xform = new Array(6).fill(0);
2186
+ p.extent = new Array(2).fill(0);
2187
+ p.radius = 0.0;
2188
+ p.feather = 0.0;
2189
+ p.innerColor = new NVGcolor();
2190
+ p.outerColor = new NVGcolor();
2191
+ p.image = 0;
2192
+ nvgTransformIdentity(p.xform);
2193
+ p.feather = 1.0;
2194
+ p.innerColor = color;
2195
+ p.outerColor = color;
2196
+ }
2197
+
2198
+ function nvg__appendCommands(ctx, vals, nvals) {
2199
+ const state = nvg__getState(ctx);
2200
+ let i;
2201
+
2202
+ if (ctx.ncommands + nvals > ctx.ccommands) {
2203
+ let commands;
2204
+ let ccommands = ctx.ncommands + nvals + Math.floor(ctx.ccommands / 2);
2205
+ commands = new Float32Array(ccommands);
2206
+ commands.set(ctx.commands);
2207
+ ctx.commands = commands;
2208
+ ctx.ccommands = ccommands;
2209
+ }
2210
+
2211
+ if (vals[0] !== NVG_CLOSE && vals[0] !== NVG_WINDING) {
2212
+ ctx.commandx = vals[nvals - 2];
2213
+ ctx.commandy = vals[nvals - 1];
2214
+ }
2215
+
2216
+ i = 0;
2217
+ while (i < nvals) {
2218
+ let cmd = vals[i];
2219
+ switch (cmd) {
2220
+ case NVG_MOVETO:{
2221
+ [vals[i + 1], vals[i + 2]] = nvgTransformPoint(state.xform, vals[i + 1], vals[i + 2]);
2222
+ i += 3;
2223
+ break;
2224
+ }
2225
+ case NVG_LINETO:
2226
+ [vals[i + 1], vals[i + 2]] = nvgTransformPoint(state.xform, vals[i + 1], vals[i + 2]);
2227
+ i += 3;
2228
+ break;
2229
+ case NVG_BEZIERTO:
2230
+ [vals[i + 1], vals[i + 2]] = nvgTransformPoint(state.xform, vals[i + 1], vals[i + 2]);
2231
+ [vals[i + 3], vals[i + 4]] = nvgTransformPoint(state.xform, vals[i + 3], vals[i + 4]);
2232
+ [vals[i + 5], vals[i + 6]] = nvgTransformPoint(state.xform, vals[i + 5], vals[i + 6]);
2233
+ i += 7;
2234
+ break;
2235
+ case NVG_CLOSE:
2236
+ i++;
2237
+ break;
2238
+ case NVG_WINDING:
2239
+ i += 2;
2240
+ break;
2241
+ default:
2242
+ i++;
2243
+ break;
2244
+ }
2245
+ }
2246
+
2247
+
2248
+ //ctx.commands.set(ctx.commands[ctx.ncommands], ctx.ncommands);
2249
+ ctx.commands.set(vals, ctx.ncommands);
2250
+ ctx.ncommands += nvals;
2251
+ }
2252
+
2253
+ function nvgTransformPoint(t, sx, sy) {
2254
+ return [
2255
+ sx * t[0] + sy * t[2] + t[4],
2256
+ sx * t[1] + sy * t[3] + t[5],
2257
+ ];
2258
+ }
2259
+
2260
+ function nvgDegToRad(deg) {
2261
+ return (deg / 180.0) * Math.PI;
2262
+ }
2263
+
2264
+ function nvgRadToDeg(rad) {
2265
+ return (rad / Math.PI) * 180.0;
2266
+ }
2267
+
2268
+ function NVG_COUNTOF(arr) {
2269
+ return arr.length;
2270
+ }
2271
+
2272
+ function nvg__ptEquals(x1, y1, x2, y2, tol)
2273
+ {
2274
+ let dx = x2 - x1;
2275
+ let dy = y2 - y1;
2276
+ return dx*dx + dy*dy < tol*tol;
2277
+ }
2278
+
2279
+ function nvg__triarea2(ax, ay, bx, by, cx, cy)
2280
+ {
2281
+ let abx = bx - ax;
2282
+ let aby = by - ay;
2283
+ let acx = cx - ax;
2284
+ let acy = cy - ay;
2285
+ return acx*aby - abx*acy;
2286
+ }
2287
+
2288
+ function nvg__polyArea(pts, npts) {
2289
+ var i;
2290
+ var area = 0;
2291
+ for (i = 2; i < npts; i++) {
2292
+ var a = pts[0];
2293
+ var b = pts[i - 1];
2294
+ var c = pts[i];
2295
+ area += nvg__triarea2(a.x, a.y, b.x, b.y, c.x, c.y);
2296
+ }
2297
+ return area * 0.5;
2298
+ }
2299
+
2300
+ function nvg__polyReverse(pts, npts) {
2301
+ var tmp;
2302
+ var i = 0, j = npts - 1;
2303
+ while (i < j) {
2304
+ tmp = pts[i];
2305
+ pts[i] = pts[j];
2306
+ pts[j] = tmp;
2307
+ i++;
2308
+ j--;
2309
+ }
2310
+ }
2311
+
2312
+ function nvg__polyReverseRange(points, first, npts) {
2313
+ let i = 0;
2314
+ let j = npts - 1;
2315
+ while (i < j) {
2316
+ const a = first + i;
2317
+ const b = first + j;
2318
+ const tmp = points[a];
2319
+ points[a] = points[b];
2320
+ points[b] = tmp;
2321
+ i++;
2322
+ j--;
2323
+ }
2324
+ }
2325
+
2326
+
2327
+ function nvg__distPtSeg(x, y, px, py, qx, qy)
2328
+ {
2329
+ let pqx, pqy, dx, dy, d, t;
2330
+ pqx = qx-px;
2331
+ pqy = qy-py;
2332
+ dx = x-px;
2333
+ dy = y-py;
2334
+ d = pqx*pqx + pqy*pqy;
2335
+ t = pqx*dx + pqy*dy;
2336
+ if (d > 0) t /= d;
2337
+ if (t < 0) t = 0;
2338
+ else if (t > 1) t = 1;
2339
+ dx = px + t*pqx - x;
2340
+ dy = py + t*pqy - y;
2341
+ return dx*dx + dy*dy;
2342
+ }
2343
+
2344
+ function nvg__normalize(x, y)
2345
+ {
2346
+ const d = Math.sqrt(x * x + y * y);
2347
+ if (d > 1e-6) {
2348
+ const id = 1.0 / d;
2349
+ x *= id;
2350
+ y *= id;
2351
+ }
2352
+ return d;
2353
+ }
2354
+
2355
+ function nvg__normalizeXY(x, y) {
2356
+ const d = nvg__sqrtf(x * x + y * y);
2357
+ if (d > 1e-6) {
2358
+ const id = 1.0 / d;
2359
+ x *= id;
2360
+ y *= id;
2361
+ }
2362
+ return [x, y, d];
2363
+ }
2364
+
2365
+ function nvg__normalize_(pt)
2366
+ {
2367
+ const d = Math.sqrt(pt.dx * pt.dx + pt.dy * pt.dy);
2368
+ if (d > 1e-6) {
2369
+ const id = 1.0 / d;
2370
+ pt.dx *= id;
2371
+ pt.dy *= id;
2372
+ }
2373
+ return d;
2374
+ }
2375
+
2376
+ function nvg__deletePathCache(c)
2377
+ {
2378
+ if (c == null) return;
2379
+ if (c != null) c = null;
2380
+ }
2381
+
2382
+ function nvg__allocPathCache()
2383
+ {
2384
+ let c = new NVGpathCache();
2385
+ if (c == null) goto_path_cache_error();
2386
+
2387
+ c.points = new Array(NVG_INIT_POINTS_SIZE);
2388
+ if (!c.points) goto_path_cache_error();
2389
+ c.npoints = 0;
2390
+ c.cpoints = NVG_INIT_POINTS_SIZE;
2391
+
2392
+ c.paths = new Array(NVG_INIT_PATHS_SIZE);
2393
+ if (!c.paths) goto_path_cache_error();
2394
+ c.npaths = 0;
2395
+ c.cpaths = NVG_INIT_PATHS_SIZE;
2396
+
2397
+ c.verts = new ArrayBuffer(NVG_INIT_VERTS_SIZE);
2398
+ if (!c.verts) goto_path_cache_error();
2399
+ c.nverts = 0;
2400
+ c.cverts = NVG_INIT_VERTS_SIZE;
2401
+
2402
+ return c;
2403
+ }
2404
+
2405
+ function goto_path_cache_error()
2406
+ {
2407
+ nvg__deletePathCache(c);
2408
+ return null;
2409
+ }
2410
+
2411
+ function nvg__minf(a, b) { return a < b ? a : b; }
2412
+ function nvg__maxf(a, b) { return a > b ? a : b; }
2413
+
2414
+ function nvg__flattenPaths(ctx) {
2415
+ let cache = ctx.cache;
2416
+ let last;
2417
+ let p0;
2418
+ let p1;
2419
+ let pts;
2420
+ let path;
2421
+ let i, j;
2422
+ let cp1;
2423
+ let cp2;
2424
+ let p;
2425
+ let area;
2426
+
2427
+ if (cache.npaths > 0)
2428
+ return;
2429
+
2430
+ i = 0;
2431
+ while (i < ctx.ncommands) {
2432
+ let cmd = ctx.commands[i];
2433
+ switch (cmd) {
2434
+ case NVG_MOVETO:
2435
+ nvg__addPath(ctx);
2436
+ p = ctx.commands.slice(i + 1, i + 3);
2437
+ nvg__addPoint(ctx, p[0], p[1], NVG_PT_CORNER);
2438
+ i += 3;
2439
+ break;
2440
+ case NVG_LINETO:
2441
+ p = ctx.commands.slice(i + 1, i + 3);
2442
+ nvg__addPoint(ctx, p[0], p[1], NVG_PT_CORNER);
2443
+ i += 3;
2444
+ break;
2445
+ case NVG_BEZIERTO:
2446
+ last = nvg__lastPoint(ctx);
2447
+ if (last != null) {
2448
+ cp1 = ctx.commands.slice(i + 1, i + 3);
2449
+ cp2 = ctx.commands.slice(i + 3, i + 5);
2450
+ p = ctx.commands.slice(i + 5, i + 7);
2451
+ nvg__tesselateBezier(
2452
+ ctx,
2453
+ last.x,
2454
+ last.y,
2455
+ cp1[0],
2456
+ cp1[1],
2457
+ cp2[0],
2458
+ cp2[1],
2459
+ p[0],
2460
+ p[1],
2461
+ 0,
2462
+ NVG_PT_CORNER
2463
+ );
2464
+ }
2465
+ i += 7;
2466
+ break;
2467
+ case NVG_CLOSE:
2468
+ nvg__closePath(ctx);
2469
+ i++;
2470
+ break;
2471
+ case NVG_WINDING:
2472
+ nvg__pathWinding(ctx, ctx.commands[i + 1]);
2473
+ i += 2;
2474
+ break;
2475
+ default:
2476
+ i++;
2477
+ break;
2478
+ }
2479
+ }
2480
+ cache.bounds[0] = cache.bounds[1] = 1e6;
2481
+ cache.bounds[2] = cache.bounds[3] = -1e6;
2482
+
2483
+ for (j = 0; j < cache.npaths; j++) {
2484
+ path = cache.paths[j];
2485
+ pts = ctx.cache.points.slice(path.first, path.first + path.count);
2486
+
2487
+ p0 = pts[path.count - 1];
2488
+ p1 = pts[0];
2489
+ if (nvg__ptEquals(p0.x, p0.y, p1.x, p1.y, ctx.distTol)) {
2490
+ path.count--;
2491
+ p0 = pts[path.count - 1];
2492
+ path.closed = 1;
2493
+ }
2494
+
2495
+ if (path.count > 2) {
2496
+ area = nvg__polyArea(pts, path.count);
2497
+ if (path.winding === NVG_CCW && area < 0.0) {
2498
+ nvg__polyReverseRange(ctx.cache.points, path.first, path.count);
2499
+ pts = ctx.cache.points.slice(path.first, path.first + path.count);
2500
+ }
2501
+ if (path.winding === NVG_CW && area > 0.0) {
2502
+ nvg__polyReverseRange(ctx.cache.points, path.first, path.count);
2503
+ pts = ctx.cache.points.slice(path.first, path.first + path.count);
2504
+ }
2505
+ }
2506
+
2507
+ p0 = pts[path.count - 1];
2508
+ p1 = pts[0];
2509
+
2510
+ for (i = 0; i < path.count; i++) {
2511
+ p0.dx = p1.x - p0.x;
2512
+ p0.dy = p1.y - p0.y;
2513
+ p0.len = nvg__normalize_(p0);
2514
+ cache.bounds[0] = nvg__minf(cache.bounds[0], p0.x);
2515
+ cache.bounds[1] = nvg__minf(cache.bounds[1], p0.y);
2516
+ cache.bounds[2] = nvg__maxf(cache.bounds[2], p0.x);
2517
+ cache.bounds[3] = nvg__maxf(cache.bounds[3], p0.y);
2518
+ p0 = p1;
2519
+ p1 = pts[i + 1];
2520
+ }
2521
+ }
2522
+ }
2523
+
2524
+ /*function nvg__addPath(ctx) {
2525
+ console.log(`nvg__addPath()`)
2526
+ let path = new NVGpath();
2527
+ if (ctx.cache.npaths + 1 > ctx.cache.cpaths) {
2528
+ const cpaths = ctx.cache.npaths + 1 + Math.floor(ctx.cache.cpaths / 2);
2529
+ const paths = new Array(cpaths);
2530
+ for (let i = 0; i < ctx.cache.paths.length; i++) {
2531
+ paths[i] = ctx.cache.paths[i];
2532
+ }
2533
+ ctx.cache.paths = paths;
2534
+ ctx.cache.cpaths = cpaths;
2535
+ }
2536
+ //path = ctx.cache.paths[ctx.cache.npaths];
2537
+ console.log(path)
2538
+ path.first = ctx.cache.npoints;
2539
+ path.winding = NVG_CCW;
2540
+ ctx.cache.npaths++;
2541
+ ctx.cache.paths.push(path);
2542
+ console.log("ctx.cache.npaths: "+ctx.cache.npaths)
2543
+ }*/
2544
+
2545
+ function nvg__addPath(ctx) {
2546
+ const cache = ctx.cache;
2547
+ if (cache.npaths + 1 > cache.cpaths) {
2548
+ const cpaths = cache.npaths + 1 + Math.floor(cache.cpaths / 2);
2549
+ const paths = new Array(cpaths);
2550
+ paths.set(cache.paths);
2551
+ cache.paths = paths;
2552
+ cache.cpaths = cpaths;
2553
+ }
2554
+ const path = new NVGpath();
2555
+ //const path = cache.paths[cache.npaths];
2556
+ path.first = cache.npoints;
2557
+ path.winding = NVG_CCW;
2558
+ cache.npaths = cache.npaths + 1;
2559
+ cache.paths[cache.npaths-1] = path;
2560
+ }
2561
+
2562
+
2563
+ function nvg__lastPoint(ctx) {
2564
+ if (ctx.cache.npoints > 0) {
2565
+ return ctx.cache.points[ctx.cache.npoints - 1];
2566
+ }
2567
+ return null;
2568
+ }
2569
+
2570
+ function nvg__addPoint(ctx, x, y, flags) {
2571
+ const path = nvg__lastPath(ctx);
2572
+ let pt = new NVGpoint();
2573
+ if (path == null) return;
2574
+
2575
+ if (path.count > 0 && ctx.cache.npoints > 0) {
2576
+ pt = nvg__lastPoint(ctx);
2577
+ if (nvg__ptEquals(pt.x, pt.y, x, y, ctx.distTol)) {
2578
+ pt.flags |= flags;
2579
+ return;
2580
+ }
2581
+ }
2582
+
2583
+ if (ctx.cache.npoints + 1 > ctx.cache.cpoints) {
2584
+ const cpoints = ctx.cache.npoints + 1 + Math.floor(ctx.cache.cpoints / 2);
2585
+ const points = new Array(cpoints);
2586
+ for (let i = 0; i < ctx.cache.points.length; i++) {
2587
+ points[i] = ctx.cache.points[i];
2588
+ }
2589
+ ctx.cache.points = points;
2590
+ ctx.cache.cpoints = cpoints;
2591
+ }
2592
+
2593
+ pt = new NVGpoint();
2594
+ pt.x = x;
2595
+ pt.y = y;
2596
+ pt.flags = flags;
2597
+
2598
+ ctx.cache.points[ctx.cache.npoints] = pt;
2599
+ ctx.cache.npoints++;
2600
+ path.count = path.count + 1;
2601
+ }
2602
+
2603
+ function nvg__clearPathCache(ctx)
2604
+ {
2605
+ ctx.cache.npoints = 0;
2606
+ ctx.cache.npaths = 0;
2607
+ }
2608
+
2609
+ function nvg__lastPath(ctx) {
2610
+ if (ctx.cache.npaths > 0) {
2611
+ return ctx.cache.paths[ctx.cache.npaths - 1];
2612
+ }
2613
+ return null;
2614
+ }
2615
+
2616
+ function nvg__closePath(ctx) {
2617
+ const path = nvg__lastPath(ctx);
2618
+ if (path == null) return;
2619
+ path.closed = 1;
2620
+ }
2621
+
2622
+ function nvg__tesselateBezier(ctx, x1, y1, x2, y2, x3, y3, x4, y4, level, type) {
2623
+ var x12, y12, x23, y23, x34, y34, x123, y123, x234, y234, x1234, y1234;
2624
+ var dx, dy, d2, d3;
2625
+
2626
+ if (level > 10) return;
2627
+
2628
+ x12 = (x1 + x2) * 0.5;
2629
+ y12 = (y1 + y2) * 0.5;
2630
+ x23 = (x2 + x3) * 0.5;
2631
+ y23 = (y2 + y3) * 0.5;
2632
+ x34 = (x3 + x4) * 0.5;
2633
+ y34 = (y3 + y4) * 0.5;
2634
+ x123 = (x12 + x23) * 0.5;
2635
+ y123 = (y12 + y23) * 0.5;
2636
+
2637
+ dx = x4 - x1;
2638
+ dy = y4 - y1;
2639
+ d2 = Math.abs((x2 - x4) * dy - (y2 - y4) * dx);
2640
+ d3 = Math.abs((x3 - x4) * dy - (y3 - y4) * dx);
2641
+
2642
+ if ((d2 + d3) * (d2 + d3) < ctx.tessTol * (dx * dx + dy * dy)) {
2643
+ nvg__addPoint(ctx, x4, y4, type);
2644
+ return;
2645
+ }
2646
+
2647
+ x234 = (x23 + x34) * 0.5;
2648
+ y234 = (y23 + y34) * 0.5;
2649
+ x1234 = (x123 + x234) * 0.5;
2650
+ y1234 = (y123 + y234) * 0.5;
2651
+
2652
+ nvg__tesselateBezier(ctx, x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1, 0);
2653
+ nvg__tesselateBezier(ctx, x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1, type);
2654
+ }
2655
+
2656
+ function nvg__pathWinding(ctx, winding)
2657
+ {
2658
+ const path = nvg__lastPath(ctx);
2659
+ if (path == null) return;
2660
+ path.winding = winding;
2661
+ }
2662
+
2663
+ function nvg__calculateJoins(ctx, w, lineJoin, miterLimit) {
2664
+ var cache = ctx.cache;
2665
+ var i, j;
2666
+ var iw = 0.0;
2667
+
2668
+ if (w > 0.0) {
2669
+ iw = 1.0 / w;
2670
+ }
2671
+
2672
+ for (i = 0; i < cache.npaths; i++) {
2673
+ var path = cache.paths[i];
2674
+ var pts = cache.points.slice(path.first, path.first + path.count);
2675
+ var p0 = pts[path.count - 1];
2676
+ var p1 = pts[0];
2677
+ var nleft = 0;
2678
+
2679
+ path.nbevel = 0;
2680
+
2681
+ for (j = 0; j < path.count; j++) {
2682
+ var dlx0 = p0.dy;
2683
+ var dly0 = -p0.dx;
2684
+ var dlx1 = p1.dy;
2685
+ var dly1 = -p1.dx;
2686
+ p1.dmx = (dlx0 + dlx1) * 0.5;
2687
+ p1.dmy = (dly0 + dly1) * 0.5;
2688
+ var dmr2 = p1.dmx * p1.dmx + p1.dmy * p1.dmy;
2689
+ if (dmr2 > 0.000001) {
2690
+ var scale = 1.0 / dmr2;
2691
+ if (scale > 600.0) {
2692
+ scale = 600.0;
2693
+ }
2694
+ p1.dmx *= scale;
2695
+ p1.dmy *= scale;
2696
+ }
2697
+
2698
+ p1.flags = (p1.flags & NVG_PT_CORNER) ? NVG_PT_CORNER : 0;
2699
+
2700
+ var cross = p1.dx * p0.dy - p0.dx * p1.dy;
2701
+ if (cross > 0.0) {
2702
+ nleft++;
2703
+ p1.flags |= NVG_PT_LEFT;
2704
+ }
2705
+
2706
+ var limit = nvg__maxf(1.01, nvg__minf(p0.len, p1.len) * iw);
2707
+ if (dmr2 * limit * limit < 1.0) {
2708
+ p1.flags |= NVG_PR_INNERBEVEL;
2709
+ }
2710
+
2711
+ if (p1.flags & NVG_PT_CORNER) {
2712
+ if (dmr2 * miterLimit * miterLimit < 1.0 || lineJoin == NVG_BEVEL || lineJoin == NVG_ROUND) {
2713
+ p1.flags |= NVG_PT_BEVEL;
2714
+ }
2715
+ }
2716
+
2717
+ if ((p1.flags & (NVG_PT_BEVEL | NVG_PR_INNERBEVEL)) !== 0) {
2718
+ path.nbevel++;
2719
+ }
2720
+
2721
+ p0 = p1;
2722
+ p1 = pts[j + 1];
2723
+ }
2724
+
2725
+ path.convex = (nleft === path.count) ? 1 : 0;
2726
+ }
2727
+ }
2728
+
2729
+ function nvg__expandFill(ctx, w, lineJoin, miterLimit) {
2730
+ let cache = ctx.cache;
2731
+ let aa = ctx.fringeWidth;
2732
+ let fringe = w > 0.0;
2733
+
2734
+ nvg__calculateJoins(ctx, w, lineJoin, miterLimit);
2735
+
2736
+ let cverts = 0;
2737
+ for (let i = 0; i < cache.npaths; i++) {
2738
+ let path = cache.paths[i];
2739
+ cverts += path.count + path.nbevel + 1;
2740
+ if (fringe) cverts += (path.count + path.nbevel * 5 + 1) * 2;
2741
+ }
2742
+
2743
+ let verts = nvg__allocTempVerts(ctx, cverts);
2744
+ if (verts == null) return 0;
2745
+
2746
+ let convex = cache.npaths === 1 && cache.paths[0].convex;
2747
+ let dst = 0;
2748
+
2749
+ for (let i = 0; i < cache.npaths; i++) {
2750
+ let path = cache.paths[i];
2751
+ let pts = cache.points.slice(path.first, path.first + path.count);
2752
+ let woff = 0.5 * aa;
2753
+
2754
+ path.fillOffset = dst;
2755
+
2756
+ if (fringe) {
2757
+ let p0 = pts[path.count - 1];
2758
+ let p1 = pts[0];
2759
+
2760
+ for (let j = 0; j < path.count; ++j) {
2761
+ if (p1.flags & NVG_PT_BEVEL) {
2762
+ let dlx0 = p0.dy;
2763
+ let dly0 = -p0.dx;
2764
+ let dlx1 = p1.dy;
2765
+ let dly1 = -p1.dx;
2766
+
2767
+ if (p1.flags & NVG_PT_LEFT) {
2768
+ let vtx = new NVGvertex(verts, dst++);
2769
+ nvg__vset(vtx, p1.x + p1.dmx * woff, p1.y + p1.dmy * woff, 0.5, 1);
2770
+ } else {
2771
+ let vtx0 = new NVGvertex(verts, dst++);
2772
+ nvg__vset(vtx0, p1.x + dlx0 * woff, p1.y + dly0 * woff, 0.5, 1);
2773
+ let vtx1 = new NVGvertex(verts, dst++);
2774
+ nvg__vset(vtx1, p1.x + dlx1 * woff, p1.y + dly1 * woff, 0.5, 1);
2775
+ }
2776
+ } else {
2777
+ let vtx = new NVGvertex(verts, dst++);
2778
+ nvg__vset(vtx, p1.x + p1.dmx * woff, p1.y + p1.dmy * woff, 0.5, 1);
2779
+ }
2780
+ p0 = p1;
2781
+ p1 = pts[j + 1];
2782
+ }
2783
+ } else {
2784
+ for (let j = 0; j < path.count; ++j) {
2785
+ let vtx = new NVGvertex(verts, dst++);
2786
+ nvg__vset(vtx, pts[j].x, pts[j].y, 0.5, 1);
2787
+ }
2788
+ }
2789
+
2790
+ path.nfill = dst - path.fillOffset;
2791
+
2792
+ let fillStart = path.fillOffset * 4;
2793
+ let fillCount = path.nfill * 4;
2794
+ let vertsView = new Float32Array(verts, path.fillOffset * NVG_VERTEX_SIZEOF, path.nfill * 4);
2795
+ path.fill = new Float32Array(fillCount);
2796
+ path.fill.set(vertsView);
2797
+
2798
+ if (fringe) {
2799
+ path.strokeOffset = dst;
2800
+ path.nstroke = dst - path.strokeOffset;
2801
+
2802
+ let strokeView = new Float32Array(verts, path.strokeOffset * NVG_VERTEX_SIZEOF, path.nstroke * 4);
2803
+ path.stroke = new Float32Array(path.nstroke * 4);
2804
+ path.stroke.set(strokeView);
2805
+ }
2806
+ }
2807
+
2808
+ return 1;
2809
+ }
2810
+
2811
+ function nvg__getAverageScale(t)
2812
+ {
2813
+ let sx = Math.sqrt(t[0]*t[0] + t[2]*t[2]);
2814
+ let sy = Math.sqrt(t[1]*t[1] + t[3]*t[3]);
2815
+ return (sx + sy) * 0.5;
2816
+ }
2817
+
2818
+ function nvg__getFontScale(state)
2819
+ {
2820
+ return nvg__minf(nvg__quantize(nvg__getAverageScale(state.xform), 0.01), 4.0);
2821
+ }
2822
+
2823
+ function nvg__quantize(a, d)
2824
+ {
2825
+ return Math.round(a / d) * d;
2826
+ }
2827
+
2828
+ function nvg__allocTempVerts(ctx, nverts) {
2829
+ //if (nverts > ctx.cache.cverts) {
2830
+ var cverts = (nverts + 0xff) & ~0xff;
2831
+ var new_verts = new ArrayBuffer(cverts * NVG_VERTEX_SIZEOF);
2832
+ //TODO: resize due to realloc
2833
+ ctx.cache.verts = new_verts;
2834
+ ctx.cache.cverts = cverts;
2835
+ //}
2836
+
2837
+ return ctx.cache.verts;
2838
+ }
2839
+
2840
+ /*function nvg__vsetCore(ctx, verts, vtx, x, y, u, v) {
2841
+ //console.log("x: " + x + " y: " + y + " vtx: " + vtx)
2842
+ var vertexOffset = vtx * (NVG_VERTEX_SIZEOF / Float32Array.BYTES_PER_ELEMENT);
2843
+
2844
+ ctx.cache.verts[vertexOffset] = x;
2845
+ ctx.cache.verts[vertexOffset + 1] = y;
2846
+ ctx.cache.verts[vertexOffset + 2] = u;
2847
+ ctx.cache.verts[vertexOffset + 3] = v;
2848
+
2849
+ verts = ctx.cache.verts;
2850
+ //verts[vtx] = {x, y, u, v};
2851
+ }*/
2852
+
2853
+ function nvg__vsetCore(ctx, verts, vtx, x, y, u, v) {
2854
+ let vert = new NVGvertex(ctx.cache.verts, vtx);
2855
+ vert.x = x;
2856
+ vert.y = y;
2857
+ vert.u = u;
2858
+ vert.v = v;
2859
+ }
2860
+
2861
+ //function nvg__vsetCore(ctx, verts, vtx, x, y, u, v) {
2862
+ // console.log("v: " + x + " y: " + y + " vtx: " + vtx)
2863
+ // verts[vtx] = {x, y, u, v};
2864
+ // ctx.cache.verts[vtx] = verts[vtx];
2865
+ // //console.log(ctx.cache.verts)
2866
+ //}
2867
+
2868
+ // Other functions
2869
+ //function fmodf(a, b) {
2870
+ // return a % b;
2871
+ //}
2872
+
2873
+
2874
+ function nvg__expandStroke(ctx, w, fringe, lineCap, lineJoin, miterLimit) {
2875
+ let cache = ctx.cache;
2876
+ let aa = fringe; // ctx.fringeWidth
2877
+ let u0 = 0.0, u1 = 1.0;
2878
+ let ncap = nvg__curveDivs(w, Math.PI, ctx.tessTol);
2879
+
2880
+ w += aa * 0.5;
2881
+
2882
+ if (aa === 0.0) {
2883
+ u0 = 0.5;
2884
+ u1 = 0.5;
2885
+ }
2886
+
2887
+ nvg__calculateJoins(ctx, w, lineJoin, miterLimit);
2888
+
2889
+ let cverts = 0;
2890
+ for (let i = 0; i < cache.npaths; i++) {
2891
+ let path = cache.paths[i];
2892
+ let loop = path.closed ? 1 : 0;
2893
+ if (lineJoin === NVG_ROUND)
2894
+ cverts += (path.count + path.nbevel * (ncap + 2) + 1) * 2;
2895
+ else
2896
+ cverts += (path.count + path.nbevel * 5 + 1) * 2;
2897
+ if (loop === 0) {
2898
+ if (lineCap === NVG_ROUND) {
2899
+ cverts += (ncap * 2 + 2) * 2;
2900
+ } else {
2901
+ cverts += (3 + 3) * 2;
2902
+ }
2903
+ }
2904
+ }
2905
+
2906
+ let verts = nvg__allocTempVerts(ctx, cverts);
2907
+ if (verts === null) return 0;
2908
+
2909
+ let dst = 0;
2910
+ for (let i = 0; i < cache.npaths; i++) {
2911
+ let path = cache.paths[i];
2912
+ let pts = cache.points.slice(path.first, path.first + path.count);
2913
+ let p0, p1;
2914
+ let s, e, loop;
2915
+ let dx, dy;
2916
+
2917
+ path.fill = null;
2918
+ path.nfill = 0;
2919
+
2920
+ loop = path.closed ? 1 : 0;
2921
+ path.strokeOffset = dst;
2922
+
2923
+ if (loop) {
2924
+ p0 = pts[path.count - 1];
2925
+ p1 = pts[0];
2926
+ s = 0;
2927
+ e = path.count;
2928
+ } else {
2929
+ p0 = pts[0];
2930
+ p1 = pts[1];
2931
+ s = 1;
2932
+ e = path.count - 1;
2933
+ }
2934
+
2935
+ if (loop === 0) {
2936
+ dx = p1.x - p0.x;
2937
+ dy = p1.y - p0.y;
2938
+ ({ x: dx, y: dy } = nvg__normalize_xy(dx, dy));
2939
+ if (lineCap === NVG_BUTT)
2940
+ dst = nvg__buttCapStart(ctx, verts, dst, p0, dx, dy, w, -aa * 0.5, aa, u0, u1);
2941
+ else if (lineCap === NVG_SQUARE)
2942
+ dst = nvg__buttCapStart(ctx, verts, dst, p0, dx, dy, w, w - aa, aa, u0, u1);
2943
+ else if (lineCap === NVG_ROUND)
2944
+ dst = nvg__roundCapStart(ctx, verts, dst, p0, dx, dy, w, ncap, aa, u0, u1);
2945
+ }
2946
+
2947
+ for (let j = s; j < e; ++j) {
2948
+ if ((p1.flags & (NVG_PT_BEVEL | NVG_PR_INNERBEVEL)) !== 0) {
2949
+ if (lineJoin === NVG_ROUND) {
2950
+ dst = nvg__roundJoin(ctx, verts, dst, p0, p1, w, w, u0, u1, ncap, aa);
2951
+ } else {
2952
+ dst = nvg__bevelJoin(ctx, verts, dst, p0, p1, w, w, u0, u1, aa);
2953
+ }
2954
+ } else {
2955
+ nvg__vsetCore(ctx, verts, dst++, p1.x + (p1.dmx * w), p1.y + (p1.dmy * w), u0, 1);
2956
+ nvg__vsetCore(ctx, verts, dst++, p1.x - (p1.dmx * w), p1.y - (p1.dmy * w), u1, 1);
2957
+ }
2958
+ p0 = p1;
2959
+ p1 = pts[j + 1];
2960
+ }
2961
+
2962
+ if (loop) {
2963
+ let first0 = new NVGvertex(verts, path.strokeOffset);
2964
+ let first1 = new NVGvertex(verts, path.strokeOffset + 1);
2965
+ nvg__vsetCore(ctx, verts, dst++, first0.x, first0.y, u0, 1);
2966
+ nvg__vsetCore(ctx, verts, dst++, first1.x, first1.y, u1, 1);
2967
+ } else {
2968
+ dx = p1.x - p0.x;
2969
+ dy = p1.y - p0.y;
2970
+ ({ x: dx, y: dy } = nvg__normalize_xy(dx, dy));
2971
+ if (lineCap === NVG_BUTT)
2972
+ dst = nvg__buttCapEnd(ctx, verts, dst, p1, dx, dy, w, -aa * 0.5, aa, u0, u1);
2973
+ else if (lineCap === NVG_SQUARE)
2974
+ dst = nvg__buttCapEnd(ctx, verts, dst, p1, dx, dy, w, w - aa, aa, u0, u1);
2975
+ else if (lineCap === NVG_ROUND)
2976
+ dst = nvg__roundCapEnd(ctx, verts, dst, p1, dx, dy, w, ncap, aa, u0, u1);
2977
+ }
2978
+
2979
+ path.nstroke = dst - path.strokeOffset;
2980
+
2981
+ let strokeView = new Float32Array(verts, path.strokeOffset * NVG_VERTEX_SIZEOF, path.nstroke * 4);
2982
+ path.stroke = new Float32Array(path.nstroke * 4);
2983
+ path.stroke.set(strokeView);
2984
+ }
2985
+
2986
+ return 1;
2987
+ }
2988
+
2989
+ function nvg__curveDivs(r, arc, tol) {
2990
+ let da = Math.acos(r / (r + tol)) * 2.0;
2991
+ return Math.max(2, Math.ceil(arc / da));
2992
+ }
2993
+
2994
+ function nvg__normalize_xy(x, y) {
2995
+ let d = Math.sqrt(x * x + y * y);
2996
+ if (d > 1e-6) {
2997
+ let id = 1.0 / d;
2998
+ x *= id;
2999
+ y *= id;
3000
+ }
3001
+ return { x, y, d };
3002
+ }
3003
+
3004
+ function nvg__buttCapStart(ctx, verts, dst, p, dx, dy, w, d, aa, u0, u1) {
3005
+ let px = p.x - dx * d;
3006
+ let py = p.y - dy * d;
3007
+ let dlx = dy;
3008
+ let dly = -dx;
3009
+ nvg__vsetCore(ctx, verts, dst++, px + dlx * w - dx * aa, py + dly * w - dy * aa, u0, 0);
3010
+ nvg__vsetCore(ctx, verts, dst++, px - dlx * w - dx * aa, py - dly * w - dy * aa, u1, 0);
3011
+ nvg__vsetCore(ctx, verts, dst++, px + dlx * w, py + dly * w, u0, 1);
3012
+ nvg__vsetCore(ctx, verts, dst++, px - dlx * w, py - dly * w, u1, 1);
3013
+ return dst;
3014
+ }
3015
+
3016
+ function nvg__buttCapEnd(ctx, verts, dst, p, dx, dy, w, d, aa, u0, u1) {
3017
+ let px = p.x + dx * d;
3018
+ let py = p.y + dy * d;
3019
+ let dlx = dy;
3020
+ let dly = -dx;
3021
+ nvg__vsetCore(ctx, verts, dst++, px + dlx * w, py + dly * w, u0, 1);
3022
+ nvg__vsetCore(ctx, verts, dst++, px - dlx * w, py - dly * w, u1, 1);
3023
+ nvg__vsetCore(ctx, verts, dst++, px + dlx * w + dx * aa, py + dly * w + dy * aa, u0, 0);
3024
+ nvg__vsetCore(ctx, verts, dst++, px - dlx * w + dx * aa, py - dly * w + dy * aa, u1, 0);
3025
+ return dst;
3026
+ }
3027
+
3028
+ function nvg__roundCapStart(ctx, verts, dst, p, dx, dy, w, ncap, aa, u0, u1) {
3029
+ let px = p.x;
3030
+ let py = p.y;
3031
+ let dlx = dy;
3032
+ let dly = -dx;
3033
+ for (let i = 0; i < ncap; i++) {
3034
+ let a = i / (ncap - 1) * Math.PI;
3035
+ let ax = Math.cos(a) * w;
3036
+ let ay = Math.sin(a) * w;
3037
+ nvg__vsetCore(ctx, verts, dst++, px - dlx * ax - dx * ay, py - dly * ax - dy * ay, u0, 1);
3038
+ nvg__vsetCore(ctx, verts, dst++, px, py, 0.5, 1);
3039
+ }
3040
+ nvg__vsetCore(ctx, verts, dst++, px + dlx * w, py + dly * w, u0, 1);
3041
+ nvg__vsetCore(ctx, verts, dst++, px - dlx * w, py - dly * w, u1, 1);
3042
+ return dst;
3043
+ }
3044
+
3045
+ function nvg__roundCapEnd(ctx, verts, dst, p, dx, dy, w, ncap, aa, u0, u1) {
3046
+ let px = p.x;
3047
+ let py = p.y;
3048
+ let dlx = dy;
3049
+ let dly = -dx;
3050
+ nvg__vsetCore(ctx, verts, dst++, px + dlx * w, py + dly * w, u0, 1);
3051
+ nvg__vsetCore(ctx, verts, dst++, px - dlx * w, py - dly * w, u1, 1);
3052
+ for (let i = 0; i < ncap; i++) {
3053
+ let a = i / (ncap - 1) * Math.PI;
3054
+ let ax = Math.cos(a) * w;
3055
+ let ay = Math.sin(a) * w;
3056
+ nvg__vsetCore(ctx, verts, dst++, px, py, 0.5, 1);
3057
+ nvg__vsetCore(ctx, verts, dst++, px - dlx * ax + dx * ay, py - dly * ax + dy * ay, u0, 1);
3058
+ }
3059
+ return dst;
3060
+ }
3061
+
3062
+ function nvg__roundJoin(ctx, verts, dst, p0, p1, lw, rw, lu, ru, ncap, fringe) {
3063
+ let dlx0 = p0.dy;
3064
+ let dly0 = -p0.dx;
3065
+ let dlx1 = p1.dy;
3066
+ let dly1 = -p1.dx;
3067
+
3068
+ if (p1.flags & NVG_PT_LEFT) {
3069
+ let lx0, ly0, lx1, ly1, a0, a1;
3070
+ let result = nvg__chooseBevel(p1.flags & NVG_PR_INNERBEVEL, p0, p1, lw);
3071
+ lx0 = result.x0; ly0 = result.y0; lx1 = result.x1; ly1 = result.y1;
3072
+ a0 = Math.atan2(-dly0, -dlx0);
3073
+ a1 = Math.atan2(-dly1, -dlx1);
3074
+ if (a1 > a0) a1 -= Math.PI * 2;
3075
+
3076
+ nvg__vsetCore(ctx, verts, dst++, lx0, ly0, lu, 1);
3077
+ nvg__vsetCore(ctx, verts, dst++, p1.x - dlx0 * rw, p1.y - dly0 * rw, ru, 1);
3078
+
3079
+ let n = Math.max(2, Math.min(Math.ceil(((a0 - a1) / Math.PI) * ncap), ncap));
3080
+ for (let i = 0; i < n; i++) {
3081
+ let u = i / (n - 1);
3082
+ let a = a0 + u * (a1 - a0);
3083
+ let rx = p1.x + Math.cos(a) * rw;
3084
+ let ry = p1.y + Math.sin(a) * rw;
3085
+ nvg__vsetCore(ctx, verts, dst++, p1.x, p1.y, 0.5, 1);
3086
+ nvg__vsetCore(ctx, verts, dst++, rx, ry, ru, 1);
3087
+ }
3088
+
3089
+ nvg__vsetCore(ctx, verts, dst++, lx1, ly1, lu, 1);
3090
+ nvg__vsetCore(ctx, verts, dst++, p1.x - dlx1 * rw, p1.y - dly1 * rw, ru, 1);
3091
+ } else {
3092
+ let rx0, ry0, rx1, ry1, a0, a1;
3093
+ let result = nvg__chooseBevel(p1.flags & NVG_PR_INNERBEVEL, p0, p1, -rw);
3094
+ rx0 = result.x0; ry0 = result.y0; rx1 = result.x1; ry1 = result.y1;
3095
+ a0 = Math.atan2(dly0, dlx0);
3096
+ a1 = Math.atan2(dly1, dlx1);
3097
+ if (a1 < a0) a1 += Math.PI * 2;
3098
+
3099
+ nvg__vsetCore(ctx, verts, dst++, p1.x + dlx0 * rw, p1.y + dly0 * rw, lu, 1);
3100
+ nvg__vsetCore(ctx, verts, dst++, rx0, ry0, ru, 1);
3101
+
3102
+ let n = Math.max(2, Math.min(Math.ceil(((a1 - a0) / Math.PI) * ncap), ncap));
3103
+ for (let i = 0; i < n; i++) {
3104
+ let u = i / (n - 1);
3105
+ let a = a0 + u * (a1 - a0);
3106
+ let lx = p1.x + Math.cos(a) * lw;
3107
+ let ly = p1.y + Math.sin(a) * lw;
3108
+ nvg__vsetCore(ctx, verts, dst++, lx, ly, lu, 1);
3109
+ nvg__vsetCore(ctx, verts, dst++, p1.x, p1.y, 0.5, 1);
3110
+ }
3111
+
3112
+ nvg__vsetCore(ctx, verts, dst++, p1.x + dlx1 * rw, p1.y + dly1 * rw, lu, 1);
3113
+ nvg__vsetCore(ctx, verts, dst++, rx1, ry1, ru, 1);
3114
+ }
3115
+ return dst;
3116
+ }
3117
+
3118
+ function nvg__bevelJoin(ctx, verts, dst, p0, p1, lw, rw, lu, ru, fringe) {
3119
+ let rx0, ry0, rx1, ry1;
3120
+ let lx0, ly0, lx1, ly1;
3121
+ let dlx0 = p0.dy;
3122
+ let dly0 = -p0.dx;
3123
+ let dlx1 = p1.dy;
3124
+ let dly1 = -p1.dx;
3125
+
3126
+ if (p1.flags & NVG_PT_LEFT) {
3127
+ let result = nvg__chooseBevel(p1.flags & NVG_PR_INNERBEVEL, p0, p1, lw);
3128
+ lx0 = result.x0; ly0 = result.y0; lx1 = result.x1; ly1 = result.y1;
3129
+
3130
+ nvg__vsetCore(ctx, verts, dst++, lx0, ly0, lu, 1);
3131
+ nvg__vsetCore(ctx, verts, dst++, p1.x - dlx0 * rw, p1.y - dly0 * rw, ru, 1);
3132
+
3133
+ if (p1.flags & NVG_PT_BEVEL) {
3134
+ nvg__vsetCore(ctx, verts, dst++, lx0, ly0, lu, 1);
3135
+ nvg__vsetCore(ctx, verts, dst++, p1.x - dlx0 * rw, p1.y - dly0 * rw, ru, 1);
3136
+
3137
+ nvg__vsetCore(ctx, verts, dst++, lx1, ly1, lu, 1);
3138
+ nvg__vsetCore(ctx, verts, dst++, p1.x - dlx1 * rw, p1.y - dly1 * rw, ru, 1);
3139
+ } else {
3140
+ rx0 = p1.x - p1.dmx * rw;
3141
+ ry0 = p1.y - p1.dmy * rw;
3142
+
3143
+ nvg__vsetCore(ctx, verts, dst++, p1.x, p1.y, 0.5, 1);
3144
+ nvg__vsetCore(ctx, verts, dst++, p1.x - dlx0 * rw, p1.y - dly0 * rw, ru, 1);
3145
+
3146
+ nvg__vsetCore(ctx, verts, dst++, rx0, ry0, ru, 1);
3147
+ nvg__vsetCore(ctx, verts, dst++, rx0, ry0, ru, 1);
3148
+
3149
+ nvg__vsetCore(ctx, verts, dst++, p1.x, p1.y, 0.5, 1);
3150
+ nvg__vsetCore(ctx, verts, dst++, p1.x - dlx1 * rw, p1.y - dly1 * rw, ru, 1);
3151
+ }
3152
+
3153
+ nvg__vsetCore(ctx, verts, dst++, lx1, ly1, lu, 1);
3154
+ nvg__vsetCore(ctx, verts, dst++, p1.x - dlx1 * rw, p1.y - dly1 * rw, ru, 1);
3155
+ } else {
3156
+ let result = nvg__chooseBevel(p1.flags & NVG_PR_INNERBEVEL, p0, p1, -rw);
3157
+ rx0 = result.x0; ry0 = result.y0; rx1 = result.x1; ry1 = result.y1;
3158
+
3159
+ nvg__vsetCore(ctx, verts, dst++, p1.x + dlx0 * lw, p1.y + dly0 * lw, lu, 1);
3160
+ nvg__vsetCore(ctx, verts, dst++, rx0, ry0, ru, 1);
3161
+
3162
+ if (p1.flags & NVG_PT_BEVEL) {
3163
+ nvg__vsetCore(ctx, verts, dst++, p1.x + dlx0 * lw, p1.y + dly0 * lw, lu, 1);
3164
+ nvg__vsetCore(ctx, verts, dst++, rx0, ry0, ru, 1);
3165
+
3166
+ nvg__vsetCore(ctx, verts, dst++, p1.x + dlx1 * lw, p1.y + dly1 * lw, lu, 1);
3167
+ nvg__vsetCore(ctx, verts, dst++, rx1, ry1, ru, 1);
3168
+ } else {
3169
+ lx0 = p1.x + p1.dmx * lw;
3170
+ ly0 = p1.y + p1.dmy * lw;
3171
+
3172
+ nvg__vsetCore(ctx, verts, dst++, p1.x + dlx0 * lw, p1.y + dly0 * lw, lu, 1);
3173
+ nvg__vsetCore(ctx, verts, dst++, p1.x, p1.y, 0.5, 1);
3174
+
3175
+ nvg__vsetCore(ctx, verts, dst++, lx0, ly0, lu, 1);
3176
+ nvg__vsetCore(ctx, verts, dst++, lx0, ly0, lu, 1);
3177
+
3178
+ nvg__vsetCore(ctx, verts, dst++, p1.x + dlx1 * lw, p1.y + dly1 * lw, lu, 1);
3179
+ nvg__vsetCore(ctx, verts, dst++, p1.x, p1.y, 0.5, 1);
3180
+ }
3181
+
3182
+ nvg__vsetCore(ctx, verts, dst++, p1.x + dlx1 * lw, p1.y + dly1 * lw, lu, 1);
3183
+ nvg__vsetCore(ctx, verts, dst++, rx1, ry1, ru, 1);
3184
+ }
3185
+
3186
+ return dst;
3187
+ }
3188
+
3189
+ function nvg__chooseBevel(bevel, p0, p1, w) {
3190
+ if (bevel) {
3191
+ return {
3192
+ x0: p1.x + p0.dy * w,
3193
+ y0: p1.y - p0.dx * w,
3194
+ x1: p1.x + p1.dy * w,
3195
+ y1: p1.y - p1.dx * w
3196
+ };
3197
+ } else {
3198
+ return {
3199
+ x0: p1.x + p1.dmx * w,
3200
+ y0: p1.y + p1.dmy * w,
3201
+ x1: p1.x + p1.dmx * w,
3202
+ y1: p1.y + p1.dmy * w
3203
+ };
3204
+ }
3205
+ }