|  |  | @@ -43,9 +43,9 @@ enum NVGcommands { | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | enum NVGpointFlags | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | NVG_BEVEL = 0x01, | 
		
	
		
			
			|  |  |  | NVG_LEFT = 0x02, | 
		
	
		
			
			|  |  |  | NVG_CUSP = 0x04, | 
		
	
		
			
			|  |  |  | NVG_PT_BEVEL = 0x01, | 
		
	
		
			
			|  |  |  | NVG_PT_LEFT = 0x02, | 
		
	
		
			
			|  |  |  | NVG_PT_CUSP = 0x04, | 
		
	
		
			
			|  |  |  | }; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | enum NVGexpandFeatures { | 
		
	
	
		
			
				|  |  | @@ -59,6 +59,8 @@ struct NVGstate { | 
		
	
		
			
			|  |  |  | struct NVGpaint stroke; | 
		
	
		
			
			|  |  |  | float strokeWidth; | 
		
	
		
			
			|  |  |  | float miterLimit; | 
		
	
		
			
			|  |  |  | int lineJoin; | 
		
	
		
			
			|  |  |  | int lineCap; | 
		
	
		
			
			|  |  |  | float xform[6]; | 
		
	
		
			
			|  |  |  | struct NVGscissor scissor; | 
		
	
		
			
			|  |  |  | float fontSize; | 
		
	
	
		
			
				|  |  | @@ -120,6 +122,7 @@ static float nvg__acosf(float a) { return acosf(a); } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static int nvg__mini(int a, int b) { return a < b ? a : b; } | 
		
	
		
			
			|  |  |  | static int nvg__maxi(int a, int b) { return a > b ? a : b; } | 
		
	
		
			
			|  |  |  | static int nvg__clampi(int a, int mn, int mx) { return a < mn ? mn : (a > mx ? mx : a); } | 
		
	
		
			
			|  |  |  | static float nvg__minf(float a, float b) { return a < b ? a : b; } | 
		
	
		
			
			|  |  |  | static float nvg__maxf(float a, float b) { return a > b ? a : b; } | 
		
	
		
			
			|  |  |  | static float nvg__absf(float a) { return a >= 0.0f ? a : -a; } | 
		
	
	
		
			
				|  |  | @@ -422,7 +425,9 @@ void nvgReset(struct NVGcontext* ctx) | 
		
	
		
			
			|  |  |  | nvg__setPaintColor(&state->fill, nvgRGBA(255,255,255,255)); | 
		
	
		
			
			|  |  |  | nvg__setPaintColor(&state->stroke, nvgRGBA(0,0,0,255)); | 
		
	
		
			
			|  |  |  | state->strokeWidth = 1.0f; | 
		
	
		
			
			|  |  |  | state->miterLimit = 1.2f; | 
		
	
		
			
			|  |  |  | state->miterLimit = 10.0f; | 
		
	
		
			
			|  |  |  | state->lineCap = NVG_BUTT; | 
		
	
		
			
			|  |  |  | state->lineJoin = NVG_MITER; | 
		
	
		
			
			|  |  |  | nvg__xformIdentity(state->xform); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | state->scissor.extent[0] = 0.0f; | 
		
	
	
		
			
				|  |  | @@ -448,6 +453,19 @@ void nvgMiterLimit(struct NVGcontext* ctx, float limit) | 
		
	
		
			
			|  |  |  | state->miterLimit = limit; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | void nvgLineCap(struct NVGcontext* ctx, int cap) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | struct NVGstate* state = nvg__getState(ctx); | 
		
	
		
			
			|  |  |  | state->lineCap = cap; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | void nvgLineJoin(struct NVGcontext* ctx, int join) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | struct NVGstate* state = nvg__getState(ctx); | 
		
	
		
			
			|  |  |  | state->lineJoin = join; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | void nvgTransform(struct NVGcontext* ctx, float a, float b, float c, float d, float e, float f) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | struct NVGstate* state = nvg__getState(ctx); | 
		
	
	
		
			
				|  |  | @@ -950,7 +968,7 @@ static void nvg__tesselateBezier(struct NVGcontext* ctx, | 
		
	
		
			
			|  |  |  | nvg__tesselateBezier(ctx, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static void nvg__flattenPaths(struct NVGcontext* ctx, float m) | 
		
	
		
			
			|  |  |  | static void nvg__flattenPaths(struct NVGcontext* ctx, int lineCap, int lineJoin, float miterLimit) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | struct NVGpathCache* cache = ctx->cache; | 
		
	
		
			
			|  |  |  | //	struct NVGstate* state = nvg__getState(ctx); | 
		
	
	
		
			
				|  |  | @@ -1058,7 +1076,7 @@ static void nvg__flattenPaths(struct NVGcontext* ctx, float m) | 
		
	
		
			
			|  |  |  | p0 = &pts[path->count-1]; | 
		
	
		
			
			|  |  |  | p1 = &pts[0]; | 
		
	
		
			
			|  |  |  | for(i = 0; i < path->count; ++i) { | 
		
	
		
			
			|  |  |  | float dlx0, dly0, dlx1, dly1, dmr2, scale, cross; | 
		
	
		
			
			|  |  |  | float dlx0, dly0, dlx1, dly1, dmr2, scale, cross, dot, d0, d1; | 
		
	
		
			
			|  |  |  | dlx0 = p0->dy; | 
		
	
		
			
			|  |  |  | dly0 = -p0->dx; | 
		
	
		
			
			|  |  |  | dlx1 = p1->dy; | 
		
	
	
		
			
				|  |  | @@ -1069,27 +1087,170 @@ static void nvg__flattenPaths(struct NVGcontext* ctx, float m) | 
		
	
		
			
			|  |  |  | dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy; | 
		
	
		
			
			|  |  |  | if (dmr2 > 0.000001f) { | 
		
	
		
			
			|  |  |  | scale = 1.0f / dmr2; | 
		
	
		
			
			|  |  |  | if (scale > 200.0f) scale = 200.0f; | 
		
	
		
			
			|  |  |  | if (scale > 600.0f) { | 
		
	
		
			
			|  |  |  | scale = 600.0f; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | p1->dmx *= scale; | 
		
	
		
			
			|  |  |  | p1->dmy *= scale; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // TODO: improve this logic | 
		
	
		
			
			|  |  |  | dot = p0->dx*p1->dx + p0->dy*p1->dy; | 
		
	
		
			
			|  |  |  | if (dot < -0.75f) | 
		
	
		
			
			|  |  |  | p1->flags |= NVG_PT_CUSP; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Keep track of left turns. | 
		
	
		
			
			|  |  |  | cross = p1->dx * p0->dy - p0->dx * p1->dy; | 
		
	
		
			
			|  |  |  | if (cross > 0.0f) { | 
		
	
		
			
			|  |  |  | nleft++; | 
		
	
		
			
			|  |  |  | p1->flags |= NVG_PT_LEFT; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Check to see if the corner needs to be beveled. | 
		
	
		
			
			|  |  |  | if ((dmr2 * m*m) < 1.0f) { | 
		
	
		
			
			|  |  |  | cross = p1->dx * p0->dy - p0->dx * p1->dy; | 
		
	
		
			
			|  |  |  | p1->flags |= NVG_BEVEL; | 
		
	
		
			
			|  |  |  | if (cross > 0.0f) { | 
		
	
		
			
			|  |  |  | p1->flags |= NVG_LEFT; | 
		
	
		
			
			|  |  |  | nleft++; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | path->nbevel++; | 
		
	
		
			
			|  |  |  | if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NVG_BEVEL || lineJoin == NVG_ROUND) { | 
		
	
		
			
			|  |  |  | p1->flags |= NVG_PT_BEVEL; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if ((p1->flags & (NVG_PT_BEVEL | NVG_PT_CUSP)) != 0) | 
		
	
		
			
			|  |  |  | path->nbevel++; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | p0 = p1++; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | path->convex = nleft == 0 ? 1 : 0; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w) | 
		
	
		
			
			|  |  |  | static int nvg__curveDivs(float r, float arc, float tol) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | float da = acosf(r / (r + tol)) * 2.0f; | 
		
	
		
			
			|  |  |  | return nvg__maxi(2, (int)ceilf(arc / da)); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static void nvg__chooseBevel(int bevel, struct NVGpoint* p0, struct NVGpoint* p1, float w, | 
		
	
		
			
			|  |  |  | float* x0, float* y0, float* x1, float* y1, float fringe) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | if (bevel) { | 
		
	
		
			
			|  |  |  | *x0 = p1->x + p0->dy * w + p0->dx * fringe; | 
		
	
		
			
			|  |  |  | *y0 = p1->y - p0->dx * w + p0->dy * fringe; | 
		
	
		
			
			|  |  |  | *x1 = p1->x + p1->dy * w - p1->dx * fringe; | 
		
	
		
			
			|  |  |  | *y1 = p1->y - p1->dx * w - p1->dy * fringe; | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | *x0 = p1->x + p1->dmx * w; | 
		
	
		
			
			|  |  |  | *y0 = p1->y + p1->dmy * w; | 
		
	
		
			
			|  |  |  | *x1 = p1->x + p1->dmx * w; | 
		
	
		
			
			|  |  |  | *y1 = p1->y + p1->dmy * w; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static struct NVGvertex* nvg__roundJoin(struct NVGvertex* dst, struct NVGpoint* p0, struct NVGpoint* p1, | 
		
	
		
			
			|  |  |  | float lw, float rw, float lu, float ru, int ncap, float fringe) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | int i, n; | 
		
	
		
			
			|  |  |  | float dlx0 = p0->dy; | 
		
	
		
			
			|  |  |  | float dly0 = -p0->dx; | 
		
	
		
			
			|  |  |  | float dlx1 = p1->dy; | 
		
	
		
			
			|  |  |  | float dly1 = -p1->dx; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (p1->flags & NVG_PT_LEFT) { | 
		
	
		
			
			|  |  |  | float lx0,ly0,lx1,ly1,a0,a1; | 
		
	
		
			
			|  |  |  | nvg__chooseBevel(p1->flags & NVG_PT_CUSP, p0, p1, lw, &lx0,&ly0, &lx1,&ly1, -fringe); | 
		
	
		
			
			|  |  |  | a0 = atan2f(-dly0, -dlx0); | 
		
	
		
			
			|  |  |  | a1 = atan2f(-dly1, -dlx1); | 
		
	
		
			
			|  |  |  | if (a1 > a0) a1 -= NVG_PI*2; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | nvg__vset(dst, lx0, ly0, lu,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, p1->x - dlx0*rw, p1->y - dly0*rw, ru,1); dst++; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | n = nvg__clampi((int)ceilf(((a0 - a1) / NVG_PI) * ncap), 2, ncap); | 
		
	
		
			
			|  |  |  | for (i = 0; i < n; i++) { | 
		
	
		
			
			|  |  |  | float u = i/(float)(n-1); | 
		
	
		
			
			|  |  |  | float a = a0 + u*(a1-a0); | 
		
	
		
			
			|  |  |  | float rx = p1->x + cosf(a) * rw; | 
		
	
		
			
			|  |  |  | float ry = p1->y + sinf(a) * rw; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, p1->x, p1->y, 0.5f,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, rx, ry, ru,1); dst++; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | nvg__vset(dst, lx1, ly1, lu,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, p1->x - dlx1*rw, p1->y - dly1*rw, ru,1); dst++; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | float rx0,ry0,rx1,ry1,a0,a1; | 
		
	
		
			
			|  |  |  | nvg__chooseBevel(p1->flags & NVG_PT_CUSP, p0, p1, -rw, &rx0,&ry0, &rx1,&ry1, -fringe); | 
		
	
		
			
			|  |  |  | a0 = atan2f(dly0, dlx0); | 
		
	
		
			
			|  |  |  | a1 = atan2f(dly1, dlx1); | 
		
	
		
			
			|  |  |  | if (a1 < a0) a1 += NVG_PI*2; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | nvg__vset(dst, p1->x + dlx0*rw, p1->y + dly0*rw, lu,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, rx0, ry0, ru,1); dst++; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | n = nvg__clampi((int)ceilf(((a1 - a0) / NVG_PI) * ncap), 2, ncap); | 
		
	
		
			
			|  |  |  | for (i = 0; i < n; i++) { | 
		
	
		
			
			|  |  |  | float u = i/(float)(n-1); | 
		
	
		
			
			|  |  |  | float a = a0 + u*(a1-a0); | 
		
	
		
			
			|  |  |  | float lx = p1->x + cosf(a) * lw; | 
		
	
		
			
			|  |  |  | float ly = p1->y + sinf(a) * lw; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, lx, ly, lu,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, p1->x, p1->y, 0.5f,1); dst++; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | nvg__vset(dst, p1->x + dlx1*rw, p1->y + dly1*rw, lu,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, rx1, ry1, ru,1); dst++; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | return dst; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static struct NVGvertex* nvg__bevelJoin(struct NVGvertex* dst, struct NVGpoint* p0, struct NVGpoint* p1, | 
		
	
		
			
			|  |  |  | float lw, float rw, float lu, float ru, float fringe) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | int left = 0, right = 0; | 
		
	
		
			
			|  |  |  | float dot, rf, lf; | 
		
	
		
			
			|  |  |  | float rx0,ry0,rx1,ry1; | 
		
	
		
			
			|  |  |  | float lx0,ly0,lx1,ly1; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (p1->flags & NVG_PT_LEFT) { | 
		
	
		
			
			|  |  |  | left = p1->flags & NVG_PT_CUSP; | 
		
	
		
			
			|  |  |  | right = p1->flags & NVG_PT_BEVEL; | 
		
	
		
			
			|  |  |  | lf = 0; | 
		
	
		
			
			|  |  |  | rf = fringe; | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | left = p1->flags & NVG_PT_BEVEL; | 
		
	
		
			
			|  |  |  | right = p1->flags & NVG_PT_CUSP; | 
		
	
		
			
			|  |  |  | lf = fringe; | 
		
	
		
			
			|  |  |  | rf = 0; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | nvg__chooseBevel(left, p0, p1, lw, &lx0,&ly0, &lx1,&ly1, lf); | 
		
	
		
			
			|  |  |  | nvg__chooseBevel(right, p0, p1, -rw, &rx0,&ry0, &rx1,&ry1, rf); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | dot = p0->dx*p1->dx + p0->dy*p1->dy; | 
		
	
		
			
			|  |  |  | dot = (1.0f - dot) * 0.5f; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | nvg__vset(dst, lx0, ly0, lu,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, rx0, ry0, ru,1); dst++; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (p1->flags & NVG_PT_CUSP) { | 
		
	
		
			
			|  |  |  | if (p1->flags & NVG_PT_LEFT) { | 
		
	
		
			
			|  |  |  | nvg__vset(dst, p1->x, p1->y, 0.5f,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, rx0, ry0, ru,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, p1->x, p1->y, 0.5f,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, rx1, ry1, ru,1); dst++; | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | nvg__vset(dst, lx0, ly0, lu,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, p1->x, p1->y, 0.5f,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, lx1, ly1, lu,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, p1->x, p1->y, 0.5f,1); dst++; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | nvg__vset(dst, lx1, ly1, lu,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, rx1, ry1, ru,1); dst++; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | return dst; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w, int lineCap, int lineJoin, float miterLimit) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | struct NVGpathCache* cache = ctx->cache; | 
		
	
		
			
			|  |  |  | struct NVGpath* path; | 
		
	
	
		
			
				|  |  | @@ -1103,6 +1264,7 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w) | 
		
	
		
			
			|  |  |  | int i, j, s, e; | 
		
	
		
			
			|  |  |  | float wo = 0; | 
		
	
		
			
			|  |  |  | float aa = ctx->fringeWidth; | 
		
	
		
			
			|  |  |  | int ncap = nvg__curveDivs(w, NVG_PI, ctx->tessTol / 4.0f); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Calculate max vertex usage. | 
		
	
		
			
			|  |  |  | cverts = 0; | 
		
	
	
		
			
				|  |  | @@ -1112,9 +1274,18 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w) | 
		
	
		
			
			|  |  |  | cverts += path->count + path->nbevel + 1; | 
		
	
		
			
			|  |  |  | if (feats & NVG_STROKE) { | 
		
	
		
			
			|  |  |  | int loop = ((feats & NVG_CAPS) && path->closed == 0) ? 0 : 1; | 
		
	
		
			
			|  |  |  | cverts += (path->count + path->nbevel + 1) * 2; // plus one for loop | 
		
	
		
			
			|  |  |  | if (loop == 0) | 
		
	
		
			
			|  |  |  | cverts += (3+3)*2; // space for caps | 
		
	
		
			
			|  |  |  | if (lineCap == NVG_ROUND) | 
		
	
		
			
			|  |  |  | cverts += (path->count + path->nbevel*(ncap+2) + 1) * 2; // plus one for loop | 
		
	
		
			
			|  |  |  | else | 
		
	
		
			
			|  |  |  | cverts += (path->count + path->nbevel*3 + 1) * 2; // plus one for loop | 
		
	
		
			
			|  |  |  | if (loop == 0) { | 
		
	
		
			
			|  |  |  | // space for caps | 
		
	
		
			
			|  |  |  | if (lineCap == NVG_ROUND) { | 
		
	
		
			
			|  |  |  | cverts += (ncap*2 + 2)*2; | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | cverts += (3+3)*2; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
	
		
			
				|  |  | @@ -1143,12 +1314,12 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w) | 
		
	
		
			
			|  |  |  | p0 = &pts[path->count-1]; | 
		
	
		
			
			|  |  |  | p1 = &pts[0]; | 
		
	
		
			
			|  |  |  | for (j = 0; j < path->count; ++j) { | 
		
	
		
			
			|  |  |  | if (p1->flags & NVG_BEVEL) { | 
		
	
		
			
			|  |  |  | if (p1->flags & NVG_PT_BEVEL) { | 
		
	
		
			
			|  |  |  | float dlx0 = p0->dy; | 
		
	
		
			
			|  |  |  | float dly0 = -p0->dx; | 
		
	
		
			
			|  |  |  | float dlx1 = p1->dy; | 
		
	
		
			
			|  |  |  | float dly1 = -p1->dx; | 
		
	
		
			
			|  |  |  | if (p1->flags & NVG_LEFT) { | 
		
	
		
			
			|  |  |  | if (p1->flags & NVG_PT_LEFT) { | 
		
	
		
			
			|  |  |  | float lx = p1->x + p1->dmx * wo; | 
		
	
		
			
			|  |  |  | float ly = p1->y + p1->dmy * wo; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, lx, ly, 0.5f,1); dst++; | 
		
	
	
		
			
				|  |  | @@ -1178,7 +1349,7 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w) | 
		
	
		
			
			|  |  |  | path->nfill = 0; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | // Calculate fringe | 
		
	
		
			
			|  |  |  | // Calculate fringe or stroke | 
		
	
		
			
			|  |  |  | if (feats & NVG_STROKE) { | 
		
	
		
			
			|  |  |  | float lw = w + wo, rw = w - wo; | 
		
	
		
			
			|  |  |  | float ru = 1, lu = 0; | 
		
	
	
		
			
				|  |  | @@ -1209,46 +1380,44 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w) | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | if (loop == 0) { | 
		
	
		
			
			|  |  |  | // Add cap | 
		
	
		
			
			|  |  |  | float dx, dy, dlx, dly; | 
		
	
		
			
			|  |  |  | float dx, dy, dlx, dly, px, py; | 
		
	
		
			
			|  |  |  | dx = p1->x - p0->x; | 
		
	
		
			
			|  |  |  | dy = p1->y - p0->y; | 
		
	
		
			
			|  |  |  | nvg__normalize(&dx, &dy); | 
		
	
		
			
			|  |  |  | dlx = dy; | 
		
	
		
			
			|  |  |  | dly = -dx; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, p0->x + dlx*lw - dx*aa, p0->y + dly*lw - dy*aa, lu,0); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, p0->x - dlx*rw - dx*aa, p0->y - dly*rw - dy*aa, ru,0); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, p0->x + dlx*lw, p0->y + dly * lw, lu,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, p0->x - dlx*rw, p0->y - dly * rw, ru,1); dst++; | 
		
	
		
			
			|  |  |  | if (lineCap == NVG_BUTT || lineCap == NVG_SQUARE) { | 
		
	
		
			
			|  |  |  | if (lineCap == NVG_BUTT) { | 
		
	
		
			
			|  |  |  | px = p0->x; | 
		
	
		
			
			|  |  |  | py = p0->y; | 
		
	
		
			
			|  |  |  | } else if (lineCap == NVG_SQUARE) { | 
		
	
		
			
			|  |  |  | px = p0->x - dx*w; | 
		
	
		
			
			|  |  |  | py = p0->y - dy*w; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | nvg__vset(dst, px + dlx*lw - dx*aa, py + dly*lw - dy*aa, lu,0); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, px - dlx*rw - dx*aa, py - dly*rw - dy*aa, ru,0); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, px + dlx*lw, py + dly * lw, lu,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, px - dlx*rw, py - dly * rw, ru,1); dst++; | 
		
	
		
			
			|  |  |  | } else if (lineCap == NVG_ROUND) { | 
		
	
		
			
			|  |  |  | px = p0->x; | 
		
	
		
			
			|  |  |  | py = p0->y; | 
		
	
		
			
			|  |  |  | for (j = 0; j < ncap; j++) { | 
		
	
		
			
			|  |  |  | float a = j/(float)(ncap-1)*NVG_PI; | 
		
	
		
			
			|  |  |  | float ax = cosf(a) * w, ay = sinf(a) * w; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, px - dlx*ax - dx*ay, py - dly*ax - dy*ay, lu,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, px, py, 0.5f,1); dst++; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | nvg__vset(dst, px + dlx*lw, py + dly * lw, lu,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, px - dlx*rw, py - dly * rw, ru,1); dst++; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | for (j = s; j < e; ++j) { | 
		
	
		
			
			|  |  |  | if (p1->flags & NVG_BEVEL) { | 
		
	
		
			
			|  |  |  | float dlx0 = p0->dy; | 
		
	
		
			
			|  |  |  | float dly0 = -p0->dx; | 
		
	
		
			
			|  |  |  | float dlx1 = p1->dy; | 
		
	
		
			
			|  |  |  | float dly1 = -p1->dx; | 
		
	
		
			
			|  |  |  | if (p1->flags & NVG_LEFT) { | 
		
	
		
			
			|  |  |  | float rx0 = p1->x - dlx0 * rw; | 
		
	
		
			
			|  |  |  | float ry0 = p1->y - dly0 * rw; | 
		
	
		
			
			|  |  |  | float rx1 = p1->x - dlx1 * rw; | 
		
	
		
			
			|  |  |  | float ry1 = p1->y - dly1 * rw; | 
		
	
		
			
			|  |  |  | float lx = p1->x + p1->dmx * lw; | 
		
	
		
			
			|  |  |  | float ly = p1->y + p1->dmy * lw; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, lx, ly, lu,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, rx0, ry0, ru,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, lx, ly, lu,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, rx1, ry1, ru,1); dst++; | 
		
	
		
			
			|  |  |  | if ((p1->flags & (NVG_PT_BEVEL | NVG_PT_CUSP)) != 0) { | 
		
	
		
			
			|  |  |  | if (lineJoin == NVG_ROUND) { | 
		
	
		
			
			|  |  |  | dst = nvg__roundJoin(dst, p0, p1, lw, rw, lu, ru, ncap, ctx->fringeWidth); | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | float rx = p1->x - p1->dmx * rw; | 
		
	
		
			
			|  |  |  | float ry = p1->y - p1->dmy * rw; | 
		
	
		
			
			|  |  |  | float lx0 = p1->x + dlx0 * lw; | 
		
	
		
			
			|  |  |  | float ly0 = p1->y + dly0 * lw; | 
		
	
		
			
			|  |  |  | float lx1 = p1->x + dlx1 * lw; | 
		
	
		
			
			|  |  |  | float ly1 = p1->y + dly1 * lw; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, lx0, ly0, lu,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, rx, ry, ru,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, lx1, ly1, lu,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, rx, ry, ru,1); dst++; | 
		
	
		
			
			|  |  |  | dst = nvg__bevelJoin(dst, p0, p1, lw, rw, lu, ru, ctx->fringeWidth); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | nvg__vset(dst, p1->x + (p1->dmx * lw), p1->y + (p1->dmy * lw), lu,1); dst++; | 
		
	
	
		
			
				|  |  | @@ -1263,16 +1432,36 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w) | 
		
	
		
			
			|  |  |  | nvg__vset(dst, verts[1].x, verts[1].y, ru,1); dst++; | 
		
	
		
			
			|  |  |  | } else { | 
		
	
		
			
			|  |  |  | // Add cap | 
		
	
		
			
			|  |  |  | float dx, dy, dlx, dly; | 
		
	
		
			
			|  |  |  | float dx, dy, dlx, dly, px, py; | 
		
	
		
			
			|  |  |  | dx = p1->x - p0->x; | 
		
	
		
			
			|  |  |  | dy = p1->y - p0->y; | 
		
	
		
			
			|  |  |  | nvg__normalize(&dx, &dy); | 
		
	
		
			
			|  |  |  | dlx = dy; | 
		
	
		
			
			|  |  |  | dly = -dx; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, p1->x + dlx*lw, p1->y + dly * lw, lu,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, p1->x - dlx*rw, p1->y - dly * rw, ru,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, p1->x + dlx*lw + dx*aa, p1->y + dly*lw + dy*aa, lu,0); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, p1->x - dlx*rw + dx*aa, p1->y - dly*rw + dy*aa, ru,0); dst++; | 
		
	
		
			
			|  |  |  | if (lineCap == NVG_BUTT || lineCap == NVG_SQUARE) { | 
		
	
		
			
			|  |  |  | if (lineCap == NVG_BUTT) { | 
		
	
		
			
			|  |  |  | px = p1->x; | 
		
	
		
			
			|  |  |  | py = p1->y; | 
		
	
		
			
			|  |  |  | } else if (lineCap == NVG_SQUARE) { | 
		
	
		
			
			|  |  |  | px = p1->x + dx*w; | 
		
	
		
			
			|  |  |  | py = p1->y + dy*w; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | nvg__vset(dst, px + dlx*lw, py + dly * lw, lu,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, px - dlx*rw, py - dly * rw, ru,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, px + dlx*lw + dx*aa, py + dly*lw + dy*aa, lu,0); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, px - dlx*rw + dx*aa, py - dly*rw + dy*aa, ru,0); dst++; | 
		
	
		
			
			|  |  |  | } else if (lineCap == NVG_ROUND) { | 
		
	
		
			
			|  |  |  | px = p1->x; | 
		
	
		
			
			|  |  |  | py = p1->y; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, px + dlx*lw, py + dly * lw, lu,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, px - dlx*rw, py - dly * rw, ru,1); dst++; | 
		
	
		
			
			|  |  |  | for (j = 0; j < ncap; j++) { | 
		
	
		
			
			|  |  |  | float a = j/(float)(ncap-1)*NVG_PI; | 
		
	
		
			
			|  |  |  | float ax = cosf(a) * w, ay = sinf(a) * w; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, px, py, 0.5f,1); dst++; | 
		
	
		
			
			|  |  |  | nvg__vset(dst, px - dlx*ax + dx*ay, py - dly*ax + dy*ay, lu,1); dst++; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | path->nstroke = (int)(dst - verts); | 
		
	
	
		
			
				|  |  | @@ -1505,11 +1694,11 @@ void nvgFill(struct NVGcontext* ctx) | 
		
	
		
			
			|  |  |  | const struct NVGpath* path; | 
		
	
		
			
			|  |  |  | int i; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | nvg__flattenPaths(ctx, state->miterLimit); | 
		
	
		
			
			|  |  |  | nvg__flattenPaths(ctx, NVG_BUTT, NVG_MITER, 1.2f); | 
		
	
		
			
			|  |  |  | if (ctx->params.edgeAntiAlias) | 
		
	
		
			
			|  |  |  | nvg__expandStrokeAndFill(ctx, NVG_FILL|NVG_STROKE, ctx->fringeWidth); | 
		
	
		
			
			|  |  |  | nvg__expandStrokeAndFill(ctx, NVG_FILL|NVG_STROKE, ctx->fringeWidth, NVG_BUTT, NVG_MITER, 1.2f); | 
		
	
		
			
			|  |  |  | else | 
		
	
		
			
			|  |  |  | nvg__expandStrokeAndFill(ctx, NVG_FILL, 0.0f); | 
		
	
		
			
			|  |  |  | nvg__expandStrokeAndFill(ctx, NVG_FILL, 0.0f, NVG_BUTT, NVG_MITER, 1.2f); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | ctx->params.renderFill(ctx->params.userPtr, &state->fill, &state->scissor, | 
		
	
		
			
			|  |  |  | ctx->cache->bounds, ctx->cache->paths, ctx->cache->npaths); | 
		
	
	
		
			
				|  |  | @@ -1531,11 +1720,11 @@ void nvgStroke(struct NVGcontext* ctx) | 
		
	
		
			
			|  |  |  | const struct NVGpath* path; | 
		
	
		
			
			|  |  |  | int i; | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | nvg__flattenPaths(ctx, state->miterLimit); | 
		
	
		
			
			|  |  |  | nvg__flattenPaths(ctx, state->lineCap, state->lineJoin, state->miterLimit); | 
		
	
		
			
			|  |  |  | if (ctx->params.edgeAntiAlias) | 
		
	
		
			
			|  |  |  | nvg__expandStrokeAndFill(ctx, NVG_STROKE|NVG_CAPS, strokeWidth*0.5f + ctx->fringeWidth/2.0f); | 
		
	
		
			
			|  |  |  | nvg__expandStrokeAndFill(ctx, NVG_STROKE|NVG_CAPS, strokeWidth*0.5f + ctx->fringeWidth/2.0f, state->lineCap, state->lineJoin, state->miterLimit); | 
		
	
		
			
			|  |  |  | else | 
		
	
		
			
			|  |  |  | nvg__expandStrokeAndFill(ctx, NVG_STROKE|NVG_CAPS, strokeWidth*0.5f); | 
		
	
		
			
			|  |  |  | nvg__expandStrokeAndFill(ctx, NVG_STROKE|NVG_CAPS, strokeWidth*0.5f, state->lineCap, state->lineJoin, state->miterLimit); | 
		
	
		
			
			|  |  |  | 
 | 
		
	
		
			
			|  |  |  | ctx->params.renderStroke(ctx->params.userPtr, &state->stroke, &state->scissor, | 
		
	
		
			
			|  |  |  | strokeWidth, ctx->cache->paths, ctx->cache->npaths); | 
		
	
	
		
			
				|  |  | 
 |