37#ifndef NANOSVGRAST_CPLUSPLUS
75 unsigned char* dst,
int w,
int h,
int stride);
81 unsigned char* dst,
int w,
int h,
int stride);
87#ifndef NANOSVGRAST_CPLUSPLUS
93#ifdef NANOSVGRAST_IMPLEMENTATION
99#define NSVG__SUBSAMPLES 5
100#define NSVG__FIXSHIFT 10
101#define NSVG__FIX (1 << NSVG__FIXSHIFT)
102#define NSVG__FIXMASK (NSVG__FIX-1)
103#define NSVG__MEMPAGE_SIZE 1024
105typedef struct NSVGedge {
108 struct NSVGedge* next;
111typedef struct NSVGpoint {
119typedef struct NSVGactiveEdge {
123 struct NSVGactiveEdge *next;
126typedef struct NSVGmemPage {
127 unsigned char mem[NSVG__MEMPAGE_SIZE];
129 struct NSVGmemPage* next;
132typedef struct NSVGcachedPaint {
136 unsigned int colors[256];
158 NSVGactiveEdge* freelist;
160 NSVGmemPage* curpage;
162 unsigned char* scanline;
165 unsigned char* bitmap;
166 int width, height, stride;
172 if (r == NULL)
goto error;
189 if (r == NULL)
return;
193 NSVGmemPage* next = p->next;
198 if (r->edges) free(r->edges);
199 if (r->points) free(r->points);
200 if (r->points2) free(r->points2);
201 if (r->scanline) free(r->scanline);
206static NSVGmemPage* nsvg__nextPage(
NSVGrasterizer* r, NSVGmemPage* cur)
211 if (cur != NULL && cur->next != NULL) {
216 newp = (NSVGmemPage*)malloc(
sizeof(NSVGmemPage));
217 if (newp == NULL)
return NULL;
218 memset(newp, 0,
sizeof(NSVGmemPage));
231 NSVGmemPage* p = r->pages;
236 r->curpage = r->pages;
242 if (size > NSVG__MEMPAGE_SIZE)
return NULL;
243 if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) {
244 r->curpage = nsvg__nextPage(r, r->curpage);
246 buf = &r->curpage->mem[r->curpage->size];
247 r->curpage->size += size;
251static int nsvg__ptEquals(
float x1,
float y1,
float x2,
float y2,
float tol)
255 return dx*dx + dy*dy < tol*tol;
258static void nsvg__addPathPoint(
NSVGrasterizer* r,
float x,
float y,
int flags)
262 if (r->npoints > 0) {
263 pt = &r->points[r->npoints-1];
264 if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) {
265 pt->flags = (
unsigned char)(pt->flags | flags);
270 if (r->npoints+1 > r->cpoints) {
271 r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
272 r->points = (NSVGpoint*)realloc(r->points,
sizeof(NSVGpoint) * r->cpoints);
273 if (r->points == NULL)
return;
276 pt = &r->points[r->npoints];
279 pt->flags = (
unsigned char)flags;
285 if (r->npoints+1 > r->cpoints) {
286 r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
287 r->points = (NSVGpoint*)realloc(r->points,
sizeof(NSVGpoint) * r->cpoints);
288 if (r->points == NULL)
return;
290 r->points[r->npoints] = pt;
296 if (r->npoints > r->cpoints2) {
297 r->cpoints2 = r->npoints;
298 r->points2 = (NSVGpoint*)realloc(r->points2,
sizeof(NSVGpoint) * r->cpoints2);
299 if (r->points2 == NULL)
return;
302 memcpy(r->points2, r->points,
sizeof(NSVGpoint) * r->npoints);
303 r->npoints2 = r->npoints;
306static void nsvg__addEdge(
NSVGrasterizer* r,
float x0,
float y0,
float x1,
float y1)
314 if (r->nedges+1 > r->cedges) {
315 r->cedges = r->cedges > 0 ? r->cedges * 2 : 64;
316 r->edges = (NSVGedge*)realloc(r->edges,
sizeof(NSVGedge) * r->cedges);
317 if (r->edges == NULL)
return;
320 e = &r->edges[r->nedges];
338static float nsvg__normalize(
float *x,
float* y)
340 float d = sqrtf((*x)*(*x) + (*y)*(*y));
349static float nsvg__absf(
float x) {
return x < 0 ? -x : x; }
350static float nsvg__roundf(
float x) {
return (x >= 0) ? floorf(x + 0.5) : ceilf(x - 0.5); }
353 float x1,
float y1,
float x2,
float y2,
354 float x3,
float y3,
float x4,
float y4,
357 float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;
360 if (level > 10)
return;
368 x123 = (x12+x23)*0.5f;
369 y123 = (y12+y23)*0.5f;
373 d2 = nsvg__absf(((x2 - x4) * dy - (y2 - y4) * dx));
374 d3 = nsvg__absf(((x3 - x4) * dy - (y3 - y4) * dx));
376 if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) {
377 nsvg__addPathPoint(r, x4, y4, type);
381 x234 = (x23+x34)*0.5f;
382 y234 = (y23+y34)*0.5f;
383 x1234 = (x123+x234)*0.5f;
384 y1234 = (y123+y234)*0.5f;
386 nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0);
387 nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type);
398 nsvg__addPathPoint(r,
path->pts[0]*sx,
path->pts[1]*sy, 0);
399 for (i = 0; i <
path->npts-1; i += 3) {
400 float* p = &
path->pts[i*2];
401 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);
404 nsvg__addPathPoint(r,
path->pts[0]*sx,
path->pts[1]*sy, 0);
406 for (i = 0, j = r->npoints-1; i < r->npoints; j = i++)
407 nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y);
413 NSVG_PT_CORNER = 0x01,
414 NSVG_PT_BEVEL = 0x02,
418static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1,
float lineWidth)
420 float w = lineWidth * 0.5f;
421 float dx = p1->x - p0->x;
422 float dy = p1->y - p0->y;
423 float len = nsvg__normalize(&dx, &dy);
424 float px = p0->x + dx*len*0.5f, py = p0->y + dy*len*0.5f;
425 float dlx = dy, dly = -dx;
426 float lx = px - dlx*w, ly = py - dly*w;
427 float rx = px + dlx*w, ry = py + dly*w;
428 left->x = lx; left->y = ly;
429 right->x = rx; right->y = ry;
432static void nsvg__buttCap(
NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p,
float dx,
float dy,
float lineWidth,
int connect)
434 float w = lineWidth * 0.5f;
435 float px = p->x, py = p->y;
436 float dlx = dy, dly = -dx;
437 float lx = px - dlx*w, ly = py - dly*w;
438 float rx = px + dlx*w, ry = py + dly*w;
440 nsvg__addEdge(r, lx, ly, rx, ry);
443 nsvg__addEdge(r, left->x, left->y, lx, ly);
444 nsvg__addEdge(r, rx, ry, right->x, right->y);
446 left->x = lx; left->y = ly;
447 right->x = rx; right->y = ry;
450static void nsvg__squareCap(
NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p,
float dx,
float dy,
float lineWidth,
int connect)
452 float w = lineWidth * 0.5f;
453 float px = p->x - dx*w, py = p->y - dy*w;
454 float dlx = dy, dly = -dx;
455 float lx = px - dlx*w, ly = py - dly*w;
456 float rx = px + dlx*w, ry = py + dly*w;
458 nsvg__addEdge(r, lx, ly, rx, ry);
461 nsvg__addEdge(r, left->x, left->y, lx, ly);
462 nsvg__addEdge(r, rx, ry, right->x, right->y);
464 left->x = lx; left->y = ly;
465 right->x = rx; right->y = ry;
469#define NSVG_PI (3.14159265358979323846264338327f)
472static void nsvg__roundCap(
NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p,
float dx,
float dy,
float lineWidth,
int ncap,
int connect)
475 float w = lineWidth * 0.5f;
476 float px = p->x, py = p->y;
477 float dlx = dy, dly = -dx;
478 float lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0;
480 for (i = 0; i < ncap; i++) {
481 float a = (float)i/(
float)(ncap-1)*NSVG_PI;
482 float ax = cosf(a) * w, ay = sinf(a) * w;
483 float x = px - dlx*ax - dx*ay;
484 float y = py - dly*ax - dy*ay;
487 nsvg__addEdge(r, prevx, prevy, x, y);
494 }
else if (i == ncap-1) {
500 nsvg__addEdge(r, left->x, left->y, lx, ly);
501 nsvg__addEdge(r, rx, ry, right->x, right->y);
504 left->x = lx; left->y = ly;
505 right->x = rx; right->y = ry;
508static void nsvg__bevelJoin(
NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1,
float lineWidth)
510 float w = lineWidth * 0.5f;
511 float dlx0 = p0->dy, dly0 = -p0->dx;
512 float dlx1 = p1->dy, dly1 = -p1->dx;
513 float lx0 = p1->x - (dlx0 * w), ly0 = p1->y - (dly0 * w);
514 float rx0 = p1->x + (dlx0 * w), ry0 = p1->y + (dly0 * w);
515 float lx1 = p1->x - (dlx1 * w), ly1 = p1->y - (dly1 * w);
516 float rx1 = p1->x + (dlx1 * w), ry1 = p1->y + (dly1 * w);
518 nsvg__addEdge(r, lx0, ly0, left->x, left->y);
519 nsvg__addEdge(r, lx1, ly1, lx0, ly0);
521 nsvg__addEdge(r, right->x, right->y, rx0, ry0);
522 nsvg__addEdge(r, rx0, ry0, rx1, ry1);
524 left->x = lx1; left->y = ly1;
525 right->x = rx1; right->y = ry1;
528static void nsvg__miterJoin(
NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1,
float lineWidth)
530 float w = lineWidth * 0.5f;
531 float dlx0 = p0->dy, dly0 = -p0->dx;
532 float dlx1 = p1->dy, dly1 = -p1->dx;
533 float lx0, rx0, lx1, rx1;
534 float ly0, ry0, ly1, ry1;
536 if (p1->flags & NSVG_PT_LEFT) {
537 lx0 = lx1 = p1->x - p1->dmx * w;
538 ly0 = ly1 = p1->y - p1->dmy * w;
539 nsvg__addEdge(r, lx1, ly1, left->x, left->y);
541 rx0 = p1->x + (dlx0 * w);
542 ry0 = p1->y + (dly0 * w);
543 rx1 = p1->x + (dlx1 * w);
544 ry1 = p1->y + (dly1 * w);
545 nsvg__addEdge(r, right->x, right->y, rx0, ry0);
546 nsvg__addEdge(r, rx0, ry0, rx1, ry1);
548 lx0 = p1->x - (dlx0 * w);
549 ly0 = p1->y - (dly0 * w);
550 lx1 = p1->x - (dlx1 * w);
551 ly1 = p1->y - (dly1 * w);
552 nsvg__addEdge(r, lx0, ly0, left->x, left->y);
553 nsvg__addEdge(r, lx1, ly1, lx0, ly0);
555 rx0 = rx1 = p1->x + p1->dmx * w;
556 ry0 = ry1 = p1->y + p1->dmy * w;
557 nsvg__addEdge(r, right->x, right->y, rx1, ry1);
560 left->x = lx1; left->y = ly1;
561 right->x = rx1; right->y = ry1;
564static void nsvg__roundJoin(
NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1,
float lineWidth,
int ncap)
567 float w = lineWidth * 0.5f;
568 float dlx0 = p0->dy, dly0 = -p0->dx;
569 float dlx1 = p1->dy, dly1 = -p1->dx;
570 float a0 = atan2f(dly0, dlx0);
571 float a1 = atan2f(dly1, dlx1);
573 float lx, ly, rx, ry;
575 if (da < NSVG_PI) da += NSVG_PI*2;
576 if (da > NSVG_PI) da -= NSVG_PI*2;
578 n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * (float)ncap);
580 if (n > ncap) n = ncap;
587 for (i = 0; i < n; i++) {
588 float u = (float)i/(
float)(n-1);
590 float ax = cosf(a) * w, ay = sinf(a) * w;
591 float lx1 = p1->x - ax, ly1 = p1->y - ay;
592 float rx1 = p1->x + ax, ry1 = p1->y + ay;
594 nsvg__addEdge(r, lx1, ly1, lx, ly);
595 nsvg__addEdge(r, rx, ry, rx1, ry1);
601 left->x = lx; left->y = ly;
602 right->x = rx; right->y = ry;
605static void nsvg__straightJoin(
NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p1,
float lineWidth)
607 float w = lineWidth * 0.5f;
608 float lx = p1->x - (p1->dmx * w), ly = p1->y - (p1->dmy * w);
609 float rx = p1->x + (p1->dmx * w), ry = p1->y + (p1->dmy * w);
611 nsvg__addEdge(r, lx, ly, left->x, left->y);
612 nsvg__addEdge(r, right->x, right->y, rx, ry);
614 left->x = lx; left->y = ly;
615 right->x = rx; right->y = ry;
618static int nsvg__curveDivs(
float r,
float arc,
float tol)
620 float da = acosf(r / (r + tol)) * 2.0f;
621 int divs = (int)ceilf(arc / da);
622 if (divs < 2) divs = 2;
626static void nsvg__expandStroke(
NSVGrasterizer* r, NSVGpoint* points,
int npoints,
int closed,
int lineJoin,
int lineCap,
float lineWidth)
628 int ncap = nsvg__curveDivs(lineWidth*0.5f, NSVG_PI, r->tessTol);
629 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};
636 p0 = &points[npoints-1];
649 nsvg__initClosed(&left, &right, p0, p1, lineWidth);
654 float dx = p1->x - p0->x;
655 float dy = p1->y - p0->y;
656 nsvg__normalize(&dx, &dy);
658 nsvg__buttCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
660 nsvg__squareCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
662 nsvg__roundCap(r, &left, &right, p0, dx, dy, lineWidth, ncap, 0);
665 for (j = s; j < e; ++j) {
666 if (p1->flags & NSVG_PT_CORNER) {
668 nsvg__roundJoin(r, &left, &right, p0, p1, lineWidth, ncap);
670 nsvg__bevelJoin(r, &left, &right, p0, p1, lineWidth);
672 nsvg__miterJoin(r, &left, &right, p0, p1, lineWidth);
674 nsvg__straightJoin(r, &left, &right, p1, lineWidth);
681 nsvg__addEdge(r, firstLeft.x, firstLeft.y, left.x, left.y);
682 nsvg__addEdge(r, right.x, right.y, firstRight.x, firstRight.y);
685 float dx = p1->x - p0->x;
686 float dy = p1->y - p0->y;
687 nsvg__normalize(&dx, &dy);
689 nsvg__buttCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
691 nsvg__squareCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
693 nsvg__roundCap(r, &right, &left, p1, -dx, -dy, lineWidth, ncap, 1);
697static void nsvg__prepareStroke(
NSVGrasterizer* r,
float miterLimit,
int lineJoin)
702 p0 = &r->points[r->npoints-1];
704 for (i = 0; i < r->npoints; i++) {
706 p0->dx = p1->x - p0->x;
707 p0->dy = p1->y - p0->y;
708 p0->len = nsvg__normalize(&p0->dx, &p0->dy);
714 p0 = &r->points[r->npoints-1];
716 for (j = 0; j < r->npoints; j++) {
717 float dlx0, dly0, dlx1, dly1, dmr2, cross;
723 p1->dmx = (dlx0 + dlx1) * 0.5f;
724 p1->dmy = (dly0 + dly1) * 0.5f;
725 dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy;
726 if (dmr2 > 0.000001f) {
727 float s2 = 1.0f / dmr2;
736 p1->flags = (p1->flags & NSVG_PT_CORNER) ? NSVG_PT_CORNER : 0;
739 cross = p1->dx * p0->dy - p0->dx * p1->dy;
741 p1->flags |= NSVG_PT_LEFT;
744 if (p1->flags & NSVG_PT_CORNER) {
746 p1->flags |= NSVG_PT_BEVEL;
762 const float sw = (sx + sy) / 2;
768 nsvg__addPathPoint(r,
path->pts[0]*sx,
path->pts[1]*sy, NSVG_PT_CORNER);
769 for (i = 0; i <
path->npts-1; i += 3) {
770 float* p = &
path->pts[i*2];
771 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);
776 closed =
path->closed;
779 p0 = &r->points[r->npoints-1];
781 if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) {
783 p0 = &r->points[r->npoints-1];
788 int idash = 0, dashState = 1;
789 float totalDist = 0, dashLen, allDashLen, dashOffset;
793 nsvg__appendPathPoint(r, r->points[0]);
796 nsvg__duplicatePoints(r);
800 nsvg__appendPathPoint(r, cur);
810 if (dashOffset < 0.0f)
811 dashOffset += allDashLen;
819 for (j = 1; j < r->npoints2; ) {
820 float dx = r->points2[j].x - cur.x;
821 float dy = r->points2[j].y - cur.y;
822 float dist = sqrtf(dx*dx + dy*dy);
824 if ((totalDist + dist) > dashLen) {
826 float d = (dashLen - totalDist) / dist;
827 float x = cur.x + dx * d;
828 float y = cur.y + dy * d;
829 nsvg__addPathPoint(r, x, y, NSVG_PT_CORNER);
832 if (r->npoints > 1 && dashState) {
833 nsvg__prepareStroke(r, miterLimit, lineJoin);
834 nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);
837 dashState = !dashState;
843 cur.flags = NSVG_PT_CORNER;
846 nsvg__appendPathPoint(r, cur);
850 nsvg__appendPathPoint(r, cur);
855 if (r->npoints > 1 && dashState)
856 nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);
858 nsvg__prepareStroke(r, miterLimit, lineJoin);
859 nsvg__expandStroke(r, r->points, r->npoints, closed, lineJoin, lineCap, lineWidth);
864static int nsvg__cmpEdge(
const void *p,
const void *q)
866 const NSVGedge* a = (
const NSVGedge*)p;
867 const NSVGedge* b = (
const NSVGedge*)q;
869 if (a->y0 < b->y0)
return -1;
870 if (a->y0 > b->y0)
return 1;
875static NSVGactiveEdge* nsvg__addActive(
NSVGrasterizer* r, NSVGedge* e,
float startPoint)
879 if (r->freelist != NULL) {
882 r->freelist = z->next;
885 z = (NSVGactiveEdge*)nsvg__alloc(r,
sizeof(NSVGactiveEdge));
886 if (z == NULL)
return NULL;
889 float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
893 z->dx = (int)(-nsvg__roundf(NSVG__FIX * -dxdy));
895 z->dx = (int)nsvg__roundf(NSVG__FIX * dxdy);
896 z->x = (int)nsvg__roundf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0)));
907 z->next = r->freelist;
911static void nsvg__fillScanline(
unsigned char* scanline,
int len,
int x0,
int x1,
int maxWeight,
int* xmin,
int* xmax)
913 int i = x0 >> NSVG__FIXSHIFT;
914 int j = x1 >> NSVG__FIXSHIFT;
915 if (i < *xmin) *xmin = i;
916 if (j > *xmax) *xmax = j;
917 if (i < len && j >= 0) {
920 scanline[i] = (
unsigned char)(scanline[i] + ((x1 - x0) * maxWeight >> NSVG__FIXSHIFT));
923 scanline[i] = (
unsigned char)(scanline[i] + (((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT));
928 scanline[j] = (
unsigned char)(scanline[j] + (((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT));
932 for (++i; i < j; ++i)
933 scanline[i] = (
unsigned char)(scanline[i] + maxWeight);
941static void nsvg__fillActiveEdges(
unsigned char* scanline,
int len, NSVGactiveEdge* e,
int maxWeight,
int* xmin,
int* xmax,
char fillRule)
951 x0 = e->x; w += e->dir;
953 int x1 = e->x; w += e->dir;
956 nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);
967 int x1 = e->x; w = 0;
968 nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);
975static float nsvg__clampf(
float a,
float mn,
float mx) {
return a < mn ? mn : (a > mx ? mx : a); }
977static unsigned int nsvg__RGBA(
unsigned char r,
unsigned char g,
unsigned char b,
unsigned char a)
979 return ((
unsigned int)r) | ((
unsigned int)g << 8) | ((
unsigned int)b << 16) | ((
unsigned int)a << 24);
982static unsigned int nsvg__lerpRGBA(
unsigned int c0,
unsigned int c1,
float u)
984 int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
985 int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8;
986 int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8;
987 int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8;
988 int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8;
989 return nsvg__RGBA((
unsigned char)r, (
unsigned char)g, (
unsigned char)b, (
unsigned char)a);
992static unsigned int nsvg__applyOpacity(
unsigned int c,
float u)
994 int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
996 int g = (c>>8) & 0xff;
997 int b = (c>>16) & 0xff;
998 int a = (((c>>24) & 0xff)*iu) >> 8;
999 return nsvg__RGBA((
unsigned char)r, (
unsigned char)g, (
unsigned char)b, (
unsigned char)a);
1002static inline int nsvg__div255(
int x)
1004 return ((x+1) * 257) >> 16;
1007static void nsvg__scanlineSolid(
unsigned char* dst,
int count,
unsigned char* cover,
int x,
int y,
1008 float tx,
float ty,
float sx,
float sy, NSVGcachedPaint* cache)
1012 int i, cr, cg, cb, ca;
1013 cr = cache->colors[0] & 0xff;
1014 cg = (cache->colors[0] >> 8) & 0xff;
1015 cb = (cache->colors[0] >> 16) & 0xff;
1016 ca = (cache->colors[0] >> 24) & 0xff;
1018 for (i = 0; i < count; i++) {
1020 int a = nsvg__div255((
int)cover[0] * ca);
1023 r = nsvg__div255(cr * a);
1024 g = nsvg__div255(cg * a);
1025 b = nsvg__div255(cb * a);
1028 r += nsvg__div255(ia * (
int)dst[0]);
1029 g += nsvg__div255(ia * (
int)dst[1]);
1030 b += nsvg__div255(ia * (
int)dst[2]);
1031 a += nsvg__div255(ia * (
int)dst[3]);
1033 dst[0] = (
unsigned char)r;
1034 dst[1] = (
unsigned char)g;
1035 dst[2] = (
unsigned char)b;
1036 dst[3] = (
unsigned char)a;
1044 float fx, fy, dx, gy;
1045 float* t = cache->xform;
1046 int i, cr, cg, cb, ca;
1049 fx = ((float)x - tx) / sx;
1050 fy = ((float)y - ty) / sy;
1053 for (i = 0; i < count; i++) {
1055 gy = fx*t[1] + fy*t[3] + t[5];
1056 c = cache->colors[(int)nsvg__clampf(gy*255.0f, 0, 255.0f)];
1058 cg = (c >> 8) & 0xff;
1059 cb = (c >> 16) & 0xff;
1060 ca = (c >> 24) & 0xff;
1062 a = nsvg__div255((
int)cover[0] * ca);
1066 r = nsvg__div255(cr * a);
1067 g = nsvg__div255(cg * a);
1068 b = nsvg__div255(cb * a);
1071 r += nsvg__div255(ia * (
int)dst[0]);
1072 g += nsvg__div255(ia * (
int)dst[1]);
1073 b += nsvg__div255(ia * (
int)dst[2]);
1074 a += nsvg__div255(ia * (
int)dst[3]);
1076 dst[0] = (
unsigned char)r;
1077 dst[1] = (
unsigned char)g;
1078 dst[2] = (
unsigned char)b;
1079 dst[3] = (
unsigned char)a;
1089 float fx, fy, dx, gx, gy, gd;
1090 float* t = cache->xform;
1091 int i, cr, cg, cb, ca;
1094 fx = ((float)x - tx) / sx;
1095 fy = ((float)y - ty) / sy;
1098 for (i = 0; i < count; i++) {
1100 gx = fx*t[0] + fy*t[2] + t[4];
1101 gy = fx*t[1] + fy*t[3] + t[5];
1102 gd = sqrtf(gx*gx + gy*gy);
1103 c = cache->colors[(int)nsvg__clampf(gd*255.0f, 0, 255.0f)];
1105 cg = (c >> 8) & 0xff;
1106 cb = (c >> 16) & 0xff;
1107 ca = (c >> 24) & 0xff;
1109 a = nsvg__div255((
int)cover[0] * ca);
1113 r = nsvg__div255(cr * a);
1114 g = nsvg__div255(cg * a);
1115 b = nsvg__div255(cb * a);
1118 r += nsvg__div255(ia * (
int)dst[0]);
1119 g += nsvg__div255(ia * (
int)dst[1]);
1120 b += nsvg__div255(ia * (
int)dst[2]);
1121 a += nsvg__div255(ia * (
int)dst[3]);
1123 dst[0] = (
unsigned char)r;
1124 dst[1] = (
unsigned char)g;
1125 dst[2] = (
unsigned char)b;
1126 dst[3] = (
unsigned char)a;
1135static void nsvg__rasterizeSortedEdges(
NSVGrasterizer *r,
float tx,
float ty,
float sx,
float sy, NSVGcachedPaint* cache,
char fillRule)
1137 NSVGactiveEdge *active = NULL;
1140 int maxWeight = (255 / NSVG__SUBSAMPLES);
1143 for (y = 0; y < r->height; y++) {
1144 memset(r->scanline, 0, r->width);
1147 for (s = 0; s < NSVG__SUBSAMPLES; ++s) {
1149 float scany = (float)(y*NSVG__SUBSAMPLES + s) + 0.5f;
1150 NSVGactiveEdge **step = &active;
1155 NSVGactiveEdge *z = *step;
1156 if (z->ey <= scany) {
1159 nsvg__freeActive(r, z);
1162 step = &((*step)->next);
1170 while (*step && (*step)->next) {
1171 if ((*step)->x > (*step)->next->x) {
1172 NSVGactiveEdge* t = *step;
1173 NSVGactiveEdge* q = t->next;
1179 step = &(*step)->next;
1181 if (!changed)
break;
1185 while (e < r->nedges && r->edges[e].y0 <= scany) {
1186 if (r->edges[e].y1 > scany) {
1187 NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany);
1188 if (z == NULL)
break;
1190 if (active == NULL) {
1192 }
else if (z->x < active->x) {
1198 NSVGactiveEdge* p = active;
1199 while (p->next && p->next->x < z->x)
1211 nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, &xmin, &xmax, fillRule);
1214 if (xmin < 0) xmin = 0;
1215 if (xmax > r->width-1) xmax = r->width-1;
1217 nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty, sx, sy, cache);
1223static void nsvg__unpremultiplyAlpha(
unsigned char*
image,
int w,
int h,
int stride)
1228 for (y = 0; y < h; y++) {
1229 unsigned char *row = &
image[y*stride];
1230 for (x = 0; x < w; x++) {
1231 int r = row[0], g = row[1], b = row[2], a = row[3];
1233 row[0] = (
unsigned char)(r*255/a);
1234 row[1] = (
unsigned char)(g*255/a);
1235 row[2] = (
unsigned char)(b*255/a);
1242 for (y = 0; y < h; y++) {
1243 unsigned char *row = &
image[y*stride];
1244 for (x = 0; x < w; x++) {
1245 int r = 0, g = 0, b = 0, a = row[3], n = 0;
1247 if (x-1 > 0 && row[-1] != 0) {
1253 if (x+1 < w && row[7] != 0) {
1259 if (y-1 > 0 && row[-stride+3] != 0) {
1261 g += row[-stride+1];
1262 b += row[-stride+2];
1265 if (y+1 < h && row[stride+3] != 0) {
1272 row[0] = (
unsigned char)(r/n);
1273 row[1] = (
unsigned char)(g/n);
1274 row[2] = (
unsigned char)(b/n);
1283static void nsvg__initPaint(NSVGcachedPaint* cache,
NSVGpaint* paint,
float opacity)
1288 cache->type = paint->
type;
1291 cache->colors[0] = nsvg__applyOpacity(paint->
v.
color, opacity);
1297 cache->spread = grad->
spread;
1298 memcpy(cache->xform, grad->
xform,
sizeof(
float)*6);
1301 for (i = 0; i < 256; i++)
1302 cache->colors[i] = 0;
1303 }
else if (grad->
nstops == 1) {
1304 for (i = 0; i < 256; i++)
1305 cache->colors[i] = nsvg__applyOpacity(grad->
stops[i].
color, opacity);
1307 unsigned int ca, cb = 0;
1308 float ua, ub, du, u;
1311 ca = nsvg__applyOpacity(grad->
stops[0].
color, opacity);
1314 ia = (int)(ua * 255.0f);
1315 ib = (int)(ub * 255.0f);
1316 for (i = 0; i < ia; i++) {
1317 cache->colors[i] = ca;
1320 for (i = 0; i < grad->
nstops-1; i++) {
1321 ca = nsvg__applyOpacity(grad->
stops[i].
color, opacity);
1322 cb = nsvg__applyOpacity(grad->
stops[i+1].
color, opacity);
1325 ia = (int)(ua * 255.0f);
1326 ib = (int)(ub * 255.0f);
1328 if (count <= 0)
continue;
1330 du = 1.0f / (float)count;
1331 for (j = 0; j < count; j++) {
1332 cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u);
1337 for (i = ib; i < 256; i++)
1338 cache->colors[i] = cb;
1388 unsigned char* dst,
int w,
int h,
int stride)
1392 NSVGcachedPaint cache;
1400 if (w > r->cscanline) {
1402 r->scanline = (
unsigned char*)realloc(r->scanline, w);
1403 if (r->scanline == NULL)
return;
1406 for (i = 0; i < h; i++)
1407 memset(&dst[i*stride], 0, w*4);
1409 for (shape =
image->shapes; shape != NULL; shape = shape->
next) {
1418 nsvg__flattenShape(r, shape, sx, sy);
1421 for (i = 0; i < r->nedges; i++) {
1424 e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
1426 e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
1431 qsort(r->edges, r->nedges,
sizeof(NSVGedge), nsvg__cmpEdge);
1434 nsvg__initPaint(&cache, &shape->
fill, shape->
opacity);
1436 nsvg__rasterizeSortedEdges(r, tx,ty, sx, sy, &cache, shape->
fillRule);
1443 nsvg__flattenShapeStroke(r, shape, sx, sy);
1448 for (i = 0; i < r->nedges; i++) {
1451 e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
1453 e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
1458 qsort(r->edges, r->nedges,
sizeof(NSVGedge), nsvg__cmpEdge);
1467 nsvg__unpremultiplyAlpha(dst, w, h, stride);
1477 unsigned char* dst,
int w,
int h,
int stride)
static void error(char *msg)
@ NSVG_PAINT_RADIAL_GRADIENT
@ NSVG_PAINT_LINEAR_GRADIENT
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 nsvgRasterizeXY(NSVGrasterizer *r, NSVGimage *image, float tx, float ty, float sx, float sy, unsigned char *dst, int w, int h, int stride)
void nsvgDeleteRasterizer(NSVGrasterizer *)
struct NSVGrasterizer NSVGrasterizer
NSVGgradientStop stops[1]