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