|
@@ -52,12 +52,6 @@ enum NVGpointFlags |
|
|
NVG_PR_INNERBEVEL = 0x08, |
|
|
NVG_PR_INNERBEVEL = 0x08, |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
enum NVGexpandFeatures { |
|
|
|
|
|
NVG_FILL = 0x01, |
|
|
|
|
|
NVG_STROKE = 0x02, |
|
|
|
|
|
NVG_CAPS = 0x04, |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
struct NVGstate { |
|
|
struct NVGstate { |
|
|
struct NVGpaint fill; |
|
|
struct NVGpaint fill; |
|
|
struct NVGpaint stroke; |
|
|
struct NVGpaint stroke; |
|
@@ -1368,31 +1362,94 @@ static struct NVGvertex* nvg__bevelJoin(struct NVGvertex* dst, struct NVGpoint* |
|
|
return dst; |
|
|
return dst; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w, int lineCap, int lineJoin, float miterLimit) |
|
|
|
|
|
|
|
|
static struct NVGvertex* nvg__buttCapStart(struct NVGvertex* dst, struct NVGpoint* p, |
|
|
|
|
|
float dx, float dy, float w, float d, float aa) |
|
|
|
|
|
{ |
|
|
|
|
|
float px = p->x - dx*d; |
|
|
|
|
|
float py = p->y - dy*d; |
|
|
|
|
|
float dlx = dy; |
|
|
|
|
|
float dly = -dx; |
|
|
|
|
|
nvg__vset(dst, px + dlx*w - dx*aa, py + dly*w - dy*aa, 0,0); dst++; |
|
|
|
|
|
nvg__vset(dst, px - dlx*w - dx*aa, py - dly*w - dy*aa, 1,0); dst++; |
|
|
|
|
|
nvg__vset(dst, px + dlx*w, py + dly*w, 0,1); dst++; |
|
|
|
|
|
nvg__vset(dst, px - dlx*w, py - dly*w, 1,1); dst++; |
|
|
|
|
|
return dst; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static struct NVGvertex* nvg__buttCapEnd(struct NVGvertex* dst, struct NVGpoint* p, |
|
|
|
|
|
float dx, float dy, float w, float d, float aa) |
|
|
|
|
|
{ |
|
|
|
|
|
float px = p->x + dx*d; |
|
|
|
|
|
float py = p->y + dy*d; |
|
|
|
|
|
float dlx = dy; |
|
|
|
|
|
float dly = -dx; |
|
|
|
|
|
nvg__vset(dst, px + dlx*w, py + dly*w, 0,1); dst++; |
|
|
|
|
|
nvg__vset(dst, px - dlx*w, py - dly*w, 1,1); dst++; |
|
|
|
|
|
nvg__vset(dst, px + dlx*w + dx*aa, py + dly*w + dy*aa, 0,0); dst++; |
|
|
|
|
|
nvg__vset(dst, px - dlx*w + dx*aa, py - dly*w + dy*aa, 1,0); dst++; |
|
|
|
|
|
return dst; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct NVGvertex* nvg__roundCapStart(struct NVGvertex* dst, struct NVGpoint* p, |
|
|
|
|
|
float dx, float dy, float w, int ncap, float aa) |
|
|
|
|
|
{ |
|
|
|
|
|
int i; |
|
|
|
|
|
float px = p->x; |
|
|
|
|
|
float py = p->y; |
|
|
|
|
|
float dlx = dy; |
|
|
|
|
|
float dly = -dx; |
|
|
|
|
|
NVG_NOTUSED(aa); |
|
|
|
|
|
for (i = 0; i < ncap; i++) { |
|
|
|
|
|
float a = i/(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, 0,1); dst++; |
|
|
|
|
|
nvg__vset(dst, px, py, 0.5f,1); dst++; |
|
|
|
|
|
} |
|
|
|
|
|
nvg__vset(dst, px + dlx*w, py + dly*w, 0,1); dst++; |
|
|
|
|
|
nvg__vset(dst, px - dlx*w, py - dly*w, 1,1); dst++; |
|
|
|
|
|
return dst; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static struct NVGvertex* nvg__roundCapEnd(struct NVGvertex* dst, struct NVGpoint* p, |
|
|
|
|
|
float dx, float dy, float w, int ncap, float aa) |
|
|
|
|
|
{ |
|
|
|
|
|
int i; |
|
|
|
|
|
float px = p->x; |
|
|
|
|
|
float py = p->y; |
|
|
|
|
|
float dlx = dy; |
|
|
|
|
|
float dly = -dx; |
|
|
|
|
|
NVG_NOTUSED(aa); |
|
|
|
|
|
nvg__vset(dst, px + dlx*w, py + dly*w, 0,1); dst++; |
|
|
|
|
|
nvg__vset(dst, px - dlx*w, py - dly*w, 1,1); dst++; |
|
|
|
|
|
for (i = 0; i < ncap; i++) { |
|
|
|
|
|
float a = i/(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, 0,1); dst++; |
|
|
|
|
|
} |
|
|
|
|
|
return dst; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void nvg__calculateJoins(struct NVGcontext* ctx, float w, int lineJoin, float miterLimit) |
|
|
{ |
|
|
{ |
|
|
struct NVGpathCache* cache = ctx->cache; |
|
|
struct NVGpathCache* cache = ctx->cache; |
|
|
struct NVGpath* path; |
|
|
|
|
|
struct NVGpoint* pts; |
|
|
|
|
|
struct NVGvertex* verts; |
|
|
|
|
|
struct NVGvertex* dst; |
|
|
|
|
|
struct NVGpoint* p0; |
|
|
|
|
|
struct NVGpoint* p1; |
|
|
|
|
|
int cverts, convex, i, j, s, e; |
|
|
|
|
|
float wo = 0, iw = 0, aa = ctx->fringeWidth; |
|
|
|
|
|
int ncap = nvg__curveDivs(w, NVG_PI, ctx->tessTol / 4.0f); |
|
|
|
|
|
int nleft = 0; |
|
|
|
|
|
|
|
|
int i, j; |
|
|
|
|
|
float iw; |
|
|
|
|
|
|
|
|
if (w > 0.0f) iw = 1.0f / w; |
|
|
if (w > 0.0f) iw = 1.0f / w; |
|
|
|
|
|
|
|
|
// Calculate which joins needs extra vertices to append, and gather vertex count. |
|
|
// Calculate which joins needs extra vertices to append, and gather vertex count. |
|
|
for (i = 0; i < cache->npaths; i++) { |
|
|
for (i = 0; i < cache->npaths; i++) { |
|
|
path = &cache->paths[i]; |
|
|
|
|
|
pts = &cache->points[path->first]; |
|
|
|
|
|
|
|
|
struct NVGpath* path = &cache->paths[i]; |
|
|
|
|
|
struct NVGpoint* pts = &cache->points[path->first]; |
|
|
|
|
|
struct NVGpoint* p0 = &pts[path->count-1]; |
|
|
|
|
|
struct NVGpoint* p1 = &pts[0]; |
|
|
|
|
|
int nleft = 0; |
|
|
|
|
|
|
|
|
path->nbevel = 0; |
|
|
path->nbevel = 0; |
|
|
nleft = 0; |
|
|
|
|
|
|
|
|
|
|
|
p0 = &pts[path->count-1]; |
|
|
|
|
|
p1 = &pts[0]; |
|
|
|
|
|
for (j = 0; j < path->count; j++) { |
|
|
for (j = 0; j < path->count; j++) { |
|
|
float dlx0, dly0, dlx1, dly1, dmr2, cross, limit; |
|
|
float dlx0, dly0, dlx1, dly1, dmr2, cross, limit; |
|
|
dlx0 = p0->dy; |
|
|
dlx0 = p0->dy; |
|
@@ -1442,160 +1499,222 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w, |
|
|
|
|
|
|
|
|
path->convex = (nleft == path->count) ? 1 : 0; |
|
|
path->convex = (nleft == path->count) ? 1 : 0; |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int nvg__expandStroke(struct NVGcontext* ctx, float w, int lineCap, int lineJoin, float miterLimit) |
|
|
|
|
|
{ |
|
|
|
|
|
struct NVGpathCache* cache = ctx->cache; |
|
|
|
|
|
struct NVGvertex* verts; |
|
|
|
|
|
struct NVGvertex* dst; |
|
|
|
|
|
int cverts, i, j; |
|
|
|
|
|
float aa = ctx->fringeWidth; |
|
|
|
|
|
int ncap = nvg__curveDivs(w, NVG_PI, ctx->tessTol / 4.0f); |
|
|
|
|
|
|
|
|
|
|
|
nvg__calculateJoins(ctx, w, lineJoin, miterLimit); |
|
|
|
|
|
|
|
|
// Calculate max vertex usage. |
|
|
// Calculate max vertex usage. |
|
|
cverts = 0; |
|
|
cverts = 0; |
|
|
for (i = 0; i < cache->npaths; i++) { |
|
|
for (i = 0; i < cache->npaths; i++) { |
|
|
path = &cache->paths[i]; |
|
|
|
|
|
if (feats & NVG_FILL) |
|
|
|
|
|
cverts += path->count + path->nbevel + 1; |
|
|
|
|
|
if (feats & NVG_STROKE) { |
|
|
|
|
|
int loop = ((feats & NVG_CAPS) && path->closed == 0) ? 0 : 1; |
|
|
|
|
|
if (lineCap == NVG_ROUND) |
|
|
|
|
|
cverts += (path->count + path->nbevel*(ncap+2) + 1) * 2; // plus one for loop |
|
|
|
|
|
else |
|
|
|
|
|
cverts += (path->count + path->nbevel*5 + 1) * 2; // plus one for loop |
|
|
|
|
|
if (loop == 0) { |
|
|
|
|
|
// space for caps |
|
|
|
|
|
if (lineCap == NVG_ROUND) { |
|
|
|
|
|
cverts += (ncap*2 + 2)*2; |
|
|
|
|
|
|
|
|
struct NVGpath* path = &cache->paths[i]; |
|
|
|
|
|
int loop = (path->closed == 0) ? 0 : 1; |
|
|
|
|
|
if (lineCap == NVG_ROUND) |
|
|
|
|
|
cverts += (path->count + path->nbevel*(ncap+2) + 1) * 2; // plus one for loop |
|
|
|
|
|
else |
|
|
|
|
|
cverts += (path->count + path->nbevel*5 + 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; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
verts = nvg__allocTempVerts(ctx, cverts); |
|
|
|
|
|
if (verts == NULL) return 0; |
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < cache->npaths; i++) { |
|
|
|
|
|
struct NVGpath* path = &cache->paths[i]; |
|
|
|
|
|
struct NVGpoint* pts = &cache->points[path->first]; |
|
|
|
|
|
struct NVGpoint* p0; |
|
|
|
|
|
struct NVGpoint* p1; |
|
|
|
|
|
int s, e, loop; |
|
|
|
|
|
float dx, dy; |
|
|
|
|
|
|
|
|
|
|
|
path->fill = 0; |
|
|
|
|
|
path->nfill = 0; |
|
|
|
|
|
|
|
|
|
|
|
// Calculate fringe or stroke |
|
|
|
|
|
loop = (path->closed == 0) ? 0 : 1; |
|
|
|
|
|
dst = verts; |
|
|
|
|
|
path->stroke = dst; |
|
|
|
|
|
|
|
|
|
|
|
if (loop) { |
|
|
|
|
|
// Looping |
|
|
|
|
|
p0 = &pts[path->count-1]; |
|
|
|
|
|
p1 = &pts[0]; |
|
|
|
|
|
s = 0; |
|
|
|
|
|
e = path->count; |
|
|
|
|
|
} else { |
|
|
|
|
|
// Add cap |
|
|
|
|
|
p0 = &pts[0]; |
|
|
|
|
|
p1 = &pts[1]; |
|
|
|
|
|
s = 1; |
|
|
|
|
|
e = path->count-1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (loop == 0) { |
|
|
|
|
|
// Add cap |
|
|
|
|
|
dx = p1->x - p0->x; |
|
|
|
|
|
dy = p1->y - p0->y; |
|
|
|
|
|
nvg__normalize(&dx, &dy); |
|
|
|
|
|
if (lineCap == NVG_BUTT) |
|
|
|
|
|
dst = nvg__buttCapStart(dst, p0, dx, dy, w, -aa*0.5f, aa); |
|
|
|
|
|
else if (lineCap == NVG_BUTT || lineCap == NVG_SQUARE) |
|
|
|
|
|
dst = nvg__buttCapStart(dst, p0, dx, dy, w, w-aa, aa); |
|
|
|
|
|
else if (lineCap == NVG_ROUND) |
|
|
|
|
|
dst = nvg__roundCapStart(dst, p0, dx, dy, w, ncap, aa); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (j = s; j < e; ++j) { |
|
|
|
|
|
if ((p1->flags & (NVG_PT_BEVEL | NVG_PR_INNERBEVEL)) != 0) { |
|
|
|
|
|
if (lineJoin == NVG_ROUND) { |
|
|
|
|
|
dst = nvg__roundJoin(dst, p0, p1, w, w, 0, 1, ncap, aa); |
|
|
} else { |
|
|
} else { |
|
|
cverts += (3+3)*2; |
|
|
|
|
|
|
|
|
dst = nvg__bevelJoin(dst, p0, p1, w, w, 0, 1, aa); |
|
|
} |
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
nvg__vset(dst, p1->x + (p1->dmx * w), p1->y + (p1->dmy * w), 0,1); dst++; |
|
|
|
|
|
nvg__vset(dst, p1->x - (p1->dmx * w), p1->y - (p1->dmy * w), 1,1); dst++; |
|
|
} |
|
|
} |
|
|
|
|
|
p0 = p1++; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (loop) { |
|
|
|
|
|
// Loop it |
|
|
|
|
|
nvg__vset(dst, verts[0].x, verts[0].y, 0,1); dst++; |
|
|
|
|
|
nvg__vset(dst, verts[1].x, verts[1].y, 1,1); dst++; |
|
|
|
|
|
} else { |
|
|
|
|
|
// Add cap |
|
|
|
|
|
dx = p1->x - p0->x; |
|
|
|
|
|
dy = p1->y - p0->y; |
|
|
|
|
|
nvg__normalize(&dx, &dy); |
|
|
|
|
|
if (lineCap == NVG_BUTT) |
|
|
|
|
|
dst = nvg__buttCapEnd(dst, p1, dx, dy, w, -aa*0.5f, aa); |
|
|
|
|
|
else if (lineCap == NVG_BUTT || lineCap == NVG_SQUARE) |
|
|
|
|
|
dst = nvg__buttCapEnd(dst, p1, dx, dy, w, w-aa, aa); |
|
|
|
|
|
else if (lineCap == NVG_ROUND) |
|
|
|
|
|
dst = nvg__roundCapEnd(dst, p1, dx, dy, w, ncap, aa); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
path->nstroke = (int)(dst - verts); |
|
|
|
|
|
|
|
|
|
|
|
verts = dst; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int nvg__expandFill(struct NVGcontext* ctx, float w, int lineJoin, float miterLimit) |
|
|
|
|
|
{ |
|
|
|
|
|
struct NVGpathCache* cache = ctx->cache; |
|
|
|
|
|
struct NVGvertex* verts; |
|
|
|
|
|
struct NVGvertex* dst; |
|
|
|
|
|
int cverts, convex, i, j; |
|
|
|
|
|
float aa = ctx->fringeWidth; |
|
|
|
|
|
int fringe = w > 0.0f; |
|
|
|
|
|
|
|
|
|
|
|
nvg__calculateJoins(ctx, w, lineJoin, miterLimit); |
|
|
|
|
|
|
|
|
|
|
|
// Calculate max vertex usage. |
|
|
|
|
|
cverts = 0; |
|
|
|
|
|
for (i = 0; i < cache->npaths; i++) { |
|
|
|
|
|
struct NVGpath* path = &cache->paths[i]; |
|
|
|
|
|
cverts += path->count + path->nbevel + 1; |
|
|
|
|
|
if (fringe) |
|
|
|
|
|
cverts += (path->count + path->nbevel*5 + 1) * 2; // plus one for loop |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
verts = nvg__allocTempVerts(ctx, cverts); |
|
|
verts = nvg__allocTempVerts(ctx, cverts); |
|
|
if (verts == NULL) return 0; |
|
|
if (verts == NULL) return 0; |
|
|
|
|
|
|
|
|
if ((feats & NVG_FILL) && cache->npaths == 1 && cache->paths[0].convex) |
|
|
|
|
|
convex = 1; |
|
|
|
|
|
else |
|
|
|
|
|
convex = 0; |
|
|
|
|
|
|
|
|
convex = cache->npaths == 1 && cache->paths[0].convex; |
|
|
|
|
|
|
|
|
for (i = 0; i < cache->npaths; i++) { |
|
|
for (i = 0; i < cache->npaths; i++) { |
|
|
path = &cache->paths[i]; |
|
|
|
|
|
pts = &cache->points[path->first]; |
|
|
|
|
|
|
|
|
struct NVGpath* path = &cache->paths[i]; |
|
|
|
|
|
struct NVGpoint* pts = &cache->points[path->first]; |
|
|
|
|
|
struct NVGpoint* p0; |
|
|
|
|
|
struct NVGpoint* p1; |
|
|
|
|
|
float rw, lw, woff; |
|
|
|
|
|
float ru, lu; |
|
|
|
|
|
|
|
|
// Calculate shape vertices. |
|
|
// Calculate shape vertices. |
|
|
if (feats & NVG_FILL) { |
|
|
|
|
|
wo = 0.5f*aa; |
|
|
|
|
|
dst = verts; |
|
|
|
|
|
path->fill = dst; |
|
|
|
|
|
|
|
|
woff = 0.5f*aa; |
|
|
|
|
|
dst = verts; |
|
|
|
|
|
path->fill = dst; |
|
|
|
|
|
|
|
|
if (w == 0.0f) { |
|
|
|
|
|
for (j = 0; j < path->count; ++j) { |
|
|
|
|
|
nvg__vset(dst, pts[j].x, pts[j].y, 0.5f,1); |
|
|
|
|
|
dst++; |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
// Looping |
|
|
|
|
|
p0 = &pts[path->count-1]; |
|
|
|
|
|
p1 = &pts[0]; |
|
|
|
|
|
for (j = 0; j < path->count; ++j) { |
|
|
|
|
|
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_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++; |
|
|
|
|
|
} else { |
|
|
|
|
|
float lx0 = p1->x + dlx0 * wo; |
|
|
|
|
|
float ly0 = p1->y + dly0 * wo; |
|
|
|
|
|
float lx1 = p1->x + dlx1 * wo; |
|
|
|
|
|
float ly1 = p1->y + dly1 * wo; |
|
|
|
|
|
nvg__vset(dst, lx0, ly0, 0.5f,1); dst++; |
|
|
|
|
|
nvg__vset(dst, lx1, ly1, 0.5f,1); dst++; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (fringe) { |
|
|
|
|
|
// Looping |
|
|
|
|
|
p0 = &pts[path->count-1]; |
|
|
|
|
|
p1 = &pts[0]; |
|
|
|
|
|
for (j = 0; j < path->count; ++j) { |
|
|
|
|
|
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_PT_LEFT) { |
|
|
|
|
|
float lx = p1->x + p1->dmx * woff; |
|
|
|
|
|
float ly = p1->y + p1->dmy * woff; |
|
|
|
|
|
nvg__vset(dst, lx, ly, 0.5f,1); dst++; |
|
|
} else { |
|
|
} else { |
|
|
nvg__vset(dst, p1->x + (p1->dmx * wo), p1->y + (p1->dmy * wo), 0.5f,1); dst++; |
|
|
|
|
|
|
|
|
float lx0 = p1->x + dlx0 * woff; |
|
|
|
|
|
float ly0 = p1->y + dly0 * woff; |
|
|
|
|
|
float lx1 = p1->x + dlx1 * woff; |
|
|
|
|
|
float ly1 = p1->y + dly1 * woff; |
|
|
|
|
|
nvg__vset(dst, lx0, ly0, 0.5f,1); dst++; |
|
|
|
|
|
nvg__vset(dst, lx1, ly1, 0.5f,1); dst++; |
|
|
} |
|
|
} |
|
|
p0 = p1++; |
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
nvg__vset(dst, p1->x + (p1->dmx * woff), p1->y + (p1->dmy * woff), 0.5f,1); dst++; |
|
|
} |
|
|
} |
|
|
|
|
|
p0 = p1++; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
path->nfill = (int)(dst - verts); |
|
|
|
|
|
verts = dst; |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
wo = 0.0f; |
|
|
|
|
|
path->fill = 0; |
|
|
|
|
|
path->nfill = 0; |
|
|
|
|
|
|
|
|
for (j = 0; j < path->count; ++j) { |
|
|
|
|
|
nvg__vset(dst, pts[j].x, pts[j].y, 0.5f,1); |
|
|
|
|
|
dst++; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Calculate fringe or stroke |
|
|
|
|
|
if (feats & NVG_STROKE) { |
|
|
|
|
|
float lw = w + wo, rw = w - wo; |
|
|
|
|
|
float lu = 0, ru = 1; |
|
|
|
|
|
int loop = ((feats & NVG_CAPS) && path->closed == 0) ? 0 : 1; |
|
|
|
|
|
|
|
|
path->nfill = (int)(dst - verts); |
|
|
|
|
|
verts = dst; |
|
|
|
|
|
|
|
|
|
|
|
// Calculate fringe |
|
|
|
|
|
if (fringe) { |
|
|
|
|
|
lw = w + woff; |
|
|
|
|
|
rw = w - woff; |
|
|
|
|
|
lu = 0; |
|
|
|
|
|
ru = 1; |
|
|
dst = verts; |
|
|
dst = verts; |
|
|
path->stroke = dst; |
|
|
path->stroke = dst; |
|
|
|
|
|
|
|
|
// Create only half a fringe for convex shapes so that |
|
|
// Create only half a fringe for convex shapes so that |
|
|
// the shape can be rendered without stenciling. |
|
|
// the shape can be rendered without stenciling. |
|
|
if (convex) { |
|
|
if (convex) { |
|
|
lw = wo; // This should generate the same vertex as fill inset above. |
|
|
|
|
|
|
|
|
lw = woff; // This should generate the same vertex as fill inset above. |
|
|
lu = 0.5f; // Set outline fade at middle. |
|
|
lu = 0.5f; // Set outline fade at middle. |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (loop) { |
|
|
|
|
|
// Looping |
|
|
|
|
|
p0 = &pts[path->count-1]; |
|
|
|
|
|
p1 = &pts[0]; |
|
|
|
|
|
s = 0; |
|
|
|
|
|
e = path->count; |
|
|
|
|
|
} else { |
|
|
|
|
|
// Add cap |
|
|
|
|
|
p0 = &pts[0]; |
|
|
|
|
|
p1 = &pts[1]; |
|
|
|
|
|
s = 1; |
|
|
|
|
|
e = path->count-1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (loop == 0) { |
|
|
|
|
|
// Add cap |
|
|
|
|
|
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; |
|
|
|
|
|
if (lineCap == NVG_BUTT || lineCap == NVG_SQUARE) { |
|
|
|
|
|
if (lineCap == NVG_BUTT) { |
|
|
|
|
|
px = p0->x + dx*ctx->fringeWidth*0.5f; |
|
|
|
|
|
py = p0->y + dy*ctx->fringeWidth*0.5f; |
|
|
|
|
|
} else /*if (lineCap == NVG_SQUARE)*/ { |
|
|
|
|
|
px = p0->x - dx*(w - ctx->fringeWidth); |
|
|
|
|
|
py = p0->y - dy*(w - ctx->fringeWidth); |
|
|
|
|
|
} |
|
|
|
|
|
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++; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// Looping |
|
|
|
|
|
p0 = &pts[path->count-1]; |
|
|
|
|
|
p1 = &pts[0]; |
|
|
|
|
|
|
|
|
for (j = s; j < e; ++j) { |
|
|
|
|
|
|
|
|
for (j = 0; j < path->count; ++j) { |
|
|
if ((p1->flags & (NVG_PT_BEVEL | NVG_PR_INNERBEVEL)) != 0) { |
|
|
if ((p1->flags & (NVG_PT_BEVEL | NVG_PR_INNERBEVEL)) != 0) { |
|
|
if (lineJoin == NVG_ROUND) { |
|
|
|
|
|
dst = nvg__roundJoin(dst, p0, p1, lw, rw, lu, ru, ncap, ctx->fringeWidth); |
|
|
|
|
|
} else { |
|
|
|
|
|
dst = nvg__bevelJoin(dst, p0, p1, lw, rw, lu, ru, ctx->fringeWidth); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
dst = nvg__bevelJoin(dst, p0, p1, lw, rw, lu, ru, ctx->fringeWidth); |
|
|
} else { |
|
|
} else { |
|
|
nvg__vset(dst, p1->x + (p1->dmx * lw), p1->y + (p1->dmy * lw), lu,1); dst++; |
|
|
nvg__vset(dst, p1->x + (p1->dmx * lw), p1->y + (p1->dmy * lw), lu,1); dst++; |
|
|
nvg__vset(dst, p1->x - (p1->dmx * rw), p1->y - (p1->dmy * rw), ru,1); dst++; |
|
|
nvg__vset(dst, p1->x - (p1->dmx * rw), p1->y - (p1->dmy * rw), ru,1); dst++; |
|
@@ -1603,49 +1722,14 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w, |
|
|
p0 = p1++; |
|
|
p0 = p1++; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (loop) { |
|
|
|
|
|
// Loop it |
|
|
|
|
|
nvg__vset(dst, verts[0].x, verts[0].y, lu,1); dst++; |
|
|
|
|
|
nvg__vset(dst, verts[1].x, verts[1].y, ru,1); dst++; |
|
|
|
|
|
} else { |
|
|
|
|
|
// Add cap |
|
|
|
|
|
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; |
|
|
|
|
|
if (lineCap == NVG_BUTT || lineCap == NVG_SQUARE) { |
|
|
|
|
|
if (lineCap == NVG_BUTT) { |
|
|
|
|
|
px = p1->x - dx*ctx->fringeWidth*0.5f; |
|
|
|
|
|
py = p1->y - dy*ctx->fringeWidth*0.5f; |
|
|
|
|
|
} else /*if (lineCap == NVG_SQUARE)*/ { |
|
|
|
|
|
px = p1->x + dx*(w - ctx->fringeWidth); |
|
|
|
|
|
py = p1->y + dy*(w - ctx->fringeWidth); |
|
|
|
|
|
} |
|
|
|
|
|
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++; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// Loop it |
|
|
|
|
|
nvg__vset(dst, verts[0].x, verts[0].y, lu,1); dst++; |
|
|
|
|
|
nvg__vset(dst, verts[1].x, verts[1].y, ru,1); dst++; |
|
|
|
|
|
|
|
|
path->nstroke = (int)(dst - verts); |
|
|
path->nstroke = (int)(dst - verts); |
|
|
|
|
|
|
|
|
verts = dst; |
|
|
verts = dst; |
|
|
} else { |
|
|
} else { |
|
|
path->stroke = 0; |
|
|
|
|
|
|
|
|
path->stroke = NULL; |
|
|
path->nstroke = 0; |
|
|
path->nstroke = 0; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@@ -1896,9 +1980,9 @@ void nvgFill(struct NVGcontext* ctx) |
|
|
|
|
|
|
|
|
nvg__flattenPaths(ctx); |
|
|
nvg__flattenPaths(ctx); |
|
|
if (ctx->params.edgeAntiAlias) |
|
|
if (ctx->params.edgeAntiAlias) |
|
|
nvg__expandStrokeAndFill(ctx, NVG_FILL|NVG_STROKE, ctx->fringeWidth, NVG_BUTT, NVG_MITER, 3.6f); |
|
|
|
|
|
|
|
|
nvg__expandFill(ctx, ctx->fringeWidth, NVG_MITER, 2.4f); |
|
|
else |
|
|
else |
|
|
nvg__expandStrokeAndFill(ctx, NVG_FILL, 0.0f, NVG_BUTT, NVG_MITER, 1.2f); |
|
|
|
|
|
|
|
|
nvg__expandFill(ctx, 0.0f, NVG_MITER, 2.4f); |
|
|
|
|
|
|
|
|
ctx->params.renderFill(ctx->params.userPtr, &state->fill, &state->scissor, ctx->fringeWidth, |
|
|
ctx->params.renderFill(ctx->params.userPtr, &state->fill, &state->scissor, ctx->fringeWidth, |
|
|
ctx->cache->bounds, ctx->cache->paths, ctx->cache->npaths); |
|
|
ctx->cache->bounds, ctx->cache->paths, ctx->cache->npaths); |
|
@@ -1931,10 +2015,11 @@ void nvgStroke(struct NVGcontext* ctx) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
nvg__flattenPaths(ctx); |
|
|
nvg__flattenPaths(ctx); |
|
|
|
|
|
|
|
|
if (ctx->params.edgeAntiAlias) |
|
|
if (ctx->params.edgeAntiAlias) |
|
|
nvg__expandStrokeAndFill(ctx, NVG_STROKE|NVG_CAPS, strokeWidth*0.5f + ctx->fringeWidth*0.5f, state->lineCap, state->lineJoin, state->miterLimit); |
|
|
|
|
|
|
|
|
nvg__expandStroke(ctx, strokeWidth*0.5f + ctx->fringeWidth*0.5f, state->lineCap, state->lineJoin, state->miterLimit); |
|
|
else |
|
|
else |
|
|
nvg__expandStrokeAndFill(ctx, NVG_STROKE|NVG_CAPS, strokeWidth*0.5f, state->lineCap, state->lineJoin, state->miterLimit); |
|
|
|
|
|
|
|
|
nvg__expandStroke(ctx, strokeWidth*0.5f, state->lineCap, state->lineJoin, state->miterLimit); |
|
|
|
|
|
|
|
|
ctx->params.renderStroke(ctx->params.userPtr, &strokePaint, &state->scissor, ctx->fringeWidth, |
|
|
ctx->params.renderStroke(ctx->params.userPtr, &strokePaint, &state->scissor, ctx->fringeWidth, |
|
|
strokeWidth, ctx->cache->paths, ctx->cache->npaths); |
|
|
strokeWidth, ctx->cache->paths, ctx->cache->npaths); |
|
|