Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-ports-kde
Path: blob/main/cad/PrusaSlicer/files/patch-src_libnanosvg_nanosvgrast.h
16462 views
1
--- src/libnanosvg/nanosvgrast.h.orig 2024-10-16 10:58:04 UTC
2
+++ src/libnanosvg/nanosvgrast.h
3
@@ -0,0 +1,1482 @@
4
+/*
5
+ * Copyright (c) 2013-14 Mikko Mononen [email protected]
6
+ *
7
+ * This software is provided 'as-is', without any express or implied
8
+ * warranty. In no event will the authors be held liable for any damages
9
+ * arising from the use of this software.
10
+ *
11
+ * Permission is granted to anyone to use this software for any purpose,
12
+ * including commercial applications, and to alter it and redistribute it
13
+ * freely, subject to the following restrictions:
14
+ *
15
+ * 1. The origin of this software must not be misrepresented; you must not
16
+ * claim that you wrote the original software. If you use this software
17
+ * in a product, an acknowledgment in the product documentation would be
18
+ * appreciated but is not required.
19
+ * 2. Altered source versions must be plainly marked as such, and must not be
20
+ * misrepresented as being the original software.
21
+ * 3. This notice may not be removed or altered from any source distribution.
22
+ *
23
+ * The polygon rasterization is heavily based on stb_truetype rasterizer
24
+ * by Sean Barrett - http://nothings.org/
25
+ *
26
+ */
27
+
28
+/* Modified by FLTK to support non-square X,Y axes scaling.
29
+ *
30
+ * Added: nsvgRasterizeXY()
31
+*/
32
+
33
+
34
+#ifndef NANOSVGRAST_H
35
+#define NANOSVGRAST_H
36
+
37
+#include "nanosvg.h"
38
+
39
+#ifndef NANOSVGRAST_CPLUSPLUS
40
+#ifdef __cplusplus
41
+extern "C" {
42
+#endif
43
+#endif
44
+
45
+typedef struct NSVGrasterizer NSVGrasterizer;
46
+
47
+/* Example Usage:
48
+ // Load SVG
49
+ NSVGimage* image;
50
+ image = nsvgParseFromFile("test.svg", "px", 96);
51
+
52
+ // Create rasterizer (can be used to render multiple images).
53
+ struct NSVGrasterizer* rast = nsvgCreateRasterizer();
54
+ // Allocate memory for image
55
+ unsigned char* img = malloc(w*h*4);
56
+ // Rasterize
57
+ nsvgRasterize(rast, image, 0,0,1, img, w, h, w*4);
58
+
59
+ // For non-square X,Y scaling, use
60
+ nsvgRasterizeXY(rast, image, 0,0,1,1, img, w, h, w*4);
61
+*/
62
+
63
+// Allocated rasterizer context.
64
+static NSVGrasterizer* nsvgCreateRasterizer(void);
65
+
66
+// Rasterizes SVG image, returns RGBA image (non-premultiplied alpha)
67
+// r - pointer to rasterizer context
68
+// image - pointer to image to rasterize
69
+// tx,ty - image offset (applied after scaling)
70
+// scale - image scale (assumes square aspect ratio)
71
+// dst - pointer to destination image data, 4 bytes per pixel (RGBA)
72
+// w - width of the image to render
73
+// h - height of the image to render
74
+// stride - number of bytes per scaleline in the destination buffer
75
+static void nsvgRasterize(NSVGrasterizer* r,
76
+ NSVGimage* image, float tx, float ty, float scale,
77
+ unsigned char* dst, int w, int h, int stride);
78
+
79
+// As above, but allow X and Y axes to scale independently for non-square aspects
80
+static void nsvgRasterizeXY(NSVGrasterizer* r,
81
+ NSVGimage* image, float tx, float ty,
82
+ float sx, float sy,
83
+ unsigned char* dst, int w, int h, int stride);
84
+
85
+// Deletes rasterizer context.
86
+static void nsvgDeleteRasterizer(NSVGrasterizer*);
87
+
88
+
89
+#ifndef NANOSVGRAST_CPLUSPLUS
90
+#ifdef __cplusplus
91
+}
92
+#endif
93
+#endif
94
+
95
+#if 1 || defined(NANOSVGRAST_IMPLEMENTATION)
96
+
97
+#include <math.h>
98
+#include <stdlib.h>
99
+#include <string.h>
100
+
101
+#define NSVG__SUBSAMPLES 5
102
+#define NSVG__FIXSHIFT 10
103
+#define NSVG__FIX (1 << NSVG__FIXSHIFT)
104
+#define NSVG__FIXMASK (NSVG__FIX-1)
105
+#define NSVG__MEMPAGE_SIZE 1024
106
+
107
+typedef struct NSVGedge {
108
+ float x0,y0, x1,y1;
109
+ int dir;
110
+ struct NSVGedge* next;
111
+} NSVGedge;
112
+
113
+typedef struct NSVGpoint {
114
+ float x, y;
115
+ float dx, dy;
116
+ float len;
117
+ float dmx, dmy;
118
+ unsigned char flags;
119
+} NSVGpoint;
120
+
121
+typedef struct NSVGactiveEdge {
122
+ int x,dx;
123
+ float ey;
124
+ int dir;
125
+ struct NSVGactiveEdge *next;
126
+} NSVGactiveEdge;
127
+
128
+typedef struct NSVGmemPage {
129
+ unsigned char mem[NSVG__MEMPAGE_SIZE];
130
+ int size;
131
+ struct NSVGmemPage* next;
132
+} NSVGmemPage;
133
+
134
+typedef struct NSVGcachedPaint {
135
+ signed char type;
136
+ char spread;
137
+ float xform[6];
138
+ unsigned int colors[256];
139
+} NSVGcachedPaint;
140
+
141
+struct NSVGrasterizer
142
+{
143
+ float px, py;
144
+
145
+ float tessTol;
146
+ float distTol;
147
+
148
+ NSVGedge* edges;
149
+ int nedges;
150
+ int cedges;
151
+
152
+ NSVGpoint* points;
153
+ int npoints;
154
+ int cpoints;
155
+
156
+ NSVGpoint* points2;
157
+ int npoints2;
158
+ int cpoints2;
159
+
160
+ NSVGactiveEdge* freelist;
161
+ NSVGmemPage* pages;
162
+ NSVGmemPage* curpage;
163
+
164
+ unsigned char* scanline;
165
+ int cscanline;
166
+
167
+ unsigned char* bitmap;
168
+ int width, height, stride;
169
+};
170
+
171
+static NSVGrasterizer* nsvgCreateRasterizer(void)
172
+{
173
+ NSVGrasterizer* r = (NSVGrasterizer*)malloc(sizeof(NSVGrasterizer));
174
+ if (r == NULL) goto error;
175
+ memset(r, 0, sizeof(NSVGrasterizer));
176
+
177
+ r->tessTol = 0.25f;
178
+ r->distTol = 0.01f;
179
+
180
+ return r;
181
+
182
+error:
183
+ nsvgDeleteRasterizer(r);
184
+ return NULL;
185
+}
186
+
187
+static void nsvgDeleteRasterizer(NSVGrasterizer* r)
188
+{
189
+ NSVGmemPage* p;
190
+
191
+ if (r == NULL) return;
192
+
193
+ p = r->pages;
194
+ while (p != NULL) {
195
+ NSVGmemPage* next = p->next;
196
+ free(p);
197
+ p = next;
198
+ }
199
+
200
+ if (r->edges) free(r->edges);
201
+ if (r->points) free(r->points);
202
+ if (r->points2) free(r->points2);
203
+ if (r->scanline) free(r->scanline);
204
+
205
+ free(r);
206
+}
207
+
208
+static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur)
209
+{
210
+ NSVGmemPage *newp;
211
+
212
+ // If using existing chain, return the next page in chain
213
+ if (cur != NULL && cur->next != NULL) {
214
+ return cur->next;
215
+ }
216
+
217
+ // Alloc new page
218
+ newp = (NSVGmemPage*)malloc(sizeof(NSVGmemPage));
219
+ if (newp == NULL) return NULL;
220
+ memset(newp, 0, sizeof(NSVGmemPage));
221
+
222
+ // Add to linked list
223
+ if (cur != NULL)
224
+ cur->next = newp;
225
+ else
226
+ r->pages = newp;
227
+
228
+ return newp;
229
+}
230
+
231
+static void nsvg__resetPool(NSVGrasterizer* r)
232
+{
233
+ NSVGmemPage* p = r->pages;
234
+ while (p != NULL) {
235
+ p->size = 0;
236
+ p = p->next;
237
+ }
238
+ r->curpage = r->pages;
239
+}
240
+
241
+static unsigned char* nsvg__alloc(NSVGrasterizer* r, int size)
242
+{
243
+ unsigned char* buf;
244
+ if (size > NSVG__MEMPAGE_SIZE) return NULL;
245
+ if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) {
246
+ r->curpage = nsvg__nextPage(r, r->curpage);
247
+ }
248
+ buf = &r->curpage->mem[r->curpage->size];
249
+ r->curpage->size += size;
250
+ return buf;
251
+}
252
+
253
+static int nsvg__ptEquals(float x1, float y1, float x2, float y2, float tol)
254
+{
255
+ float dx = x2 - x1;
256
+ float dy = y2 - y1;
257
+ return dx*dx + dy*dy < tol*tol;
258
+}
259
+
260
+static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int flags)
261
+{
262
+ NSVGpoint* pt;
263
+
264
+ if (r->npoints > 0) {
265
+ pt = &r->points[r->npoints-1];
266
+ if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) {
267
+ pt->flags = (unsigned char)(pt->flags | flags);
268
+ return;
269
+ }
270
+ }
271
+
272
+ if (r->npoints+1 > r->cpoints) {
273
+ r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
274
+ r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints);
275
+ if (r->points == NULL) return;
276
+ }
277
+
278
+ pt = &r->points[r->npoints];
279
+ pt->x = x;
280
+ pt->y = y;
281
+ pt->flags = (unsigned char)flags;
282
+ r->npoints++;
283
+}
284
+
285
+static void nsvg__appendPathPoint(NSVGrasterizer* r, NSVGpoint pt)
286
+{
287
+ if (r->npoints+1 > r->cpoints) {
288
+ r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
289
+ r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints);
290
+ if (r->points == NULL) return;
291
+ }
292
+ r->points[r->npoints] = pt;
293
+ r->npoints++;
294
+}
295
+
296
+static void nsvg__duplicatePoints(NSVGrasterizer* r)
297
+{
298
+ if (r->npoints > r->cpoints2) {
299
+ r->cpoints2 = r->npoints;
300
+ r->points2 = (NSVGpoint*)realloc(r->points2, sizeof(NSVGpoint) * r->cpoints2);
301
+ if (r->points2 == NULL) return;
302
+ }
303
+
304
+ memcpy(r->points2, r->points, sizeof(NSVGpoint) * r->npoints);
305
+ r->npoints2 = r->npoints;
306
+}
307
+
308
+static void nsvg__addEdge(NSVGrasterizer* r, float x0, float y0, float x1, float y1)
309
+{
310
+ NSVGedge* e;
311
+
312
+ // Skip horizontal edges
313
+ if (y0 == y1)
314
+ return;
315
+
316
+ if (r->nedges+1 > r->cedges) {
317
+ r->cedges = r->cedges > 0 ? r->cedges * 2 : 64;
318
+ r->edges = (NSVGedge*)realloc(r->edges, sizeof(NSVGedge) * r->cedges);
319
+ if (r->edges == NULL) return;
320
+ }
321
+
322
+ e = &r->edges[r->nedges];
323
+ r->nedges++;
324
+
325
+ if (y0 < y1) {
326
+ e->x0 = x0;
327
+ e->y0 = y0;
328
+ e->x1 = x1;
329
+ e->y1 = y1;
330
+ e->dir = 1;
331
+ } else {
332
+ e->x0 = x1;
333
+ e->y0 = y1;
334
+ e->x1 = x0;
335
+ e->y1 = y0;
336
+ e->dir = -1;
337
+ }
338
+}
339
+
340
+static float nsvg__normalize(float *x, float* y)
341
+{
342
+ float d = sqrtf((*x)*(*x) + (*y)*(*y));
343
+ if (d > 1e-6f) {
344
+ float id = 1.0f / d;
345
+ *x *= id;
346
+ *y *= id;
347
+ }
348
+ return d;
349
+}
350
+
351
+static float nsvg__absf(float x) { return x < 0 ? -x : x; }
352
+
353
+static void nsvg__flattenCubicBez(NSVGrasterizer* r,
354
+ float x1, float y1, float x2, float y2,
355
+ float x3, float y3, float x4, float y4,
356
+ int level, int type)
357
+{
358
+ float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;
359
+ float dx,dy,d2,d3;
360
+
361
+ if (level > 10) return;
362
+
363
+ x12 = (x1+x2)*0.5f;
364
+ y12 = (y1+y2)*0.5f;
365
+ x23 = (x2+x3)*0.5f;
366
+ y23 = (y2+y3)*0.5f;
367
+ x34 = (x3+x4)*0.5f;
368
+ y34 = (y3+y4)*0.5f;
369
+ x123 = (x12+x23)*0.5f;
370
+ y123 = (y12+y23)*0.5f;
371
+
372
+ dx = x4 - x1;
373
+ dy = y4 - y1;
374
+ d2 = nsvg__absf(((x2 - x4) * dy - (y2 - y4) * dx));
375
+ d3 = nsvg__absf(((x3 - x4) * dy - (y3 - y4) * dx));
376
+
377
+ if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) {
378
+ nsvg__addPathPoint(r, x4, y4, type);
379
+ return;
380
+ }
381
+
382
+ x234 = (x23+x34)*0.5f;
383
+ y234 = (y23+y34)*0.5f;
384
+ x1234 = (x123+x234)*0.5f;
385
+ y1234 = (y123+y234)*0.5f;
386
+
387
+ nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0);
388
+ nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type);
389
+}
390
+
391
+static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, float sx, float sy)
392
+{
393
+ int i, j;
394
+ NSVGpath* path;
395
+
396
+ for (path = shape->paths; path != NULL; path = path->next) {
397
+ r->npoints = 0;
398
+ // Flatten path
399
+ nsvg__addPathPoint(r, path->pts[0]*sx, path->pts[1]*sy, 0);
400
+ for (i = 0; i < path->npts-1; i += 3) {
401
+ float* p = &path->pts[i*2];
402
+ nsvg__flattenCubicBez(r, p[0]*sx,p[1]*sy, p[2]*sx,p[3]*sy, p[4]*sx,p[5]*sy, p[6]*sx,p[7]*sy, 0, 0);
403
+ }
404
+ // Close path
405
+ nsvg__addPathPoint(r, path->pts[0]*sx, path->pts[1]*sy, 0);
406
+ // Build edges
407
+ for (i = 0, j = r->npoints-1; i < r->npoints; j = i++)
408
+ nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y);
409
+ }
410
+}
411
+
412
+enum NSVGpointFlags
413
+{
414
+ NSVG_PT_CORNER = 0x01,
415
+ NSVG_PT_BEVEL = 0x02,
416
+ NSVG_PT_LEFT = 0x04
417
+};
418
+
419
+static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
420
+{
421
+ float w = lineWidth * 0.5f;
422
+ float dx = p1->x - p0->x;
423
+ float dy = p1->y - p0->y;
424
+ float len = nsvg__normalize(&dx, &dy);
425
+ float px = p0->x + dx*len*0.5f, py = p0->y + dy*len*0.5f;
426
+ float dlx = dy, dly = -dx;
427
+ float lx = px - dlx*w, ly = py - dly*w;
428
+ float rx = px + dlx*w, ry = py + dly*w;
429
+ left->x = lx; left->y = ly;
430
+ right->x = rx; right->y = ry;
431
+}
432
+
433
+static void nsvg__buttCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect)
434
+{
435
+ float w = lineWidth * 0.5f;
436
+ float px = p->x, py = p->y;
437
+ float dlx = dy, dly = -dx;
438
+ float lx = px - dlx*w, ly = py - dly*w;
439
+ float rx = px + dlx*w, ry = py + dly*w;
440
+
441
+ nsvg__addEdge(r, lx, ly, rx, ry);
442
+
443
+ if (connect) {
444
+ nsvg__addEdge(r, left->x, left->y, lx, ly);
445
+ nsvg__addEdge(r, rx, ry, right->x, right->y);
446
+ }
447
+ left->x = lx; left->y = ly;
448
+ right->x = rx; right->y = ry;
449
+}
450
+
451
+static void nsvg__squareCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect)
452
+{
453
+ float w = lineWidth * 0.5f;
454
+ float px = p->x - dx*w, py = p->y - dy*w;
455
+ float dlx = dy, dly = -dx;
456
+ float lx = px - dlx*w, ly = py - dly*w;
457
+ float rx = px + dlx*w, ry = py + dly*w;
458
+
459
+ nsvg__addEdge(r, lx, ly, rx, ry);
460
+
461
+ if (connect) {
462
+ nsvg__addEdge(r, left->x, left->y, lx, ly);
463
+ nsvg__addEdge(r, rx, ry, right->x, right->y);
464
+ }
465
+ left->x = lx; left->y = ly;
466
+ right->x = rx; right->y = ry;
467
+}
468
+
469
+#ifndef NSVG_PI
470
+#define NSVG_PI (3.14159265358979323846264338327f)
471
+#endif
472
+
473
+static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int ncap, int connect)
474
+{
475
+ int i;
476
+ float w = lineWidth * 0.5f;
477
+ float px = p->x, py = p->y;
478
+ float dlx = dy, dly = -dx;
479
+ float lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0;
480
+
481
+ for (i = 0; i < ncap; i++) {
482
+ float a = (float)i/(float)(ncap-1)*NSVG_PI;
483
+ float ax = cosf(a) * w, ay = sinf(a) * w;
484
+ float x = px - dlx*ax - dx*ay;
485
+ float y = py - dly*ax - dy*ay;
486
+
487
+ if (i > 0)
488
+ nsvg__addEdge(r, prevx, prevy, x, y);
489
+
490
+ prevx = x;
491
+ prevy = y;
492
+
493
+ if (i == 0) {
494
+ lx = x; ly = y;
495
+ } else if (i == ncap-1) {
496
+ rx = x; ry = y;
497
+ }
498
+ }
499
+
500
+ if (connect) {
501
+ nsvg__addEdge(r, left->x, left->y, lx, ly);
502
+ nsvg__addEdge(r, rx, ry, right->x, right->y);
503
+ }
504
+
505
+ left->x = lx; left->y = ly;
506
+ right->x = rx; right->y = ry;
507
+}
508
+
509
+static void nsvg__bevelJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
510
+{
511
+ float w = lineWidth * 0.5f;
512
+ float dlx0 = p0->dy, dly0 = -p0->dx;
513
+ float dlx1 = p1->dy, dly1 = -p1->dx;
514
+ float lx0 = p1->x - (dlx0 * w), ly0 = p1->y - (dly0 * w);
515
+ float rx0 = p1->x + (dlx0 * w), ry0 = p1->y + (dly0 * w);
516
+ float lx1 = p1->x - (dlx1 * w), ly1 = p1->y - (dly1 * w);
517
+ float rx1 = p1->x + (dlx1 * w), ry1 = p1->y + (dly1 * w);
518
+
519
+ nsvg__addEdge(r, lx0, ly0, left->x, left->y);
520
+ nsvg__addEdge(r, lx1, ly1, lx0, ly0);
521
+
522
+ nsvg__addEdge(r, right->x, right->y, rx0, ry0);
523
+ nsvg__addEdge(r, rx0, ry0, rx1, ry1);
524
+
525
+ left->x = lx1; left->y = ly1;
526
+ right->x = rx1; right->y = ry1;
527
+}
528
+
529
+static void nsvg__miterJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
530
+{
531
+ float w = lineWidth * 0.5f;
532
+ float dlx0 = p0->dy, dly0 = -p0->dx;
533
+ float dlx1 = p1->dy, dly1 = -p1->dx;
534
+ float lx0, rx0, lx1, rx1;
535
+ float ly0, ry0, ly1, ry1;
536
+
537
+ if (p1->flags & NSVG_PT_LEFT) {
538
+ lx0 = lx1 = p1->x - p1->dmx * w;
539
+ ly0 = ly1 = p1->y - p1->dmy * w;
540
+ nsvg__addEdge(r, lx1, ly1, left->x, left->y);
541
+
542
+ rx0 = p1->x + (dlx0 * w);
543
+ ry0 = p1->y + (dly0 * w);
544
+ rx1 = p1->x + (dlx1 * w);
545
+ ry1 = p1->y + (dly1 * w);
546
+ nsvg__addEdge(r, right->x, right->y, rx0, ry0);
547
+ nsvg__addEdge(r, rx0, ry0, rx1, ry1);
548
+ } else {
549
+ lx0 = p1->x - (dlx0 * w);
550
+ ly0 = p1->y - (dly0 * w);
551
+ lx1 = p1->x - (dlx1 * w);
552
+ ly1 = p1->y - (dly1 * w);
553
+ nsvg__addEdge(r, lx0, ly0, left->x, left->y);
554
+ nsvg__addEdge(r, lx1, ly1, lx0, ly0);
555
+
556
+ rx0 = rx1 = p1->x + p1->dmx * w;
557
+ ry0 = ry1 = p1->y + p1->dmy * w;
558
+ nsvg__addEdge(r, right->x, right->y, rx1, ry1);
559
+ }
560
+
561
+ left->x = lx1; left->y = ly1;
562
+ right->x = rx1; right->y = ry1;
563
+}
564
+
565
+static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth, int ncap)
566
+{
567
+ int i, n;
568
+ float w = lineWidth * 0.5f;
569
+ float dlx0 = p0->dy, dly0 = -p0->dx;
570
+ float dlx1 = p1->dy, dly1 = -p1->dx;
571
+ float a0 = atan2f(dly0, dlx0);
572
+ float a1 = atan2f(dly1, dlx1);
573
+ float da = a1 - a0;
574
+ float lx, ly, rx, ry;
575
+
576
+ if (da < NSVG_PI) da += NSVG_PI*2;
577
+ if (da > NSVG_PI) da -= NSVG_PI*2;
578
+
579
+ n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * (float)ncap);
580
+ if (n < 2) n = 2;
581
+ if (n > ncap) n = ncap;
582
+
583
+ lx = left->x;
584
+ ly = left->y;
585
+ rx = right->x;
586
+ ry = right->y;
587
+
588
+ for (i = 0; i < n; i++) {
589
+ float u = (float)i/(float)(n-1);
590
+ float a = a0 + u*da;
591
+ float ax = cosf(a) * w, ay = sinf(a) * w;
592
+ float lx1 = p1->x - ax, ly1 = p1->y - ay;
593
+ float rx1 = p1->x + ax, ry1 = p1->y + ay;
594
+
595
+ nsvg__addEdge(r, lx1, ly1, lx, ly);
596
+ nsvg__addEdge(r, rx, ry, rx1, ry1);
597
+
598
+ lx = lx1; ly = ly1;
599
+ rx = rx1; ry = ry1;
600
+ }
601
+
602
+ left->x = lx; left->y = ly;
603
+ right->x = rx; right->y = ry;
604
+}
605
+
606
+static void nsvg__straightJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p1, float lineWidth)
607
+{
608
+ float w = lineWidth * 0.5f;
609
+ float lx = p1->x - (p1->dmx * w), ly = p1->y - (p1->dmy * w);
610
+ float rx = p1->x + (p1->dmx * w), ry = p1->y + (p1->dmy * w);
611
+
612
+ nsvg__addEdge(r, lx, ly, left->x, left->y);
613
+ nsvg__addEdge(r, right->x, right->y, rx, ry);
614
+
615
+ left->x = lx; left->y = ly;
616
+ right->x = rx; right->y = ry;
617
+}
618
+
619
+static int nsvg__curveDivs(float r, float arc, float tol)
620
+{
621
+ float da = acosf(r / (r + tol)) * 2.0f;
622
+ int divs = (int)ceilf(arc / da);
623
+ if (divs < 2) divs = 2;
624
+ return divs;
625
+}
626
+
627
+static void nsvg__expandStroke(NSVGrasterizer* r, NSVGpoint* points, int npoints, int closed, int lineJoin, int lineCap, float lineWidth)
628
+{
629
+ int ncap = nsvg__curveDivs(lineWidth*0.5f, NSVG_PI, r->tessTol); // Calculate divisions per half circle.
630
+ NSVGpoint left = {0,0,0,0,0,0,0,0}, right = {0,0,0,0,0,0,0,0}, firstLeft = {0,0,0,0,0,0,0,0}, firstRight = {0,0,0,0,0,0,0,0};
631
+ NSVGpoint* p0, *p1;
632
+ int j, s, e;
633
+
634
+ // Build stroke edges
635
+ if (closed) {
636
+ // Looping
637
+ p0 = &points[npoints-1];
638
+ p1 = &points[0];
639
+ s = 0;
640
+ e = npoints;
641
+ } else {
642
+ // Add cap
643
+ p0 = &points[0];
644
+ p1 = &points[1];
645
+ s = 1;
646
+ e = npoints-1;
647
+ }
648
+
649
+ if (closed) {
650
+ nsvg__initClosed(&left, &right, p0, p1, lineWidth);
651
+ firstLeft = left;
652
+ firstRight = right;
653
+ } else {
654
+ // Add cap
655
+ float dx = p1->x - p0->x;
656
+ float dy = p1->y - p0->y;
657
+ nsvg__normalize(&dx, &dy);
658
+ if (lineCap == NSVG_CAP_BUTT)
659
+ nsvg__buttCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
660
+ else if (lineCap == NSVG_CAP_SQUARE)
661
+ nsvg__squareCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
662
+ else if (lineCap == NSVG_CAP_ROUND)
663
+ nsvg__roundCap(r, &left, &right, p0, dx, dy, lineWidth, ncap, 0);
664
+ }
665
+
666
+ for (j = s; j < e; ++j) {
667
+ if (p1->flags & NSVG_PT_CORNER) {
668
+ if (lineJoin == NSVG_JOIN_ROUND)
669
+ nsvg__roundJoin(r, &left, &right, p0, p1, lineWidth, ncap);
670
+ else if (lineJoin == NSVG_JOIN_BEVEL || (p1->flags & NSVG_PT_BEVEL))
671
+ nsvg__bevelJoin(r, &left, &right, p0, p1, lineWidth);
672
+ else
673
+ nsvg__miterJoin(r, &left, &right, p0, p1, lineWidth);
674
+ } else {
675
+ nsvg__straightJoin(r, &left, &right, p1, lineWidth);
676
+ }
677
+ p0 = p1++;
678
+ }
679
+
680
+ if (closed) {
681
+ // Loop it
682
+ nsvg__addEdge(r, firstLeft.x, firstLeft.y, left.x, left.y);
683
+ nsvg__addEdge(r, right.x, right.y, firstRight.x, firstRight.y);
684
+ } else {
685
+ // Add cap
686
+ float dx = p1->x - p0->x;
687
+ float dy = p1->y - p0->y;
688
+ nsvg__normalize(&dx, &dy);
689
+ if (lineCap == NSVG_CAP_BUTT)
690
+ nsvg__buttCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
691
+ else if (lineCap == NSVG_CAP_SQUARE)
692
+ nsvg__squareCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
693
+ else if (lineCap == NSVG_CAP_ROUND)
694
+ nsvg__roundCap(r, &right, &left, p1, -dx, -dy, lineWidth, ncap, 1);
695
+ }
696
+}
697
+
698
+static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int lineJoin)
699
+{
700
+ int i, j;
701
+ NSVGpoint* p0, *p1;
702
+
703
+ p0 = &r->points[r->npoints-1];
704
+ p1 = &r->points[0];
705
+ for (i = 0; i < r->npoints; i++) {
706
+ // Calculate segment direction and length
707
+ p0->dx = p1->x - p0->x;
708
+ p0->dy = p1->y - p0->y;
709
+ p0->len = nsvg__normalize(&p0->dx, &p0->dy);
710
+ // Advance
711
+ p0 = p1++;
712
+ }
713
+
714
+ // calculate joins
715
+ p0 = &r->points[r->npoints-1];
716
+ p1 = &r->points[0];
717
+ for (j = 0; j < r->npoints; j++) {
718
+ float dlx0, dly0, dlx1, dly1, dmr2, cross;
719
+ dlx0 = p0->dy;
720
+ dly0 = -p0->dx;
721
+ dlx1 = p1->dy;
722
+ dly1 = -p1->dx;
723
+ // Calculate extrusions
724
+ p1->dmx = (dlx0 + dlx1) * 0.5f;
725
+ p1->dmy = (dly0 + dly1) * 0.5f;
726
+ dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy;
727
+ if (dmr2 > 0.000001f) {
728
+ float s2 = 1.0f / dmr2;
729
+ if (s2 > 600.0f) {
730
+ s2 = 600.0f;
731
+ }
732
+ p1->dmx *= s2;
733
+ p1->dmy *= s2;
734
+ }
735
+
736
+ // Clear flags, but keep the corner.
737
+ p1->flags = (p1->flags & NSVG_PT_CORNER) ? NSVG_PT_CORNER : 0;
738
+
739
+ // Keep track of left turns.
740
+ cross = p1->dx * p0->dy - p0->dx * p1->dy;
741
+ if (cross > 0.0f)
742
+ p1->flags |= NSVG_PT_LEFT;
743
+
744
+ // Check to see if the corner needs to be beveled.
745
+ if (p1->flags & NSVG_PT_CORNER) {
746
+ if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NSVG_JOIN_BEVEL || lineJoin == NSVG_JOIN_ROUND) {
747
+ p1->flags |= NSVG_PT_BEVEL;
748
+ }
749
+ }
750
+
751
+ p0 = p1++;
752
+ }
753
+}
754
+
755
+static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float sx, float sy)
756
+{
757
+ int i, j, closed;
758
+ NSVGpath* path;
759
+ NSVGpoint* p0, *p1;
760
+ float miterLimit = shape->miterLimit;
761
+ int lineJoin = shape->strokeLineJoin;
762
+ int lineCap = shape->strokeLineCap;
763
+ const float sw = (sx + sy) / 2; // average scaling factor
764
+ const float lineWidth = shape->strokeWidth * sw; // FIXME (?)
765
+
766
+ for (path = shape->paths; path != NULL; path = path->next) {
767
+ // Flatten path
768
+ r->npoints = 0;
769
+ nsvg__addPathPoint(r, path->pts[0]*sx, path->pts[1]*sy, NSVG_PT_CORNER);
770
+ for (i = 0; i < path->npts-1; i += 3) {
771
+ float* p = &path->pts[i*2];
772
+ nsvg__flattenCubicBez(r, p[0]*sx,p[1]*sy, p[2]*sx,p[3]*sy, p[4]*sx,p[5]*sy, p[6]*sx,p[7]*sy, 0, NSVG_PT_CORNER);
773
+ }
774
+ if (r->npoints < 2)
775
+ continue;
776
+
777
+ closed = path->closed;
778
+
779
+ // If the first and last points are the same, remove the last, mark as closed path.
780
+ p0 = &r->points[r->npoints-1];
781
+ p1 = &r->points[0];
782
+ if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) {
783
+ r->npoints--;
784
+ p0 = &r->points[r->npoints-1];
785
+ closed = 1;
786
+ }
787
+
788
+ if (shape->strokeDashCount > 0) {
789
+ int idash = 0, dashState = 1;
790
+ float totalDist = 0, dashLen, allDashLen, dashOffset;
791
+ NSVGpoint cur;
792
+
793
+ if (closed)
794
+ nsvg__appendPathPoint(r, r->points[0]);
795
+
796
+ // Duplicate points -> points2.
797
+ nsvg__duplicatePoints(r);
798
+
799
+ r->npoints = 0;
800
+ cur = r->points2[0];
801
+ nsvg__appendPathPoint(r, cur);
802
+
803
+ // Figure out dash offset.
804
+ allDashLen = 0;
805
+ for (j = 0; j < shape->strokeDashCount; j++)
806
+ allDashLen += shape->strokeDashArray[j];
807
+ if (shape->strokeDashCount & 1)
808
+ allDashLen *= 2.0f;
809
+ // Find location inside pattern
810
+ dashOffset = fmodf(shape->strokeDashOffset, allDashLen);
811
+ if (dashOffset < 0.0f)
812
+ dashOffset += allDashLen;
813
+
814
+ while (dashOffset > shape->strokeDashArray[idash]) {
815
+ dashOffset -= shape->strokeDashArray[idash];
816
+ idash = (idash + 1) % shape->strokeDashCount;
817
+ }
818
+ dashLen = (shape->strokeDashArray[idash] - dashOffset) * sw;
819
+
820
+ for (j = 1; j < r->npoints2; ) {
821
+ float dx = r->points2[j].x - cur.x;
822
+ float dy = r->points2[j].y - cur.y;
823
+ float dist = sqrtf(dx*dx + dy*dy);
824
+
825
+ if ((totalDist + dist) > dashLen) {
826
+ // Calculate intermediate point
827
+ float d = (dashLen - totalDist) / dist;
828
+ float x = cur.x + dx * d;
829
+ float y = cur.y + dy * d;
830
+ nsvg__addPathPoint(r, x, y, NSVG_PT_CORNER);
831
+
832
+ // Stroke
833
+ if (r->npoints > 1 && dashState) {
834
+ nsvg__prepareStroke(r, miterLimit, lineJoin);
835
+ nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);
836
+ }
837
+ // Advance dash pattern
838
+ dashState = !dashState;
839
+ idash = (idash+1) % shape->strokeDashCount;
840
+ dashLen = shape->strokeDashArray[idash] * sw;
841
+ // Restart
842
+ cur.x = x;
843
+ cur.y = y;
844
+ cur.flags = NSVG_PT_CORNER;
845
+ totalDist = 0.0f;
846
+ r->npoints = 0;
847
+ nsvg__appendPathPoint(r, cur);
848
+ } else {
849
+ totalDist += dist;
850
+ cur = r->points2[j];
851
+ nsvg__appendPathPoint(r, cur);
852
+ j++;
853
+ }
854
+ }
855
+ // Stroke any leftover path
856
+ if (r->npoints > 1 && dashState)
857
+ nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);
858
+ } else {
859
+ nsvg__prepareStroke(r, miterLimit, lineJoin);
860
+ nsvg__expandStroke(r, r->points, r->npoints, closed, lineJoin, lineCap, lineWidth);
861
+ }
862
+ }
863
+}
864
+
865
+static int nsvg__cmpEdge(const void *p, const void *q)
866
+{
867
+ const NSVGedge* a = (const NSVGedge*)p;
868
+ const NSVGedge* b = (const NSVGedge*)q;
869
+
870
+ if (a->y0 < b->y0) return -1;
871
+ if (a->y0 > b->y0) return 1;
872
+ return 0;
873
+}
874
+
875
+
876
+static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float startPoint)
877
+{
878
+ NSVGactiveEdge* z;
879
+
880
+ if (r->freelist != NULL) {
881
+ // Restore from freelist.
882
+ z = r->freelist;
883
+ r->freelist = z->next;
884
+ } else {
885
+ // Alloc new edge.
886
+ z = (NSVGactiveEdge*)nsvg__alloc(r, sizeof(NSVGactiveEdge));
887
+ if (z == NULL) return NULL;
888
+ }
889
+
890
+ float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
891
+// STBTT_assert(e->y0 <= start_point);
892
+ // round dx down to avoid going too far
893
+ if (dxdy < 0)
894
+ z->dx = (int)(-floorf(NSVG__FIX * -dxdy));
895
+ else
896
+ z->dx = (int)floorf(NSVG__FIX * dxdy);
897
+ z->x = (int)floorf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0)));
898
+// z->x -= off_x * FIX;
899
+ z->ey = e->y1;
900
+ z->next = 0;
901
+ z->dir = e->dir;
902
+
903
+ return z;
904
+}
905
+
906
+static void nsvg__freeActive(NSVGrasterizer* r, NSVGactiveEdge* z)
907
+{
908
+ z->next = r->freelist;
909
+ r->freelist = z;
910
+}
911
+
912
+static void nsvg__fillScanline(unsigned char* scanline, int len, int x0, int x1, int maxWeight, int* xmin, int* xmax)
913
+{
914
+ int i = x0 >> NSVG__FIXSHIFT;
915
+ int j = x1 >> NSVG__FIXSHIFT;
916
+ if (i < *xmin) *xmin = i;
917
+ if (j > *xmax) *xmax = j;
918
+ if (i < len && j >= 0) {
919
+ if (i == j) {
920
+ // x0,x1 are the same pixel, so compute combined coverage
921
+ scanline[i] = (unsigned char)(scanline[i] + ((x1 - x0) * maxWeight >> NSVG__FIXSHIFT));
922
+ } else {
923
+ if (i >= 0) // add antialiasing for x0
924
+ scanline[i] = (unsigned char)(scanline[i] + (((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT));
925
+ else
926
+ i = -1; // clip
927
+
928
+ if (j < len) // add antialiasing for x1
929
+ scanline[j] = (unsigned char)(scanline[j] + (((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT));
930
+ else
931
+ j = len; // clip
932
+
933
+ for (++i; i < j; ++i) // fill pixels between x0 and x1
934
+ scanline[i] = (unsigned char)(scanline[i] + maxWeight);
935
+ }
936
+ }
937
+}
938
+
939
+// note: this routine clips fills that extend off the edges... ideally this
940
+// wouldn't happen, but it could happen if the truetype glyph bounding boxes
941
+// are wrong, or if the user supplies a too-small bitmap
942
+static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVGactiveEdge* e, int maxWeight, int* xmin, int* xmax, char fillRule)
943
+{
944
+ // non-zero winding fill
945
+ int x0 = 0, w = 0;
946
+
947
+ if (fillRule == NSVG_FILLRULE_NONZERO) {
948
+ // Non-zero
949
+ while (e != NULL) {
950
+ if (w == 0) {
951
+ // if we're currently at zero, we need to record the edge start point
952
+ x0 = e->x; w += e->dir;
953
+ } else {
954
+ int x1 = e->x; w += e->dir;
955
+ // if we went to zero, we need to draw
956
+ if (w == 0)
957
+ nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);
958
+ }
959
+ e = e->next;
960
+ }
961
+ } else if (fillRule == NSVG_FILLRULE_EVENODD) {
962
+ // Even-odd
963
+ while (e != NULL) {
964
+ if (w == 0) {
965
+ // if we're currently at zero, we need to record the edge start point
966
+ x0 = e->x; w = 1;
967
+ } else {
968
+ int x1 = e->x; w = 0;
969
+ nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);
970
+ }
971
+ e = e->next;
972
+ }
973
+ }
974
+}
975
+
976
+static float nsvg__clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); }
977
+
978
+static unsigned int nsvg__RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
979
+{
980
+ return ((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16) | ((unsigned int)a << 24);
981
+}
982
+
983
+static unsigned int nsvg__lerpRGBA(unsigned int c0, unsigned int c1, float u)
984
+{
985
+ int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
986
+ int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8;
987
+ int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8;
988
+ int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8;
989
+ int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8;
990
+ return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a);
991
+}
992
+
993
+static unsigned int nsvg__applyOpacity(unsigned int c, float u)
994
+{
995
+ int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
996
+ int r = (c) & 0xff;
997
+ int g = (c>>8) & 0xff;
998
+ int b = (c>>16) & 0xff;
999
+ int a = (((c>>24) & 0xff)*iu) >> 8;
1000
+ return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a);
1001
+}
1002
+
1003
+static inline int nsvg__div255(int x)
1004
+{
1005
+ return ((x+1) * 257) >> 16;
1006
+}
1007
+
1008
+static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* cover, int x, int y,
1009
+ float tx, float ty, float sx, float sy, NSVGcachedPaint* cache)
1010
+{
1011
+
1012
+ if (cache->type == NSVG_PAINT_COLOR) {
1013
+ int i, cr, cg, cb, ca;
1014
+ cr = cache->colors[0] & 0xff;
1015
+ cg = (cache->colors[0] >> 8) & 0xff;
1016
+ cb = (cache->colors[0] >> 16) & 0xff;
1017
+ ca = (cache->colors[0] >> 24) & 0xff;
1018
+
1019
+ for (i = 0; i < count; i++) {
1020
+ int r,g,b;
1021
+ int a = nsvg__div255((int)cover[0] * ca);
1022
+ int ia = 255 - a;
1023
+ // Premultiply
1024
+ r = nsvg__div255(cr * a);
1025
+ g = nsvg__div255(cg * a);
1026
+ b = nsvg__div255(cb * a);
1027
+
1028
+ // Blend over
1029
+ r += nsvg__div255(ia * (int)dst[0]);
1030
+ g += nsvg__div255(ia * (int)dst[1]);
1031
+ b += nsvg__div255(ia * (int)dst[2]);
1032
+ a += nsvg__div255(ia * (int)dst[3]);
1033
+
1034
+ dst[0] = (unsigned char)r;
1035
+ dst[1] = (unsigned char)g;
1036
+ dst[2] = (unsigned char)b;
1037
+ dst[3] = (unsigned char)a;
1038
+
1039
+ cover++;
1040
+ dst += 4;
1041
+ }
1042
+ } else if (cache->type == NSVG_PAINT_LINEAR_GRADIENT) {
1043
+ // TODO: spread modes.
1044
+ // TODO: plenty of opportunities to optimize.
1045
+ float fx, fy, dx, gy;
1046
+ float* t = cache->xform;
1047
+ int i, cr, cg, cb, ca;
1048
+ unsigned int c;
1049
+
1050
+ fx = ((float)x - tx) / sx;
1051
+ fy = ((float)y - ty) / sy;
1052
+ dx = 1.0f / sx;
1053
+
1054
+ for (i = 0; i < count; i++) {
1055
+ int r,g,b,a,ia;
1056
+ gy = fx*t[1] + fy*t[3] + t[5];
1057
+ c = cache->colors[(int)nsvg__clampf(gy*255.0f, 0, 255.0f)];
1058
+ cr = (c) & 0xff;
1059
+ cg = (c >> 8) & 0xff;
1060
+ cb = (c >> 16) & 0xff;
1061
+ ca = (c >> 24) & 0xff;
1062
+
1063
+ a = nsvg__div255((int)cover[0] * ca);
1064
+ ia = 255 - a;
1065
+
1066
+ // Premultiply
1067
+ r = nsvg__div255(cr * a);
1068
+ g = nsvg__div255(cg * a);
1069
+ b = nsvg__div255(cb * a);
1070
+
1071
+ // Blend over
1072
+ r += nsvg__div255(ia * (int)dst[0]);
1073
+ g += nsvg__div255(ia * (int)dst[1]);
1074
+ b += nsvg__div255(ia * (int)dst[2]);
1075
+ a += nsvg__div255(ia * (int)dst[3]);
1076
+
1077
+ dst[0] = (unsigned char)r;
1078
+ dst[1] = (unsigned char)g;
1079
+ dst[2] = (unsigned char)b;
1080
+ dst[3] = (unsigned char)a;
1081
+
1082
+ cover++;
1083
+ dst += 4;
1084
+ fx += dx;
1085
+ }
1086
+ } else if (cache->type == NSVG_PAINT_RADIAL_GRADIENT) {
1087
+ // TODO: spread modes.
1088
+ // TODO: plenty of opportunities to optimize.
1089
+ // TODO: focus (fx,fy)
1090
+ float fx, fy, dx, gx, gy, gd;
1091
+ float* t = cache->xform;
1092
+ int i, cr, cg, cb, ca;
1093
+ unsigned int c;
1094
+
1095
+ fx = ((float)x - tx) / sx;
1096
+ fy = ((float)y - ty) / sy;
1097
+ dx = 1.0f / sx;
1098
+
1099
+ for (i = 0; i < count; i++) {
1100
+ int r,g,b,a,ia;
1101
+ gx = fx*t[0] + fy*t[2] + t[4];
1102
+ gy = fx*t[1] + fy*t[3] + t[5];
1103
+ gd = sqrtf(gx*gx + gy*gy);
1104
+ c = cache->colors[(int)nsvg__clampf(gd*255.0f, 0, 255.0f)];
1105
+ cr = (c) & 0xff;
1106
+ cg = (c >> 8) & 0xff;
1107
+ cb = (c >> 16) & 0xff;
1108
+ ca = (c >> 24) & 0xff;
1109
+
1110
+ a = nsvg__div255((int)cover[0] * ca);
1111
+ ia = 255 - a;
1112
+
1113
+ // Premultiply
1114
+ r = nsvg__div255(cr * a);
1115
+ g = nsvg__div255(cg * a);
1116
+ b = nsvg__div255(cb * a);
1117
+
1118
+ // Blend over
1119
+ r += nsvg__div255(ia * (int)dst[0]);
1120
+ g += nsvg__div255(ia * (int)dst[1]);
1121
+ b += nsvg__div255(ia * (int)dst[2]);
1122
+ a += nsvg__div255(ia * (int)dst[3]);
1123
+
1124
+ dst[0] = (unsigned char)r;
1125
+ dst[1] = (unsigned char)g;
1126
+ dst[2] = (unsigned char)b;
1127
+ dst[3] = (unsigned char)a;
1128
+
1129
+ cover++;
1130
+ dst += 4;
1131
+ fx += dx;
1132
+ }
1133
+ }
1134
+}
1135
+
1136
+static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, float sx, float sy, NSVGcachedPaint* cache, char fillRule)
1137
+{
1138
+ NSVGactiveEdge *active = NULL;
1139
+ int y, s;
1140
+ int e = 0;
1141
+ int maxWeight = (255 / NSVG__SUBSAMPLES); // weight per vertical scanline
1142
+ int xmin, xmax;
1143
+
1144
+ for (y = 0; y < r->height; y++) {
1145
+ memset(r->scanline, 0, r->width);
1146
+ xmin = r->width;
1147
+ xmax = 0;
1148
+ for (s = 0; s < NSVG__SUBSAMPLES; ++s) {
1149
+ // find center of pixel for this scanline
1150
+ float scany = (float)(y*NSVG__SUBSAMPLES + s) + 0.5f;
1151
+ NSVGactiveEdge **step = &active;
1152
+
1153
+ // update all active edges;
1154
+ // remove all active edges that terminate before the center of this scanline
1155
+ while (*step) {
1156
+ NSVGactiveEdge *z = *step;
1157
+ if (z->ey <= scany) {
1158
+ *step = z->next; // delete from list
1159
+// NSVG__assert(z->valid);
1160
+ nsvg__freeActive(r, z);
1161
+ } else {
1162
+ z->x += z->dx; // advance to position for current scanline
1163
+ step = &((*step)->next); // advance through list
1164
+ }
1165
+ }
1166
+
1167
+ // resort the list if needed
1168
+ for (;;) {
1169
+ int changed = 0;
1170
+ step = &active;
1171
+ while (*step && (*step)->next) {
1172
+ if ((*step)->x > (*step)->next->x) {
1173
+ NSVGactiveEdge* t = *step;
1174
+ NSVGactiveEdge* q = t->next;
1175
+ t->next = q->next;
1176
+ q->next = t;
1177
+ *step = q;
1178
+ changed = 1;
1179
+ }
1180
+ step = &(*step)->next;
1181
+ }
1182
+ if (!changed) break;
1183
+ }
1184
+
1185
+ // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline
1186
+ while (e < r->nedges && r->edges[e].y0 <= scany) {
1187
+ if (r->edges[e].y1 > scany) {
1188
+ NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany);
1189
+ if (z == NULL) break;
1190
+ // find insertion point
1191
+ if (active == NULL) {
1192
+ active = z;
1193
+ } else if (z->x < active->x) {
1194
+ // insert at front
1195
+ z->next = active;
1196
+ active = z;
1197
+ } else {
1198
+ // find thing to insert AFTER
1199
+ NSVGactiveEdge* p = active;
1200
+ while (p->next && p->next->x < z->x)
1201
+ p = p->next;
1202
+ // at this point, p->next->x is NOT < z->x
1203
+ z->next = p->next;
1204
+ p->next = z;
1205
+ }
1206
+ }
1207
+ e++;
1208
+ }
1209
+
1210
+ // now process all active edges in non-zero fashion
1211
+ if (active != NULL)
1212
+ nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, &xmin, &xmax, fillRule);
1213
+ }
1214
+ // Blit
1215
+ if (xmin < 0) xmin = 0;
1216
+ if (xmax > r->width-1) xmax = r->width-1;
1217
+ if (xmin <= xmax) {
1218
+ nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty, sx, sy, cache);
1219
+ }
1220
+ }
1221
+
1222
+}
1223
+
1224
+static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int stride)
1225
+{
1226
+ int x,y;
1227
+
1228
+ // Unpremultiply
1229
+ for (y = 0; y < h; y++) {
1230
+ unsigned char *row = &image[y*stride];
1231
+ for (x = 0; x < w; x++) {
1232
+ int r = row[0], g = row[1], b = row[2], a = row[3];
1233
+ if (a != 0) {
1234
+ row[0] = (unsigned char)(r*255/a);
1235
+ row[1] = (unsigned char)(g*255/a);
1236
+ row[2] = (unsigned char)(b*255/a);
1237
+ }
1238
+ row += 4;
1239
+ }
1240
+ }
1241
+
1242
+ // Defringe
1243
+ for (y = 0; y < h; y++) {
1244
+ unsigned char *row = &image[y*stride];
1245
+ for (x = 0; x < w; x++) {
1246
+ int r = 0, g = 0, b = 0, a = row[3], n = 0;
1247
+ if (a == 0) {
1248
+ if (x-1 > 0 && row[-1] != 0) {
1249
+ r += row[-4];
1250
+ g += row[-3];
1251
+ b += row[-2];
1252
+ n++;
1253
+ }
1254
+ if (x+1 < w && row[7] != 0) {
1255
+ r += row[4];
1256
+ g += row[5];
1257
+ b += row[6];
1258
+ n++;
1259
+ }
1260
+ if (y-1 > 0 && row[-stride+3] != 0) {
1261
+ r += row[-stride];
1262
+ g += row[-stride+1];
1263
+ b += row[-stride+2];
1264
+ n++;
1265
+ }
1266
+ if (y+1 < h && row[stride+3] != 0) {
1267
+ r += row[stride];
1268
+ g += row[stride+1];
1269
+ b += row[stride+2];
1270
+ n++;
1271
+ }
1272
+ if (n > 0) {
1273
+ row[0] = (unsigned char)(r/n);
1274
+ row[1] = (unsigned char)(g/n);
1275
+ row[2] = (unsigned char)(b/n);
1276
+ }
1277
+ }
1278
+ row += 4;
1279
+ }
1280
+ }
1281
+}
1282
+
1283
+
1284
+static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opacity)
1285
+{
1286
+ int i, j;
1287
+ NSVGgradient* grad;
1288
+
1289
+ cache->type = paint->type;
1290
+
1291
+ if (paint->type == NSVG_PAINT_COLOR) {
1292
+ cache->colors[0] = nsvg__applyOpacity(paint->color, opacity);
1293
+ return;
1294
+ }
1295
+
1296
+ grad = paint->gradient;
1297
+
1298
+ cache->spread = grad->spread;
1299
+ memcpy(cache->xform, grad->xform, sizeof(float)*6);
1300
+
1301
+ if (grad->nstops == 0) {
1302
+ for (i = 0; i < 256; i++)
1303
+ cache->colors[i] = 0;
1304
+ } if (grad->nstops == 1) {
1305
+ for (i = 0; i < 256; i++)
1306
+ cache->colors[i] = nsvg__applyOpacity(grad->stops[i].color, opacity);
1307
+ } else {
1308
+ unsigned int ca, cb = 0;
1309
+ float ua, ub, du, u;
1310
+ int ia, ib, count;
1311
+
1312
+ ca = nsvg__applyOpacity(grad->stops[0].color, opacity);
1313
+ ua = nsvg__clampf(grad->stops[0].offset, 0, 1);
1314
+ ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1);
1315
+ ia = (int)(ua * 255.0f);
1316
+ ib = (int)(ub * 255.0f);
1317
+ for (i = 0; i < ia; i++) {
1318
+ cache->colors[i] = ca;
1319
+ }
1320
+
1321
+ for (i = 0; i < grad->nstops-1; i++) {
1322
+ ca = nsvg__applyOpacity(grad->stops[i].color, opacity);
1323
+ cb = nsvg__applyOpacity(grad->stops[i+1].color, opacity);
1324
+ ua = nsvg__clampf(grad->stops[i].offset, 0, 1);
1325
+ ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1);
1326
+ ia = (int)(ua * 255.0f);
1327
+ ib = (int)(ub * 255.0f);
1328
+ count = ib - ia;
1329
+ if (count <= 0) continue;
1330
+ u = 0;
1331
+ du = 1.0f / (float)count;
1332
+ for (j = 0; j < count; j++) {
1333
+ cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u);
1334
+ u += du;
1335
+ }
1336
+ }
1337
+
1338
+ for (i = ib; i < 256; i++)
1339
+ cache->colors[i] = cb;
1340
+ }
1341
+
1342
+}
1343
+
1344
+/*
1345
+static void dumpEdges(NSVGrasterizer* r, const char* name)
1346
+{
1347
+ float xmin = 0, xmax = 0, ymin = 0, ymax = 0;
1348
+ NSVGedge *e = NULL;
1349
+ int i;
1350
+ if (r->nedges == 0) return;
1351
+ FILE* fp = fopen(name, "w");
1352
+ if (fp == NULL) return;
1353
+
1354
+ xmin = xmax = r->edges[0].x0;
1355
+ ymin = ymax = r->edges[0].y0;
1356
+ for (i = 0; i < r->nedges; i++) {
1357
+ e = &r->edges[i];
1358
+ xmin = nsvg__minf(xmin, e->x0);
1359
+ xmin = nsvg__minf(xmin, e->x1);
1360
+ xmax = nsvg__maxf(xmax, e->x0);
1361
+ xmax = nsvg__maxf(xmax, e->x1);
1362
+ ymin = nsvg__minf(ymin, e->y0);
1363
+ ymin = nsvg__minf(ymin, e->y1);
1364
+ ymax = nsvg__maxf(ymax, e->y0);
1365
+ ymax = nsvg__maxf(ymax, e->y1);
1366
+ }
1367
+
1368
+ fprintf(fp, "<svg viewBox=\"%f %f %f %f\" xmlns=\"http://www.w3.org/2000/svg\">", xmin, ymin, (xmax - xmin), (ymax - ymin));
1369
+
1370
+ for (i = 0; i < r->nedges; i++) {
1371
+ e = &r->edges[i];
1372
+ fprintf(fp ,"<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" style=\"stroke:#000;\" />", e->x0,e->y0, e->x1,e->y1);
1373
+ }
1374
+
1375
+ for (i = 0; i < r->npoints; i++) {
1376
+ if (i+1 < r->npoints)
1377
+ fprintf(fp ,"<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" style=\"stroke:#f00;\" />", r->points[i].x, r->points[i].y, r->points[i+1].x, r->points[i+1].y);
1378
+ fprintf(fp ,"<circle cx=\"%f\" cy=\"%f\" r=\"1\" style=\"fill:%s;\" />", r->points[i].x, r->points[i].y, r->points[i].flags == 0 ? "#f00" : "#0f0");
1379
+ }
1380
+
1381
+ fprintf(fp, "</svg>");
1382
+ fclose(fp);
1383
+}
1384
+*/
1385
+
1386
+static void nsvgRasterizeXY(NSVGrasterizer* r,
1387
+ NSVGimage* image, float tx, float ty,
1388
+ float sx, float sy,
1389
+ unsigned char* dst, int w, int h, int stride)
1390
+{
1391
+ NSVGshape *shape = NULL;
1392
+ NSVGedge *e = NULL;
1393
+ NSVGcachedPaint cache;
1394
+ int i;
1395
+
1396
+ r->bitmap = dst;
1397
+ r->width = w;
1398
+ r->height = h;
1399
+ r->stride = stride;
1400
+
1401
+ if (w > r->cscanline) {
1402
+ r->cscanline = w;
1403
+ r->scanline = (unsigned char*)realloc(r->scanline, w);
1404
+ if (r->scanline == NULL) return;
1405
+ }
1406
+
1407
+ for (i = 0; i < h; i++)
1408
+ memset(&dst[i*stride], 0, w*4);
1409
+
1410
+ for (shape = image->shapes; shape != NULL; shape = shape->next) {
1411
+ if (!(shape->flags & NSVG_FLAGS_VISIBLE))
1412
+ continue;
1413
+
1414
+ if (shape->fill.type != NSVG_PAINT_NONE) {
1415
+ nsvg__resetPool(r);
1416
+ r->freelist = NULL;
1417
+ r->nedges = 0;
1418
+
1419
+ nsvg__flattenShape(r, shape, sx, sy);
1420
+
1421
+ // Scale and translate edges
1422
+ for (i = 0; i < r->nedges; i++) {
1423
+ e = &r->edges[i];
1424
+ e->x0 = tx + e->x0;
1425
+ e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
1426
+ e->x1 = tx + e->x1;
1427
+ e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
1428
+ }
1429
+
1430
+ // Rasterize edges
1431
+ if (r->nedges != 0)
1432
+ qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
1433
+
1434
+ // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
1435
+ nsvg__initPaint(&cache, &shape->fill, shape->opacity);
1436
+
1437
+ nsvg__rasterizeSortedEdges(r, tx,ty, sx, sy, &cache, shape->fillRule);
1438
+ }
1439
+ if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * sx) > 0.01f) {
1440
+ nsvg__resetPool(r);
1441
+ r->freelist = NULL;
1442
+ r->nedges = 0;
1443
+
1444
+ nsvg__flattenShapeStroke(r, shape, sx, sy);
1445
+
1446
+// dumpEdges(r, "edge.svg");
1447
+
1448
+ // Scale and translate edges
1449
+ for (i = 0; i < r->nedges; i++) {
1450
+ e = &r->edges[i];
1451
+ e->x0 = tx + e->x0;
1452
+ e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
1453
+ e->x1 = tx + e->x1;
1454
+ e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
1455
+ }
1456
+
1457
+ // Rasterize edges
1458
+ if (r->nedges != 0)
1459
+ qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
1460
+
1461
+ // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
1462
+ nsvg__initPaint(&cache, &shape->stroke, shape->opacity);
1463
+
1464
+ nsvg__rasterizeSortedEdges(r, tx,ty,sx, sy, &cache, NSVG_FILLRULE_NONZERO);
1465
+ }
1466
+ }
1467
+
1468
+ nsvg__unpremultiplyAlpha(dst, w, h, stride);
1469
+
1470
+ r->bitmap = NULL;
1471
+ r->width = 0;
1472
+ r->height = 0;
1473
+ r->stride = 0;
1474
+}
1475
+
1476
+static void nsvgRasterize(NSVGrasterizer* r,
1477
+ NSVGimage* image, float tx, float ty, float scale,
1478
+ unsigned char* dst, int w, int h, int stride)
1479
+{
1480
+ nsvgRasterizeXY(r,image, tx, ty, scale, scale, dst, w, h, stride);
1481
+}
1482
+
1483
+#endif // NANOSVGRAST_IMPLEMENTATION
1484
+
1485
+#endif // NANOSVGRAST_H
1486
1487