DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

nanovg.c (83231B)


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