lnvis

nanovg lightning network visualizer
git clone git://jb55.com/lnvis
Log | Files | Refs | README | LICENSE

nanovg.c (76815B)


      1 //
      2 // Copyright (c) 2013 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 // Permission is granted to anyone to use this software for any purpose,
      8 // including commercial applications, and to alter it and redistribute it
      9 // freely, subject to the following restrictions:
     10 // 1. The origin of this software must not be misrepresented; you must not
     11 //    claim that you wrote the original software. If you use this software
     12 //    in a product, an acknowledgment in the product documentation would be
     13 //    appreciated but is not required.
     14 // 2. Altered source versions must be plainly marked as such, and must not be
     15 //    misrepresented as being the original software.
     16 // 3. This notice may not be removed or altered from any source distribution.
     17 //
     18 
     19 #include <stdlib.h>
     20 #include <stdio.h>
     21 #include <math.h>
     22 #include <memory.h>
     23 
     24 #include "nanovg.h"
     25 #define FONTSTASH_IMPLEMENTATION
     26 #include "fontstash.h"
     27 #define STB_IMAGE_IMPLEMENTATION
     28 
     29 #pragma GCC diagnostic push
     30 #pragma GCC diagnostic ignored "-Wmisleading-indentation"
     31 #pragma GCC diagnostic ignored "-Wshift-negative-value"
     32 #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
     33 #include "stb_image.h"
     34 #pragma GCC diagnostic pop
     35 
     36 #ifdef _MSC_VER
     37 #pragma warning(disable: 4100)  // unreferenced formal parameter
     38 #pragma warning(disable: 4127)  // conditional expression is constant
     39 #pragma warning(disable: 4204)  // nonstandard extension used : non-constant aggregate initializer
     40 #pragma warning(disable: 4706)  // assignment within conditional expression
     41 #endif
     42 
     43 #define NVG_INIT_FONTIMAGE_SIZE  512
     44 #define NVG_MAX_FONTIMAGE_SIZE   2048
     45 #define NVG_MAX_FONTIMAGES       4
     46 
     47 #define NVG_INIT_COMMANDS_SIZE 256
     48 #define NVG_INIT_POINTS_SIZE 128
     49 #define NVG_INIT_PATHS_SIZE 16
     50 #define NVG_INIT_VERTS_SIZE 256
     51 #define NVG_MAX_STATES 32
     52 
     53 #define NVG_KAPPA90 0.5522847493f	// Length proportional to radius of a cubic bezier handle for 90deg arcs.
     54 
     55 #define NVG_COUNTOF(arr) (sizeof(arr) / sizeof(0[arr]))
     56 
     57 
     58 enum NVGcommands {
     59 	NVG_MOVETO = 0,
     60 	NVG_LINETO = 1,
     61 	NVG_BEZIERTO = 2,
     62 	NVG_CLOSE = 3,
     63 	NVG_WINDING = 4,
     64 };
     65 
     66 enum NVGpointFlags
     67 {
     68 	NVG_PT_CORNER = 0x01,
     69 	NVG_PT_LEFT = 0x02,
     70 	NVG_PT_BEVEL = 0x04,
     71 	NVG_PR_INNERBEVEL = 0x08,
     72 };
     73 
     74 struct NVGstate {
     75 	NVGcompositeOperationState compositeOperation;
     76 	int shapeAntiAlias;
     77 	NVGpaint fill;
     78 	NVGpaint stroke;
     79 	float strokeWidth;
     80 	float miterLimit;
     81 	int lineJoin;
     82 	int lineCap;
     83 	float alpha;
     84 	float xform[6];
     85 	NVGscissor scissor;
     86 	float fontSize;
     87 	float letterSpacing;
     88 	float lineHeight;
     89 	float fontBlur;
     90 	int textAlign;
     91 	int fontId;
     92 };
     93 typedef struct NVGstate NVGstate;
     94 
     95 struct NVGpoint {
     96 	float x,y;
     97 	float dx, dy;
     98 	float len;
     99 	float dmx, dmy;
    100 	unsigned char flags;
    101 };
    102 typedef struct NVGpoint NVGpoint;
    103 
    104 struct NVGpathCache {
    105 	NVGpoint* points;
    106 	int npoints;
    107 	int cpoints;
    108 	NVGpath* paths;
    109 	int npaths;
    110 	int cpaths;
    111 	NVGvertex* verts;
    112 	int nverts;
    113 	int cverts;
    114 	float bounds[4];
    115 };
    116 typedef struct NVGpathCache NVGpathCache;
    117 
    118 struct NVGcontext {
    119 	NVGparams params;
    120 	float* commands;
    121 	int ccommands;
    122 	int ncommands;
    123 	float commandx, commandy;
    124 	NVGstate states[NVG_MAX_STATES];
    125 	int nstates;
    126 	NVGpathCache* cache;
    127 	float tessTol;
    128 	float distTol;
    129 	float fringeWidth;
    130 	float devicePxRatio;
    131 	struct FONScontext* fs;
    132 	int fontImages[NVG_MAX_FONTIMAGES];
    133 	int fontImageIdx;
    134 	int drawCallCount;
    135 	int fillTriCount;
    136 	int strokeTriCount;
    137 	int textTriCount;
    138 };
    139 
    140 static float nvg__sqrtf(float a) { return sqrtf(a); }
    141 static float nvg__modf(float a, float b) { return fmodf(a, b); }
    142 static float nvg__sinf(float a) { return sinf(a); }
    143 static float nvg__cosf(float a) { return cosf(a); }
    144 static float nvg__tanf(float a) { return tanf(a); }
    145 static float nvg__atan2f(float a,float b) { return atan2f(a, b); }
    146 static float nvg__acosf(float a) { return acosf(a); }
    147 
    148 static int nvg__mini(int a, int b) { return a < b ? a : b; }
    149 static int nvg__maxi(int a, int b) { return a > b ? a : b; }
    150 static int nvg__clampi(int a, int mn, int mx) { return a < mn ? mn : (a > mx ? mx : a); }
    151 static float nvg__minf(float a, float b) { return a < b ? a : b; }
    152 static float nvg__maxf(float a, float b) { return a > b ? a : b; }
    153 static float nvg__absf(float a) { return a >= 0.0f ? a : -a; }
    154 static float nvg__signf(float a) { return a >= 0.0f ? 1.0f : -1.0f; }
    155 static float nvg__clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); }
    156 static float nvg__cross(float dx0, float dy0, float dx1, float dy1) { return dx1*dy0 - dx0*dy1; }
    157 
    158 static float nvg__normalize(float *x, float* y)
    159 {
    160 	float d = nvg__sqrtf((*x)*(*x) + (*y)*(*y));
    161 	if (d > 1e-6f) {
    162 		float id = 1.0f / d;
    163 		*x *= id;
    164 		*y *= id;
    165 	}
    166 	return d;
    167 }
    168 
    169 
    170 static void nvg__deletePathCache(NVGpathCache* c)
    171 {
    172 	if (c == NULL) return;
    173 	if (c->points != NULL) free(c->points);
    174 	if (c->paths != NULL) free(c->paths);
    175 	if (c->verts != NULL) free(c->verts);
    176 	free(c);
    177 }
    178 
    179 static NVGpathCache* nvg__allocPathCache(void)
    180 {
    181 	NVGpathCache* c = (NVGpathCache*)malloc(sizeof(NVGpathCache));
    182 	if (c == NULL) goto error;
    183 	memset(c, 0, sizeof(NVGpathCache));
    184 
    185 	c->points = (NVGpoint*)malloc(sizeof(NVGpoint)*NVG_INIT_POINTS_SIZE);
    186 	if (!c->points) goto error;
    187 	c->npoints = 0;
    188 	c->cpoints = NVG_INIT_POINTS_SIZE;
    189 
    190 	c->paths = (NVGpath*)malloc(sizeof(NVGpath)*NVG_INIT_PATHS_SIZE);
    191 	if (!c->paths) goto error;
    192 	c->npaths = 0;
    193 	c->cpaths = NVG_INIT_PATHS_SIZE;
    194 
    195 	c->verts = (NVGvertex*)malloc(sizeof(NVGvertex)*NVG_INIT_VERTS_SIZE);
    196 	if (!c->verts) goto error;
    197 	c->nverts = 0;
    198 	c->cverts = NVG_INIT_VERTS_SIZE;
    199 
    200 	return c;
    201 error:
    202 	nvg__deletePathCache(c);
    203 	return NULL;
    204 }
    205 
    206 static void nvg__setDevicePixelRatio(NVGcontext* ctx, float ratio)
    207 {
    208 	ctx->tessTol = 0.25f / ratio;
    209 	ctx->distTol = 0.01f / ratio;
    210 	ctx->fringeWidth = 1.0f / ratio;
    211 	ctx->devicePxRatio = ratio;
    212 }
    213 
    214 static NVGcompositeOperationState nvg__compositeOperationState(int op)
    215 {
    216 	int sfactor, dfactor;
    217 
    218 	if (op == NVG_SOURCE_OVER)
    219 	{
    220 		sfactor = NVG_ONE;
    221 		dfactor = NVG_ONE_MINUS_SRC_ALPHA;
    222 	}
    223 	else if (op == NVG_SOURCE_IN)
    224 	{
    225 		sfactor = NVG_DST_ALPHA;
    226 		dfactor = NVG_ZERO;
    227 	}
    228 	else if (op == NVG_SOURCE_OUT)
    229 	{
    230 		sfactor = NVG_ONE_MINUS_DST_ALPHA;
    231 		dfactor = NVG_ZERO;
    232 	}
    233 	else if (op == NVG_ATOP)
    234 	{
    235 		sfactor = NVG_DST_ALPHA;
    236 		dfactor = NVG_ONE_MINUS_SRC_ALPHA;
    237 	}
    238 	else if (op == NVG_DESTINATION_OVER)
    239 	{
    240 		sfactor = NVG_ONE_MINUS_DST_ALPHA;
    241 		dfactor = NVG_ONE;
    242 	}
    243 	else if (op == NVG_DESTINATION_IN)
    244 	{
    245 		sfactor = NVG_ZERO;
    246 		dfactor = NVG_SRC_ALPHA;
    247 	}
    248 	else if (op == NVG_DESTINATION_OUT)
    249 	{
    250 		sfactor = NVG_ZERO;
    251 		dfactor = NVG_ONE_MINUS_SRC_ALPHA;
    252 	}
    253 	else if (op == NVG_DESTINATION_ATOP)
    254 	{
    255 		sfactor = NVG_ONE_MINUS_DST_ALPHA;
    256 		dfactor = NVG_SRC_ALPHA;
    257 	}
    258 	else if (op == NVG_LIGHTER)
    259 	{
    260 		sfactor = NVG_ONE;
    261 		dfactor = NVG_ONE;
    262 	}
    263 	else if (op == NVG_COPY)
    264 	{
    265 		sfactor = NVG_ONE;
    266 		dfactor = NVG_ZERO;
    267 	}
    268 	else if (op == NVG_XOR)
    269 	{
    270 		sfactor = NVG_ONE_MINUS_DST_ALPHA;
    271 		dfactor = NVG_ONE_MINUS_SRC_ALPHA;
    272 	}
    273 	else
    274 	{
    275 		sfactor = NVG_ONE;
    276 		dfactor = NVG_ZERO;
    277 	}
    278 
    279 	NVGcompositeOperationState state;
    280 	state.srcRGB = sfactor;
    281 	state.dstRGB = dfactor;
    282 	state.srcAlpha = sfactor;
    283 	state.dstAlpha = dfactor;
    284 	return state;
    285 }
    286 
    287 static NVGstate* nvg__getState(NVGcontext* ctx)
    288 {
    289 	return &ctx->states[ctx->nstates-1];
    290 }
    291 
    292 NVGcontext* nvgCreateInternal(NVGparams* params)
    293 {
    294 	FONSparams fontParams;
    295 	NVGcontext* ctx = (NVGcontext*)malloc(sizeof(NVGcontext));
    296 	int i;
    297 	if (ctx == NULL) goto error;
    298 	memset(ctx, 0, sizeof(NVGcontext));
    299 
    300 	ctx->params = *params;
    301 	for (i = 0; i < NVG_MAX_FONTIMAGES; i++)
    302 		ctx->fontImages[i] = 0;
    303 
    304 	ctx->commands = (float*)malloc(sizeof(float)*NVG_INIT_COMMANDS_SIZE);
    305 	if (!ctx->commands) goto error;
    306 	ctx->ncommands = 0;
    307 	ctx->ccommands = NVG_INIT_COMMANDS_SIZE;
    308 
    309 	ctx->cache = nvg__allocPathCache();
    310 	if (ctx->cache == NULL) goto error;
    311 
    312 	nvgSave(ctx);
    313 	nvgReset(ctx);
    314 
    315 	nvg__setDevicePixelRatio(ctx, 1.0f);
    316 
    317 	if (ctx->params.renderCreate(ctx->params.userPtr) == 0) goto error;
    318 
    319 	// Init font rendering
    320 	memset(&fontParams, 0, sizeof(fontParams));
    321 	fontParams.width = NVG_INIT_FONTIMAGE_SIZE;
    322 	fontParams.height = NVG_INIT_FONTIMAGE_SIZE;
    323 	fontParams.flags = FONS_ZERO_TOPLEFT;
    324 	fontParams.renderCreate = NULL;
    325 	fontParams.renderUpdate = NULL;
    326 	fontParams.renderDraw = NULL;
    327 	fontParams.renderDelete = NULL;
    328 	fontParams.userPtr = NULL;
    329 	ctx->fs = fonsCreateInternal(&fontParams);
    330 	if (ctx->fs == NULL) goto error;
    331 
    332 	// Create font texture
    333 	ctx->fontImages[0] = ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_ALPHA, fontParams.width, fontParams.height, 0, NULL);
    334 	if (ctx->fontImages[0] == 0) goto error;
    335 	ctx->fontImageIdx = 0;
    336 
    337 	return ctx;
    338 
    339 error:
    340 	nvgDeleteInternal(ctx);
    341 	return 0;
    342 }
    343 
    344 NVGparams* nvgInternalParams(NVGcontext* ctx)
    345 {
    346     return &ctx->params;
    347 }
    348 
    349 void nvgDeleteInternal(NVGcontext* ctx)
    350 {
    351 	int i;
    352 	if (ctx == NULL) return;
    353 	if (ctx->commands != NULL) free(ctx->commands);
    354 	if (ctx->cache != NULL) nvg__deletePathCache(ctx->cache);
    355 
    356 	if (ctx->fs)
    357 		fonsDeleteInternal(ctx->fs);
    358 
    359 	for (i = 0; i < NVG_MAX_FONTIMAGES; i++) {
    360 		if (ctx->fontImages[i] != 0) {
    361 			nvgDeleteImage(ctx, ctx->fontImages[i]);
    362 			ctx->fontImages[i] = 0;
    363 		}
    364 	}
    365 
    366 	if (ctx->params.renderDelete != NULL)
    367 		ctx->params.renderDelete(ctx->params.userPtr);
    368 
    369 	free(ctx);
    370 }
    371 
    372 void nvgBeginFrame(NVGcontext* ctx, float windowWidth, float windowHeight, float devicePixelRatio)
    373 {
    374 /*	printf("Tris: draws:%d  fill:%d  stroke:%d  text:%d  TOT:%d\n",
    375 		ctx->drawCallCount, ctx->fillTriCount, ctx->strokeTriCount, ctx->textTriCount,
    376 		ctx->fillTriCount+ctx->strokeTriCount+ctx->textTriCount);*/
    377 
    378 	ctx->nstates = 0;
    379 	nvgSave(ctx);
    380 	nvgReset(ctx);
    381 
    382 	nvg__setDevicePixelRatio(ctx, devicePixelRatio);
    383 
    384 	ctx->params.renderViewport(ctx->params.userPtr, windowWidth, windowHeight, devicePixelRatio);
    385 
    386 	ctx->drawCallCount = 0;
    387 	ctx->fillTriCount = 0;
    388 	ctx->strokeTriCount = 0;
    389 	ctx->textTriCount = 0;
    390 }
    391 
    392 void nvgCancelFrame(NVGcontext* ctx)
    393 {
    394 	ctx->params.renderCancel(ctx->params.userPtr);
    395 }
    396 
    397 void nvgEndFrame(NVGcontext* ctx)
    398 {
    399 	ctx->params.renderFlush(ctx->params.userPtr);
    400 	if (ctx->fontImageIdx != 0) {
    401 		int fontImage = ctx->fontImages[ctx->fontImageIdx];
    402 		int i, j, iw, ih;
    403 		// delete images that smaller than current one
    404 		if (fontImage == 0)
    405 			return;
    406 		nvgImageSize(ctx, fontImage, &iw, &ih);
    407 		for (i = j = 0; i < ctx->fontImageIdx; i++) {
    408 			if (ctx->fontImages[i] != 0) {
    409 				int nw, nh;
    410 				nvgImageSize(ctx, ctx->fontImages[i], &nw, &nh);
    411 				if (nw < iw || nh < ih)
    412 					nvgDeleteImage(ctx, ctx->fontImages[i]);
    413 				else
    414 					ctx->fontImages[j++] = ctx->fontImages[i];
    415 			}
    416 		}
    417 		// make current font image to first
    418 		ctx->fontImages[j++] = ctx->fontImages[0];
    419 		ctx->fontImages[0] = fontImage;
    420 		ctx->fontImageIdx = 0;
    421 		// clear all images after j
    422 		for (i = j; i < NVG_MAX_FONTIMAGES; i++)
    423 			ctx->fontImages[i] = 0;
    424 	}
    425 }
    426 
    427 NVGcolor nvgRGB(unsigned char r, unsigned char g, unsigned char b)
    428 {
    429 	return nvgRGBA(r,g,b,255);
    430 }
    431 
    432 NVGcolor nvgRGBf(float r, float g, float b)
    433 {
    434 	return nvgRGBAf(r,g,b,1.0f);
    435 }
    436 
    437 NVGcolor nvgRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
    438 {
    439 	NVGcolor color;
    440 	// Use longer initialization to suppress warning.
    441 	color.r = r / 255.0f;
    442 	color.g = g / 255.0f;
    443 	color.b = b / 255.0f;
    444 	color.a = a / 255.0f;
    445 	return color;
    446 }
    447 
    448 NVGcolor nvgRGBAf(float r, float g, float b, float a)
    449 {
    450 	NVGcolor color;
    451 	// Use longer initialization to suppress warning.
    452 	color.r = r;
    453 	color.g = g;
    454 	color.b = b;
    455 	color.a = a;
    456 	return color;
    457 }
    458 
    459 NVGcolor nvgTransRGBA(NVGcolor c, unsigned char a)
    460 {
    461 	c.a = a / 255.0f;
    462 	return c;
    463 }
    464 
    465 NVGcolor nvgTransRGBAf(NVGcolor c, float a)
    466 {
    467 	c.a = a;
    468 	return c;
    469 }
    470 
    471 NVGcolor nvgLerpRGBA(NVGcolor c0, NVGcolor c1, float u)
    472 {
    473 	int i;
    474 	float oneminu;
    475 	NVGcolor cint = {{{0}}};
    476 
    477 	u = nvg__clampf(u, 0.0f, 1.0f);
    478 	oneminu = 1.0f - u;
    479 	for( i = 0; i <4; i++ )
    480 	{
    481 		cint.rgba[i] = c0.rgba[i] * oneminu + c1.rgba[i] * u;
    482 	}
    483 
    484 	return cint;
    485 }
    486 
    487 NVGcolor nvgHSL(float h, float s, float l)
    488 {
    489 	return nvgHSLA(h,s,l,255);
    490 }
    491 
    492 static float nvg__hue(float h, float m1, float m2)
    493 {
    494 	if (h < 0) h += 1;
    495 	if (h > 1) h -= 1;
    496 	if (h < 1.0f/6.0f)
    497 		return m1 + (m2 - m1) * h * 6.0f;
    498 	else if (h < 3.0f/6.0f)
    499 		return m2;
    500 	else if (h < 4.0f/6.0f)
    501 		return m1 + (m2 - m1) * (2.0f/3.0f - h) * 6.0f;
    502 	return m1;
    503 }
    504 
    505 NVGcolor nvgHSLA(float h, float s, float l, unsigned char a)
    506 {
    507 	float m1, m2;
    508 	NVGcolor col;
    509 	h = nvg__modf(h, 1.0f);
    510 	if (h < 0.0f) h += 1.0f;
    511 	s = nvg__clampf(s, 0.0f, 1.0f);
    512 	l = nvg__clampf(l, 0.0f, 1.0f);
    513 	m2 = l <= 0.5f ? (l * (1 + s)) : (l + s - l * s);
    514 	m1 = 2 * l - m2;
    515 	col.r = nvg__clampf(nvg__hue(h + 1.0f/3.0f, m1, m2), 0.0f, 1.0f);
    516 	col.g = nvg__clampf(nvg__hue(h, m1, m2), 0.0f, 1.0f);
    517 	col.b = nvg__clampf(nvg__hue(h - 1.0f/3.0f, m1, m2), 0.0f, 1.0f);
    518 	col.a = a/255.0f;
    519 	return col;
    520 }
    521 
    522 void nvgTransformIdentity(float* t)
    523 {
    524 	t[0] = 1.0f; t[1] = 0.0f;
    525 	t[2] = 0.0f; t[3] = 1.0f;
    526 	t[4] = 0.0f; t[5] = 0.0f;
    527 }
    528 
    529 void nvgTransformTranslate(float* t, float tx, float ty)
    530 {
    531 	t[0] = 1.0f; t[1] = 0.0f;
    532 	t[2] = 0.0f; t[3] = 1.0f;
    533 	t[4] = tx; t[5] = ty;
    534 }
    535 
    536 void nvgTransformScale(float* t, float sx, float sy)
    537 {
    538 	t[0] = sx; t[1] = 0.0f;
    539 	t[2] = 0.0f; t[3] = sy;
    540 	t[4] = 0.0f; t[5] = 0.0f;
    541 }
    542 
    543 void nvgTransformRotate(float* t, float a)
    544 {
    545 	float cs = nvg__cosf(a), sn = nvg__sinf(a);
    546 	t[0] = cs; t[1] = sn;
    547 	t[2] = -sn; t[3] = cs;
    548 	t[4] = 0.0f; t[5] = 0.0f;
    549 }
    550 
    551 void nvgTransformSkewX(float* t, float a)
    552 {
    553 	t[0] = 1.0f; t[1] = 0.0f;
    554 	t[2] = nvg__tanf(a); t[3] = 1.0f;
    555 	t[4] = 0.0f; t[5] = 0.0f;
    556 }
    557 
    558 void nvgTransformSkewY(float* t, float a)
    559 {
    560 	t[0] = 1.0f; t[1] = nvg__tanf(a);
    561 	t[2] = 0.0f; t[3] = 1.0f;
    562 	t[4] = 0.0f; t[5] = 0.0f;
    563 }
    564 
    565 void nvgTransformMultiply(float* t, const float* s)
    566 {
    567 	float t0 = t[0] * s[0] + t[1] * s[2];
    568 	float t2 = t[2] * s[0] + t[3] * s[2];
    569 	float t4 = t[4] * s[0] + t[5] * s[2] + s[4];
    570 	t[1] = t[0] * s[1] + t[1] * s[3];
    571 	t[3] = t[2] * s[1] + t[3] * s[3];
    572 	t[5] = t[4] * s[1] + t[5] * s[3] + s[5];
    573 	t[0] = t0;
    574 	t[2] = t2;
    575 	t[4] = t4;
    576 }
    577 
    578 void nvgTransformPremultiply(float* t, const float* s)
    579 {
    580 	float s2[6];
    581 	memcpy(s2, s, sizeof(float)*6);
    582 	nvgTransformMultiply(s2, t);
    583 	memcpy(t, s2, sizeof(float)*6);
    584 }
    585 
    586 int nvgTransformInverse(float* inv, const float* t)
    587 {
    588 	double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1];
    589 	if (det > -1e-6 && det < 1e-6) {
    590 		nvgTransformIdentity(inv);
    591 		return 0;
    592 	}
    593 	invdet = 1.0 / det;
    594 	inv[0] = (float)(t[3] * invdet);
    595 	inv[2] = (float)(-t[2] * invdet);
    596 	inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet);
    597 	inv[1] = (float)(-t[1] * invdet);
    598 	inv[3] = (float)(t[0] * invdet);
    599 	inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet);
    600 	return 1;
    601 }
    602 
    603 void nvgTransformPoint(float* dx, float* dy, const float* t, float sx, float sy)
    604 {
    605 	*dx = sx*t[0] + sy*t[2] + t[4];
    606 	*dy = sx*t[1] + sy*t[3] + t[5];
    607 }
    608 
    609 float nvgDegToRad(float deg)
    610 {
    611 	return deg / 180.0f * NVG_PI;
    612 }
    613 
    614 float nvgRadToDeg(float rad)
    615 {
    616 	return rad / NVG_PI * 180.0f;
    617 }
    618 
    619 static void nvg__setPaintColor(NVGpaint* p, NVGcolor color)
    620 {
    621 	memset(p, 0, sizeof(*p));
    622 	nvgTransformIdentity(p->xform);
    623 	p->radius = 0.0f;
    624 	p->feather = 1.0f;
    625 	p->innerColor = color;
    626 	p->outerColor = color;
    627 }
    628 
    629 
    630 // State handling
    631 void nvgSave(NVGcontext* ctx)
    632 {
    633 	if (ctx->nstates >= NVG_MAX_STATES)
    634 		return;
    635 	if (ctx->nstates > 0)
    636 		memcpy(&ctx->states[ctx->nstates], &ctx->states[ctx->nstates-1], sizeof(NVGstate));
    637 	ctx->nstates++;
    638 }
    639 
    640 void nvgRestore(NVGcontext* ctx)
    641 {
    642 	if (ctx->nstates <= 1)
    643 		return;
    644 	ctx->nstates--;
    645 }
    646 
    647 void nvgReset(NVGcontext* ctx)
    648 {
    649 	NVGstate* state = nvg__getState(ctx);
    650 	memset(state, 0, sizeof(*state));
    651 
    652 	nvg__setPaintColor(&state->fill, nvgRGBA(255,255,255,255));
    653 	nvg__setPaintColor(&state->stroke, nvgRGBA(0,0,0,255));
    654 	state->compositeOperation = nvg__compositeOperationState(NVG_SOURCE_OVER);
    655 	state->shapeAntiAlias = 1;
    656 	state->strokeWidth = 1.0f;
    657 	state->miterLimit = 10.0f;
    658 	state->lineCap = NVG_BUTT;
    659 	state->lineJoin = NVG_MITER;
    660 	state->alpha = 1.0f;
    661 	nvgTransformIdentity(state->xform);
    662 
    663 	state->scissor.extent[0] = -1.0f;
    664 	state->scissor.extent[1] = -1.0f;
    665 
    666 	state->fontSize = 16.0f;
    667 	state->letterSpacing = 0.0f;
    668 	state->lineHeight = 1.0f;
    669 	state->fontBlur = 0.0f;
    670 	state->textAlign = NVG_ALIGN_LEFT | NVG_ALIGN_BASELINE;
    671 	state->fontId = 0;
    672 }
    673 
    674 // State setting
    675 void nvgShapeAntiAlias(NVGcontext* ctx, int enabled)
    676 {
    677 	NVGstate* state = nvg__getState(ctx);
    678 	state->shapeAntiAlias = enabled;
    679 }
    680 
    681 void nvgStrokeWidth(NVGcontext* ctx, float width)
    682 {
    683 	NVGstate* state = nvg__getState(ctx);
    684 	state->strokeWidth = width;
    685 }
    686 
    687 void nvgMiterLimit(NVGcontext* ctx, float limit)
    688 {
    689 	NVGstate* state = nvg__getState(ctx);
    690 	state->miterLimit = limit;
    691 }
    692 
    693 void nvgLineCap(NVGcontext* ctx, int cap)
    694 {
    695 	NVGstate* state = nvg__getState(ctx);
    696 	state->lineCap = cap;
    697 }
    698 
    699 void nvgLineJoin(NVGcontext* ctx, int join)
    700 {
    701 	NVGstate* state = nvg__getState(ctx);
    702 	state->lineJoin = join;
    703 }
    704 
    705 void nvgGlobalAlpha(NVGcontext* ctx, float alpha)
    706 {
    707 	NVGstate* state = nvg__getState(ctx);
    708 	state->alpha = alpha;
    709 }
    710 
    711 void nvgTransform(NVGcontext* ctx, float a, float b, float c, float d, float e, float f)
    712 {
    713 	NVGstate* state = nvg__getState(ctx);
    714 	float t[6] = { a, b, c, d, e, f };
    715 	nvgTransformPremultiply(state->xform, t);
    716 }
    717 
    718 void nvgResetTransform(NVGcontext* ctx)
    719 {
    720 	NVGstate* state = nvg__getState(ctx);
    721 	nvgTransformIdentity(state->xform);
    722 }
    723 
    724 void nvgTranslate(NVGcontext* ctx, float x, float y)
    725 {
    726 	NVGstate* state = nvg__getState(ctx);
    727 	float t[6];
    728 	nvgTransformTranslate(t, x,y);
    729 	nvgTransformPremultiply(state->xform, t);
    730 }
    731 
    732 void nvgRotate(NVGcontext* ctx, float angle)
    733 {
    734 	NVGstate* state = nvg__getState(ctx);
    735 	float t[6];
    736 	nvgTransformRotate(t, angle);
    737 	nvgTransformPremultiply(state->xform, t);
    738 }
    739 
    740 void nvgSkewX(NVGcontext* ctx, float angle)
    741 {
    742 	NVGstate* state = nvg__getState(ctx);
    743 	float t[6];
    744 	nvgTransformSkewX(t, angle);
    745 	nvgTransformPremultiply(state->xform, t);
    746 }
    747 
    748 void nvgSkewY(NVGcontext* ctx, float angle)
    749 {
    750 	NVGstate* state = nvg__getState(ctx);
    751 	float t[6];
    752 	nvgTransformSkewY(t, angle);
    753 	nvgTransformPremultiply(state->xform, t);
    754 }
    755 
    756 void nvgScale(NVGcontext* ctx, float x, float y)
    757 {
    758 	NVGstate* state = nvg__getState(ctx);
    759 	float t[6];
    760 	nvgTransformScale(t, x,y);
    761 	nvgTransformPremultiply(state->xform, t);
    762 }
    763 
    764 void nvgCurrentTransform(NVGcontext* ctx, float* xform)
    765 {
    766 	NVGstate* state = nvg__getState(ctx);
    767 	if (xform == NULL) return;
    768 	memcpy(xform, state->xform, sizeof(float)*6);
    769 }
    770 
    771 void nvgStrokeColor(NVGcontext* ctx, NVGcolor color)
    772 {
    773 	NVGstate* state = nvg__getState(ctx);
    774 	nvg__setPaintColor(&state->stroke, color);
    775 }
    776 
    777 void nvgStrokePaint(NVGcontext* ctx, NVGpaint paint)
    778 {
    779 	NVGstate* state = nvg__getState(ctx);
    780 	state->stroke = paint;
    781 	nvgTransformMultiply(state->stroke.xform, state->xform);
    782 }
    783 
    784 void nvgFillColor(NVGcontext* ctx, NVGcolor color)
    785 {
    786 	NVGstate* state = nvg__getState(ctx);
    787 	nvg__setPaintColor(&state->fill, color);
    788 }
    789 
    790 void nvgFillPaint(NVGcontext* ctx, NVGpaint paint)
    791 {
    792 	NVGstate* state = nvg__getState(ctx);
    793 	state->fill = paint;
    794 	nvgTransformMultiply(state->fill.xform, state->xform);
    795 }
    796 
    797 int nvgCreateImage(NVGcontext* ctx, const char* filename, int imageFlags)
    798 {
    799 	int w, h, n, image;
    800 	unsigned char* img;
    801 	stbi_set_unpremultiply_on_load(1);
    802 	stbi_convert_iphone_png_to_rgb(1);
    803 	img = stbi_load(filename, &w, &h, &n, 4);
    804 	if (img == NULL) {
    805 //		printf("Failed to load %s - %s\n", filename, stbi_failure_reason());
    806 		return 0;
    807 	}
    808 	image = nvgCreateImageRGBA(ctx, w, h, imageFlags, img);
    809 	stbi_image_free(img);
    810 	return image;
    811 }
    812 
    813 int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int ndata)
    814 {
    815 	int w, h, n, image;
    816 	unsigned char* img = stbi_load_from_memory(data, ndata, &w, &h, &n, 4);
    817 	if (img == NULL) {
    818 //		printf("Failed to load %s - %s\n", filename, stbi_failure_reason());
    819 		return 0;
    820 	}
    821 	image = nvgCreateImageRGBA(ctx, w, h, imageFlags, img);
    822 	stbi_image_free(img);
    823 	return image;
    824 }
    825 
    826 int nvgCreateImageRGBA(NVGcontext* ctx, int w, int h, int imageFlags, const unsigned char* data)
    827 {
    828 	return ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_RGBA, w, h, imageFlags, data);
    829 }
    830 
    831 void nvgUpdateImage(NVGcontext* ctx, int image, const unsigned char* data)
    832 {
    833 	int w, h;
    834 	ctx->params.renderGetTextureSize(ctx->params.userPtr, image, &w, &h);
    835 	ctx->params.renderUpdateTexture(ctx->params.userPtr, image, 0,0, w,h, data);
    836 }
    837 
    838 void nvgImageSize(NVGcontext* ctx, int image, int* w, int* h)
    839 {
    840 	ctx->params.renderGetTextureSize(ctx->params.userPtr, image, w, h);
    841 }
    842 
    843 void nvgDeleteImage(NVGcontext* ctx, int image)
    844 {
    845 	ctx->params.renderDeleteTexture(ctx->params.userPtr, image);
    846 }
    847 
    848 NVGpaint nvgLinearGradient(NVGcontext* ctx, float sx, float sy, float ex, float ey,
    849 			   NVGcolor icol, NVGcolor ocol)
    850 {
    851 	NVGpaint p;
    852 	float dx, dy, d;
    853 	const float large = 1e5;
    854 	NVG_NOTUSED(ctx);
    855 	memset(&p, 0, sizeof(p));
    856 
    857 	// Calculate transform aligned to the line
    858 	dx = ex - sx;
    859 	dy = ey - sy;
    860 	d = sqrtf(dx*dx + dy*dy);
    861 	if (d > 0.0001f) {
    862 		dx /= d;
    863 		dy /= d;
    864 	} else {
    865 		dx = 0;
    866 		dy = 1;
    867 	}
    868 
    869 	p.xform[0] = dy; p.xform[1] = -dx;
    870 	p.xform[2] = dx; p.xform[3] = dy;
    871 	p.xform[4] = sx - dx*large; p.xform[5] = sy - dy*large;
    872 
    873 	p.extent[0] = large;
    874 	p.extent[1] = large + d*0.5f;
    875 
    876 	p.radius = 0.0f;
    877 
    878 	p.feather = nvg__maxf(1.0f, d);
    879 
    880 	p.innerColor = icol;
    881 	p.outerColor = ocol;
    882 
    883 	return p;
    884 }
    885 
    886 NVGpaint nvgRadialGradient(NVGcontext* ctx,
    887 								  float cx, float cy, float inr, float outr,
    888 								  NVGcolor icol, NVGcolor ocol)
    889 {
    890 	NVGpaint p;
    891 	float r = (inr+outr)*0.5f;
    892 	float f = (outr-inr);
    893 	NVG_NOTUSED(ctx);
    894 	memset(&p, 0, sizeof(p));
    895 
    896 	nvgTransformIdentity(p.xform);
    897 	p.xform[4] = cx;
    898 	p.xform[5] = cy;
    899 
    900 	p.extent[0] = r;
    901 	p.extent[1] = r;
    902 
    903 	p.radius = r;
    904 
    905 	p.feather = nvg__maxf(1.0f, f);
    906 
    907 	p.innerColor = icol;
    908 	p.outerColor = ocol;
    909 
    910 	return p;
    911 }
    912 
    913 NVGpaint nvgBoxGradient(NVGcontext* ctx,
    914 							   float x, float y, float w, float h, float r, float f,
    915 							   NVGcolor icol, NVGcolor ocol)
    916 {
    917 	NVGpaint p;
    918 	NVG_NOTUSED(ctx);
    919 	memset(&p, 0, sizeof(p));
    920 
    921 	nvgTransformIdentity(p.xform);
    922 	p.xform[4] = x+w*0.5f;
    923 	p.xform[5] = y+h*0.5f;
    924 
    925 	p.extent[0] = w*0.5f;
    926 	p.extent[1] = h*0.5f;
    927 
    928 	p.radius = r;
    929 
    930 	p.feather = nvg__maxf(1.0f, f);
    931 
    932 	p.innerColor = icol;
    933 	p.outerColor = ocol;
    934 
    935 	return p;
    936 }
    937 
    938 
    939 NVGpaint nvgImagePattern(NVGcontext* ctx,
    940 								float cx, float cy, float w, float h, float angle,
    941 								int image, float alpha)
    942 {
    943 	NVGpaint p;
    944 	NVG_NOTUSED(ctx);
    945 	memset(&p, 0, sizeof(p));
    946 
    947 	nvgTransformRotate(p.xform, angle);
    948 	p.xform[4] = cx;
    949 	p.xform[5] = cy;
    950 
    951 	p.extent[0] = w;
    952 	p.extent[1] = h;
    953 
    954 	p.image = image;
    955 
    956 	p.innerColor = p.outerColor = nvgRGBAf(1,1,1,alpha);
    957 
    958 	return p;
    959 }
    960 
    961 // Scissoring
    962 void nvgScissor(NVGcontext* ctx, float x, float y, float w, float h)
    963 {
    964 	NVGstate* state = nvg__getState(ctx);
    965 
    966 	w = nvg__maxf(0.0f, w);
    967 	h = nvg__maxf(0.0f, h);
    968 
    969 	nvgTransformIdentity(state->scissor.xform);
    970 	state->scissor.xform[4] = x+w*0.5f;
    971 	state->scissor.xform[5] = y+h*0.5f;
    972 	nvgTransformMultiply(state->scissor.xform, state->xform);
    973 
    974 	state->scissor.extent[0] = w*0.5f;
    975 	state->scissor.extent[1] = h*0.5f;
    976 }
    977 
    978 static void nvg__isectRects(float* dst,
    979 							float ax, float ay, float aw, float ah,
    980 							float bx, float by, float bw, float bh)
    981 {
    982 	float minx = nvg__maxf(ax, bx);
    983 	float miny = nvg__maxf(ay, by);
    984 	float maxx = nvg__minf(ax+aw, bx+bw);
    985 	float maxy = nvg__minf(ay+ah, by+bh);
    986 	dst[0] = minx;
    987 	dst[1] = miny;
    988 	dst[2] = nvg__maxf(0.0f, maxx - minx);
    989 	dst[3] = nvg__maxf(0.0f, maxy - miny);
    990 }
    991 
    992 void nvgIntersectScissor(NVGcontext* ctx, float x, float y, float w, float h)
    993 {
    994 	NVGstate* state = nvg__getState(ctx);
    995 	float pxform[6], invxorm[6];
    996 	float rect[4];
    997 	float ex, ey, tex, tey;
    998 
    999 	// If no previous scissor has been set, set the scissor as current scissor.
   1000 	if (state->scissor.extent[0] < 0) {
   1001 		nvgScissor(ctx, x, y, w, h);
   1002 		return;
   1003 	}
   1004 
   1005 	// Transform the current scissor rect into current transform space.
   1006 	// If there is difference in rotation, this will be approximation.
   1007 	memcpy(pxform, state->scissor.xform, sizeof(float)*6);
   1008 	ex = state->scissor.extent[0];
   1009 	ey = state->scissor.extent[1];
   1010 	nvgTransformInverse(invxorm, state->xform);
   1011 	nvgTransformMultiply(pxform, invxorm);
   1012 	tex = ex*nvg__absf(pxform[0]) + ey*nvg__absf(pxform[2]);
   1013 	tey = ex*nvg__absf(pxform[1]) + ey*nvg__absf(pxform[3]);
   1014 
   1015 	// Intersect rects.
   1016 	nvg__isectRects(rect, pxform[4]-tex,pxform[5]-tey,tex*2,tey*2, x,y,w,h);
   1017 
   1018 	nvgScissor(ctx, rect[0], rect[1], rect[2], rect[3]);
   1019 }
   1020 
   1021 void nvgResetScissor(NVGcontext* ctx)
   1022 {
   1023 	NVGstate* state = nvg__getState(ctx);
   1024 	memset(state->scissor.xform, 0, sizeof(state->scissor.xform));
   1025 	state->scissor.extent[0] = -1.0f;
   1026 	state->scissor.extent[1] = -1.0f;
   1027 }
   1028 
   1029 // Global composite operation.
   1030 void nvgGlobalCompositeOperation(NVGcontext* ctx, int op)
   1031 {
   1032 	NVGstate* state = nvg__getState(ctx);
   1033 	state->compositeOperation = nvg__compositeOperationState(op);
   1034 }
   1035 
   1036 void nvgGlobalCompositeBlendFunc(NVGcontext* ctx, int sfactor, int dfactor)
   1037 {
   1038 	nvgGlobalCompositeBlendFuncSeparate(ctx, sfactor, dfactor, sfactor, dfactor);
   1039 }
   1040 
   1041 void nvgGlobalCompositeBlendFuncSeparate(NVGcontext* ctx, int srcRGB, int dstRGB, int srcAlpha, int dstAlpha)
   1042 {
   1043 	NVGcompositeOperationState op;
   1044 	op.srcRGB = srcRGB;
   1045 	op.dstRGB = dstRGB;
   1046 	op.srcAlpha = srcAlpha;
   1047 	op.dstAlpha = dstAlpha;
   1048 
   1049 	NVGstate* state = nvg__getState(ctx);
   1050 	state->compositeOperation = op;
   1051 }
   1052 
   1053 static int nvg__ptEquals(float x1, float y1, float x2, float y2, float tol)
   1054 {
   1055 	float dx = x2 - x1;
   1056 	float dy = y2 - y1;
   1057 	return dx*dx + dy*dy < tol*tol;
   1058 }
   1059 
   1060 static float nvg__distPtSeg(float x, float y, float px, float py, float qx, float qy)
   1061 {
   1062 	float pqx, pqy, dx, dy, d, t;
   1063 	pqx = qx-px;
   1064 	pqy = qy-py;
   1065 	dx = x-px;
   1066 	dy = y-py;
   1067 	d = pqx*pqx + pqy*pqy;
   1068 	t = pqx*dx + pqy*dy;
   1069 	if (d > 0) t /= d;
   1070 	if (t < 0) t = 0;
   1071 	else if (t > 1) t = 1;
   1072 	dx = px + t*pqx - x;
   1073 	dy = py + t*pqy - y;
   1074 	return dx*dx + dy*dy;
   1075 }
   1076 
   1077 static void nvg__appendCommands(NVGcontext* ctx, float* vals, int nvals)
   1078 {
   1079 	NVGstate* state = nvg__getState(ctx);
   1080 	int i;
   1081 
   1082 	if (ctx->ncommands+nvals > ctx->ccommands) {
   1083 		float* commands;
   1084 		int ccommands = ctx->ncommands+nvals + ctx->ccommands/2;
   1085 		commands = (float*)realloc(ctx->commands, sizeof(float)*ccommands);
   1086 		if (commands == NULL) return;
   1087 		ctx->commands = commands;
   1088 		ctx->ccommands = ccommands;
   1089 	}
   1090 
   1091 	if ((int)vals[0] != NVG_CLOSE && (int)vals[0] != NVG_WINDING) {
   1092 		ctx->commandx = vals[nvals-2];
   1093 		ctx->commandy = vals[nvals-1];
   1094 	}
   1095 
   1096 	// transform commands
   1097 	i = 0;
   1098 	while (i < nvals) {
   1099 		int cmd = (int)vals[i];
   1100 		switch (cmd) {
   1101 		case NVG_MOVETO:
   1102 			nvgTransformPoint(&vals[i+1],&vals[i+2], state->xform, vals[i+1],vals[i+2]);
   1103 			i += 3;
   1104 			break;
   1105 		case NVG_LINETO:
   1106 			nvgTransformPoint(&vals[i+1],&vals[i+2], state->xform, vals[i+1],vals[i+2]);
   1107 			i += 3;
   1108 			break;
   1109 		case NVG_BEZIERTO:
   1110 			nvgTransformPoint(&vals[i+1],&vals[i+2], state->xform, vals[i+1],vals[i+2]);
   1111 			nvgTransformPoint(&vals[i+3],&vals[i+4], state->xform, vals[i+3],vals[i+4]);
   1112 			nvgTransformPoint(&vals[i+5],&vals[i+6], state->xform, vals[i+5],vals[i+6]);
   1113 			i += 7;
   1114 			break;
   1115 		case NVG_CLOSE:
   1116 			i++;
   1117 			break;
   1118 		case NVG_WINDING:
   1119 			i += 2;
   1120 			break;
   1121 		default:
   1122 			i++;
   1123 		}
   1124 	}
   1125 
   1126 	memcpy(&ctx->commands[ctx->ncommands], vals, nvals*sizeof(float));
   1127 
   1128 	ctx->ncommands += nvals;
   1129 }
   1130 
   1131 
   1132 static void nvg__clearPathCache(NVGcontext* ctx)
   1133 {
   1134 	ctx->cache->npoints = 0;
   1135 	ctx->cache->npaths = 0;
   1136 }
   1137 
   1138 static NVGpath* nvg__lastPath(NVGcontext* ctx)
   1139 {
   1140 	if (ctx->cache->npaths > 0)
   1141 		return &ctx->cache->paths[ctx->cache->npaths-1];
   1142 	return NULL;
   1143 }
   1144 
   1145 static void nvg__addPath(NVGcontext* ctx)
   1146 {
   1147 	NVGpath* path;
   1148 	if (ctx->cache->npaths+1 > ctx->cache->cpaths) {
   1149 		NVGpath* paths;
   1150 		int cpaths = ctx->cache->npaths+1 + ctx->cache->cpaths/2;
   1151 		paths = (NVGpath*)realloc(ctx->cache->paths, sizeof(NVGpath)*cpaths);
   1152 		if (paths == NULL) return;
   1153 		ctx->cache->paths = paths;
   1154 		ctx->cache->cpaths = cpaths;
   1155 	}
   1156 	path = &ctx->cache->paths[ctx->cache->npaths];
   1157 	memset(path, 0, sizeof(*path));
   1158 	path->first = ctx->cache->npoints;
   1159 	path->winding = NVG_CCW;
   1160 
   1161 	ctx->cache->npaths++;
   1162 }
   1163 
   1164 static NVGpoint* nvg__lastPoint(NVGcontext* ctx)
   1165 {
   1166 	if (ctx->cache->npoints > 0)
   1167 		return &ctx->cache->points[ctx->cache->npoints-1];
   1168 	return NULL;
   1169 }
   1170 
   1171 static void nvg__addPoint(NVGcontext* ctx, float x, float y, int flags)
   1172 {
   1173 	NVGpath* path = nvg__lastPath(ctx);
   1174 	NVGpoint* pt;
   1175 	if (path == NULL) return;
   1176 
   1177 	if (path->count > 0 && ctx->cache->npoints > 0) {
   1178 		pt = nvg__lastPoint(ctx);
   1179 		if (nvg__ptEquals(pt->x,pt->y, x,y, ctx->distTol)) {
   1180 			pt->flags |= flags;
   1181 			return;
   1182 		}
   1183 	}
   1184 
   1185 	if (ctx->cache->npoints+1 > ctx->cache->cpoints) {
   1186 		NVGpoint* points;
   1187 		int cpoints = ctx->cache->npoints+1 + ctx->cache->cpoints/2;
   1188 		points = (NVGpoint*)realloc(ctx->cache->points, sizeof(NVGpoint)*cpoints);
   1189 		if (points == NULL) return;
   1190 		ctx->cache->points = points;
   1191 		ctx->cache->cpoints = cpoints;
   1192 	}
   1193 
   1194 	pt = &ctx->cache->points[ctx->cache->npoints];
   1195 	memset(pt, 0, sizeof(*pt));
   1196 	pt->x = x;
   1197 	pt->y = y;
   1198 	pt->flags = (unsigned char)flags;
   1199 
   1200 	ctx->cache->npoints++;
   1201 	path->count++;
   1202 }
   1203 
   1204 static void nvg__closePath(NVGcontext* ctx)
   1205 {
   1206 	NVGpath* path = nvg__lastPath(ctx);
   1207 	if (path == NULL) return;
   1208 	path->closed = 1;
   1209 }
   1210 
   1211 static void nvg__pathWinding(NVGcontext* ctx, int winding)
   1212 {
   1213 	NVGpath* path = nvg__lastPath(ctx);
   1214 	if (path == NULL) return;
   1215 	path->winding = winding;
   1216 }
   1217 
   1218 static float nvg__getAverageScale(float *t)
   1219 {
   1220 	float sx = sqrtf(t[0]*t[0] + t[2]*t[2]);
   1221 	float sy = sqrtf(t[1]*t[1] + t[3]*t[3]);
   1222 	return (sx + sy) * 0.5f;
   1223 }
   1224 
   1225 static NVGvertex* nvg__allocTempVerts(NVGcontext* ctx, int nverts)
   1226 {
   1227 	if (nverts > ctx->cache->cverts) {
   1228 		NVGvertex* verts;
   1229 		int cverts = (nverts + 0xff) & ~0xff; // Round up to prevent allocations when things change just slightly.
   1230 		verts = (NVGvertex*)realloc(ctx->cache->verts, sizeof(NVGvertex)*cverts);
   1231 		if (verts == NULL) return NULL;
   1232 		ctx->cache->verts = verts;
   1233 		ctx->cache->cverts = cverts;
   1234 	}
   1235 
   1236 	return ctx->cache->verts;
   1237 }
   1238 
   1239 static float nvg__triarea2(float ax, float ay, float bx, float by, float cx, float cy)
   1240 {
   1241 	float abx = bx - ax;
   1242 	float aby = by - ay;
   1243 	float acx = cx - ax;
   1244 	float acy = cy - ay;
   1245 	return acx*aby - abx*acy;
   1246 }
   1247 
   1248 static float nvg__polyArea(NVGpoint* pts, int npts)
   1249 {
   1250 	int i;
   1251 	float area = 0;
   1252 	for (i = 2; i < npts; i++) {
   1253 		NVGpoint* a = &pts[0];
   1254 		NVGpoint* b = &pts[i-1];
   1255 		NVGpoint* c = &pts[i];
   1256 		area += nvg__triarea2(a->x,a->y, b->x,b->y, c->x,c->y);
   1257 	}
   1258 	return area * 0.5f;
   1259 }
   1260 
   1261 static void nvg__polyReverse(NVGpoint* pts, int npts)
   1262 {
   1263 	NVGpoint tmp;
   1264 	int i = 0, j = npts-1;
   1265 	while (i < j) {
   1266 		tmp = pts[i];
   1267 		pts[i] = pts[j];
   1268 		pts[j] = tmp;
   1269 		i++;
   1270 		j--;
   1271 	}
   1272 }
   1273 
   1274 
   1275 static void nvg__vset(NVGvertex* vtx, float x, float y, float u, float v)
   1276 {
   1277 	vtx->x = x;
   1278 	vtx->y = y;
   1279 	vtx->u = u;
   1280 	vtx->v = v;
   1281 }
   1282 
   1283 static void nvg__tesselateBezier(NVGcontext* ctx,
   1284 								 float x1, float y1, float x2, float y2,
   1285 								 float x3, float y3, float x4, float y4,
   1286 								 int level, int type)
   1287 {
   1288 	float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;
   1289 	float dx,dy,d2,d3;
   1290 
   1291 	if (level > 10) return;
   1292 
   1293 	x12 = (x1+x2)*0.5f;
   1294 	y12 = (y1+y2)*0.5f;
   1295 	x23 = (x2+x3)*0.5f;
   1296 	y23 = (y2+y3)*0.5f;
   1297 	x34 = (x3+x4)*0.5f;
   1298 	y34 = (y3+y4)*0.5f;
   1299 	x123 = (x12+x23)*0.5f;
   1300 	y123 = (y12+y23)*0.5f;
   1301 
   1302 	dx = x4 - x1;
   1303 	dy = y4 - y1;
   1304 	d2 = nvg__absf(((x2 - x4) * dy - (y2 - y4) * dx));
   1305 	d3 = nvg__absf(((x3 - x4) * dy - (y3 - y4) * dx));
   1306 
   1307 	if ((d2 + d3)*(d2 + d3) < ctx->tessTol * (dx*dx + dy*dy)) {
   1308 		nvg__addPoint(ctx, x4, y4, type);
   1309 		return;
   1310 	}
   1311 
   1312 /*	if (nvg__absf(x1+x3-x2-x2) + nvg__absf(y1+y3-y2-y2) + nvg__absf(x2+x4-x3-x3) + nvg__absf(y2+y4-y3-y3) < ctx->tessTol) {
   1313 		nvg__addPoint(ctx, x4, y4, type);
   1314 		return;
   1315 	}*/
   1316 
   1317 	x234 = (x23+x34)*0.5f;
   1318 	y234 = (y23+y34)*0.5f;
   1319 	x1234 = (x123+x234)*0.5f;
   1320 	y1234 = (y123+y234)*0.5f;
   1321 
   1322 	nvg__tesselateBezier(ctx, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0);
   1323 	nvg__tesselateBezier(ctx, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type);
   1324 }
   1325 
   1326 static void nvg__flattenPaths(NVGcontext* ctx)
   1327 {
   1328 	NVGpathCache* cache = ctx->cache;
   1329 //	NVGstate* state = nvg__getState(ctx);
   1330 	NVGpoint* last;
   1331 	NVGpoint* p0;
   1332 	NVGpoint* p1;
   1333 	NVGpoint* pts;
   1334 	NVGpath* path;
   1335 	int i, j;
   1336 	float* cp1;
   1337 	float* cp2;
   1338 	float* p;
   1339 	float area;
   1340 
   1341 	if (cache->npaths > 0)
   1342 		return;
   1343 
   1344 	// Flatten
   1345 	i = 0;
   1346 	while (i < ctx->ncommands) {
   1347 		int cmd = (int)ctx->commands[i];
   1348 		switch (cmd) {
   1349 		case NVG_MOVETO:
   1350 			nvg__addPath(ctx);
   1351 			p = &ctx->commands[i+1];
   1352 			nvg__addPoint(ctx, p[0], p[1], NVG_PT_CORNER);
   1353 			i += 3;
   1354 			break;
   1355 		case NVG_LINETO:
   1356 			p = &ctx->commands[i+1];
   1357 			nvg__addPoint(ctx, p[0], p[1], NVG_PT_CORNER);
   1358 			i += 3;
   1359 			break;
   1360 		case NVG_BEZIERTO:
   1361 			last = nvg__lastPoint(ctx);
   1362 			if (last != NULL) {
   1363 				cp1 = &ctx->commands[i+1];
   1364 				cp2 = &ctx->commands[i+3];
   1365 				p = &ctx->commands[i+5];
   1366 				nvg__tesselateBezier(ctx, last->x,last->y, cp1[0],cp1[1], cp2[0],cp2[1], p[0],p[1], 0, NVG_PT_CORNER);
   1367 			}
   1368 			i += 7;
   1369 			break;
   1370 		case NVG_CLOSE:
   1371 			nvg__closePath(ctx);
   1372 			i++;
   1373 			break;
   1374 		case NVG_WINDING:
   1375 			nvg__pathWinding(ctx, (int)ctx->commands[i+1]);
   1376 			i += 2;
   1377 			break;
   1378 		default:
   1379 			i++;
   1380 		}
   1381 	}
   1382 
   1383 	cache->bounds[0] = cache->bounds[1] = 1e6f;
   1384 	cache->bounds[2] = cache->bounds[3] = -1e6f;
   1385 
   1386 	// Calculate the direction and length of line segments.
   1387 	for (j = 0; j < cache->npaths; j++) {
   1388 		path = &cache->paths[j];
   1389 		pts = &cache->points[path->first];
   1390 
   1391 		// If the first and last points are the same, remove the last, mark as closed path.
   1392 		p0 = &pts[path->count-1];
   1393 		p1 = &pts[0];
   1394 		if (nvg__ptEquals(p0->x,p0->y, p1->x,p1->y, ctx->distTol)) {
   1395 			path->count--;
   1396 			p0 = &pts[path->count-1];
   1397 			path->closed = 1;
   1398 		}
   1399 
   1400 		// Enforce winding.
   1401 		if (path->count > 2) {
   1402 			area = nvg__polyArea(pts, path->count);
   1403 			if (path->winding == NVG_CCW && area < 0.0f)
   1404 				nvg__polyReverse(pts, path->count);
   1405 			if (path->winding == NVG_CW && area > 0.0f)
   1406 				nvg__polyReverse(pts, path->count);
   1407 		}
   1408 
   1409 		for(i = 0; i < path->count; i++) {
   1410 			// Calculate segment direction and length
   1411 			p0->dx = p1->x - p0->x;
   1412 			p0->dy = p1->y - p0->y;
   1413 			p0->len = nvg__normalize(&p0->dx, &p0->dy);
   1414 			// Update bounds
   1415 			cache->bounds[0] = nvg__minf(cache->bounds[0], p0->x);
   1416 			cache->bounds[1] = nvg__minf(cache->bounds[1], p0->y);
   1417 			cache->bounds[2] = nvg__maxf(cache->bounds[2], p0->x);
   1418 			cache->bounds[3] = nvg__maxf(cache->bounds[3], p0->y);
   1419 			// Advance
   1420 			p0 = p1++;
   1421 		}
   1422 	}
   1423 }
   1424 
   1425 static int nvg__curveDivs(float r, float arc, float tol)
   1426 {
   1427 	float da = acosf(r / (r + tol)) * 2.0f;
   1428 	return nvg__maxi(2, (int)ceilf(arc / da));
   1429 }
   1430 
   1431 static void nvg__chooseBevel(int bevel, NVGpoint* p0, NVGpoint* p1, float w,
   1432 							float* x0, float* y0, float* x1, float* y1)
   1433 {
   1434 	if (bevel) {
   1435 		*x0 = p1->x + p0->dy * w;
   1436 		*y0 = p1->y - p0->dx * w;
   1437 		*x1 = p1->x + p1->dy * w;
   1438 		*y1 = p1->y - p1->dx * w;
   1439 	} else {
   1440 		*x0 = p1->x + p1->dmx * w;
   1441 		*y0 = p1->y + p1->dmy * w;
   1442 		*x1 = p1->x + p1->dmx * w;
   1443 		*y1 = p1->y + p1->dmy * w;
   1444 	}
   1445 }
   1446 
   1447 static NVGvertex* nvg__roundJoin(NVGvertex* dst, NVGpoint* p0, NVGpoint* p1,
   1448 								 float lw, float rw, float lu, float ru, int ncap,
   1449 								 float fringe)
   1450 {
   1451 	int i, n;
   1452 	float dlx0 = p0->dy;
   1453 	float dly0 = -p0->dx;
   1454 	float dlx1 = p1->dy;
   1455 	float dly1 = -p1->dx;
   1456 	NVG_NOTUSED(fringe);
   1457 
   1458 	if (p1->flags & NVG_PT_LEFT) {
   1459 		float lx0,ly0,lx1,ly1,a0,a1;
   1460 		nvg__chooseBevel(p1->flags & NVG_PR_INNERBEVEL, p0, p1, lw, &lx0,&ly0, &lx1,&ly1);
   1461 		a0 = atan2f(-dly0, -dlx0);
   1462 		a1 = atan2f(-dly1, -dlx1);
   1463 		if (a1 > a0) a1 -= NVG_PI*2;
   1464 
   1465 		nvg__vset(dst, lx0, ly0, lu,1); dst++;
   1466 		nvg__vset(dst, p1->x - dlx0*rw, p1->y - dly0*rw, ru,1); dst++;
   1467 
   1468 		n = nvg__clampi((int)ceilf(((a0 - a1) / NVG_PI) * ncap), 2, ncap);
   1469 		for (i = 0; i < n; i++) {
   1470 			float u = i/(float)(n-1);
   1471 			float a = a0 + u*(a1-a0);
   1472 			float rx = p1->x + cosf(a) * rw;
   1473 			float ry = p1->y + sinf(a) * rw;
   1474 			nvg__vset(dst, p1->x, p1->y, 0.5f,1); dst++;
   1475 			nvg__vset(dst, rx, ry, ru,1); dst++;
   1476 		}
   1477 
   1478 		nvg__vset(dst, lx1, ly1, lu,1); dst++;
   1479 		nvg__vset(dst, p1->x - dlx1*rw, p1->y - dly1*rw, ru,1); dst++;
   1480 
   1481 	} else {
   1482 		float rx0,ry0,rx1,ry1,a0,a1;
   1483 		nvg__chooseBevel(p1->flags & NVG_PR_INNERBEVEL, p0, p1, -rw, &rx0,&ry0, &rx1,&ry1);
   1484 		a0 = atan2f(dly0, dlx0);
   1485 		a1 = atan2f(dly1, dlx1);
   1486 		if (a1 < a0) a1 += NVG_PI*2;
   1487 
   1488 		nvg__vset(dst, p1->x + dlx0*rw, p1->y + dly0*rw, lu,1); dst++;
   1489 		nvg__vset(dst, rx0, ry0, ru,1); dst++;
   1490 
   1491 		n = nvg__clampi((int)ceilf(((a1 - a0) / NVG_PI) * ncap), 2, ncap);
   1492 		for (i = 0; i < n; i++) {
   1493 			float u = i/(float)(n-1);
   1494 			float a = a0 + u*(a1-a0);
   1495 			float lx = p1->x + cosf(a) * lw;
   1496 			float ly = p1->y + sinf(a) * lw;
   1497 			nvg__vset(dst, lx, ly, lu,1); dst++;
   1498 			nvg__vset(dst, p1->x, p1->y, 0.5f,1); dst++;
   1499 		}
   1500 
   1501 		nvg__vset(dst, p1->x + dlx1*rw, p1->y + dly1*rw, lu,1); dst++;
   1502 		nvg__vset(dst, rx1, ry1, ru,1); dst++;
   1503 
   1504 	}
   1505 	return dst;
   1506 }
   1507 
   1508 static NVGvertex* nvg__bevelJoin(NVGvertex* dst, NVGpoint* p0, NVGpoint* p1,
   1509 										float lw, float rw, float lu, float ru, float fringe)
   1510 {
   1511 	float rx0,ry0,rx1,ry1;
   1512 	float lx0,ly0,lx1,ly1;
   1513 	float dlx0 = p0->dy;
   1514 	float dly0 = -p0->dx;
   1515 	float dlx1 = p1->dy;
   1516 	float dly1 = -p1->dx;
   1517 	NVG_NOTUSED(fringe);
   1518 
   1519 	if (p1->flags & NVG_PT_LEFT) {
   1520 		nvg__chooseBevel(p1->flags & NVG_PR_INNERBEVEL, p0, p1, lw, &lx0,&ly0, &lx1,&ly1);
   1521 
   1522 		nvg__vset(dst, lx0, ly0, lu,1); dst++;
   1523 		nvg__vset(dst, p1->x - dlx0*rw, p1->y - dly0*rw, ru,1); dst++;
   1524 
   1525 		if (p1->flags & NVG_PT_BEVEL) {
   1526 			nvg__vset(dst, lx0, ly0, lu,1); dst++;
   1527 			nvg__vset(dst, p1->x - dlx0*rw, p1->y - dly0*rw, ru,1); dst++;
   1528 
   1529 			nvg__vset(dst, lx1, ly1, lu,1); dst++;
   1530 			nvg__vset(dst, p1->x - dlx1*rw, p1->y - dly1*rw, ru,1); dst++;
   1531 		} else {
   1532 			rx0 = p1->x - p1->dmx * rw;
   1533 			ry0 = p1->y - p1->dmy * rw;
   1534 
   1535 			nvg__vset(dst, p1->x, p1->y, 0.5f,1); dst++;
   1536 			nvg__vset(dst, p1->x - dlx0*rw, p1->y - dly0*rw, ru,1); dst++;
   1537 
   1538 			nvg__vset(dst, rx0, ry0, ru,1); dst++;
   1539 			nvg__vset(dst, rx0, ry0, ru,1); dst++;
   1540 
   1541 			nvg__vset(dst, p1->x, p1->y, 0.5f,1); dst++;
   1542 			nvg__vset(dst, p1->x - dlx1*rw, p1->y - dly1*rw, ru,1); dst++;
   1543 		}
   1544 
   1545 		nvg__vset(dst, lx1, ly1, lu,1); dst++;
   1546 		nvg__vset(dst, p1->x - dlx1*rw, p1->y - dly1*rw, ru,1); dst++;
   1547 
   1548 	} else {
   1549 		nvg__chooseBevel(p1->flags & NVG_PR_INNERBEVEL, p0, p1, -rw, &rx0,&ry0, &rx1,&ry1);
   1550 
   1551 		nvg__vset(dst, p1->x + dlx0*lw, p1->y + dly0*lw, lu,1); dst++;
   1552 		nvg__vset(dst, rx0, ry0, ru,1); dst++;
   1553 
   1554 		if (p1->flags & NVG_PT_BEVEL) {
   1555 			nvg__vset(dst, p1->x + dlx0*lw, p1->y + dly0*lw, lu,1); dst++;
   1556 			nvg__vset(dst, rx0, ry0, ru,1); dst++;
   1557 
   1558 			nvg__vset(dst, p1->x + dlx1*lw, p1->y + dly1*lw, lu,1); dst++;
   1559 			nvg__vset(dst, rx1, ry1, ru,1); dst++;
   1560 		} else {
   1561 			lx0 = p1->x + p1->dmx * lw;
   1562 			ly0 = p1->y + p1->dmy * lw;
   1563 
   1564 			nvg__vset(dst, p1->x + dlx0*lw, p1->y + dly0*lw, lu,1); dst++;
   1565 			nvg__vset(dst, p1->x, p1->y, 0.5f,1); dst++;
   1566 
   1567 			nvg__vset(dst, lx0, ly0, lu,1); dst++;
   1568 			nvg__vset(dst, lx0, ly0, lu,1); dst++;
   1569 
   1570 			nvg__vset(dst, p1->x + dlx1*lw, p1->y + dly1*lw, lu,1); dst++;
   1571 			nvg__vset(dst, p1->x, p1->y, 0.5f,1); dst++;
   1572 		}
   1573 
   1574 		nvg__vset(dst, p1->x + dlx1*lw, p1->y + dly1*lw, lu,1); dst++;
   1575 		nvg__vset(dst, rx1, ry1, ru,1); dst++;
   1576 	}
   1577 
   1578 	return dst;
   1579 }
   1580 
   1581 static NVGvertex* nvg__buttCapStart(NVGvertex* dst, NVGpoint* p,
   1582 									float dx, float dy, float w, float d,
   1583 									float aa, float u0, float u1)
   1584 {
   1585 	float px = p->x - dx*d;
   1586 	float py = p->y - dy*d;
   1587 	float dlx = dy;
   1588 	float dly = -dx;
   1589 	nvg__vset(dst, px + dlx*w - dx*aa, py + dly*w - dy*aa, u0,0); dst++;
   1590 	nvg__vset(dst, px - dlx*w - dx*aa, py - dly*w - dy*aa, u1,0); dst++;
   1591 	nvg__vset(dst, px + dlx*w, py + dly*w, u0,1); dst++;
   1592 	nvg__vset(dst, px - dlx*w, py - dly*w, u1,1); dst++;
   1593 	return dst;
   1594 }
   1595 
   1596 static NVGvertex* nvg__buttCapEnd(NVGvertex* dst, NVGpoint* p,
   1597 								  float dx, float dy, float w, float d,
   1598 								  float aa, float u0, float u1)
   1599 {
   1600 	float px = p->x + dx*d;
   1601 	float py = p->y + dy*d;
   1602 	float dlx = dy;
   1603 	float dly = -dx;
   1604 	nvg__vset(dst, px + dlx*w, py + dly*w, u0,1); dst++;
   1605 	nvg__vset(dst, px - dlx*w, py - dly*w, u1,1); dst++;
   1606 	nvg__vset(dst, px + dlx*w + dx*aa, py + dly*w + dy*aa, u0,0); dst++;
   1607 	nvg__vset(dst, px - dlx*w + dx*aa, py - dly*w + dy*aa, u1,0); dst++;
   1608 	return dst;
   1609 }
   1610 
   1611 
   1612 static NVGvertex* nvg__roundCapStart(NVGvertex* dst, NVGpoint* p,
   1613 									 float dx, float dy, float w, int ncap,
   1614 									 float aa, float u0, float u1)
   1615 {
   1616 	int i;
   1617 	float px = p->x;
   1618 	float py = p->y;
   1619 	float dlx = dy;
   1620 	float dly = -dx;
   1621 	NVG_NOTUSED(aa);
   1622 	for (i = 0; i < ncap; i++) {
   1623 		float a = i/(float)(ncap-1)*NVG_PI;
   1624 		float ax = cosf(a) * w, ay = sinf(a) * w;
   1625 		nvg__vset(dst, px - dlx*ax - dx*ay, py - dly*ax - dy*ay, u0,1); dst++;
   1626 		nvg__vset(dst, px, py, 0.5f,1); dst++;
   1627 	}
   1628 	nvg__vset(dst, px + dlx*w, py + dly*w, u0,1); dst++;
   1629 	nvg__vset(dst, px - dlx*w, py - dly*w, u1,1); dst++;
   1630 	return dst;
   1631 }
   1632 
   1633 static NVGvertex* nvg__roundCapEnd(NVGvertex* dst, NVGpoint* p,
   1634 								   float dx, float dy, float w, int ncap,
   1635 								   float aa, float u0, float u1)
   1636 {
   1637 	int i;
   1638 	float px = p->x;
   1639 	float py = p->y;
   1640 	float dlx = dy;
   1641 	float dly = -dx;
   1642 	NVG_NOTUSED(aa);
   1643 	nvg__vset(dst, px + dlx*w, py + dly*w, u0,1); dst++;
   1644 	nvg__vset(dst, px - dlx*w, py - dly*w, u1,1); dst++;
   1645 	for (i = 0; i < ncap; i++) {
   1646 		float a = i/(float)(ncap-1)*NVG_PI;
   1647 		float ax = cosf(a) * w, ay = sinf(a) * w;
   1648 		nvg__vset(dst, px, py, 0.5f,1); dst++;
   1649 		nvg__vset(dst, px - dlx*ax + dx*ay, py - dly*ax + dy*ay, u0,1); dst++;
   1650 	}
   1651 	return dst;
   1652 }
   1653 
   1654 
   1655 static void nvg__calculateJoins(NVGcontext* ctx, float w, int lineJoin, float miterLimit)
   1656 {
   1657 	NVGpathCache* cache = ctx->cache;
   1658 	int i, j;
   1659 	float iw = 0.0f;
   1660 
   1661 	if (w > 0.0f) iw = 1.0f / w;
   1662 
   1663 	// Calculate which joins needs extra vertices to append, and gather vertex count.
   1664 	for (i = 0; i < cache->npaths; i++) {
   1665 		NVGpath* path = &cache->paths[i];
   1666 		NVGpoint* pts = &cache->points[path->first];
   1667 		NVGpoint* p0 = &pts[path->count-1];
   1668 		NVGpoint* p1 = &pts[0];
   1669 		int nleft = 0;
   1670 
   1671 		path->nbevel = 0;
   1672 
   1673 		for (j = 0; j < path->count; j++) {
   1674 			float dlx0, dly0, dlx1, dly1, dmr2, cross, limit;
   1675 			dlx0 = p0->dy;
   1676 			dly0 = -p0->dx;
   1677 			dlx1 = p1->dy;
   1678 			dly1 = -p1->dx;
   1679 			// Calculate extrusions
   1680 			p1->dmx = (dlx0 + dlx1) * 0.5f;
   1681 			p1->dmy = (dly0 + dly1) * 0.5f;
   1682 			dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy;
   1683 			if (dmr2 > 0.000001f) {
   1684 				float scale = 1.0f / dmr2;
   1685 				if (scale > 600.0f) {
   1686 					scale = 600.0f;
   1687 				}
   1688 				p1->dmx *= scale;
   1689 				p1->dmy *= scale;
   1690 			}
   1691 
   1692 			// Clear flags, but keep the corner.
   1693 			p1->flags = (p1->flags & NVG_PT_CORNER) ? NVG_PT_CORNER : 0;
   1694 
   1695 			// Keep track of left turns.
   1696 			cross = p1->dx * p0->dy - p0->dx * p1->dy;
   1697 			if (cross > 0.0f) {
   1698 				nleft++;
   1699 				p1->flags |= NVG_PT_LEFT;
   1700 			}
   1701 
   1702 			// Calculate if we should use bevel or miter for inner join.
   1703 			limit = nvg__maxf(1.01f, nvg__minf(p0->len, p1->len) * iw);
   1704 			if ((dmr2 * limit*limit) < 1.0f)
   1705 				p1->flags |= NVG_PR_INNERBEVEL;
   1706 
   1707 			// Check to see if the corner needs to be beveled.
   1708 			if (p1->flags & NVG_PT_CORNER) {
   1709 				if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NVG_BEVEL || lineJoin == NVG_ROUND) {
   1710 					p1->flags |= NVG_PT_BEVEL;
   1711 				}
   1712 			}
   1713 
   1714 			if ((p1->flags & (NVG_PT_BEVEL | NVG_PR_INNERBEVEL)) != 0)
   1715 				path->nbevel++;
   1716 
   1717 			p0 = p1++;
   1718 		}
   1719 
   1720 		path->convex = (nleft == path->count) ? 1 : 0;
   1721 	}
   1722 }
   1723 
   1724 
   1725 static int nvg__expandStroke(NVGcontext* ctx, float w, float fringe, int lineCap, int lineJoin, float miterLimit)
   1726 {
   1727 	NVGpathCache* cache = ctx->cache;
   1728 	NVGvertex* verts;
   1729 	NVGvertex* dst;
   1730 	int cverts, i, j;
   1731 	float aa = fringe;//ctx->fringeWidth;
   1732 	float u0 = 0.0f, u1 = 1.0f;
   1733 	int ncap = nvg__curveDivs(w, NVG_PI, ctx->tessTol);	// Calculate divisions per half circle.
   1734 
   1735 	w += aa * 0.5f;
   1736 
   1737 	// Disable the gradient used for antialiasing when antialiasing is not used.
   1738 	if (aa == 0.0f) {
   1739 		u0 = 0.5f;
   1740 		u1 = 0.5f;
   1741 	}
   1742 
   1743 	nvg__calculateJoins(ctx, w, lineJoin, miterLimit);
   1744 
   1745 	// Calculate max vertex usage.
   1746 	cverts = 0;
   1747 	for (i = 0; i < cache->npaths; i++) {
   1748 		NVGpath* path = &cache->paths[i];
   1749 		int loop = (path->closed == 0) ? 0 : 1;
   1750 		if (lineJoin == NVG_ROUND)
   1751 			cverts += (path->count + path->nbevel*(ncap+2) + 1) * 2; // plus one for loop
   1752 		else
   1753 			cverts += (path->count + path->nbevel*5 + 1) * 2; // plus one for loop
   1754 		if (loop == 0) {
   1755 			// space for caps
   1756 			if (lineCap == NVG_ROUND) {
   1757 				cverts += (ncap*2 + 2)*2;
   1758 			} else {
   1759 				cverts += (3+3)*2;
   1760 			}
   1761 		}
   1762 	}
   1763 
   1764 	verts = nvg__allocTempVerts(ctx, cverts);
   1765 	if (verts == NULL) return 0;
   1766 
   1767 	for (i = 0; i < cache->npaths; i++) {
   1768 		NVGpath* path = &cache->paths[i];
   1769 		NVGpoint* pts = &cache->points[path->first];
   1770 		NVGpoint* p0;
   1771 		NVGpoint* p1;
   1772 		int s, e, loop;
   1773 		float dx, dy;
   1774 
   1775 		path->fill = 0;
   1776 		path->nfill = 0;
   1777 
   1778 		// Calculate fringe or stroke
   1779 		loop = (path->closed == 0) ? 0 : 1;
   1780 		dst = verts;
   1781 		path->stroke = dst;
   1782 
   1783 		if (loop) {
   1784 			// Looping
   1785 			p0 = &pts[path->count-1];
   1786 			p1 = &pts[0];
   1787 			s = 0;
   1788 			e = path->count;
   1789 		} else {
   1790 			// Add cap
   1791 			p0 = &pts[0];
   1792 			p1 = &pts[1];
   1793 			s = 1;
   1794 			e = path->count-1;
   1795 		}
   1796 
   1797 		if (loop == 0) {
   1798 			// Add cap
   1799 			dx = p1->x - p0->x;
   1800 			dy = p1->y - p0->y;
   1801 			nvg__normalize(&dx, &dy);
   1802 			if (lineCap == NVG_BUTT)
   1803 				dst = nvg__buttCapStart(dst, p0, dx, dy, w, -aa*0.5f, aa, u0, u1);
   1804 			else if (lineCap == NVG_BUTT || lineCap == NVG_SQUARE)
   1805 				dst = nvg__buttCapStart(dst, p0, dx, dy, w, w-aa, aa, u0, u1);
   1806 			else if (lineCap == NVG_ROUND)
   1807 				dst = nvg__roundCapStart(dst, p0, dx, dy, w, ncap, aa, u0, u1);
   1808 		}
   1809 
   1810 		for (j = s; j < e; ++j) {
   1811 			if ((p1->flags & (NVG_PT_BEVEL | NVG_PR_INNERBEVEL)) != 0) {
   1812 				if (lineJoin == NVG_ROUND) {
   1813 					dst = nvg__roundJoin(dst, p0, p1, w, w, u0, u1, ncap, aa);
   1814 				} else {
   1815 					dst = nvg__bevelJoin(dst, p0, p1, w, w, u0, u1, aa);
   1816 				}
   1817 			} else {
   1818 				nvg__vset(dst, p1->x + (p1->dmx * w), p1->y + (p1->dmy * w), u0,1); dst++;
   1819 				nvg__vset(dst, p1->x - (p1->dmx * w), p1->y - (p1->dmy * w), u1,1); dst++;
   1820 			}
   1821 			p0 = p1++;
   1822 		}
   1823 
   1824 		if (loop) {
   1825 			// Loop it
   1826 			nvg__vset(dst, verts[0].x, verts[0].y, u0,1); dst++;
   1827 			nvg__vset(dst, verts[1].x, verts[1].y, u1,1); dst++;
   1828 		} else {
   1829 			// Add cap
   1830 			dx = p1->x - p0->x;
   1831 			dy = p1->y - p0->y;
   1832 			nvg__normalize(&dx, &dy);
   1833 			if (lineCap == NVG_BUTT)
   1834 				dst = nvg__buttCapEnd(dst, p1, dx, dy, w, -aa*0.5f, aa, u0, u1);
   1835 			else if (lineCap == NVG_BUTT || lineCap == NVG_SQUARE)
   1836 				dst = nvg__buttCapEnd(dst, p1, dx, dy, w, w-aa, aa, u0, u1);
   1837 			else if (lineCap == NVG_ROUND)
   1838 				dst = nvg__roundCapEnd(dst, p1, dx, dy, w, ncap, aa, u0, u1);
   1839 		}
   1840 
   1841 		path->nstroke = (int)(dst - verts);
   1842 
   1843 		verts = dst;
   1844 	}
   1845 
   1846 	return 1;
   1847 }
   1848 
   1849 static int nvg__expandFill(NVGcontext* ctx, float w, int lineJoin, float miterLimit)
   1850 {
   1851 	NVGpathCache* cache = ctx->cache;
   1852 	NVGvertex* verts;
   1853 	NVGvertex* dst;
   1854 	int cverts, convex, i, j;
   1855 	float aa = ctx->fringeWidth;
   1856 	int fringe = w > 0.0f;
   1857 
   1858 	nvg__calculateJoins(ctx, w, lineJoin, miterLimit);
   1859 
   1860 	// Calculate max vertex usage.
   1861 	cverts = 0;
   1862 	for (i = 0; i < cache->npaths; i++) {
   1863 		NVGpath* path = &cache->paths[i];
   1864 		cverts += path->count + path->nbevel + 1;
   1865 		if (fringe)
   1866 			cverts += (path->count + path->nbevel*5 + 1) * 2; // plus one for loop
   1867 	}
   1868 
   1869 	verts = nvg__allocTempVerts(ctx, cverts);
   1870 	if (verts == NULL) return 0;
   1871 
   1872 	convex = cache->npaths == 1 && cache->paths[0].convex;
   1873 
   1874 	for (i = 0; i < cache->npaths; i++) {
   1875 		NVGpath* path = &cache->paths[i];
   1876 		NVGpoint* pts = &cache->points[path->first];
   1877 		NVGpoint* p0;
   1878 		NVGpoint* p1;
   1879 		float rw, lw, woff;
   1880 		float ru, lu;
   1881 
   1882 		// Calculate shape vertices.
   1883 		woff = 0.5f*aa;
   1884 		dst = verts;
   1885 		path->fill = dst;
   1886 
   1887 		if (fringe) {
   1888 			// Looping
   1889 			p0 = &pts[path->count-1];
   1890 			p1 = &pts[0];
   1891 			for (j = 0; j < path->count; ++j) {
   1892 				if (p1->flags & NVG_PT_BEVEL) {
   1893 					float dlx0 = p0->dy;
   1894 					float dly0 = -p0->dx;
   1895 					float dlx1 = p1->dy;
   1896 					float dly1 = -p1->dx;
   1897 					if (p1->flags & NVG_PT_LEFT) {
   1898 						float lx = p1->x + p1->dmx * woff;
   1899 						float ly = p1->y + p1->dmy * woff;
   1900 						nvg__vset(dst, lx, ly, 0.5f,1); dst++;
   1901 					} else {
   1902 						float lx0 = p1->x + dlx0 * woff;
   1903 						float ly0 = p1->y + dly0 * woff;
   1904 						float lx1 = p1->x + dlx1 * woff;
   1905 						float ly1 = p1->y + dly1 * woff;
   1906 						nvg__vset(dst, lx0, ly0, 0.5f,1); dst++;
   1907 						nvg__vset(dst, lx1, ly1, 0.5f,1); dst++;
   1908 					}
   1909 				} else {
   1910 					nvg__vset(dst, p1->x + (p1->dmx * woff), p1->y + (p1->dmy * woff), 0.5f,1); dst++;
   1911 				}
   1912 				p0 = p1++;
   1913 			}
   1914 		} else {
   1915 			for (j = 0; j < path->count; ++j) {
   1916 				nvg__vset(dst, pts[j].x, pts[j].y, 0.5f,1);
   1917 				dst++;
   1918 			}
   1919 		}
   1920 
   1921 		path->nfill = (int)(dst - verts);
   1922 		verts = dst;
   1923 
   1924 		// Calculate fringe
   1925 		if (fringe) {
   1926 			lw = w + woff;
   1927 			rw = w - woff;
   1928 			lu = 0;
   1929 			ru = 1;
   1930 			dst = verts;
   1931 			path->stroke = dst;
   1932 
   1933 			// Create only half a fringe for convex shapes so that
   1934 			// the shape can be rendered without stenciling.
   1935 			if (convex) {
   1936 				lw = woff;	// This should generate the same vertex as fill inset above.
   1937 				lu = 0.5f;	// Set outline fade at middle.
   1938 			}
   1939 
   1940 			// Looping
   1941 			p0 = &pts[path->count-1];
   1942 			p1 = &pts[0];
   1943 
   1944 			for (j = 0; j < path->count; ++j) {
   1945 				if ((p1->flags & (NVG_PT_BEVEL | NVG_PR_INNERBEVEL)) != 0) {
   1946 					dst = nvg__bevelJoin(dst, p0, p1, lw, rw, lu, ru, ctx->fringeWidth);
   1947 				} else {
   1948 					nvg__vset(dst, p1->x + (p1->dmx * lw), p1->y + (p1->dmy * lw), lu,1); dst++;
   1949 					nvg__vset(dst, p1->x - (p1->dmx * rw), p1->y - (p1->dmy * rw), ru,1); dst++;
   1950 				}
   1951 				p0 = p1++;
   1952 			}
   1953 
   1954 			// Loop it
   1955 			nvg__vset(dst, verts[0].x, verts[0].y, lu,1); dst++;
   1956 			nvg__vset(dst, verts[1].x, verts[1].y, ru,1); dst++;
   1957 
   1958 			path->nstroke = (int)(dst - verts);
   1959 			verts = dst;
   1960 		} else {
   1961 			path->stroke = NULL;
   1962 			path->nstroke = 0;
   1963 		}
   1964 	}
   1965 
   1966 	return 1;
   1967 }
   1968 
   1969 
   1970 // Draw
   1971 void nvgBeginPath(NVGcontext* ctx)
   1972 {
   1973 	ctx->ncommands = 0;
   1974 	nvg__clearPathCache(ctx);
   1975 }
   1976 
   1977 void nvgMoveTo(NVGcontext* ctx, float x, float y)
   1978 {
   1979 	float vals[] = { NVG_MOVETO, x, y };
   1980 	nvg__appendCommands(ctx, vals, NVG_COUNTOF(vals));
   1981 }
   1982 
   1983 void nvgLineTo(NVGcontext* ctx, float x, float y)
   1984 {
   1985 	float vals[] = { NVG_LINETO, x, y };
   1986 	nvg__appendCommands(ctx, vals, NVG_COUNTOF(vals));
   1987 }
   1988 
   1989 void nvgBezierTo(NVGcontext* ctx, float c1x, float c1y, float c2x, float c2y, float x, float y)
   1990 {
   1991 	float vals[] = { NVG_BEZIERTO, c1x, c1y, c2x, c2y, x, y };
   1992 	nvg__appendCommands(ctx, vals, NVG_COUNTOF(vals));
   1993 }
   1994 
   1995 void nvgQuadTo(NVGcontext* ctx, float cx, float cy, float x, float y)
   1996 {
   1997     float x0 = ctx->commandx;
   1998     float y0 = ctx->commandy;
   1999     float vals[] = { NVG_BEZIERTO,
   2000         x0 + 2.0f/3.0f*(cx - x0), y0 + 2.0f/3.0f*(cy - y0),
   2001         x + 2.0f/3.0f*(cx - x), y + 2.0f/3.0f*(cy - y),
   2002         x, y };
   2003     nvg__appendCommands(ctx, vals, NVG_COUNTOF(vals));
   2004 }
   2005 
   2006 void nvgArcTo(NVGcontext* ctx, float x1, float y1, float x2, float y2, float radius)
   2007 {
   2008 	float x0 = ctx->commandx;
   2009 	float y0 = ctx->commandy;
   2010 	float dx0,dy0, dx1,dy1, a, d, cx,cy, a0,a1;
   2011 	int dir;
   2012 
   2013 	if (ctx->ncommands == 0) {
   2014 		return;
   2015 	}
   2016 
   2017 	// Handle degenerate cases.
   2018 	if (nvg__ptEquals(x0,y0, x1,y1, ctx->distTol) ||
   2019 		nvg__ptEquals(x1,y1, x2,y2, ctx->distTol) ||
   2020 		nvg__distPtSeg(x1,y1, x0,y0, x2,y2) < ctx->distTol*ctx->distTol ||
   2021 		radius < ctx->distTol) {
   2022 		nvgLineTo(ctx, x1,y1);
   2023 		return;
   2024 	}
   2025 
   2026 	// Calculate tangential circle to lines (x0,y0)-(x1,y1) and (x1,y1)-(x2,y2).
   2027 	dx0 = x0-x1;
   2028 	dy0 = y0-y1;
   2029 	dx1 = x2-x1;
   2030 	dy1 = y2-y1;
   2031 	nvg__normalize(&dx0,&dy0);
   2032 	nvg__normalize(&dx1,&dy1);
   2033 	a = nvg__acosf(dx0*dx1 + dy0*dy1);
   2034 	d = radius / nvg__tanf(a/2.0f);
   2035 
   2036 //	printf("a=%f° d=%f\n", a/NVG_PI*180.0f, d);
   2037 
   2038 	if (d > 10000.0f) {
   2039 		nvgLineTo(ctx, x1,y1);
   2040 		return;
   2041 	}
   2042 
   2043 	if (nvg__cross(dx0,dy0, dx1,dy1) > 0.0f) {
   2044 		cx = x1 + dx0*d + dy0*radius;
   2045 		cy = y1 + dy0*d + -dx0*radius;
   2046 		a0 = nvg__atan2f(dx0, -dy0);
   2047 		a1 = nvg__atan2f(-dx1, dy1);
   2048 		dir = NVG_CW;
   2049 //		printf("CW c=(%f, %f) a0=%f° a1=%f°\n", cx, cy, a0/NVG_PI*180.0f, a1/NVG_PI*180.0f);
   2050 	} else {
   2051 		cx = x1 + dx0*d + -dy0*radius;
   2052 		cy = y1 + dy0*d + dx0*radius;
   2053 		a0 = nvg__atan2f(-dx0, dy0);
   2054 		a1 = nvg__atan2f(dx1, -dy1);
   2055 		dir = NVG_CCW;
   2056 //		printf("CCW c=(%f, %f) a0=%f° a1=%f°\n", cx, cy, a0/NVG_PI*180.0f, a1/NVG_PI*180.0f);
   2057 	}
   2058 
   2059 	nvgArc(ctx, cx, cy, radius, a0, a1, dir);
   2060 }
   2061 
   2062 void nvgClosePath(NVGcontext* ctx)
   2063 {
   2064 	float vals[] = { NVG_CLOSE };
   2065 	nvg__appendCommands(ctx, vals, NVG_COUNTOF(vals));
   2066 }
   2067 
   2068 void nvgPathWinding(NVGcontext* ctx, int dir)
   2069 {
   2070 	float vals[] = { NVG_WINDING, (float)dir };
   2071 	nvg__appendCommands(ctx, vals, NVG_COUNTOF(vals));
   2072 }
   2073 
   2074 void nvgArc(NVGcontext* ctx, float cx, float cy, float r, float a0, float a1, int dir)
   2075 {
   2076 	float a = 0, da = 0, hda = 0, kappa = 0;
   2077 	float dx = 0, dy = 0, x = 0, y = 0, tanx = 0, tany = 0;
   2078 	float px = 0, py = 0, ptanx = 0, ptany = 0;
   2079 	float vals[3 + 5*7 + 100];
   2080 	int i, ndivs, nvals;
   2081 	int move = ctx->ncommands > 0 ? NVG_LINETO : NVG_MOVETO;
   2082 
   2083 	// Clamp angles
   2084 	da = a1 - a0;
   2085 	if (dir == NVG_CW) {
   2086 		if (nvg__absf(da) >= NVG_PI*2) {
   2087 			da = NVG_PI*2;
   2088 		} else {
   2089 			while (da < 0.0f) da += NVG_PI*2;
   2090 		}
   2091 	} else {
   2092 		if (nvg__absf(da) >= NVG_PI*2) {
   2093 			da = -NVG_PI*2;
   2094 		} else {
   2095 			while (da > 0.0f) da -= NVG_PI*2;
   2096 		}
   2097 	}
   2098 
   2099 	// Split arc into max 90 degree segments.
   2100 	ndivs = nvg__maxi(1, nvg__mini((int)(nvg__absf(da) / (NVG_PI*0.5f) + 0.5f), 5));
   2101 	hda = (da / (float)ndivs) / 2.0f;
   2102 	kappa = nvg__absf(4.0f / 3.0f * (1.0f - nvg__cosf(hda)) / nvg__sinf(hda));
   2103 
   2104 	if (dir == NVG_CCW)
   2105 		kappa = -kappa;
   2106 
   2107 	nvals = 0;
   2108 	for (i = 0; i <= ndivs; i++) {
   2109 		a = a0 + da * (i/(float)ndivs);
   2110 		dx = nvg__cosf(a);
   2111 		dy = nvg__sinf(a);
   2112 		x = cx + dx*r;
   2113 		y = cy + dy*r;
   2114 		tanx = -dy*r*kappa;
   2115 		tany = dx*r*kappa;
   2116 
   2117 		if (i == 0) {
   2118 			vals[nvals++] = (float)move;
   2119 			vals[nvals++] = x;
   2120 			vals[nvals++] = y;
   2121 		} else {
   2122 			vals[nvals++] = NVG_BEZIERTO;
   2123 			vals[nvals++] = px+ptanx;
   2124 			vals[nvals++] = py+ptany;
   2125 			vals[nvals++] = x-tanx;
   2126 			vals[nvals++] = y-tany;
   2127 			vals[nvals++] = x;
   2128 			vals[nvals++] = y;
   2129 		}
   2130 		px = x;
   2131 		py = y;
   2132 		ptanx = tanx;
   2133 		ptany = tany;
   2134 	}
   2135 
   2136 	nvg__appendCommands(ctx, vals, nvals);
   2137 }
   2138 
   2139 void nvgRect(NVGcontext* ctx, float x, float y, float w, float h)
   2140 {
   2141 	float vals[] = {
   2142 		NVG_MOVETO, x,y,
   2143 		NVG_LINETO, x,y+h,
   2144 		NVG_LINETO, x+w,y+h,
   2145 		NVG_LINETO, x+w,y,
   2146 		NVG_CLOSE
   2147 	};
   2148 	nvg__appendCommands(ctx, vals, NVG_COUNTOF(vals));
   2149 }
   2150 
   2151 void nvgRoundedRect(NVGcontext* ctx, float x, float y, float w, float h, float r)
   2152 {
   2153 	nvgRoundedRectVarying(ctx, x, y, w, h, r, r, r, r);
   2154 }
   2155 
   2156 void nvgRoundedRectVarying(NVGcontext* ctx, float x, float y, float w, float h, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft)
   2157 {
   2158 	if(radTopLeft < 0.1f && radTopRight < 0.1f && radBottomRight < 0.1f && radBottomLeft < 0.1f) {
   2159 		nvgRect(ctx, x, y, w, h);
   2160 		return;
   2161 	} else {
   2162 		float halfw = nvg__absf(w)*0.5f;
   2163 		float halfh = nvg__absf(h)*0.5f;
   2164 		float rxBL = nvg__minf(radBottomLeft, halfw) * nvg__signf(w), ryBL = nvg__minf(radBottomLeft, halfh) * nvg__signf(h);
   2165 		float rxBR = nvg__minf(radBottomRight, halfw) * nvg__signf(w), ryBR = nvg__minf(radBottomRight, halfh) * nvg__signf(h);
   2166 		float rxTR = nvg__minf(radTopRight, halfw) * nvg__signf(w), ryTR = nvg__minf(radTopRight, halfh) * nvg__signf(h);
   2167 		float rxTL = nvg__minf(radTopLeft, halfw) * nvg__signf(w), ryTL = nvg__minf(radTopLeft, halfh) * nvg__signf(h);
   2168 		float vals[] = {
   2169 			NVG_MOVETO, x, y + ryTL,
   2170 			NVG_LINETO, x, y + h - ryBL,
   2171 			NVG_BEZIERTO, x, y + h - ryBL*(1 - NVG_KAPPA90), x + rxBL*(1 - NVG_KAPPA90), y + h, x + rxBL, y + h,
   2172 			NVG_LINETO, x + w - rxBR, y + h,
   2173 			NVG_BEZIERTO, x + w - rxBR*(1 - NVG_KAPPA90), y + h, x + w, y + h - ryBR*(1 - NVG_KAPPA90), x + w, y + h - ryBR,
   2174 			NVG_LINETO, x + w, y + ryTR,
   2175 			NVG_BEZIERTO, x + w, y + ryTR*(1 - NVG_KAPPA90), x + w - rxTR*(1 - NVG_KAPPA90), y, x + w - rxTR, y,
   2176 			NVG_LINETO, x + rxTL, y,
   2177 			NVG_BEZIERTO, x + rxTL*(1 - NVG_KAPPA90), y, x, y + ryTL*(1 - NVG_KAPPA90), x, y + ryTL,
   2178 			NVG_CLOSE
   2179 		};
   2180 		nvg__appendCommands(ctx, vals, NVG_COUNTOF(vals));
   2181 	}
   2182 }
   2183 
   2184 void nvgEllipse(NVGcontext* ctx, float cx, float cy, float rx, float ry)
   2185 {
   2186 	float vals[] = {
   2187 		NVG_MOVETO, cx-rx, cy,
   2188 		NVG_BEZIERTO, cx-rx, cy+ry*NVG_KAPPA90, cx-rx*NVG_KAPPA90, cy+ry, cx, cy+ry,
   2189 		NVG_BEZIERTO, cx+rx*NVG_KAPPA90, cy+ry, cx+rx, cy+ry*NVG_KAPPA90, cx+rx, cy,
   2190 		NVG_BEZIERTO, cx+rx, cy-ry*NVG_KAPPA90, cx+rx*NVG_KAPPA90, cy-ry, cx, cy-ry,
   2191 		NVG_BEZIERTO, cx-rx*NVG_KAPPA90, cy-ry, cx-rx, cy-ry*NVG_KAPPA90, cx-rx, cy,
   2192 		NVG_CLOSE
   2193 	};
   2194 	nvg__appendCommands(ctx, vals, NVG_COUNTOF(vals));
   2195 }
   2196 
   2197 void nvgCircle(NVGcontext* ctx, float cx, float cy, float r)
   2198 {
   2199 	nvgEllipse(ctx, cx,cy, r,r);
   2200 }
   2201 
   2202 void nvgDebugDumpPathCache(NVGcontext* ctx)
   2203 {
   2204 	const NVGpath* path;
   2205 	int i, j;
   2206 
   2207 	printf("Dumping %d cached paths\n", ctx->cache->npaths);
   2208 	for (i = 0; i < ctx->cache->npaths; i++) {
   2209 		path = &ctx->cache->paths[i];
   2210 		printf(" - Path %d\n", i);
   2211 		if (path->nfill) {
   2212 			printf("   - fill: %d\n", path->nfill);
   2213 			for (j = 0; j < path->nfill; j++)
   2214 				printf("%f\t%f\n", path->fill[j].x, path->fill[j].y);
   2215 		}
   2216 		if (path->nstroke) {
   2217 			printf("   - stroke: %d\n", path->nstroke);
   2218 			for (j = 0; j < path->nstroke; j++)
   2219 				printf("%f\t%f\n", path->stroke[j].x, path->stroke[j].y);
   2220 		}
   2221 	}
   2222 }
   2223 
   2224 void nvgFill(NVGcontext* ctx)
   2225 {
   2226 	NVGstate* state = nvg__getState(ctx);
   2227 	const NVGpath* path;
   2228 	NVGpaint fillPaint = state->fill;
   2229 	int i;
   2230 
   2231 	nvg__flattenPaths(ctx);
   2232 	if (ctx->params.edgeAntiAlias && state->shapeAntiAlias)
   2233 		nvg__expandFill(ctx, ctx->fringeWidth, NVG_MITER, 2.4f);
   2234 	else
   2235 		nvg__expandFill(ctx, 0.0f, NVG_MITER, 2.4f);
   2236 
   2237 	// Apply global alpha
   2238 	fillPaint.innerColor.a *= state->alpha;
   2239 	fillPaint.outerColor.a *= state->alpha;
   2240 
   2241 	ctx->params.renderFill(ctx->params.userPtr, &fillPaint, state->compositeOperation, &state->scissor, ctx->fringeWidth,
   2242 						   ctx->cache->bounds, ctx->cache->paths, ctx->cache->npaths);
   2243 
   2244 	// Count triangles
   2245 	for (i = 0; i < ctx->cache->npaths; i++) {
   2246 		path = &ctx->cache->paths[i];
   2247 		ctx->fillTriCount += path->nfill-2;
   2248 		ctx->fillTriCount += path->nstroke-2;
   2249 		ctx->drawCallCount += 2;
   2250 	}
   2251 }
   2252 
   2253 void nvgStroke(NVGcontext* ctx)
   2254 {
   2255 	NVGstate* state = nvg__getState(ctx);
   2256 	float scale = nvg__getAverageScale(state->xform);
   2257 	float strokeWidth = nvg__clampf(state->strokeWidth * scale, 0.0f, 200.0f);
   2258 	NVGpaint strokePaint = state->stroke;
   2259 	const NVGpath* path;
   2260 	int i;
   2261 
   2262 
   2263 	if (strokeWidth < ctx->fringeWidth) {
   2264 		// If the stroke width is less than pixel size, use alpha to emulate coverage.
   2265 		// Since coverage is area, scale by alpha*alpha.
   2266 		float alpha = nvg__clampf(strokeWidth / ctx->fringeWidth, 0.0f, 1.0f);
   2267 		strokePaint.innerColor.a *= alpha*alpha;
   2268 		strokePaint.outerColor.a *= alpha*alpha;
   2269 		strokeWidth = ctx->fringeWidth;
   2270 	}
   2271 
   2272 	// Apply global alpha
   2273 	strokePaint.innerColor.a *= state->alpha;
   2274 	strokePaint.outerColor.a *= state->alpha;
   2275 
   2276 	nvg__flattenPaths(ctx);
   2277 
   2278 	if (ctx->params.edgeAntiAlias && state->shapeAntiAlias)
   2279 		nvg__expandStroke(ctx, strokeWidth*0.5f, ctx->fringeWidth, state->lineCap, state->lineJoin, state->miterLimit);
   2280 	else
   2281 		nvg__expandStroke(ctx, strokeWidth*0.5f, 0.0f, state->lineCap, state->lineJoin, state->miterLimit);
   2282 
   2283 	ctx->params.renderStroke(ctx->params.userPtr, &strokePaint, state->compositeOperation, &state->scissor, ctx->fringeWidth,
   2284 							 strokeWidth, ctx->cache->paths, ctx->cache->npaths);
   2285 
   2286 	// Count triangles
   2287 	for (i = 0; i < ctx->cache->npaths; i++) {
   2288 		path = &ctx->cache->paths[i];
   2289 		ctx->strokeTriCount += path->nstroke-2;
   2290 		ctx->drawCallCount++;
   2291 	}
   2292 }
   2293 
   2294 // Add fonts
   2295 int nvgCreateFont(NVGcontext* ctx, const char* name, const char* path)
   2296 {
   2297 	return fonsAddFont(ctx->fs, name, path);
   2298 }
   2299 
   2300 int nvgCreateFontMem(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData)
   2301 {
   2302 	return fonsAddFontMem(ctx->fs, name, data, ndata, freeData);
   2303 }
   2304 
   2305 int nvgFindFont(NVGcontext* ctx, const char* name)
   2306 {
   2307 	if (name == NULL) return -1;
   2308 	return fonsGetFontByName(ctx->fs, name);
   2309 }
   2310 
   2311 
   2312 int nvgAddFallbackFontId(NVGcontext* ctx, int baseFont, int fallbackFont)
   2313 {
   2314 	if(baseFont == -1 || fallbackFont == -1) return 0;
   2315 	return fonsAddFallbackFont(ctx->fs, baseFont, fallbackFont);
   2316 }
   2317 
   2318 int nvgAddFallbackFont(NVGcontext* ctx, const char* baseFont, const char* fallbackFont)
   2319 {
   2320 	return nvgAddFallbackFontId(ctx, nvgFindFont(ctx, baseFont), nvgFindFont(ctx, fallbackFont));
   2321 }
   2322 
   2323 // State setting
   2324 void nvgFontSize(NVGcontext* ctx, float size)
   2325 {
   2326 	NVGstate* state = nvg__getState(ctx);
   2327 	state->fontSize = size;
   2328 }
   2329 
   2330 void nvgFontBlur(NVGcontext* ctx, float blur)
   2331 {
   2332 	NVGstate* state = nvg__getState(ctx);
   2333 	state->fontBlur = blur;
   2334 }
   2335 
   2336 void nvgTextLetterSpacing(NVGcontext* ctx, float spacing)
   2337 {
   2338 	NVGstate* state = nvg__getState(ctx);
   2339 	state->letterSpacing = spacing;
   2340 }
   2341 
   2342 void nvgTextLineHeight(NVGcontext* ctx, float lineHeight)
   2343 {
   2344 	NVGstate* state = nvg__getState(ctx);
   2345 	state->lineHeight = lineHeight;
   2346 }
   2347 
   2348 void nvgTextAlign(NVGcontext* ctx, int align)
   2349 {
   2350 	NVGstate* state = nvg__getState(ctx);
   2351 	state->textAlign = align;
   2352 }
   2353 
   2354 void nvgFontFaceId(NVGcontext* ctx, int font)
   2355 {
   2356 	NVGstate* state = nvg__getState(ctx);
   2357 	state->fontId = font;
   2358 }
   2359 
   2360 void nvgFontFace(NVGcontext* ctx, const char* font)
   2361 {
   2362 	NVGstate* state = nvg__getState(ctx);
   2363 	state->fontId = fonsGetFontByName(ctx->fs, font);
   2364 }
   2365 
   2366 static float nvg__quantize(float a, float d)
   2367 {
   2368 	return ((int)(a / d + 0.5f)) * d;
   2369 }
   2370 
   2371 static float nvg__getFontScale(NVGstate* state)
   2372 {
   2373 	return nvg__minf(nvg__quantize(nvg__getAverageScale(state->xform), 0.01f), 4.0f);
   2374 }
   2375 
   2376 static void nvg__flushTextTexture(NVGcontext* ctx)
   2377 {
   2378 	int dirty[4];
   2379 
   2380 	if (fonsValidateTexture(ctx->fs, dirty)) {
   2381 		int fontImage = ctx->fontImages[ctx->fontImageIdx];
   2382 		// Update texture
   2383 		if (fontImage != 0) {
   2384 			int iw, ih;
   2385 			const unsigned char* data = fonsGetTextureData(ctx->fs, &iw, &ih);
   2386 			int x = dirty[0];
   2387 			int y = dirty[1];
   2388 			int w = dirty[2] - dirty[0];
   2389 			int h = dirty[3] - dirty[1];
   2390 			ctx->params.renderUpdateTexture(ctx->params.userPtr, fontImage, x,y, w,h, data);
   2391 		}
   2392 	}
   2393 }
   2394 
   2395 static int nvg__allocTextAtlas(NVGcontext* ctx)
   2396 {
   2397 	int iw, ih;
   2398 	nvg__flushTextTexture(ctx);
   2399 	if (ctx->fontImageIdx >= NVG_MAX_FONTIMAGES-1)
   2400 		return 0;
   2401 	// if next fontImage already have a texture
   2402 	if (ctx->fontImages[ctx->fontImageIdx+1] != 0)
   2403 		nvgImageSize(ctx, ctx->fontImages[ctx->fontImageIdx+1], &iw, &ih);
   2404 	else { // calculate the new font image size and create it.
   2405 		nvgImageSize(ctx, ctx->fontImages[ctx->fontImageIdx], &iw, &ih);
   2406 		if (iw > ih)
   2407 			ih *= 2;
   2408 		else
   2409 			iw *= 2;
   2410 		if (iw > NVG_MAX_FONTIMAGE_SIZE || ih > NVG_MAX_FONTIMAGE_SIZE)
   2411 			iw = ih = NVG_MAX_FONTIMAGE_SIZE;
   2412 		ctx->fontImages[ctx->fontImageIdx+1] = ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_ALPHA, iw, ih, 0, NULL);
   2413 	}
   2414 	++ctx->fontImageIdx;
   2415 	fonsResetAtlas(ctx->fs, iw, ih);
   2416 	return 1;
   2417 }
   2418 
   2419 static void nvg__renderText(NVGcontext* ctx, NVGvertex* verts, int nverts)
   2420 {
   2421 	NVGstate* state = nvg__getState(ctx);
   2422 	NVGpaint paint = state->fill;
   2423 
   2424 	// Render triangles.
   2425 	paint.image = ctx->fontImages[ctx->fontImageIdx];
   2426 
   2427 	// Apply global alpha
   2428 	paint.innerColor.a *= state->alpha;
   2429 	paint.outerColor.a *= state->alpha;
   2430 
   2431 	ctx->params.renderTriangles(ctx->params.userPtr, &paint, state->compositeOperation, &state->scissor, verts, nverts);
   2432 
   2433 	ctx->drawCallCount++;
   2434 	ctx->textTriCount += nverts/3;
   2435 }
   2436 
   2437 float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char* end)
   2438 {
   2439 	NVGstate* state = nvg__getState(ctx);
   2440 	FONStextIter iter, prevIter;
   2441 	FONSquad q;
   2442 	NVGvertex* verts;
   2443 	float scale = nvg__getFontScale(state) * ctx->devicePxRatio;
   2444 	float invscale = 1.0f / scale;
   2445 	int cverts = 0;
   2446 	int nverts = 0;
   2447 
   2448 	if (end == NULL)
   2449 		end = string + strlen(string);
   2450 
   2451 	if (state->fontId == FONS_INVALID) return x;
   2452 
   2453 	fonsSetSize(ctx->fs, state->fontSize*scale);
   2454 	fonsSetSpacing(ctx->fs, state->letterSpacing*scale);
   2455 	fonsSetBlur(ctx->fs, state->fontBlur*scale);
   2456 	fonsSetAlign(ctx->fs, state->textAlign);
   2457 	fonsSetFont(ctx->fs, state->fontId);
   2458 
   2459 	cverts = nvg__maxi(2, (int)(end - string)) * 6; // conservative estimate.
   2460 	verts = nvg__allocTempVerts(ctx, cverts);
   2461 	if (verts == NULL) return x;
   2462 
   2463 	fonsTextIterInit(ctx->fs, &iter, x*scale, y*scale, string, end, FONS_GLYPH_BITMAP_REQUIRED);
   2464 	prevIter = iter;
   2465 	while (fonsTextIterNext(ctx->fs, &iter, &q)) {
   2466 		float c[4*2];
   2467 		if (iter.prevGlyphIndex == -1) { // can not retrieve glyph?
   2468 			if (nverts != 0) {
   2469 				nvg__renderText(ctx, verts, nverts);
   2470 				nverts = 0;
   2471 			}
   2472 			if (!nvg__allocTextAtlas(ctx))
   2473 				break; // no memory :(
   2474 			iter = prevIter;
   2475 			fonsTextIterNext(ctx->fs, &iter, &q); // try again
   2476 			if (iter.prevGlyphIndex == -1) // still can not find glyph?
   2477 				break;
   2478 		}
   2479 		prevIter = iter;
   2480 		// Transform corners.
   2481 		nvgTransformPoint(&c[0],&c[1], state->xform, q.x0*invscale, q.y0*invscale);
   2482 		nvgTransformPoint(&c[2],&c[3], state->xform, q.x1*invscale, q.y0*invscale);
   2483 		nvgTransformPoint(&c[4],&c[5], state->xform, q.x1*invscale, q.y1*invscale);
   2484 		nvgTransformPoint(&c[6],&c[7], state->xform, q.x0*invscale, q.y1*invscale);
   2485 		// Create triangles
   2486 		if (nverts+6 <= cverts) {
   2487 			nvg__vset(&verts[nverts], c[0], c[1], q.s0, q.t0); nverts++;
   2488 			nvg__vset(&verts[nverts], c[4], c[5], q.s1, q.t1); nverts++;
   2489 			nvg__vset(&verts[nverts], c[2], c[3], q.s1, q.t0); nverts++;
   2490 			nvg__vset(&verts[nverts], c[0], c[1], q.s0, q.t0); nverts++;
   2491 			nvg__vset(&verts[nverts], c[6], c[7], q.s0, q.t1); nverts++;
   2492 			nvg__vset(&verts[nverts], c[4], c[5], q.s1, q.t1); nverts++;
   2493 		}
   2494 	}
   2495 
   2496 	// TODO: add back-end bit to do this just once per frame.
   2497 	nvg__flushTextTexture(ctx);
   2498 
   2499 	nvg__renderText(ctx, verts, nverts);
   2500 
   2501 	return iter.nextx / scale;
   2502 }
   2503 
   2504 void nvgTextBox(NVGcontext* ctx, float x, float y, float breakRowWidth, const char* string, const char* end)
   2505 {
   2506 	NVGstate* state = nvg__getState(ctx);
   2507 	NVGtextRow rows[2];
   2508 	int nrows = 0, i;
   2509 	int oldAlign = state->textAlign;
   2510 	int haling = state->textAlign & (NVG_ALIGN_LEFT | NVG_ALIGN_CENTER | NVG_ALIGN_RIGHT);
   2511 	int valign = state->textAlign & (NVG_ALIGN_TOP | NVG_ALIGN_MIDDLE | NVG_ALIGN_BOTTOM | NVG_ALIGN_BASELINE);
   2512 	float lineh = 0;
   2513 
   2514 	if (state->fontId == FONS_INVALID) return;
   2515 
   2516 	nvgTextMetrics(ctx, NULL, NULL, &lineh);
   2517 
   2518 	state->textAlign = NVG_ALIGN_LEFT | valign;
   2519 
   2520 	while ((nrows = nvgTextBreakLines(ctx, string, end, breakRowWidth, rows, 2))) {
   2521 		for (i = 0; i < nrows; i++) {
   2522 			NVGtextRow* row = &rows[i];
   2523 			if (haling & NVG_ALIGN_LEFT)
   2524 				nvgText(ctx, x, y, row->start, row->end);
   2525 			else if (haling & NVG_ALIGN_CENTER)
   2526 				nvgText(ctx, x + breakRowWidth*0.5f - row->width*0.5f, y, row->start, row->end);
   2527 			else if (haling & NVG_ALIGN_RIGHT)
   2528 				nvgText(ctx, x + breakRowWidth - row->width, y, row->start, row->end);
   2529 			y += lineh * state->lineHeight;
   2530 		}
   2531 		string = rows[nrows-1].next;
   2532 	}
   2533 
   2534 	state->textAlign = oldAlign;
   2535 }
   2536 
   2537 int nvgTextGlyphPositions(NVGcontext* ctx, float x, float y, const char* string, const char* end, NVGglyphPosition* positions, int maxPositions)
   2538 {
   2539 	NVGstate* state = nvg__getState(ctx);
   2540 	float scale = nvg__getFontScale(state) * ctx->devicePxRatio;
   2541 	float invscale = 1.0f / scale;
   2542 	FONStextIter iter, prevIter;
   2543 	FONSquad q;
   2544 	int npos = 0;
   2545 
   2546 	if (state->fontId == FONS_INVALID) return 0;
   2547 
   2548 	if (end == NULL)
   2549 		end = string + strlen(string);
   2550 
   2551 	if (string == end)
   2552 		return 0;
   2553 
   2554 	fonsSetSize(ctx->fs, state->fontSize*scale);
   2555 	fonsSetSpacing(ctx->fs, state->letterSpacing*scale);
   2556 	fonsSetBlur(ctx->fs, state->fontBlur*scale);
   2557 	fonsSetAlign(ctx->fs, state->textAlign);
   2558 	fonsSetFont(ctx->fs, state->fontId);
   2559 
   2560 	fonsTextIterInit(ctx->fs, &iter, x*scale, y*scale, string, end, FONS_GLYPH_BITMAP_OPTIONAL);
   2561 	prevIter = iter;
   2562 	while (fonsTextIterNext(ctx->fs, &iter, &q)) {
   2563 		if (iter.prevGlyphIndex < 0 && nvg__allocTextAtlas(ctx)) { // can not retrieve glyph?
   2564 			iter = prevIter;
   2565 			fonsTextIterNext(ctx->fs, &iter, &q); // try again
   2566 		}
   2567 		prevIter = iter;
   2568 		positions[npos].str = iter.str;
   2569 		positions[npos].x = iter.x * invscale;
   2570 		positions[npos].minx = nvg__minf(iter.x, q.x0) * invscale;
   2571 		positions[npos].maxx = nvg__maxf(iter.nextx, q.x1) * invscale;
   2572 		npos++;
   2573 		if (npos >= maxPositions)
   2574 			break;
   2575 	}
   2576 
   2577 	return npos;
   2578 }
   2579 
   2580 enum NVGcodepointType {
   2581 	NVG_SPACE,
   2582 	NVG_NEWLINE,
   2583 	NVG_CHAR,
   2584 	NVG_CJK_CHAR,
   2585 };
   2586 
   2587 int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, float breakRowWidth, NVGtextRow* rows, int maxRows)
   2588 {
   2589 	NVGstate* state = nvg__getState(ctx);
   2590 	float scale = nvg__getFontScale(state) * ctx->devicePxRatio;
   2591 	float invscale = 1.0f / scale;
   2592 	FONStextIter iter, prevIter;
   2593 	FONSquad q;
   2594 	int nrows = 0;
   2595 	float rowStartX = 0;
   2596 	float rowWidth = 0;
   2597 	float rowMinX = 0;
   2598 	float rowMaxX = 0;
   2599 	const char* rowStart = NULL;
   2600 	const char* rowEnd = NULL;
   2601 	const char* wordStart = NULL;
   2602 	float wordStartX = 0;
   2603 	float wordMinX = 0;
   2604 	const char* breakEnd = NULL;
   2605 	float breakWidth = 0;
   2606 	float breakMaxX = 0;
   2607 	int type = NVG_SPACE, ptype = NVG_SPACE;
   2608 	unsigned int pcodepoint = 0;
   2609 
   2610 	if (maxRows == 0) return 0;
   2611 	if (state->fontId == FONS_INVALID) return 0;
   2612 
   2613 	if (end == NULL)
   2614 		end = string + strlen(string);
   2615 
   2616 	if (string == end) return 0;
   2617 
   2618 	fonsSetSize(ctx->fs, state->fontSize*scale);
   2619 	fonsSetSpacing(ctx->fs, state->letterSpacing*scale);
   2620 	fonsSetBlur(ctx->fs, state->fontBlur*scale);
   2621 	fonsSetAlign(ctx->fs, state->textAlign);
   2622 	fonsSetFont(ctx->fs, state->fontId);
   2623 
   2624 	breakRowWidth *= scale;
   2625 
   2626 	fonsTextIterInit(ctx->fs, &iter, 0, 0, string, end, FONS_GLYPH_BITMAP_OPTIONAL);
   2627 	prevIter = iter;
   2628 	while (fonsTextIterNext(ctx->fs, &iter, &q)) {
   2629 		if (iter.prevGlyphIndex < 0 && nvg__allocTextAtlas(ctx)) { // can not retrieve glyph?
   2630 			iter = prevIter;
   2631 			fonsTextIterNext(ctx->fs, &iter, &q); // try again
   2632 		}
   2633 		prevIter = iter;
   2634 		switch (iter.codepoint) {
   2635 			case 9:			// \t
   2636 			case 11:		// \v
   2637 			case 12:		// \f
   2638 			case 32:		// space
   2639 			case 0x00a0:	// NBSP
   2640 				type = NVG_SPACE;
   2641 				break;
   2642 			case 10:		// \n
   2643 				type = pcodepoint == 13 ? NVG_SPACE : NVG_NEWLINE;
   2644 				break;
   2645 			case 13:		// \r
   2646 				type = pcodepoint == 10 ? NVG_SPACE : NVG_NEWLINE;
   2647 				break;
   2648 			case 0x0085:	// NEL
   2649 				type = NVG_NEWLINE;
   2650 				break;
   2651 			default:
   2652 				if ((iter.codepoint >= 0x4E00 && iter.codepoint <= 0x9FFF) ||
   2653 					(iter.codepoint >= 0x3000 && iter.codepoint <= 0x30FF) ||
   2654 					(iter.codepoint >= 0xFF00 && iter.codepoint <= 0xFFEF) ||
   2655 					(iter.codepoint >= 0x1100 && iter.codepoint <= 0x11FF) ||
   2656 					(iter.codepoint >= 0x3130 && iter.codepoint <= 0x318F) ||
   2657 					(iter.codepoint >= 0xAC00 && iter.codepoint <= 0xD7AF))
   2658 					type = NVG_CJK_CHAR;
   2659 				else
   2660 					type = NVG_CHAR;
   2661 				break;
   2662 		}
   2663 
   2664 		if (type == NVG_NEWLINE) {
   2665 			// Always handle new lines.
   2666 			rows[nrows].start = rowStart != NULL ? rowStart : iter.str;
   2667 			rows[nrows].end = rowEnd != NULL ? rowEnd : iter.str;
   2668 			rows[nrows].width = rowWidth * invscale;
   2669 			rows[nrows].minx = rowMinX * invscale;
   2670 			rows[nrows].maxx = rowMaxX * invscale;
   2671 			rows[nrows].next = iter.next;
   2672 			nrows++;
   2673 			if (nrows >= maxRows)
   2674 				return nrows;
   2675 			// Set null break point
   2676 			breakEnd = rowStart;
   2677 			breakWidth = 0.0;
   2678 			breakMaxX = 0.0;
   2679 			// Indicate to skip the white space at the beginning of the row.
   2680 			rowStart = NULL;
   2681 			rowEnd = NULL;
   2682 			rowWidth = 0;
   2683 			rowMinX = rowMaxX = 0;
   2684 		} else {
   2685 			if (rowStart == NULL) {
   2686 				// Skip white space until the beginning of the line
   2687 				if (type == NVG_CHAR || type == NVG_CJK_CHAR) {
   2688 					// The current char is the row so far
   2689 					rowStartX = iter.x;
   2690 					rowStart = iter.str;
   2691 					rowEnd = iter.next;
   2692 					rowWidth = iter.nextx - rowStartX; // q.x1 - rowStartX;
   2693 					rowMinX = q.x0 - rowStartX;
   2694 					rowMaxX = q.x1 - rowStartX;
   2695 					wordStart = iter.str;
   2696 					wordStartX = iter.x;
   2697 					wordMinX = q.x0 - rowStartX;
   2698 					// Set null break point
   2699 					breakEnd = rowStart;
   2700 					breakWidth = 0.0;
   2701 					breakMaxX = 0.0;
   2702 				}
   2703 			} else {
   2704 				float nextWidth = iter.nextx - rowStartX;
   2705 
   2706 				// track last non-white space character
   2707 				if (type == NVG_CHAR || type == NVG_CJK_CHAR) {
   2708 					rowEnd = iter.next;
   2709 					rowWidth = iter.nextx - rowStartX;
   2710 					rowMaxX = q.x1 - rowStartX;
   2711 				}
   2712 				// track last end of a word
   2713 				if (((ptype == NVG_CHAR || ptype == NVG_CJK_CHAR) && type == NVG_SPACE) || type == NVG_CJK_CHAR) {
   2714 					breakEnd = iter.str;
   2715 					breakWidth = rowWidth;
   2716 					breakMaxX = rowMaxX;
   2717 				}
   2718 				// track last beginning of a word
   2719 				if ((ptype == NVG_SPACE && (type == NVG_CHAR || type == NVG_CJK_CHAR)) || type == NVG_CJK_CHAR) {
   2720 					wordStart = iter.str;
   2721 					wordStartX = iter.x;
   2722 					wordMinX = q.x0 - rowStartX;
   2723 				}
   2724 
   2725 				// Break to new line when a character is beyond break width.
   2726 				if ((type == NVG_CHAR || type == NVG_CJK_CHAR) && nextWidth > breakRowWidth) {
   2727 					// The run length is too long, need to break to new line.
   2728 					if (breakEnd == rowStart) {
   2729 						// The current word is longer than the row length, just break it from here.
   2730 						rows[nrows].start = rowStart;
   2731 						rows[nrows].end = iter.str;
   2732 						rows[nrows].width = rowWidth * invscale;
   2733 						rows[nrows].minx = rowMinX * invscale;
   2734 						rows[nrows].maxx = rowMaxX * invscale;
   2735 						rows[nrows].next = iter.str;
   2736 						nrows++;
   2737 						if (nrows >= maxRows)
   2738 							return nrows;
   2739 						rowStartX = iter.x;
   2740 						rowStart = iter.str;
   2741 						rowEnd = iter.next;
   2742 						rowWidth = iter.nextx - rowStartX;
   2743 						rowMinX = q.x0 - rowStartX;
   2744 						rowMaxX = q.x1 - rowStartX;
   2745 						wordStart = iter.str;
   2746 						wordStartX = iter.x;
   2747 						wordMinX = q.x0 - rowStartX;
   2748 					} else {
   2749 						// Break the line from the end of the last word, and start new line from the beginning of the new.
   2750 						rows[nrows].start = rowStart;
   2751 						rows[nrows].end = breakEnd;
   2752 						rows[nrows].width = breakWidth * invscale;
   2753 						rows[nrows].minx = rowMinX * invscale;
   2754 						rows[nrows].maxx = breakMaxX * invscale;
   2755 						rows[nrows].next = wordStart;
   2756 						nrows++;
   2757 						if (nrows >= maxRows)
   2758 							return nrows;
   2759 						rowStartX = wordStartX;
   2760 						rowStart = wordStart;
   2761 						rowEnd = iter.next;
   2762 						rowWidth = iter.nextx - rowStartX;
   2763 						rowMinX = wordMinX;
   2764 						rowMaxX = q.x1 - rowStartX;
   2765 						// No change to the word start
   2766 					}
   2767 					// Set null break point
   2768 					breakEnd = rowStart;
   2769 					breakWidth = 0.0;
   2770 					breakMaxX = 0.0;
   2771 				}
   2772 			}
   2773 		}
   2774 
   2775 		pcodepoint = iter.codepoint;
   2776 		ptype = type;
   2777 	}
   2778 
   2779 	// Break the line from the end of the last word, and start new line from the beginning of the new.
   2780 	if (rowStart != NULL) {
   2781 		rows[nrows].start = rowStart;
   2782 		rows[nrows].end = rowEnd;
   2783 		rows[nrows].width = rowWidth * invscale;
   2784 		rows[nrows].minx = rowMinX * invscale;
   2785 		rows[nrows].maxx = rowMaxX * invscale;
   2786 		rows[nrows].next = end;
   2787 		nrows++;
   2788 	}
   2789 
   2790 	return nrows;
   2791 }
   2792 
   2793 float nvgTextBounds(NVGcontext* ctx, float x, float y, const char* string, const char* end, float* bounds)
   2794 {
   2795 	NVGstate* state = nvg__getState(ctx);
   2796 	float scale = nvg__getFontScale(state) * ctx->devicePxRatio;
   2797 	float invscale = 1.0f / scale;
   2798 	float width;
   2799 
   2800 	if (state->fontId == FONS_INVALID) return 0;
   2801 
   2802 	fonsSetSize(ctx->fs, state->fontSize*scale);
   2803 	fonsSetSpacing(ctx->fs, state->letterSpacing*scale);
   2804 	fonsSetBlur(ctx->fs, state->fontBlur*scale);
   2805 	fonsSetAlign(ctx->fs, state->textAlign);
   2806 	fonsSetFont(ctx->fs, state->fontId);
   2807 
   2808 	width = fonsTextBounds(ctx->fs, x*scale, y*scale, string, end, bounds);
   2809 	if (bounds != NULL) {
   2810 		// Use line bounds for height.
   2811 		fonsLineBounds(ctx->fs, y*scale, &bounds[1], &bounds[3]);
   2812 		bounds[0] *= invscale;
   2813 		bounds[1] *= invscale;
   2814 		bounds[2] *= invscale;
   2815 		bounds[3] *= invscale;
   2816 	}
   2817 	return width * invscale;
   2818 }
   2819 
   2820 void nvgTextBoxBounds(NVGcontext* ctx, float x, float y, float breakRowWidth, const char* string, const char* end, float* bounds)
   2821 {
   2822 	NVGstate* state = nvg__getState(ctx);
   2823 	NVGtextRow rows[2];
   2824 	float scale = nvg__getFontScale(state) * ctx->devicePxRatio;
   2825 	float invscale = 1.0f / scale;
   2826 	int nrows = 0, i;
   2827 	int oldAlign = state->textAlign;
   2828 	int haling = state->textAlign & (NVG_ALIGN_LEFT | NVG_ALIGN_CENTER | NVG_ALIGN_RIGHT);
   2829 	int valign = state->textAlign & (NVG_ALIGN_TOP | NVG_ALIGN_MIDDLE | NVG_ALIGN_BOTTOM | NVG_ALIGN_BASELINE);
   2830 	float lineh = 0, rminy = 0, rmaxy = 0;
   2831 	float minx, miny, maxx, maxy;
   2832 
   2833 	if (state->fontId == FONS_INVALID) {
   2834 		if (bounds != NULL)
   2835 			bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0f;
   2836 		return;
   2837 	}
   2838 
   2839 	nvgTextMetrics(ctx, NULL, NULL, &lineh);
   2840 
   2841 	state->textAlign = NVG_ALIGN_LEFT | valign;
   2842 
   2843 	minx = maxx = x;
   2844 	miny = maxy = y;
   2845 
   2846 	fonsSetSize(ctx->fs, state->fontSize*scale);
   2847 	fonsSetSpacing(ctx->fs, state->letterSpacing*scale);
   2848 	fonsSetBlur(ctx->fs, state->fontBlur*scale);
   2849 	fonsSetAlign(ctx->fs, state->textAlign);
   2850 	fonsSetFont(ctx->fs, state->fontId);
   2851 	fonsLineBounds(ctx->fs, 0, &rminy, &rmaxy);
   2852 	rminy *= invscale;
   2853 	rmaxy *= invscale;
   2854 
   2855 	while ((nrows = nvgTextBreakLines(ctx, string, end, breakRowWidth, rows, 2))) {
   2856 		for (i = 0; i < nrows; i++) {
   2857 			NVGtextRow* row = &rows[i];
   2858 			float rminx, rmaxx, dx = 0;
   2859 			// Horizontal bounds
   2860 			if (haling & NVG_ALIGN_LEFT)
   2861 				dx = 0;
   2862 			else if (haling & NVG_ALIGN_CENTER)
   2863 				dx = breakRowWidth*0.5f - row->width*0.5f;
   2864 			else if (haling & NVG_ALIGN_RIGHT)
   2865 				dx = breakRowWidth - row->width;
   2866 			rminx = x + row->minx + dx;
   2867 			rmaxx = x + row->maxx + dx;
   2868 			minx = nvg__minf(minx, rminx);
   2869 			maxx = nvg__maxf(maxx, rmaxx);
   2870 			// Vertical bounds.
   2871 			miny = nvg__minf(miny, y + rminy);
   2872 			maxy = nvg__maxf(maxy, y + rmaxy);
   2873 
   2874 			y += lineh * state->lineHeight;
   2875 		}
   2876 		string = rows[nrows-1].next;
   2877 	}
   2878 
   2879 	state->textAlign = oldAlign;
   2880 
   2881 	if (bounds != NULL) {
   2882 		bounds[0] = minx;
   2883 		bounds[1] = miny;
   2884 		bounds[2] = maxx;
   2885 		bounds[3] = maxy;
   2886 	}
   2887 }
   2888 
   2889 void nvgTextMetrics(NVGcontext* ctx, float* ascender, float* descender, float* lineh)
   2890 {
   2891 	NVGstate* state = nvg__getState(ctx);
   2892 	float scale = nvg__getFontScale(state) * ctx->devicePxRatio;
   2893 	float invscale = 1.0f / scale;
   2894 
   2895 	if (state->fontId == FONS_INVALID) return;
   2896 
   2897 	fonsSetSize(ctx->fs, state->fontSize*scale);
   2898 	fonsSetSpacing(ctx->fs, state->letterSpacing*scale);
   2899 	fonsSetBlur(ctx->fs, state->fontBlur*scale);
   2900 	fonsSetAlign(ctx->fs, state->textAlign);
   2901 	fonsSetFont(ctx->fs, state->fontId);
   2902 
   2903 	fonsVertMetrics(ctx->fs, ascender, descender, lineh);
   2904 	if (ascender != NULL)
   2905 		*ascender *= invscale;
   2906 	if (descender != NULL)
   2907 		*descender *= invscale;
   2908 	if (lineh != NULL)
   2909 		*lineh *= invscale;
   2910 }
   2911 // vim: ft=c nu noet ts=4