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