You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1910 lines
49KB

  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. #include <stdio.h>
  19. #include <math.h>
  20. #include "nanovg.h"
  21. #define FONTSTASH_IMPLEMENTATION
  22. #include "fontstash.h"
  23. #define STBI_HEADER_FILE_ONLY
  24. #include "stb_image.c"
  25. #define NVG_INIT_PATH_SIZE 256
  26. #define NVG_MAX_STATES 32
  27. #define NVG_KAPPA90 0.5522847493f // Lenght proportional to radius of a cubic bezier handle for 90deg arcs.
  28. #define NVG_COUNTOF(arr) (sizeof(arr) / sizeof(0[arr]))
  29. enum NVGcommands {
  30. NVG_MOVETO = 0,
  31. NVG_LINETO = 1,
  32. NVG_BEZIERTO = 2,
  33. NVG_CLOSE = 3,
  34. NVG_WINDING = 4,
  35. };
  36. enum NVGpointFlags
  37. {
  38. NVG_PT_BEVEL = 0x01,
  39. NVG_PT_LEFT = 0x02,
  40. NVG_PT_CUSP = 0x04,
  41. NVG_PT_CORNER = 0x08,
  42. };
  43. enum NVGexpandFeatures {
  44. NVG_FILL = 0x01,
  45. NVG_STROKE = 0x02,
  46. NVG_CAPS = 0x04,
  47. };
  48. struct NVGstate {
  49. struct NVGpaint fill;
  50. struct NVGpaint stroke;
  51. float strokeWidth;
  52. float miterLimit;
  53. int lineJoin;
  54. int lineCap;
  55. float xform[6];
  56. struct NVGscissor scissor;
  57. float fontSize;
  58. float letterSpacing;
  59. float fontBlur;
  60. int textAlign;
  61. int fontId;
  62. };
  63. struct NVGpoint {
  64. float x,y;
  65. float dx, dy;
  66. float len;
  67. float dmx, dmy;
  68. unsigned char flags;
  69. };
  70. struct NVGpathCache {
  71. struct NVGpoint* points;
  72. int npoints;
  73. int cpoints;
  74. struct NVGpath* paths;
  75. int npaths;
  76. int cpaths;
  77. struct NVGvertex* verts;
  78. int nverts;
  79. int cverts;
  80. float bounds[4];
  81. };
  82. struct NVGcontext {
  83. struct NVGparams params;
  84. float* commands;
  85. int ccommands;
  86. int ncommands;
  87. float commandx, commandy;
  88. struct NVGstate states[NVG_MAX_STATES];
  89. int nstates;
  90. struct NVGpathCache* cache;
  91. float tessTol;
  92. float distTol;
  93. float fringeWidth;
  94. float devicePxRatio;
  95. struct FONScontext* fs;
  96. int fontImage;
  97. int drawCallCount;
  98. int fillTriCount;
  99. int strokeTriCount;
  100. int textTriCount;
  101. };
  102. static float nvg__sqrtf(float a) { return sqrtf(a); }
  103. static float nvg__modf(float a, float b) { return fmodf(a, b); }
  104. static float nvg__sinf(float a) { return sinf(a); }
  105. static float nvg__cosf(float a) { return cosf(a); }
  106. static float nvg__tanf(float a) { return tanf(a); }
  107. static float nvg__atan2f(float a,float b) { return atan2f(a, b); }
  108. static float nvg__acosf(float a) { return acosf(a); }
  109. static int nvg__mini(int a, int b) { return a < b ? a : b; }
  110. static int nvg__maxi(int a, int b) { return a > b ? a : b; }
  111. static int nvg__clampi(int a, int mn, int mx) { return a < mn ? mn : (a > mx ? mx : a); }
  112. static float nvg__minf(float a, float b) { return a < b ? a : b; }
  113. static float nvg__maxf(float a, float b) { return a > b ? a : b; }
  114. static float nvg__absf(float a) { return a >= 0.0f ? a : -a; }
  115. static float nvg__clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); }
  116. static float nvg__cross(float dx0, float dy0, float dx1, float dy1) { return dx1*dy0 - dx0*dy1; }
  117. static float nvg__normalize(float *x, float* y)
  118. {
  119. float d = nvg__sqrtf((*x)*(*x) + (*y)*(*y));
  120. if (d > 1e-6f) {
  121. d = 1.0f / d;
  122. *x *= d;
  123. *y *= d;
  124. }
  125. return d;
  126. }
  127. static void nvg__deletePathCache(struct NVGpathCache* c)
  128. {
  129. if (c == NULL) return;
  130. if (c->points != NULL) free(c->points);
  131. if (c->paths != NULL) free(c->paths);
  132. if (c->verts != NULL) free(c->verts);
  133. free(c);
  134. }
  135. static struct NVGpathCache* nvg__allocPathCache()
  136. {
  137. struct NVGpathCache* c = (struct NVGpathCache*)malloc(sizeof(struct NVGpathCache));
  138. if (c == NULL) goto error;
  139. memset(c, 0, sizeof(struct NVGpathCache));
  140. c->points = (struct NVGpoint*)malloc(sizeof(struct NVGpoint)*4);
  141. if (!c->points) goto error;
  142. c->npoints = 0;
  143. c->cpoints = 4;
  144. c->paths = (struct NVGpath*)malloc(sizeof(struct NVGpath)*4);
  145. if (!c->paths) goto error;
  146. c->npaths = 0;
  147. c->cpaths = 4;
  148. c->verts = (struct NVGvertex*)malloc(sizeof(struct NVGvertex)*4);
  149. if (!c->verts) goto error;
  150. c->nverts = 0;
  151. c->cverts = 4;
  152. return c;
  153. error:
  154. nvg__deletePathCache(c);
  155. return NULL;
  156. }
  157. static void nvg__setDevicePixelRatio(struct NVGcontext* ctx, float ratio)
  158. {
  159. ctx->tessTol = 0.3f * 4.0f / ratio;
  160. ctx->distTol = 0.01f / ratio;
  161. ctx->fringeWidth = 1.0f / ratio;
  162. ctx->devicePxRatio = ratio;
  163. }
  164. struct NVGcontext* nvgCreateInternal(struct NVGparams* params)
  165. {
  166. struct FONSparams fontParams;
  167. struct NVGcontext* ctx = (struct NVGcontext*)malloc(sizeof(struct NVGcontext));
  168. if (ctx == NULL) goto error;
  169. memset(ctx, 0, sizeof(struct NVGcontext));
  170. ctx->params = *params;
  171. ctx->commands = (float*)malloc(sizeof(float)*NVG_INIT_PATH_SIZE);
  172. if (!ctx->commands) goto error;
  173. ctx->ncommands = 0;
  174. ctx->ccommands = NVG_INIT_PATH_SIZE;
  175. ctx->cache = nvg__allocPathCache();
  176. if (ctx->cache == NULL) goto error;
  177. nvgSave(ctx);
  178. nvgReset(ctx);
  179. nvg__setDevicePixelRatio(ctx, 1.0f);
  180. if (ctx->params.renderCreate(ctx->params.userPtr) == 0) goto error;
  181. // Init font rendering
  182. memset(&fontParams, 0, sizeof(fontParams));
  183. fontParams.width = params->atlasWidth;
  184. fontParams.height = params->atlasHeight;
  185. fontParams.flags = FONS_ZERO_TOPLEFT;
  186. fontParams.renderCreate = NULL;
  187. fontParams.renderUpdate = NULL;
  188. fontParams.renderDraw = NULL;
  189. fontParams.renderDelete = NULL;
  190. fontParams.userPtr = NULL;
  191. ctx->fs = fonsCreateInternal(&fontParams);
  192. if (ctx->fs == NULL) goto error;
  193. // Create font texture
  194. ctx->fontImage = ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_ALPHA, fontParams.width, fontParams.height, NULL);
  195. if (ctx->fontImage == 0) goto error;
  196. return ctx;
  197. error:
  198. nvgDeleteInternal(ctx);
  199. return 0;
  200. }
  201. void nvgDeleteInternal(struct NVGcontext* ctx)
  202. {
  203. if (ctx == NULL) return;
  204. if (ctx->commands != NULL) free(ctx->commands);
  205. if (ctx->cache != NULL) nvg__deletePathCache(ctx->cache);
  206. if (ctx->fs)
  207. fonsDeleteInternal(ctx->fs);
  208. if (ctx->params.renderDelete != NULL)
  209. ctx->params.renderDelete(ctx->params.userPtr);
  210. free(ctx);
  211. }
  212. void nvgBeginFrame(struct NVGcontext* ctx, int windowWidth, int windowHeight, float devicePixelRatio)
  213. {
  214. /* printf("Tris: draws:%d fill:%d stroke:%d text:%d TOT:%d\n",
  215. ctx->drawCallCount, ctx->fillTriCount, ctx->strokeTriCount, ctx->textTriCount,
  216. ctx->fillTriCount+ctx->strokeTriCount+ctx->textTriCount);*/
  217. ctx->nstates = 0;
  218. nvgSave(ctx);
  219. nvgReset(ctx);
  220. nvg__setDevicePixelRatio(ctx, devicePixelRatio);
  221. ctx->params.renderViewport(ctx->params.userPtr, windowWidth, windowHeight);
  222. ctx->drawCallCount = 0;
  223. ctx->fillTriCount = 0;
  224. ctx->strokeTriCount = 0;
  225. ctx->textTriCount = 0;
  226. }
  227. void nvgEndFrame(struct NVGcontext* ctx)
  228. {
  229. ctx->params.renderFlush(ctx->params.userPtr);
  230. }
  231. unsigned int nvgRGB(unsigned char r, unsigned char g, unsigned char b)
  232. {
  233. return nvgRGBA(r,g,b,255);
  234. }
  235. unsigned int nvgRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
  236. {
  237. return (r) | (g << 8) | (b << 16) | (a << 24);
  238. }
  239. unsigned int nvgTransRGBA(unsigned int c, unsigned char a)
  240. {
  241. int r = (c) & 0xff;
  242. int g = (c>>8) & 0xff;
  243. int b = (c>>16) & 0xff;
  244. return nvgRGBA(r,g,b,a);
  245. }
  246. unsigned int nvgLerpRGBA(unsigned int c0, unsigned int c1, float u)
  247. {
  248. int iu = (float)(nvg__clampf(u, 0.0f, 1.0f) * 256.0f);
  249. int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8;
  250. int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8;
  251. int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8;
  252. int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8;
  253. return nvgRGBA(r,g,b,a);
  254. }
  255. unsigned int nvgHSL(float h, float s, float l)
  256. {
  257. return nvgHSLA(h,s,l,255);
  258. }
  259. static float nvg__hue(float h, float m1, float m2)
  260. {
  261. if (h < 0) h += 1;
  262. if (h > 1) h -= 1;
  263. if (h < 1.0f/6.0f)
  264. return m1 + (m2 - m1) * h * 6.0f;
  265. else if (h < 3.0f/6.0f)
  266. return m2;
  267. else if (h < 4.0f/6.0f)
  268. return m1 + (m2 - m1) * (2.0f/3.0f - h) * 6.0f;
  269. return m1;
  270. }
  271. unsigned int nvgHSLA(float h, float s, float l, unsigned char a)
  272. {
  273. h = nvg__modf(h, 1.0f);
  274. if (h < 0.0f) h += 1.0f;
  275. s = nvg__clampf(s, 0.0f, 1.0f);
  276. l = nvg__clampf(l, 0.0f, 1.0f);
  277. float m2 = l <= 0.5f ? (l * (1 + s)) : (l + s - l * s);
  278. float m1 = 2 * l - m2;
  279. unsigned char r = (unsigned char)nvg__clampf(nvg__hue(h + 1.0f/3.0f, m1, m2) * 255.0f, 0, 255);
  280. unsigned char g = (unsigned char)nvg__clampf(nvg__hue(h, m1, m2) * 255.0f, 0, 255);
  281. unsigned char b = (unsigned char)nvg__clampf(nvg__hue(h - 1.0f/3.0f, m1, m2) * 255.0f, 0, 255);
  282. return nvgRGBA(r,g,b,a);
  283. }
  284. static struct NVGstate* nvg__getState(struct NVGcontext* ctx)
  285. {
  286. return &ctx->states[ctx->nstates-1];
  287. }
  288. static void nvg__xformIdentity(float* t)
  289. {
  290. t[0] = 1.0f; t[1] = 0.0f;
  291. t[2] = 0.0f; t[3] = 1.0f;
  292. t[4] = 0.0f; t[5] = 0.0f;
  293. }
  294. static void nvg__xformTranslate(float* t, float tx, float ty)
  295. {
  296. t[0] = 1.0f; t[1] = 0.0f;
  297. t[2] = 0.0f; t[3] = 1.0f;
  298. t[4] = tx; t[5] = ty;
  299. }
  300. static void nvg__xformScale(float* t, float sx, float sy)
  301. {
  302. t[0] = sx; t[1] = 0.0f;
  303. t[2] = 0.0f; t[3] = sy;
  304. t[4] = 0.0f; t[5] = 0.0f;
  305. }
  306. static void nvg__xformRotate(float* t, float a)
  307. {
  308. float cs = nvg__cosf(a), sn = nvg__sinf(a);
  309. t[0] = cs; t[1] = sn;
  310. t[2] = -sn; t[3] = cs;
  311. t[4] = 0.0f; t[5] = 0.0f;
  312. }
  313. static void nvg__xformMultiply(float* t, float* s)
  314. {
  315. float t0 = t[0] * s[0] + t[1] * s[2];
  316. float t2 = t[2] * s[0] + t[3] * s[2];
  317. float t4 = t[4] * s[0] + t[5] * s[2] + s[4];
  318. t[1] = t[0] * s[1] + t[1] * s[3];
  319. t[3] = t[2] * s[1] + t[3] * s[3];
  320. t[5] = t[4] * s[1] + t[5] * s[3] + s[5];
  321. t[0] = t0;
  322. t[2] = t2;
  323. t[4] = t4;
  324. }
  325. static void nvg__xformPremultiply(float* t, float* s)
  326. {
  327. float s2[6];
  328. memcpy(s2, s, sizeof(float)*6);
  329. nvg__xformMultiply(s2, t);
  330. memcpy(t, s2, sizeof(float)*6);
  331. }
  332. static void nvg__setPaintColor(struct NVGpaint* p, unsigned int color)
  333. {
  334. memset(p, 0, sizeof(*p));
  335. nvg__xformIdentity(p->xform);
  336. p->radius = 0.0f;
  337. p->feather = 1.0f;
  338. p->innerColor = color;
  339. p->outerColor = color;
  340. }
  341. // State handling
  342. void nvgSave(struct NVGcontext* ctx)
  343. {
  344. if (ctx->nstates >= NVG_MAX_STATES)
  345. return;
  346. if (ctx->nstates > 0)
  347. memcpy(&ctx->states[ctx->nstates], &ctx->states[ctx->nstates-1], sizeof(struct NVGstate));
  348. ctx->nstates++;
  349. }
  350. void nvgRestore(struct NVGcontext* ctx)
  351. {
  352. if (ctx->nstates <= 1)
  353. return;
  354. ctx->nstates--;
  355. }
  356. void nvgReset(struct NVGcontext* ctx)
  357. {
  358. struct NVGstate* state = nvg__getState(ctx);
  359. memset(state, 0, sizeof(*state));
  360. nvg__setPaintColor(&state->fill, nvgRGBA(255,255,255,255));
  361. nvg__setPaintColor(&state->stroke, nvgRGBA(0,0,0,255));
  362. state->strokeWidth = 1.0f;
  363. state->miterLimit = 10.0f;
  364. state->lineCap = NVG_BUTT;
  365. state->lineJoin = NVG_MITER;
  366. nvg__xformIdentity(state->xform);
  367. state->scissor.extent[0] = 0.0f;
  368. state->scissor.extent[1] = 0.0f;
  369. state->fontSize = 16.0f;
  370. state->letterSpacing = 0.0f;
  371. state->fontBlur = 0.0f;
  372. state->textAlign = NVG_ALIGN_LEFT | NVG_ALIGN_BASELINE;
  373. state->fontId = 0;
  374. }
  375. // State setting
  376. void nvgStrokeWidth(struct NVGcontext* ctx, float width)
  377. {
  378. struct NVGstate* state = nvg__getState(ctx);
  379. state->strokeWidth = width;
  380. }
  381. void nvgMiterLimit(struct NVGcontext* ctx, float limit)
  382. {
  383. struct NVGstate* state = nvg__getState(ctx);
  384. state->miterLimit = limit;
  385. }
  386. void nvgLineCap(struct NVGcontext* ctx, int cap)
  387. {
  388. struct NVGstate* state = nvg__getState(ctx);
  389. state->lineCap = cap;
  390. }
  391. void nvgLineJoin(struct NVGcontext* ctx, int join)
  392. {
  393. struct NVGstate* state = nvg__getState(ctx);
  394. state->lineJoin = join;
  395. }
  396. void nvgTransform(struct NVGcontext* ctx, float a, float b, float c, float d, float e, float f)
  397. {
  398. struct NVGstate* state = nvg__getState(ctx);
  399. float t[6] = { a, b, c, d, e, f };
  400. nvg__xformPremultiply(state->xform, t);
  401. }
  402. void nvgResetTransform(struct NVGcontext* ctx)
  403. {
  404. struct NVGstate* state = nvg__getState(ctx);
  405. nvg__xformIdentity(state->xform);
  406. }
  407. void nvgTranslate(struct NVGcontext* ctx, float x, float y)
  408. {
  409. struct NVGstate* state = nvg__getState(ctx);
  410. float t[6];
  411. nvg__xformTranslate(t, x,y);
  412. nvg__xformPremultiply(state->xform, t);
  413. }
  414. void nvgRotate(struct NVGcontext* ctx, float angle)
  415. {
  416. struct NVGstate* state = nvg__getState(ctx);
  417. float t[6];
  418. nvg__xformRotate(t, angle);
  419. nvg__xformPremultiply(state->xform, t);
  420. }
  421. void nvgScale(struct NVGcontext* ctx, float x, float y)
  422. {
  423. struct NVGstate* state = nvg__getState(ctx);
  424. float t[6];
  425. nvg__xformScale(t, x,y);
  426. nvg__xformPremultiply(state->xform, t);
  427. }
  428. void nvgStrokeColor(struct NVGcontext* ctx, unsigned int color)
  429. {
  430. struct NVGstate* state = nvg__getState(ctx);
  431. nvg__setPaintColor(&state->stroke, color);
  432. }
  433. void nvgStrokePaint(struct NVGcontext* ctx, struct NVGpaint paint)
  434. {
  435. struct NVGstate* state = nvg__getState(ctx);
  436. state->stroke = paint;
  437. nvg__xformMultiply(state->stroke.xform, state->xform);
  438. }
  439. void nvgFillColor(struct NVGcontext* ctx, unsigned int color)
  440. {
  441. struct NVGstate* state = nvg__getState(ctx);
  442. nvg__setPaintColor(&state->fill, color);
  443. }
  444. void nvgFillPaint(struct NVGcontext* ctx, struct NVGpaint paint)
  445. {
  446. struct NVGstate* state = nvg__getState(ctx);
  447. state->fill = paint;
  448. nvg__xformMultiply(state->fill.xform, state->xform);
  449. }
  450. int nvgCreateImage(struct NVGcontext* ctx, const char* filename)
  451. {
  452. int w, h, n, image;
  453. unsigned char* img = stbi_load(filename, &w, &h, &n, 4);
  454. if (img == NULL) {
  455. // printf("Failed to load %s - %s\n", filename, stbi_failure_reason());
  456. return 0;
  457. }
  458. image = nvgCreateImageRGBA(ctx, w, h, img);
  459. stbi_image_free(img);
  460. return image;
  461. }
  462. int nvgCreateImageMem(struct NVGcontext* ctx, unsigned char* data, int ndata, int freeData)
  463. {
  464. int w, h, n, image;
  465. unsigned char* img = stbi_load_from_memory(data, ndata, &w, &h, &n, 4);
  466. if (img == NULL) {
  467. // printf("Failed to load %s - %s\n", filename, stbi_failure_reason());
  468. return 0;
  469. }
  470. image = nvgCreateImageRGBA(ctx, w, h, img);
  471. stbi_image_free(img);
  472. return image;
  473. }
  474. int nvgCreateImageRGBA(struct NVGcontext* ctx, int w, int h, const unsigned char* data)
  475. {
  476. return ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_RGBA, w, h, data);
  477. }
  478. void nvgUpdateImage(struct NVGcontext* ctx, int image, const unsigned char* data)
  479. {
  480. int w, h;
  481. ctx->params.renderGetTextureSize(ctx->params.userPtr, image, &w, &h);
  482. ctx->params.renderUpdateTexture(ctx->params.userPtr, image, 0,0, w,h, data);
  483. }
  484. void nvgImageSize(struct NVGcontext* ctx, int image, int* w, int* h)
  485. {
  486. ctx->params.renderGetTextureSize(ctx->params.userPtr, image, w, h);
  487. }
  488. void nvgDeleteImage(struct NVGcontext* ctx, int image)
  489. {
  490. ctx->params.renderDeleteTexture(ctx->params.userPtr, image);
  491. }
  492. struct NVGpaint nvgLinearGradient(struct NVGcontext* ctx,
  493. float sx, float sy, float ex, float ey,
  494. unsigned int icol, unsigned int ocol)
  495. {
  496. struct NVGpaint p;
  497. float dx, dy, d;
  498. const float large = 1e5;
  499. memset(&p, 0, sizeof(p));
  500. // Calculate transform aligned to the line
  501. dx = ex - sx;
  502. dy = ey - sy;
  503. d = sqrtf(dx*dx + dy*dy);
  504. if (d > 0.0001f) {
  505. dx /= d;
  506. dy /= d;
  507. } else {
  508. dx = 0;
  509. dy = 1;
  510. }
  511. p.xform[0] = dy; p.xform[1] = -dx;
  512. p.xform[2] = dx; p.xform[3] = dy;
  513. p.xform[4] = sx - dx*large; p.xform[5] = sy - dy*large;
  514. p.extent[0] = large;
  515. p.extent[1] = large + d*0.5f;
  516. p.radius = 0.0f;
  517. p.feather = nvg__maxf(1.0f, d);
  518. p.innerColor = icol;
  519. p.outerColor = ocol;
  520. return p;
  521. }
  522. struct NVGpaint nvgRadialGradient(struct NVGcontext* ctx,
  523. float cx, float cy, float inr, float outr,
  524. unsigned int icol, unsigned int ocol)
  525. {
  526. struct NVGpaint p;
  527. float r = (inr+outr)*0.5f;
  528. float f = (outr-inr);
  529. memset(&p, 0, sizeof(p));
  530. nvg__xformIdentity(p.xform);
  531. p.xform[4] = cx;
  532. p.xform[5] = cy;
  533. p.extent[0] = r;
  534. p.extent[1] = r;
  535. p.radius = r;
  536. p.feather = nvg__maxf(1.0f, f);
  537. p.innerColor = icol;
  538. p.outerColor = ocol;
  539. return p;
  540. }
  541. struct NVGpaint nvgBoxGradient(struct NVGcontext* ctx,
  542. float x, float y, float w, float h, float r, float f,
  543. unsigned int icol, unsigned int ocol)
  544. {
  545. struct NVGpaint p;
  546. memset(&p, 0, sizeof(p));
  547. nvg__xformIdentity(p.xform);
  548. p.xform[4] = x+w*0.5f;
  549. p.xform[5] = y+h*0.5f;
  550. p.extent[0] = w*0.5f;
  551. p.extent[1] = h*0.5f;
  552. p.radius = r;
  553. p.feather = nvg__maxf(1.0f, f);
  554. p.innerColor = icol;
  555. p.outerColor = ocol;
  556. return p;
  557. }
  558. struct NVGpaint nvgImagePattern(struct NVGcontext* ctx,
  559. float cx, float cy, float w, float h, float angle,
  560. int image, int repeat)
  561. {
  562. struct NVGpaint p;
  563. memset(&p, 0, sizeof(p));
  564. nvg__xformRotate(p.xform, angle);
  565. p.xform[4] = cx;
  566. p.xform[5] = cy;
  567. p.extent[0] = w;
  568. p.extent[1] = h;
  569. p.image = image;
  570. p.repeat = repeat;
  571. return p;
  572. }
  573. // Scissoring
  574. void nvgScissor(struct NVGcontext* ctx, float x, float y, float w, float h)
  575. {
  576. struct NVGstate* state = nvg__getState(ctx);
  577. nvg__xformIdentity(state->scissor.xform);
  578. state->scissor.xform[4] = x+w*0.5f;
  579. state->scissor.xform[5] = y+h*0.5f;
  580. nvg__xformMultiply(state->scissor.xform, state->xform);
  581. state->scissor.extent[0] = w*0.5f;
  582. state->scissor.extent[1] = h*0.5f;
  583. }
  584. void nvgResetScissor(struct NVGcontext* ctx)
  585. {
  586. struct NVGstate* state = nvg__getState(ctx);
  587. memset(state->scissor.xform, 0, sizeof(state->scissor.xform));
  588. state->scissor.extent[0] = 0;
  589. state->scissor.extent[1] = 0;
  590. }
  591. static void nvg__xformPt(float* dx, float* dy, float sx, float sy, const float* t)
  592. {
  593. *dx = sx*t[0] + sy*t[2] + t[4];
  594. *dy = sx*t[1] + sy*t[3] + t[5];
  595. }
  596. static int nvg__ptEquals(float x1, float y1, float x2, float y2, float tol)
  597. {
  598. float dx = x2 - x1;
  599. float dy = y2 - y1;
  600. return dx*dx + dy*dy < tol*tol;
  601. }
  602. static float nvg__distPtSeg(float x, float y, float px, float py, float qx, float qy)
  603. {
  604. float pqx, pqy, dx, dy, d, t;
  605. pqx = qx-px;
  606. pqy = qy-py;
  607. dx = x-px;
  608. dy = y-py;
  609. d = pqx*pqx + pqy*pqy;
  610. t = pqx*dx + pqy*dy;
  611. if (d > 0) t /= d;
  612. if (t < 0) t = 0;
  613. else if (t > 1) t = 1;
  614. dx = px + t*pqx - x;
  615. dy = py + t*pqy - y;
  616. return dx*dx + dy*dy;
  617. }
  618. static void nvg__appendCommands(struct NVGcontext* ctx, float* vals, int nvals)
  619. {
  620. struct NVGstate* state = nvg__getState(ctx);
  621. int i;
  622. if (ctx->ncommands+nvals > ctx->ccommands) {
  623. if (ctx->ccommands == 0) ctx->ccommands = 8;
  624. while (ctx->ccommands < ctx->ncommands+nvals)
  625. ctx->ccommands *= 2;
  626. ctx->commands = (float*)realloc(ctx->commands, ctx->ccommands*sizeof(float));
  627. if (ctx->commands == NULL) return;
  628. }
  629. // transform commands
  630. i = 0;
  631. while (i < nvals) {
  632. int cmd = (int)vals[i];
  633. switch (cmd) {
  634. case NVG_MOVETO:
  635. nvg__xformPt(&vals[i+1],&vals[i+2], vals[i+1],vals[i+2], state->xform);
  636. i += 3;
  637. break;
  638. case NVG_LINETO:
  639. nvg__xformPt(&vals[i+1],&vals[i+2], vals[i+1],vals[i+2], state->xform);
  640. i += 3;
  641. break;
  642. case NVG_BEZIERTO:
  643. nvg__xformPt(&vals[i+1],&vals[i+2], vals[i+1],vals[i+2], state->xform);
  644. nvg__xformPt(&vals[i+3],&vals[i+4], vals[i+3],vals[i+4], state->xform);
  645. nvg__xformPt(&vals[i+5],&vals[i+6], vals[i+5],vals[i+6], state->xform);
  646. i += 7;
  647. break;
  648. case NVG_CLOSE:
  649. i++;
  650. break;
  651. case NVG_WINDING:
  652. i += 2;
  653. break;
  654. default:
  655. i++;
  656. }
  657. }
  658. memcpy(&ctx->commands[ctx->ncommands], vals, nvals*sizeof(float));
  659. ctx->ncommands += nvals;
  660. if ((int)vals[0] != NVG_CLOSE && (int)vals[0] != NVG_WINDING) {
  661. ctx->commandx = vals[nvals-2];
  662. ctx->commandy = vals[nvals-1];
  663. }
  664. }
  665. static void nvg__clearPathCache(struct NVGcontext* ctx)
  666. {
  667. ctx->cache->npoints = 0;
  668. ctx->cache->npaths = 0;
  669. }
  670. static struct NVGpath* nvg__lastPath(struct NVGcontext* ctx)
  671. {
  672. if (ctx->cache->npaths > 0)
  673. return &ctx->cache->paths[ctx->cache->npaths-1];
  674. return NULL;
  675. }
  676. static void nvg__addPath(struct NVGcontext* ctx)
  677. {
  678. struct NVGpath* path;
  679. if (ctx->cache->npaths+1 > ctx->cache->cpaths) {
  680. ctx->cache->cpaths = (ctx->cache->cpaths == 0) ? 8 : (ctx->cache->cpaths*2);
  681. ctx->cache->paths = (struct NVGpath*)realloc(ctx->cache->paths, sizeof(struct NVGpath)*ctx->cache->cpaths);
  682. if (ctx->cache->paths == NULL) return;
  683. }
  684. path = &ctx->cache->paths[ctx->cache->npaths];
  685. memset(path, 0, sizeof(*path));
  686. path->first = ctx->cache->npoints;
  687. path->winding = NVG_CCW;
  688. ctx->cache->npaths++;
  689. }
  690. static struct NVGpoint* nvg__lastPoint(struct NVGcontext* ctx)
  691. {
  692. if (ctx->cache->npoints > 0)
  693. return &ctx->cache->points[ctx->cache->npoints-1];
  694. return NULL;
  695. }
  696. static void nvg__addPoint(struct NVGcontext* ctx, float x, float y, int flags)
  697. {
  698. struct NVGpath* path = nvg__lastPath(ctx);
  699. struct NVGpoint* pt;
  700. if (path == NULL) return;
  701. if (ctx->cache->npoints > 0) {
  702. pt = nvg__lastPoint(ctx);
  703. if (nvg__ptEquals(pt->x,pt->y, x,y, ctx->distTol)) {
  704. pt->flags |= flags;
  705. return;
  706. }
  707. }
  708. if (ctx->cache->npoints+1 > ctx->cache->cpoints) {
  709. ctx->cache->cpoints = (ctx->cache->cpoints == 0) ? 8 : (ctx->cache->cpoints*2);
  710. ctx->cache->points = (struct NVGpoint*)realloc(ctx->cache->points, sizeof(struct NVGpoint)*ctx->cache->cpoints);
  711. if (ctx->cache->points == NULL) return;
  712. }
  713. pt = &ctx->cache->points[ctx->cache->npoints];
  714. memset(pt, 0, sizeof(*pt));
  715. pt->x = x;
  716. pt->y = y;
  717. pt->flags = flags;
  718. ctx->cache->npoints++;
  719. path->count++;
  720. }
  721. static void nvg__closePath(struct NVGcontext* ctx)
  722. {
  723. struct NVGpath* path = nvg__lastPath(ctx);
  724. if (path == NULL) return;
  725. path->closed = 1;
  726. }
  727. static void nvg__pathWinding(struct NVGcontext* ctx, int winding)
  728. {
  729. struct NVGpath* path = nvg__lastPath(ctx);
  730. if (path == NULL) return;
  731. path->winding = winding;
  732. }
  733. static float nvg__getAverageScale(float *t)
  734. {
  735. float sx = sqrtf(t[0]*t[0] + t[2]*t[2]);
  736. float sy = sqrtf(t[1]*t[1] + t[3]*t[3]);
  737. return (sx + sy) * 0.5f;
  738. }
  739. static struct NVGvertex* nvg__allocTempVerts(struct NVGcontext* ctx, int nverts)
  740. {
  741. if (nverts > ctx->cache->cverts) {
  742. if (ctx->cache->cverts == 0) ctx->cache->cverts = 8;
  743. while (ctx->cache->cverts < nverts)
  744. ctx->cache->cverts *= 2;
  745. ctx->cache->verts = (struct NVGvertex*)realloc(ctx->cache->verts, sizeof(struct NVGvertex)*ctx->cache->cverts);
  746. if (ctx->cache->verts == NULL) return NULL;
  747. }
  748. return ctx->cache->verts;
  749. }
  750. static float nvg__triarea2(float ax, float ay, float bx, float by, float cx, float cy)
  751. {
  752. float abx = bx - ax;
  753. float aby = by - ay;
  754. float acx = cx - ax;
  755. float acy = cy - ay;
  756. return acx*aby - abx*acy;
  757. }
  758. static float nvg__polyArea(struct NVGpoint* pts, int npts)
  759. {
  760. int i;
  761. float area = 0;
  762. for (i = 2; i < npts; i++) {
  763. struct NVGpoint* a = &pts[0];
  764. struct NVGpoint* b = &pts[i-1];
  765. struct NVGpoint* c = &pts[i];
  766. area += nvg__triarea2(a->x,a->y, b->x,b->y, c->x,c->y);
  767. }
  768. return area * 0.5f;
  769. }
  770. static void nvg__polyReverse(struct NVGpoint* pts, int npts)
  771. {
  772. struct NVGpoint tmp;
  773. int i = 0, j = npts-1;
  774. while (i < j) {
  775. tmp = pts[i];
  776. pts[i] = pts[j];
  777. pts[j] = tmp;
  778. i++;
  779. j--;
  780. }
  781. }
  782. static void nvg__vset(struct NVGvertex* vtx, float x, float y, float u, float v)
  783. {
  784. vtx->x = x;
  785. vtx->y = y;
  786. vtx->u = u;
  787. vtx->v = v;
  788. }
  789. static void nvg__tesselateBezier(struct NVGcontext* ctx,
  790. float x1, float y1, float x2, float y2,
  791. float x3, float y3, float x4, float y4,
  792. int level, int type)
  793. {
  794. float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;
  795. if (level > 10) return;
  796. 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) {
  797. nvg__addPoint(ctx, x4, y4, type);
  798. return;
  799. }
  800. x12 = (x1+x2)*0.5f;
  801. y12 = (y1+y2)*0.5f;
  802. x23 = (x2+x3)*0.5f;
  803. y23 = (y2+y3)*0.5f;
  804. x34 = (x3+x4)*0.5f;
  805. y34 = (y3+y4)*0.5f;
  806. x123 = (x12+x23)*0.5f;
  807. y123 = (y12+y23)*0.5f;
  808. x234 = (x23+x34)*0.5f;
  809. y234 = (y23+y34)*0.5f;
  810. x1234 = (x123+x234)*0.5f;
  811. y1234 = (y123+y234)*0.5f;
  812. nvg__tesselateBezier(ctx, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0);
  813. nvg__tesselateBezier(ctx, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type);
  814. }
  815. static void nvg__flattenPaths(struct NVGcontext* ctx, int lineCap, int lineJoin, float miterLimit)
  816. {
  817. struct NVGpathCache* cache = ctx->cache;
  818. // struct NVGstate* state = nvg__getState(ctx);
  819. struct NVGpoint* last;
  820. struct NVGpoint* p0;
  821. struct NVGpoint* p1;
  822. struct NVGpoint* pts;
  823. struct NVGpath* path;
  824. int i, j, nleft;
  825. float* cp1;
  826. float* cp2;
  827. float* p;
  828. float area;
  829. if (cache->npaths > 0)
  830. return;
  831. // Flatten
  832. i = 0;
  833. while (i < ctx->ncommands) {
  834. int cmd = (int)ctx->commands[i];
  835. switch (cmd) {
  836. case NVG_MOVETO:
  837. nvg__addPath(ctx);
  838. p = &ctx->commands[i+1];
  839. nvg__addPoint(ctx, p[0], p[1], NVG_PT_CORNER);
  840. i += 3;
  841. break;
  842. case NVG_LINETO:
  843. p = &ctx->commands[i+1];
  844. nvg__addPoint(ctx, p[0], p[1], NVG_PT_CORNER);
  845. i += 3;
  846. break;
  847. case NVG_BEZIERTO:
  848. last = nvg__lastPoint(ctx);
  849. if (last != NULL) {
  850. cp1 = &ctx->commands[i+1];
  851. cp2 = &ctx->commands[i+3];
  852. p = &ctx->commands[i+5];
  853. nvg__tesselateBezier(ctx, last->x,last->y, cp1[0],cp1[1], cp2[0],cp2[1], p[0],p[1], 0, NVG_PT_CORNER);
  854. }
  855. i += 7;
  856. break;
  857. case NVG_CLOSE:
  858. nvg__closePath(ctx);
  859. i++;
  860. break;
  861. case NVG_WINDING:
  862. nvg__pathWinding(ctx, (int)ctx->commands[i+1]);
  863. i += 2;
  864. break;
  865. default:
  866. i++;
  867. }
  868. }
  869. cache->bounds[0] = cache->bounds[1] = 1e6f;
  870. cache->bounds[2] = cache->bounds[3] = -1e6f;
  871. // Calculate the direction and length of line segments.
  872. for (j = 0; j < cache->npaths; j++) {
  873. path = &cache->paths[j];
  874. pts = &cache->points[path->first];
  875. // If the first and last points are the same, remove the last, mark as closed path.
  876. p0 = &pts[path->count-1];
  877. p1 = &pts[0];
  878. if (nvg__ptEquals(p0->x,p0->y, p1->x,p1->y, ctx->distTol)) {
  879. path->count--;
  880. p0 = &pts[path->count-1];
  881. path->closed = 1;
  882. }
  883. // Enforce winding.
  884. if (path->count > 2) {
  885. area = nvg__polyArea(pts, path->count);
  886. if (path->winding == NVG_CCW && area < 0.0f)
  887. nvg__polyReverse(pts, path->count);
  888. if (path->winding == NVG_CW && area > 0.0f)
  889. nvg__polyReverse(pts, path->count);
  890. }
  891. for(i = 0; i < path->count; ++i) {
  892. // Calculate segment direction and length
  893. p0->dx = p1->x - p0->x;
  894. p0->dy = p1->y - p0->y;
  895. p0->len = nvg__normalize(&p0->dx, &p0->dy);
  896. // Update bounds
  897. cache->bounds[0] = nvg__minf(cache->bounds[0], p0->x);
  898. cache->bounds[1] = nvg__minf(cache->bounds[1], p0->y);
  899. cache->bounds[2] = nvg__maxf(cache->bounds[2], p0->x);
  900. cache->bounds[3] = nvg__maxf(cache->bounds[3], p0->y);
  901. // Advance
  902. p0 = p1++;
  903. }
  904. }
  905. // Calculate which joins needs extra vertices to append, and gather vertex count.
  906. for (j = 0; j < cache->npaths; j++) {
  907. path = &cache->paths[j];
  908. pts = &cache->points[path->first];
  909. path->nbevel = 0;
  910. nleft = 0;
  911. p0 = &pts[path->count-1];
  912. p1 = &pts[0];
  913. for(i = 0; i < path->count; ++i) {
  914. float dlx0, dly0, dlx1, dly1, dmr2, scale, cross, dot, d0, d1;
  915. dlx0 = p0->dy;
  916. dly0 = -p0->dx;
  917. dlx1 = p1->dy;
  918. dly1 = -p1->dx;
  919. // Calculate extrusions
  920. p1->dmx = (dlx0 + dlx1) * 0.5f;
  921. p1->dmy = (dly0 + dly1) * 0.5f;
  922. dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy;
  923. if (dmr2 > 0.000001f) {
  924. scale = 1.0f / dmr2;
  925. if (scale > 600.0f) {
  926. scale = 600.0f;
  927. }
  928. p1->dmx *= scale;
  929. p1->dmy *= scale;
  930. }
  931. // TODO: improve this logic
  932. dot = p0->dx*p1->dx + p0->dy*p1->dy;
  933. if (dot < -0.75f)
  934. p1->flags |= NVG_PT_CUSP;
  935. // Keep track of left turns.
  936. cross = p1->dx * p0->dy - p0->dx * p1->dy;
  937. if (cross > 0.0f) {
  938. nleft++;
  939. p1->flags |= NVG_PT_LEFT;
  940. }
  941. // Check to see if the corner needs to be beveled.
  942. if (p1->flags & NVG_PT_CORNER) {
  943. if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NVG_BEVEL || lineJoin == NVG_ROUND) {
  944. p1->flags |= NVG_PT_BEVEL;
  945. }
  946. }
  947. if ((p1->flags & (NVG_PT_BEVEL | NVG_PT_CUSP)) != 0)
  948. path->nbevel++;
  949. p0 = p1++;
  950. }
  951. path->convex = nleft == 0 ? 1 : 0;
  952. }
  953. }
  954. static int nvg__curveDivs(float r, float arc, float tol)
  955. {
  956. float da = acosf(r / (r + tol)) * 2.0f;
  957. return nvg__maxi(2, (int)ceilf(arc / da));
  958. }
  959. static void nvg__chooseBevel(int bevel, struct NVGpoint* p0, struct NVGpoint* p1, float w,
  960. float* x0, float* y0, float* x1, float* y1, float fringe)
  961. {
  962. if (bevel) {
  963. *x0 = p1->x + p0->dy * w + p0->dx * fringe;
  964. *y0 = p1->y - p0->dx * w + p0->dy * fringe;
  965. *x1 = p1->x + p1->dy * w - p1->dx * fringe;
  966. *y1 = p1->y - p1->dx * w - p1->dy * fringe;
  967. } else {
  968. *x0 = p1->x + p1->dmx * w;
  969. *y0 = p1->y + p1->dmy * w;
  970. *x1 = p1->x + p1->dmx * w;
  971. *y1 = p1->y + p1->dmy * w;
  972. }
  973. }
  974. static struct NVGvertex* nvg__roundJoin(struct NVGvertex* dst, struct NVGpoint* p0, struct NVGpoint* p1,
  975. float lw, float rw, float lu, float ru, int ncap, float fringe)
  976. {
  977. int i, n;
  978. float dlx0 = p0->dy;
  979. float dly0 = -p0->dx;
  980. float dlx1 = p1->dy;
  981. float dly1 = -p1->dx;
  982. if (p1->flags & NVG_PT_LEFT) {
  983. float lx0,ly0,lx1,ly1,a0,a1;
  984. nvg__chooseBevel(p1->flags & NVG_PT_CUSP, p0, p1, lw, &lx0,&ly0, &lx1,&ly1, -fringe);
  985. a0 = atan2f(-dly0, -dlx0);
  986. a1 = atan2f(-dly1, -dlx1);
  987. if (a1 > a0) a1 -= NVG_PI*2;
  988. nvg__vset(dst, lx0, ly0, lu,1); dst++;
  989. nvg__vset(dst, p1->x - dlx0*rw, p1->y - dly0*rw, ru,1); dst++;
  990. n = nvg__clampi((int)ceilf(((a0 - a1) / NVG_PI) * ncap), 2, ncap);
  991. for (i = 0; i < n; i++) {
  992. float u = i/(float)(n-1);
  993. float a = a0 + u*(a1-a0);
  994. float rx = p1->x + cosf(a) * rw;
  995. float ry = p1->y + sinf(a) * rw;
  996. nvg__vset(dst, p1->x, p1->y, 0.5f,1); dst++;
  997. nvg__vset(dst, rx, ry, ru,1); dst++;
  998. }
  999. nvg__vset(dst, lx1, ly1, lu,1); dst++;
  1000. nvg__vset(dst, p1->x - dlx1*rw, p1->y - dly1*rw, ru,1); dst++;
  1001. } else {
  1002. float rx0,ry0,rx1,ry1,a0,a1;
  1003. nvg__chooseBevel(p1->flags & NVG_PT_CUSP, p0, p1, -rw, &rx0,&ry0, &rx1,&ry1, -fringe);
  1004. a0 = atan2f(dly0, dlx0);
  1005. a1 = atan2f(dly1, dlx1);
  1006. if (a1 < a0) a1 += NVG_PI*2;
  1007. nvg__vset(dst, p1->x + dlx0*rw, p1->y + dly0*rw, lu,1); dst++;
  1008. nvg__vset(dst, rx0, ry0, ru,1); dst++;
  1009. n = nvg__clampi((int)ceilf(((a1 - a0) / NVG_PI) * ncap), 2, ncap);
  1010. for (i = 0; i < n; i++) {
  1011. float u = i/(float)(n-1);
  1012. float a = a0 + u*(a1-a0);
  1013. float lx = p1->x + cosf(a) * lw;
  1014. float ly = p1->y + sinf(a) * lw;
  1015. nvg__vset(dst, lx, ly, lu,1); dst++;
  1016. nvg__vset(dst, p1->x, p1->y, 0.5f,1); dst++;
  1017. }
  1018. nvg__vset(dst, p1->x + dlx1*rw, p1->y + dly1*rw, lu,1); dst++;
  1019. nvg__vset(dst, rx1, ry1, ru,1); dst++;
  1020. }
  1021. return dst;
  1022. }
  1023. static struct NVGvertex* nvg__bevelJoin(struct NVGvertex* dst, struct NVGpoint* p0, struct NVGpoint* p1,
  1024. float lw, float rw, float lu, float ru, float fringe)
  1025. {
  1026. int left = 0, right = 0;
  1027. float dot, rf, lf;
  1028. float rx0,ry0,rx1,ry1;
  1029. float lx0,ly0,lx1,ly1;
  1030. if (p1->flags & NVG_PT_LEFT) {
  1031. left = p1->flags & NVG_PT_CUSP;
  1032. right = p1->flags & NVG_PT_BEVEL;
  1033. lf = 0;
  1034. rf = fringe;
  1035. } else {
  1036. left = p1->flags & NVG_PT_BEVEL;
  1037. right = p1->flags & NVG_PT_CUSP;
  1038. lf = fringe;
  1039. rf = 0;
  1040. }
  1041. nvg__chooseBevel(left, p0, p1, lw, &lx0,&ly0, &lx1,&ly1, lf);
  1042. nvg__chooseBevel(right, p0, p1, -rw, &rx0,&ry0, &rx1,&ry1, rf);
  1043. dot = p0->dx*p1->dx + p0->dy*p1->dy;
  1044. dot = (1.0f - dot) * 0.5f;
  1045. nvg__vset(dst, lx0, ly0, lu,1); dst++;
  1046. nvg__vset(dst, rx0, ry0, ru,1); dst++;
  1047. if (p1->flags & NVG_PT_CUSP) {
  1048. if (p1->flags & NVG_PT_LEFT) {
  1049. nvg__vset(dst, p1->x, p1->y, 0.5f,1); dst++;
  1050. nvg__vset(dst, rx0, ry0, ru,1); dst++;
  1051. nvg__vset(dst, p1->x, p1->y, 0.5f,1); dst++;
  1052. nvg__vset(dst, rx1, ry1, ru,1); dst++;
  1053. } else {
  1054. nvg__vset(dst, lx0, ly0, lu,1); dst++;
  1055. nvg__vset(dst, p1->x, p1->y, 0.5f,1); dst++;
  1056. nvg__vset(dst, lx1, ly1, lu,1); dst++;
  1057. nvg__vset(dst, p1->x, p1->y, 0.5f,1); dst++;
  1058. }
  1059. }
  1060. nvg__vset(dst, lx1, ly1, lu,1); dst++;
  1061. nvg__vset(dst, rx1, ry1, ru,1); dst++;
  1062. return dst;
  1063. }
  1064. static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w, int lineCap, int lineJoin, float miterLimit)
  1065. {
  1066. struct NVGpathCache* cache = ctx->cache;
  1067. struct NVGpath* path;
  1068. struct NVGpoint* pts;
  1069. struct NVGvertex* verts;
  1070. struct NVGvertex* dst;
  1071. struct NVGpoint* p0;
  1072. struct NVGpoint* p1;
  1073. int nstroke, cverts;
  1074. int convex = 0;
  1075. int i, j, s, e;
  1076. float wo = 0;
  1077. float aa = ctx->fringeWidth;
  1078. int ncap = nvg__curveDivs(w, NVG_PI, ctx->tessTol / 4.0f);
  1079. // Calculate max vertex usage.
  1080. cverts = 0;
  1081. for (i = 0; i < cache->npaths; i++) {
  1082. path = &cache->paths[i];
  1083. if (feats & NVG_FILL)
  1084. cverts += path->count + path->nbevel + 1;
  1085. if (feats & NVG_STROKE) {
  1086. int loop = ((feats & NVG_CAPS) && path->closed == 0) ? 0 : 1;
  1087. if (lineCap == NVG_ROUND)
  1088. cverts += (path->count + path->nbevel*(ncap+2) + 1) * 2; // plus one for loop
  1089. else
  1090. cverts += (path->count + path->nbevel*3 + 1) * 2; // plus one for loop
  1091. if (loop == 0) {
  1092. // space for caps
  1093. if (lineCap == NVG_ROUND) {
  1094. cverts += (ncap*2 + 2)*2;
  1095. } else {
  1096. cverts += (3+3)*2;
  1097. }
  1098. }
  1099. }
  1100. }
  1101. verts = nvg__allocTempVerts(ctx, cverts);
  1102. if (verts == NULL) return 0;
  1103. for (i = 0; i < cache->npaths; i++) {
  1104. path = &cache->paths[i];
  1105. pts = &cache->points[path->first];
  1106. nstroke = (path->count + path->nbevel + 1) * 2;
  1107. convex = 0;
  1108. // Calculate shape vertices.
  1109. if (feats & NVG_FILL) {
  1110. wo = 0.5f*aa;
  1111. dst = verts;
  1112. path->fill = dst;
  1113. if (w == 0.0f) {
  1114. for (j = 0; j < path->count; ++j) {
  1115. nvg__vset(dst, pts[j].x, pts[j].y, 0.5f,1);
  1116. dst++;
  1117. }
  1118. } else {
  1119. // Looping
  1120. p0 = &pts[path->count-1];
  1121. p1 = &pts[0];
  1122. for (j = 0; j < path->count; ++j) {
  1123. if (p1->flags & NVG_PT_BEVEL) {
  1124. float dlx0 = p0->dy;
  1125. float dly0 = -p0->dx;
  1126. float dlx1 = p1->dy;
  1127. float dly1 = -p1->dx;
  1128. if (p1->flags & NVG_PT_LEFT) {
  1129. float lx = p1->x + p1->dmx * wo;
  1130. float ly = p1->y + p1->dmy * wo;
  1131. nvg__vset(dst, lx, ly, 0.5f,1); dst++;
  1132. } else {
  1133. float lx0 = p1->x + dlx0 * wo;
  1134. float ly0 = p1->y + dly0 * wo;
  1135. float lx1 = p1->x + dlx1 * wo;
  1136. float ly1 = p1->y + dly1 * wo;
  1137. nvg__vset(dst, lx0, ly0, 0.5f,1); dst++;
  1138. nvg__vset(dst, lx1, ly1, 0.5f,1); dst++;
  1139. }
  1140. } else {
  1141. nvg__vset(dst, p1->x + (p1->dmx * wo), p1->y + (p1->dmy * wo), 0.5f,1); dst++;
  1142. }
  1143. p0 = p1++;
  1144. }
  1145. }
  1146. path->nfill = (int)(dst - verts);
  1147. verts += path->nfill;
  1148. if (path->convex && cache->npaths == 1)
  1149. convex = 1;
  1150. } else {
  1151. wo = 0.0f;
  1152. path->fill = 0;
  1153. path->nfill = 0;
  1154. }
  1155. // Calculate fringe or stroke
  1156. if (feats & NVG_STROKE) {
  1157. float lw = w + wo, rw = w - wo;
  1158. float ru = 1, lu = 0;
  1159. int loop = ((feats & NVG_CAPS) && path->closed == 0) ? 0 : 1;
  1160. dst = verts;
  1161. path->stroke = dst;
  1162. // Create only half a fringe for convex shapes so that
  1163. // the shape can be rendered without stenciling.
  1164. if (convex) {
  1165. lw = wo; // This should generate the same vertex as fill inset above.
  1166. lu = 0.5f; // Set outline fade at middle.
  1167. }
  1168. if (loop) {
  1169. // Looping
  1170. p0 = &pts[path->count-1];
  1171. p1 = &pts[0];
  1172. s = 0;
  1173. e = path->count;
  1174. } else {
  1175. // Add cap
  1176. p0 = &pts[0];
  1177. p1 = &pts[1];
  1178. s = 1;
  1179. e = path->count-1;
  1180. }
  1181. if (loop == 0) {
  1182. // Add cap
  1183. float dx, dy, dlx, dly, px, py;
  1184. dx = p1->x - p0->x;
  1185. dy = p1->y - p0->y;
  1186. nvg__normalize(&dx, &dy);
  1187. dlx = dy;
  1188. dly = -dx;
  1189. if (lineCap == NVG_BUTT || lineCap == NVG_SQUARE) {
  1190. if (lineCap == NVG_BUTT) {
  1191. px = p0->x;
  1192. py = p0->y;
  1193. } else if (lineCap == NVG_SQUARE) {
  1194. px = p0->x - dx*w;
  1195. py = p0->y - dy*w;
  1196. }
  1197. nvg__vset(dst, px + dlx*lw - dx*aa, py + dly*lw - dy*aa, lu,0); dst++;
  1198. nvg__vset(dst, px - dlx*rw - dx*aa, py - dly*rw - dy*aa, ru,0); dst++;
  1199. nvg__vset(dst, px + dlx*lw, py + dly * lw, lu,1); dst++;
  1200. nvg__vset(dst, px - dlx*rw, py - dly * rw, ru,1); dst++;
  1201. } else if (lineCap == NVG_ROUND) {
  1202. px = p0->x;
  1203. py = p0->y;
  1204. for (j = 0; j < ncap; j++) {
  1205. float a = j/(float)(ncap-1)*NVG_PI;
  1206. float ax = cosf(a) * w, ay = sinf(a) * w;
  1207. nvg__vset(dst, px - dlx*ax - dx*ay, py - dly*ax - dy*ay, lu,1); dst++;
  1208. nvg__vset(dst, px, py, 0.5f,1); dst++;
  1209. }
  1210. nvg__vset(dst, px + dlx*lw, py + dly * lw, lu,1); dst++;
  1211. nvg__vset(dst, px - dlx*rw, py - dly * rw, ru,1); dst++;
  1212. }
  1213. }
  1214. for (j = s; j < e; ++j) {
  1215. if ((p1->flags & (NVG_PT_BEVEL | NVG_PT_CUSP)) != 0) {
  1216. if (lineJoin == NVG_ROUND) {
  1217. dst = nvg__roundJoin(dst, p0, p1, lw, rw, lu, ru, ncap, ctx->fringeWidth);
  1218. } else {
  1219. dst = nvg__bevelJoin(dst, p0, p1, lw, rw, lu, ru, ctx->fringeWidth);
  1220. }
  1221. } else {
  1222. nvg__vset(dst, p1->x + (p1->dmx * lw), p1->y + (p1->dmy * lw), lu,1); dst++;
  1223. nvg__vset(dst, p1->x - (p1->dmx * rw), p1->y - (p1->dmy * rw), ru,1); dst++;
  1224. }
  1225. p0 = p1++;
  1226. }
  1227. if (loop) {
  1228. // Loop it
  1229. nvg__vset(dst, verts[0].x, verts[0].y, lu,1); dst++;
  1230. nvg__vset(dst, verts[1].x, verts[1].y, ru,1); dst++;
  1231. } else {
  1232. // Add cap
  1233. float dx, dy, dlx, dly, px, py;
  1234. dx = p1->x - p0->x;
  1235. dy = p1->y - p0->y;
  1236. nvg__normalize(&dx, &dy);
  1237. dlx = dy;
  1238. dly = -dx;
  1239. if (lineCap == NVG_BUTT || lineCap == NVG_SQUARE) {
  1240. if (lineCap == NVG_BUTT) {
  1241. px = p1->x;
  1242. py = p1->y;
  1243. } else if (lineCap == NVG_SQUARE) {
  1244. px = p1->x + dx*w;
  1245. py = p1->y + dy*w;
  1246. }
  1247. nvg__vset(dst, px + dlx*lw, py + dly * lw, lu,1); dst++;
  1248. nvg__vset(dst, px - dlx*rw, py - dly * rw, ru,1); dst++;
  1249. nvg__vset(dst, px + dlx*lw + dx*aa, py + dly*lw + dy*aa, lu,0); dst++;
  1250. nvg__vset(dst, px - dlx*rw + dx*aa, py - dly*rw + dy*aa, ru,0); dst++;
  1251. } else if (lineCap == NVG_ROUND) {
  1252. px = p1->x;
  1253. py = p1->y;
  1254. nvg__vset(dst, px + dlx*lw, py + dly * lw, lu,1); dst++;
  1255. nvg__vset(dst, px - dlx*rw, py - dly * rw, ru,1); dst++;
  1256. for (j = 0; j < ncap; j++) {
  1257. float a = j/(float)(ncap-1)*NVG_PI;
  1258. float ax = cosf(a) * w, ay = sinf(a) * w;
  1259. nvg__vset(dst, px, py, 0.5f,1); dst++;
  1260. nvg__vset(dst, px - dlx*ax + dx*ay, py - dly*ax + dy*ay, lu,1); dst++;
  1261. }
  1262. }
  1263. }
  1264. path->nstroke = (int)(dst - verts);
  1265. verts += nstroke;
  1266. } else {
  1267. path->stroke = 0;
  1268. path->nstroke = 0;
  1269. }
  1270. }
  1271. return 1;
  1272. }
  1273. // Draw
  1274. void nvgBeginPath(struct NVGcontext* ctx)
  1275. {
  1276. ctx->ncommands = 0;
  1277. nvg__clearPathCache(ctx);
  1278. }
  1279. void nvgMoveTo(struct NVGcontext* ctx, float x, float y)
  1280. {
  1281. float vals[] = { NVG_MOVETO, x, y };
  1282. nvg__appendCommands(ctx, vals, NVG_COUNTOF(vals));
  1283. }
  1284. void nvgLineTo(struct NVGcontext* ctx, float x, float y)
  1285. {
  1286. float vals[] = { NVG_LINETO, x, y };
  1287. nvg__appendCommands(ctx, vals, NVG_COUNTOF(vals));
  1288. }
  1289. void nvgBezierTo(struct NVGcontext* ctx, float c1x, float c1y, float c2x, float c2y, float x, float y)
  1290. {
  1291. float vals[] = { NVG_BEZIERTO, c1x, c1y, c2x, c2y, x, y };
  1292. nvg__appendCommands(ctx, vals, NVG_COUNTOF(vals));
  1293. }
  1294. void nvgArcTo(struct NVGcontext* ctx, float x1, float y1, float x2, float y2, float radius)
  1295. {
  1296. float x0 = ctx->commandx;
  1297. float y0 = ctx->commandy;
  1298. float dx0,dy0, dx1,dy1, a, d, cx,cy, a0,a1;
  1299. int dir;
  1300. if (ctx->ncommands == 0) {
  1301. return;
  1302. }
  1303. // Handle degenerate cases.
  1304. if (nvg__ptEquals(x0,y0, x1,y1, ctx->distTol) ||
  1305. nvg__ptEquals(x1,y1, x2,y2, ctx->distTol) ||
  1306. nvg__distPtSeg(x1,y1, x0,y0, x2,y2) < ctx->distTol*ctx->distTol ||
  1307. radius < ctx->distTol) {
  1308. nvgLineTo(ctx, x1,y1);
  1309. return;
  1310. }
  1311. // Calculate tangential circle to lines (x0,y0)-(x1,y1) and (x1,y1)-(x2,y2).
  1312. dx0 = x0-x1;
  1313. dy0 = y0-y1;
  1314. dx1 = x2-x1;
  1315. dy1 = y2-y1;
  1316. nvg__normalize(&dx0,&dy0);
  1317. nvg__normalize(&dx1,&dy1);
  1318. a = nvg__acosf(dx0*dx1 + dy0*dy1);
  1319. d = radius / nvg__tanf(a/2.0f);
  1320. // printf("a=%f° d=%f\n", a/NVG_PI*180.0f, d);
  1321. if (d > 10000.0f) {
  1322. nvgLineTo(ctx, x1,y1);
  1323. return;
  1324. }
  1325. if (nvg__cross(dx0,dy0, dx1,dy1) > 0.0f) {
  1326. cx = x1 + dx0*d + dy0*radius;
  1327. cy = y1 + dy0*d + -dx0*radius;
  1328. a0 = nvg__atan2f(dx0, -dy0);
  1329. a1 = nvg__atan2f(-dx1, dy1);
  1330. dir = NVG_CW;
  1331. // printf("CW c=(%f, %f) a0=%f° a1=%f°\n", cx, cy, a0/NVG_PI*180.0f, a1/NVG_PI*180.0f);
  1332. } else {
  1333. cx = x1 + dx0*d + -dy0*radius;
  1334. cy = y1 + dy0*d + dx0*radius;
  1335. a0 = nvg__atan2f(-dx0, dy0);
  1336. a1 = nvg__atan2f(dx1, -dy1);
  1337. dir = NVG_CCW;
  1338. // printf("CCW c=(%f, %f) a0=%f° a1=%f°\n", cx, cy, a0/NVG_PI*180.0f, a1/NVG_PI*180.0f);
  1339. }
  1340. nvgArc(ctx, cx, cy, radius, a0, a1, dir);
  1341. }
  1342. void nvgClosePath(struct NVGcontext* ctx)
  1343. {
  1344. float vals[] = { NVG_CLOSE };
  1345. nvg__appendCommands(ctx, vals, NVG_COUNTOF(vals));
  1346. }
  1347. void nvgPathWinding(struct NVGcontext* ctx, int dir)
  1348. {
  1349. float vals[] = { NVG_WINDING, (float)dir };
  1350. nvg__appendCommands(ctx, vals, NVG_COUNTOF(vals));
  1351. }
  1352. void nvgArc(struct NVGcontext* ctx, float cx, float cy, float r, float a0, float a1, int dir)
  1353. {
  1354. float a, da, hda, kappa;
  1355. float dx, dy, x, y, tanx, tany;
  1356. float px, py, ptanx, ptany;
  1357. float vals[3 + 5*7 + 100];
  1358. int i, ndivs, nvals;
  1359. int move = ctx->ncommands > 0 ? NVG_LINETO : NVG_MOVETO;
  1360. // Clamp angles
  1361. da = a1 - a0;
  1362. if (dir == NVG_CW) {
  1363. if (nvg__absf(da) >= NVG_PI*2) {
  1364. da = NVG_PI*2;
  1365. } else {
  1366. while (da < 0.0f) da += NVG_PI*2;
  1367. }
  1368. } else {
  1369. if (nvg__absf(da) >= NVG_PI*2) {
  1370. da = -NVG_PI*2;
  1371. } else {
  1372. while (da > 0.0f) da -= NVG_PI*2;
  1373. }
  1374. }
  1375. // Split arc into max 90 degree segments.
  1376. ndivs = nvg__maxi(1, nvg__mini((int)(nvg__absf(da) / (NVG_PI*0.5f) + 0.5f), 5));
  1377. hda = (da / (float)ndivs) / 2.0f;
  1378. kappa = nvg__absf(4.0f / 3.0f * (1.0f - nvg__cosf(hda)) / nvg__sinf(hda));
  1379. if (dir == NVG_CCW)
  1380. kappa = -kappa;
  1381. nvals = 0;
  1382. for (i = 0; i <= ndivs; i++) {
  1383. a = a0 + da * (i/(float)ndivs);
  1384. dx = nvg__cosf(a);
  1385. dy = nvg__sinf(a);
  1386. x = cx + dx*r;
  1387. y = cy + dy*r;
  1388. tanx = -dy*r*kappa;
  1389. tany = dx*r*kappa;
  1390. if (i == 0) {
  1391. vals[nvals++] = move;
  1392. vals[nvals++] = x;
  1393. vals[nvals++] = y;
  1394. } else {
  1395. vals[nvals++] = NVG_BEZIERTO;
  1396. vals[nvals++] = px+ptanx;
  1397. vals[nvals++] = py+ptany;
  1398. vals[nvals++] = x-tanx;
  1399. vals[nvals++] = y-tany;
  1400. vals[nvals++] = x;
  1401. vals[nvals++] = y;
  1402. }
  1403. px = x;
  1404. py = y;
  1405. ptanx = tanx;
  1406. ptany = tany;
  1407. }
  1408. nvg__appendCommands(ctx, vals, nvals);
  1409. }
  1410. void nvgRect(struct NVGcontext* ctx, float x, float y, float w, float h)
  1411. {
  1412. float vals[] = {
  1413. NVG_MOVETO, x,y,
  1414. NVG_LINETO, x+w,y,
  1415. NVG_LINETO, x+w,y+h,
  1416. NVG_LINETO, x,y+h,
  1417. NVG_CLOSE
  1418. };
  1419. nvg__appendCommands(ctx, vals, NVG_COUNTOF(vals));
  1420. }
  1421. void nvgRoundedRect(struct NVGcontext* ctx, float x, float y, float w, float h, float r)
  1422. {
  1423. if (r < 0.1f) {
  1424. nvgRect(ctx, x,y,w,h);
  1425. return;
  1426. }
  1427. float vals[] = {
  1428. NVG_MOVETO, x+r, y,
  1429. NVG_LINETO, x+w-r, y,
  1430. NVG_BEZIERTO, x+w-r*(1-NVG_KAPPA90), y, x+w, y+r*(1-NVG_KAPPA90), x+w, y+r,
  1431. NVG_LINETO, x+w, y+h-r,
  1432. NVG_BEZIERTO, x+w, y+h-r*(1-NVG_KAPPA90), x+w-r*(1-NVG_KAPPA90), y+h, x+w-r, y+h,
  1433. NVG_LINETO, x+r, y+h,
  1434. NVG_BEZIERTO, x+r*(1-NVG_KAPPA90), y+h, x, y+h-r*(1-NVG_KAPPA90), x, y+h-r,
  1435. NVG_LINETO, x, y+r,
  1436. NVG_BEZIERTO, x, y+r*(1-NVG_KAPPA90), x+r*(1-NVG_KAPPA90), y, x+r, y,
  1437. NVG_CLOSE
  1438. };
  1439. nvg__appendCommands(ctx, vals, NVG_COUNTOF(vals));
  1440. }
  1441. void nvgEllipse(struct NVGcontext* ctx, float cx, float cy, float rx, float ry)
  1442. {
  1443. float vals[] = {
  1444. NVG_MOVETO, cx+rx, cy,
  1445. NVG_BEZIERTO, cx+rx, cy+ry*NVG_KAPPA90, cx+rx*NVG_KAPPA90, cy+ry, cx, cy+ry,
  1446. NVG_BEZIERTO, cx-rx*NVG_KAPPA90, cy+ry, cx-rx, cy+ry*NVG_KAPPA90, cx-rx, cy,
  1447. NVG_BEZIERTO, cx-rx, cy-ry*NVG_KAPPA90, cx-rx*NVG_KAPPA90, cy-ry, cx, cy-ry,
  1448. NVG_BEZIERTO, cx+rx*NVG_KAPPA90, cy-ry, cx+rx, cy-ry*NVG_KAPPA90, cx+rx, cy,
  1449. NVG_CLOSE
  1450. };
  1451. nvg__appendCommands(ctx, vals, NVG_COUNTOF(vals));
  1452. }
  1453. void nvgCircle(struct NVGcontext* ctx, float cx, float cy, float r)
  1454. {
  1455. nvgEllipse(ctx, cx,cy, r,r);
  1456. }
  1457. void nvgFill(struct NVGcontext* ctx)
  1458. {
  1459. struct NVGstate* state = nvg__getState(ctx);
  1460. const struct NVGpath* path;
  1461. int i;
  1462. nvg__flattenPaths(ctx, NVG_BUTT, NVG_MITER, 1.2f);
  1463. if (ctx->params.edgeAntiAlias)
  1464. nvg__expandStrokeAndFill(ctx, NVG_FILL|NVG_STROKE, ctx->fringeWidth, NVG_BUTT, NVG_MITER, 1.2f);
  1465. else
  1466. nvg__expandStrokeAndFill(ctx, NVG_FILL, 0.0f, NVG_BUTT, NVG_MITER, 1.2f);
  1467. ctx->params.renderFill(ctx->params.userPtr, &state->fill, &state->scissor,
  1468. ctx->cache->bounds, ctx->cache->paths, ctx->cache->npaths);
  1469. // Count triangles
  1470. for (i = 0; i < ctx->cache->npaths; i++) {
  1471. path = &ctx->cache->paths[i];
  1472. ctx->fillTriCount += path->nfill-2;
  1473. ctx->fillTriCount += path->nstroke-2;
  1474. ctx->drawCallCount += 2;
  1475. }
  1476. }
  1477. void nvgStroke(struct NVGcontext* ctx)
  1478. {
  1479. struct NVGstate* state = nvg__getState(ctx);
  1480. float scale = nvg__getAverageScale(state->xform);
  1481. float strokeWidth = nvg__clampf(state->strokeWidth * scale, 1.0f, 20.0f);
  1482. const struct NVGpath* path;
  1483. int i;
  1484. nvg__flattenPaths(ctx, state->lineCap, state->lineJoin, state->miterLimit);
  1485. if (ctx->params.edgeAntiAlias)
  1486. nvg__expandStrokeAndFill(ctx, NVG_STROKE|NVG_CAPS, strokeWidth*0.5f + ctx->fringeWidth/2.0f, state->lineCap, state->lineJoin, state->miterLimit);
  1487. else
  1488. nvg__expandStrokeAndFill(ctx, NVG_STROKE|NVG_CAPS, strokeWidth*0.5f, state->lineCap, state->lineJoin, state->miterLimit);
  1489. ctx->params.renderStroke(ctx->params.userPtr, &state->stroke, &state->scissor,
  1490. strokeWidth, ctx->cache->paths, ctx->cache->npaths);
  1491. // Count triangles
  1492. for (i = 0; i < ctx->cache->npaths; i++) {
  1493. path = &ctx->cache->paths[i];
  1494. ctx->strokeTriCount += path->nstroke-2;
  1495. ctx->drawCallCount++;
  1496. }
  1497. }
  1498. // Add fonts
  1499. int nvgCreateFont(struct NVGcontext* ctx, const char* name, const char* path)
  1500. {
  1501. return fonsAddFont(ctx->fs, name, path);
  1502. }
  1503. int nvgCreateFontMem(struct NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData)
  1504. {
  1505. return fonsAddFontMem(ctx->fs, name, data, ndata, freeData);
  1506. }
  1507. int nvgFindFont(struct NVGcontext* ctx, const char* name)
  1508. {
  1509. if (name == NULL) return -1;
  1510. return fonsGetFontByName(ctx->fs, name);
  1511. }
  1512. // State setting
  1513. void nvgFontSize(struct NVGcontext* ctx, float size)
  1514. {
  1515. struct NVGstate* state = nvg__getState(ctx);
  1516. state->fontSize = size;
  1517. }
  1518. void nvgLetterSpacing(struct NVGcontext* ctx, float spacing)
  1519. {
  1520. struct NVGstate* state = nvg__getState(ctx);
  1521. state->letterSpacing = spacing;
  1522. }
  1523. void nvgFontBlur(struct NVGcontext* ctx, float blur)
  1524. {
  1525. struct NVGstate* state = nvg__getState(ctx);
  1526. state->fontBlur = blur;
  1527. }
  1528. void nvgTextAlign(struct NVGcontext* ctx, int align)
  1529. {
  1530. struct NVGstate* state = nvg__getState(ctx);
  1531. state->textAlign = align;
  1532. }
  1533. void nvgFontFaceId(struct NVGcontext* ctx, int font)
  1534. {
  1535. struct NVGstate* state = nvg__getState(ctx);
  1536. state->fontId = font;
  1537. }
  1538. void nvgFontFace(struct NVGcontext* ctx, const char* font)
  1539. {
  1540. struct NVGstate* state = nvg__getState(ctx);
  1541. state->fontId = fonsGetFontByName(ctx->fs, font);
  1542. }
  1543. static float nvg__quantize(float a, float d)
  1544. {
  1545. return ((int)(a / d + 0.5f)) * d;
  1546. }
  1547. static float nvg__getFontScale(struct NVGstate* state)
  1548. {
  1549. return nvg__minf(nvg__quantize(nvg__getAverageScale(state->xform), 0.01f), 4.0f);
  1550. }
  1551. float nvgText(struct NVGcontext* ctx, float x, float y, const char* string, const char* end)
  1552. {
  1553. struct NVGstate* state = nvg__getState(ctx);
  1554. struct NVGpaint paint;
  1555. struct FONStextIter iter;
  1556. struct FONSquad q;
  1557. struct NVGvertex* verts;
  1558. float scale = nvg__getFontScale(state) * ctx->devicePxRatio;
  1559. float invscale = 1.0f / scale;
  1560. int dirty[4];
  1561. int cverts = 0;
  1562. int nverts = 0;
  1563. if (end == NULL)
  1564. end = string + strlen(string);
  1565. if (state->fontId == FONS_INVALID) return x;
  1566. fonsSetSize(ctx->fs, state->fontSize*scale);
  1567. fonsSetSpacing(ctx->fs, state->letterSpacing*scale);
  1568. fonsSetBlur(ctx->fs, state->fontBlur*scale);
  1569. fonsSetAlign(ctx->fs, state->textAlign);
  1570. fonsSetFont(ctx->fs, state->fontId);
  1571. cverts = nvg__maxi(2, (int)(end - string)) * 6; // conservative estimate.
  1572. verts = nvg__allocTempVerts(ctx, cverts);
  1573. if (verts == NULL) return x;
  1574. fonsTextIterInit(ctx->fs, &iter, x*scale, y*scale, string, end);
  1575. while (fonsTextIterNext(ctx->fs, &iter, &q)) {
  1576. // Trasnform corners.
  1577. float c[4*2];
  1578. nvg__xformPt(&c[0],&c[1], q.x0*invscale, q.y0*invscale, state->xform);
  1579. nvg__xformPt(&c[2],&c[3], q.x1*invscale, q.y0*invscale, state->xform);
  1580. nvg__xformPt(&c[4],&c[5], q.x1*invscale, q.y1*invscale, state->xform);
  1581. nvg__xformPt(&c[6],&c[7], q.x0*invscale, q.y1*invscale, state->xform);
  1582. // Create triangles
  1583. if (nverts+6 <= cverts) {
  1584. nvg__vset(&verts[nverts], c[0], c[1], q.s0, q.t0); nverts++;
  1585. nvg__vset(&verts[nverts], c[4], c[5], q.s1, q.t1); nverts++;
  1586. nvg__vset(&verts[nverts], c[2], c[3], q.s1, q.t0); nverts++;
  1587. nvg__vset(&verts[nverts], c[0], c[1], q.s0, q.t0); nverts++;
  1588. nvg__vset(&verts[nverts], c[6], c[7], q.s0, q.t1); nverts++;
  1589. nvg__vset(&verts[nverts], c[4], c[5], q.s1, q.t1); nverts++;
  1590. }
  1591. }
  1592. if (fonsValidateTexture(ctx->fs, dirty)) {
  1593. // Update texture
  1594. if (ctx->fontImage != 0) {
  1595. int iw, ih;
  1596. const unsigned char* data = fonsGetTextureData(ctx->fs, &iw, &ih);
  1597. int x = dirty[0];
  1598. int y = dirty[1];
  1599. int w = dirty[2] - dirty[0];
  1600. int h = dirty[3] - dirty[1];
  1601. ctx->params.renderUpdateTexture(ctx->params.userPtr, ctx->fontImage, x,y, w,h, data);
  1602. }
  1603. }
  1604. // Render triangles.
  1605. paint = state->fill;
  1606. paint.image = ctx->fontImage;
  1607. ctx->params.renderTriangles(ctx->params.userPtr, &paint, &state->scissor, verts, nverts);
  1608. ctx->drawCallCount++;
  1609. ctx->textTriCount += nverts/3;
  1610. return iter.x;
  1611. }
  1612. float nvgTextBounds(struct NVGcontext* ctx, const char* string, const char* end, float* bounds)
  1613. {
  1614. struct NVGstate* state = nvg__getState(ctx);
  1615. if (state->fontId == FONS_INVALID) return 0;
  1616. fonsSetSize(ctx->fs, state->fontSize);
  1617. fonsSetSpacing(ctx->fs, state->letterSpacing);
  1618. fonsSetBlur(ctx->fs, state->fontBlur);
  1619. fonsSetAlign(ctx->fs, state->textAlign);
  1620. fonsSetFont(ctx->fs, state->fontId);
  1621. return fonsTextBounds(ctx->fs, string, end, bounds);
  1622. }
  1623. void nvgVertMetrics(struct NVGcontext* ctx, float* ascender, float* descender, float* lineh)
  1624. {
  1625. struct NVGstate* state = nvg__getState(ctx);
  1626. if (state->fontId == FONS_INVALID) return;
  1627. fonsSetSize(ctx->fs, state->fontSize);
  1628. fonsSetSpacing(ctx->fs, state->letterSpacing);
  1629. fonsSetBlur(ctx->fs, state->fontBlur);
  1630. fonsSetAlign(ctx->fs, state->textAlign);
  1631. fonsSetFont(ctx->fs, state->fontId);
  1632. fonsVertMetrics(ctx->fs, ascender, descender, lineh);
  1633. }