lnvis

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

demo.c (32872B)


      1 #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
      2 
      3 #include "demo.h"
      4 #include <stdio.h>
      5 #include <string.h>
      6 #include <math.h>
      7 #ifdef NANOVG_GLEW
      8 #include <GL/glew.h>
      9 #endif
     10 #include <GLFW/glfw3.h>
     11 #include "nanovg/nanovg.h"
     12 
     13 #ifdef _MSC_VER
     14 #define snprintf _snprintf
     15 #elif !defined(__MINGW32__)
     16 #include <iconv.h>
     17 #endif
     18 
     19 #define ICON_SEARCH 0x1F50D
     20 #define ICON_CIRCLED_CROSS 0x2716
     21 #define ICON_CHEVRON_RIGHT 0xE75E
     22 #define ICON_CHECK 0x2713
     23 #define ICON_LOGIN 0xE740
     24 #define ICON_TRASH 0xE729
     25 
     26 //static float minf(float a, float b) { return a < b ? a : b; }
     27 static float maxf(float a, float b)
     28 {
     29 	return a > b ? a : b;
     30 }
     31 //static float absf(float a) { return a >= 0.0f ? a : -a; }
     32 static float clampf(float a, float mn, float mx)
     33 {
     34 	return a < mn ? mn : (a > mx ? mx : a);
     35 }
     36 
     37 // Returns 1 if col.rgba is 0.0f,0.0f,0.0f,0.0f, 0 otherwise
     38 int isBlack(NVGcolor col)
     39 {
     40 	if (col.r == 0.0f && col.g == 0.0f && col.b == 0.0f && col.a == 0.0f) {
     41 		return 1;
     42 	}
     43 	return 0;
     44 }
     45 
     46 static char *cpToUTF8(int cp, char *str)
     47 {
     48 	int n = 0;
     49 	if (cp < 0x80)
     50 		n = 1;
     51 	else if (cp < 0x800)
     52 		n = 2;
     53 	else if (cp < 0x10000)
     54 		n = 3;
     55 	else if (cp < 0x200000)
     56 		n = 4;
     57 	else if (cp < 0x4000000)
     58 		n = 5;
     59 	else if (cp <= 0x7fffffff)
     60 		n = 6;
     61 	str[n] = '\0';
     62 	switch (n) {
     63 	case 6:
     64 		str[5] = 0x80 | (cp & 0x3f);
     65 		cp = cp >> 6;
     66 		cp |= 0x4000000;
     67 	case 5:
     68 		str[4] = 0x80 | (cp & 0x3f);
     69 		cp = cp >> 6;
     70 		cp |= 0x200000;
     71 	case 4:
     72 		str[3] = 0x80 | (cp & 0x3f);
     73 		cp = cp >> 6;
     74 		cp |= 0x10000;
     75 	case 3:
     76 		str[2] = 0x80 | (cp & 0x3f);
     77 		cp = cp >> 6;
     78 		cp |= 0x800;
     79 	case 2:
     80 		str[1] = 0x80 | (cp & 0x3f);
     81 		cp = cp >> 6;
     82 		cp |= 0xc0;
     83 	case 1:
     84 		str[0] = cp;
     85 	}
     86 	return str;
     87 }
     88 
     89 void drawWindow(NVGcontext *vg, const char *title, float x, float y, float w,
     90 		float h)
     91 {
     92 	float cornerRadius = 3.0f;
     93 	NVGpaint shadowPaint;
     94 	NVGpaint headerPaint;
     95 
     96 	nvgSave(vg);
     97 	//	nvgClearState(vg);
     98 
     99 	// Window
    100 	nvgBeginPath(vg);
    101 	nvgRoundedRect(vg, x, y, w, h, cornerRadius);
    102 	nvgFillColor(vg, nvgRGBA(28, 30, 34, 192));
    103 	//	nvgFillColor(vg, nvgRGBA(0,0,0,128));
    104 	nvgFill(vg);
    105 
    106 	// Drop shadow
    107 	shadowPaint =
    108 		nvgBoxGradient(vg, x, y + 2, w, h, cornerRadius * 2, 10,
    109 			       nvgRGBA(0, 0, 0, 128), nvgRGBA(0, 0, 0, 0));
    110 	nvgBeginPath(vg);
    111 	nvgRect(vg, x - 10, y - 10, w + 20, h + 30);
    112 	nvgRoundedRect(vg, x, y, w, h, cornerRadius);
    113 	nvgPathWinding(vg, NVG_HOLE);
    114 	nvgFillPaint(vg, shadowPaint);
    115 	nvgFill(vg);
    116 
    117 	// Header
    118 	headerPaint = nvgLinearGradient(vg, x, y, x, y + 15,
    119 					nvgRGBA(255, 255, 255, 8),
    120 					nvgRGBA(0, 0, 0, 16));
    121 	nvgBeginPath(vg);
    122 	nvgRoundedRect(vg, x + 1, y + 1, w - 2, 30, cornerRadius - 1);
    123 	nvgFillPaint(vg, headerPaint);
    124 	nvgFill(vg);
    125 	nvgBeginPath(vg);
    126 	nvgMoveTo(vg, x + 0.5f, y + 0.5f + 30);
    127 	nvgLineTo(vg, x + 0.5f + w - 1, y + 0.5f + 30);
    128 	nvgStrokeColor(vg, nvgRGBA(0, 0, 0, 32));
    129 	nvgStroke(vg);
    130 
    131 	nvgFontSize(vg, 18.0f);
    132 	nvgFontFace(vg, "sans-bold");
    133 	nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
    134 
    135 	nvgFontBlur(vg, 2);
    136 	nvgFillColor(vg, nvgRGBA(0, 0, 0, 128));
    137 	nvgText(vg, x + w / 2, y + 16 + 1, title, NULL);
    138 
    139 	nvgFontBlur(vg, 0);
    140 	nvgFillColor(vg, nvgRGBA(220, 220, 220, 160));
    141 	nvgText(vg, x + w / 2, y + 16, title, NULL);
    142 
    143 	nvgRestore(vg);
    144 }
    145 
    146 void drawSearchBox(NVGcontext *vg, const char *text, float x, float y, float w,
    147 		   float h)
    148 {
    149 	NVGpaint bg;
    150 	char icon[8];
    151 	float cornerRadius = h / 2 - 1;
    152 
    153 	// Edit
    154 	bg = nvgBoxGradient(vg, x, y + 1.5f, w, h, h / 2, 5,
    155 			    nvgRGBA(0, 0, 0, 16), nvgRGBA(0, 0, 0, 92));
    156 	nvgBeginPath(vg);
    157 	nvgRoundedRect(vg, x, y, w, h, cornerRadius);
    158 	nvgFillPaint(vg, bg);
    159 	nvgFill(vg);
    160 
    161 	/*	nvgBeginPath(vg);
    162 	nvgRoundedRect(vg, x+0.5f,y+0.5f, w-1,h-1, cornerRadius-0.5f);
    163 	nvgStrokeColor(vg, nvgRGBA(0,0,0,48));
    164 	nvgStroke(vg);*/
    165 
    166 	nvgFontSize(vg, h * 1.3f);
    167 	nvgFontFace(vg, "icons");
    168 	nvgFillColor(vg, nvgRGBA(255, 255, 255, 64));
    169 	nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
    170 	nvgText(vg, x + h * 0.55f, y + h * 0.55f, cpToUTF8(ICON_SEARCH, icon),
    171 		NULL);
    172 
    173 	nvgFontSize(vg, 20.0f);
    174 	nvgFontFace(vg, "sans");
    175 	nvgFillColor(vg, nvgRGBA(255, 255, 255, 32));
    176 
    177 	nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
    178 	nvgText(vg, x + h * 1.05f, y + h * 0.5f, text, NULL);
    179 
    180 	nvgFontSize(vg, h * 1.3f);
    181 	nvgFontFace(vg, "icons");
    182 	nvgFillColor(vg, nvgRGBA(255, 255, 255, 32));
    183 	nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
    184 	nvgText(vg, x + w - h * 0.55f, y + h * 0.55f,
    185 		cpToUTF8(ICON_CIRCLED_CROSS, icon), NULL);
    186 }
    187 
    188 void drawDropDown(NVGcontext *vg, const char *text, float x, float y, float w,
    189 		  float h)
    190 {
    191 	NVGpaint bg;
    192 	char icon[8];
    193 	float cornerRadius = 4.0f;
    194 
    195 	bg = nvgLinearGradient(vg, x, y, x, y + h, nvgRGBA(255, 255, 255, 16),
    196 			       nvgRGBA(0, 0, 0, 16));
    197 	nvgBeginPath(vg);
    198 	nvgRoundedRect(vg, x + 1, y + 1, w - 2, h - 2, cornerRadius - 1);
    199 	nvgFillPaint(vg, bg);
    200 	nvgFill(vg);
    201 
    202 	nvgBeginPath(vg);
    203 	nvgRoundedRect(vg, x + 0.5f, y + 0.5f, w - 1, h - 1,
    204 		       cornerRadius - 0.5f);
    205 	nvgStrokeColor(vg, nvgRGBA(0, 0, 0, 48));
    206 	nvgStroke(vg);
    207 
    208 	nvgFontSize(vg, 20.0f);
    209 	nvgFontFace(vg, "sans");
    210 	nvgFillColor(vg, nvgRGBA(255, 255, 255, 160));
    211 	nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
    212 	nvgText(vg, x + h * 0.3f, y + h * 0.5f, text, NULL);
    213 
    214 	nvgFontSize(vg, h * 1.3f);
    215 	nvgFontFace(vg, "icons");
    216 	nvgFillColor(vg, nvgRGBA(255, 255, 255, 64));
    217 	nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
    218 	nvgText(vg, x + w - h * 0.5f, y + h * 0.5f,
    219 		cpToUTF8(ICON_CHEVRON_RIGHT, icon), NULL);
    220 }
    221 
    222 void drawLabel(NVGcontext *vg, const char *text, float x, float y, float w,
    223 	       float h)
    224 {
    225 	NVG_NOTUSED(w);
    226 
    227 	nvgFontSize(vg, 18.0f);
    228 	nvgFontFace(vg, "sans");
    229 	nvgFillColor(vg, nvgRGBA(255, 255, 255, 128));
    230 
    231 	nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
    232 	nvgText(vg, x, y + h * 0.5f, text, NULL);
    233 }
    234 
    235 void drawEditBoxBase(NVGcontext *vg, float x, float y, float w, float h)
    236 {
    237 	NVGpaint bg;
    238 	// Edit
    239 	bg = nvgBoxGradient(vg, x + 1, y + 1 + 1.5f, w - 2, h - 2, 3, 4,
    240 			    nvgRGBA(255, 255, 255, 32),
    241 			    nvgRGBA(32, 32, 32, 32));
    242 	nvgBeginPath(vg);
    243 	nvgRoundedRect(vg, x + 1, y + 1, w - 2, h - 2, 4 - 1);
    244 	nvgFillPaint(vg, bg);
    245 	nvgFill(vg);
    246 
    247 	nvgBeginPath(vg);
    248 	nvgRoundedRect(vg, x + 0.5f, y + 0.5f, w - 1, h - 1, 4 - 0.5f);
    249 	nvgStrokeColor(vg, nvgRGBA(0, 0, 0, 48));
    250 	nvgStroke(vg);
    251 }
    252 
    253 void drawEditBox(NVGcontext *vg, const char *text, float x, float y, float w,
    254 		 float h)
    255 {
    256 	drawEditBoxBase(vg, x, y, w, h);
    257 
    258 	nvgFontSize(vg, 20.0f);
    259 	nvgFontFace(vg, "sans");
    260 	nvgFillColor(vg, nvgRGBA(255, 255, 255, 64));
    261 	nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
    262 	nvgText(vg, x + h * 0.3f, y + h * 0.5f, text, NULL);
    263 }
    264 
    265 void drawEditBoxNum(NVGcontext *vg, const char *text, const char *units,
    266 		    float x, float y, float w, float h)
    267 {
    268 	float uw;
    269 
    270 	drawEditBoxBase(vg, x, y, w, h);
    271 
    272 	uw = nvgTextBounds(vg, 0, 0, units, NULL, NULL);
    273 
    274 	nvgFontSize(vg, 18.0f);
    275 	nvgFontFace(vg, "sans");
    276 	nvgFillColor(vg, nvgRGBA(255, 255, 255, 64));
    277 	nvgTextAlign(vg, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE);
    278 	nvgText(vg, x + w - h * 0.3f, y + h * 0.5f, units, NULL);
    279 
    280 	nvgFontSize(vg, 20.0f);
    281 	nvgFontFace(vg, "sans");
    282 	nvgFillColor(vg, nvgRGBA(255, 255, 255, 128));
    283 	nvgTextAlign(vg, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE);
    284 	nvgText(vg, x + w - uw - h * 0.5f, y + h * 0.5f, text, NULL);
    285 }
    286 
    287 void drawCheckBox(NVGcontext *vg, const char *text, float x, float y, float w,
    288 		  float h)
    289 {
    290 	NVGpaint bg;
    291 	char icon[8];
    292 	NVG_NOTUSED(w);
    293 
    294 	nvgFontSize(vg, 18.0f);
    295 	nvgFontFace(vg, "sans");
    296 	nvgFillColor(vg, nvgRGBA(255, 255, 255, 160));
    297 
    298 	nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
    299 	nvgText(vg, x + 28, y + h * 0.5f, text, NULL);
    300 
    301 	bg = nvgBoxGradient(vg, x + 1, y + (int)(h * 0.5f) - 9 + 1, 18, 18, 3,
    302 			    3, nvgRGBA(0, 0, 0, 32), nvgRGBA(0, 0, 0, 92));
    303 	nvgBeginPath(vg);
    304 	nvgRoundedRect(vg, x + 1, y + (int)(h * 0.5f) - 9, 18, 18, 3);
    305 	nvgFillPaint(vg, bg);
    306 	nvgFill(vg);
    307 
    308 	nvgFontSize(vg, 40);
    309 	nvgFontFace(vg, "icons");
    310 	nvgFillColor(vg, nvgRGBA(255, 255, 255, 128));
    311 	nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
    312 	nvgText(vg, x + 9 + 2, y + h * 0.5f, cpToUTF8(ICON_CHECK, icon), NULL);
    313 }
    314 
    315 void drawButton(NVGcontext *vg, int preicon, const char *text, float x, float y,
    316 		float w, float h, NVGcolor col)
    317 {
    318 	NVGpaint bg;
    319 	char icon[8];
    320 	float cornerRadius = 4.0f;
    321 	float tw = 0, iw = 0;
    322 
    323 	bg = nvgLinearGradient(vg, x, y, x, y + h,
    324 			       nvgRGBA(255, 255, 255, isBlack(col) ? 16 : 32),
    325 			       nvgRGBA(0, 0, 0, isBlack(col) ? 16 : 32));
    326 	nvgBeginPath(vg);
    327 	nvgRoundedRect(vg, x + 1, y + 1, w - 2, h - 2, cornerRadius - 1);
    328 	if (!isBlack(col)) {
    329 		nvgFillColor(vg, col);
    330 		nvgFill(vg);
    331 	}
    332 	nvgFillPaint(vg, bg);
    333 	nvgFill(vg);
    334 
    335 	nvgBeginPath(vg);
    336 	nvgRoundedRect(vg, x + 0.5f, y + 0.5f, w - 1, h - 1,
    337 		       cornerRadius - 0.5f);
    338 	nvgStrokeColor(vg, nvgRGBA(0, 0, 0, 48));
    339 	nvgStroke(vg);
    340 
    341 	nvgFontSize(vg, 20.0f);
    342 	nvgFontFace(vg, "sans-bold");
    343 	tw = nvgTextBounds(vg, 0, 0, text, NULL, NULL);
    344 	if (preicon != 0) {
    345 		nvgFontSize(vg, h * 1.3f);
    346 		nvgFontFace(vg, "icons");
    347 		iw = nvgTextBounds(vg, 0, 0, cpToUTF8(preicon, icon), NULL,
    348 				   NULL);
    349 		iw += h * 0.15f;
    350 	}
    351 
    352 	if (preicon != 0) {
    353 		nvgFontSize(vg, h * 1.3f);
    354 		nvgFontFace(vg, "icons");
    355 		nvgFillColor(vg, nvgRGBA(255, 255, 255, 96));
    356 		nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
    357 		nvgText(vg, x + w * 0.5f - tw * 0.5f - iw * 0.75f, y + h * 0.5f,
    358 			cpToUTF8(preicon, icon), NULL);
    359 	}
    360 
    361 	nvgFontSize(vg, 20.0f);
    362 	nvgFontFace(vg, "sans-bold");
    363 	nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
    364 	nvgFillColor(vg, nvgRGBA(0, 0, 0, 160));
    365 	nvgText(vg, x + w * 0.5f - tw * 0.5f + iw * 0.25f, y + h * 0.5f - 1,
    366 		text, NULL);
    367 	nvgFillColor(vg, nvgRGBA(255, 255, 255, 160));
    368 	nvgText(vg, x + w * 0.5f - tw * 0.5f + iw * 0.25f, y + h * 0.5f, text,
    369 		NULL);
    370 }
    371 
    372 void drawSlider(NVGcontext *vg, float pos, float x, float y, float w, float h)
    373 {
    374 	NVGpaint bg, knob;
    375 	float cy = y + (int)(h * 0.5f);
    376 	float kr = (int)(h * 0.25f);
    377 
    378 	nvgSave(vg);
    379 	//	nvgClearState(vg);
    380 
    381 	// Slot
    382 	bg = nvgBoxGradient(vg, x, cy - 2 + 1, w, 4, 2, 2, nvgRGBA(0, 0, 0, 32),
    383 			    nvgRGBA(0, 0, 0, 128));
    384 	nvgBeginPath(vg);
    385 	nvgRoundedRect(vg, x, cy - 2, w, 4, 2);
    386 	nvgFillPaint(vg, bg);
    387 	nvgFill(vg);
    388 
    389 	// Knob Shadow
    390 	bg = nvgRadialGradient(vg, x + (int)(pos * w), cy + 1, kr - 3, kr + 3,
    391 			       nvgRGBA(0, 0, 0, 64), nvgRGBA(0, 0, 0, 0));
    392 	nvgBeginPath(vg);
    393 	nvgRect(vg, x + (int)(pos * w) - kr - 5, cy - kr - 5, kr * 2 + 5 + 5,
    394 		kr * 2 + 5 + 5 + 3);
    395 	nvgCircle(vg, x + (int)(pos * w), cy, kr);
    396 	nvgPathWinding(vg, NVG_HOLE);
    397 	nvgFillPaint(vg, bg);
    398 	nvgFill(vg);
    399 
    400 	// Knob
    401 	knob = nvgLinearGradient(vg, x, cy - kr, x, cy + kr,
    402 				 nvgRGBA(255, 255, 255, 16),
    403 				 nvgRGBA(0, 0, 0, 16));
    404 	nvgBeginPath(vg);
    405 	nvgCircle(vg, x + (int)(pos * w), cy, kr - 1);
    406 	nvgFillColor(vg, nvgRGBA(40, 43, 48, 255));
    407 	nvgFill(vg);
    408 	nvgFillPaint(vg, knob);
    409 	nvgFill(vg);
    410 
    411 	nvgBeginPath(vg);
    412 	nvgCircle(vg, x + (int)(pos * w), cy, kr - 0.5f);
    413 	nvgStrokeColor(vg, nvgRGBA(0, 0, 0, 92));
    414 	nvgStroke(vg);
    415 
    416 	nvgRestore(vg);
    417 }
    418 
    419 void drawEyes(NVGcontext *vg, float x, float y, float w, float h, float mx,
    420 	      float my, float t)
    421 {
    422 	NVGpaint gloss, bg;
    423 	float ex = w * 0.23f;
    424 	float ey = h * 0.5f;
    425 	float lx = x + ex;
    426 	float ly = y + ey;
    427 	float rx = x + w - ex;
    428 	float ry = y + ey;
    429 	float dx, dy, d;
    430 	float br = (ex < ey ? ex : ey) * 0.5f;
    431 	float blink = 1 - pow(sinf(t * 0.5f), 200) * 0.8f;
    432 
    433 	bg = nvgLinearGradient(vg, x, y + h * 0.5f, x + w * 0.1f, y + h,
    434 			       nvgRGBA(0, 0, 0, 32), nvgRGBA(0, 0, 0, 16));
    435 	nvgBeginPath(vg);
    436 	nvgEllipse(vg, lx + 3.0f, ly + 16.0f, ex, ey);
    437 	nvgEllipse(vg, rx + 3.0f, ry + 16.0f, ex, ey);
    438 	nvgFillPaint(vg, bg);
    439 	nvgFill(vg);
    440 
    441 	bg = nvgLinearGradient(vg, x, y + h * 0.25f, x + w * 0.1f, y + h,
    442 			       nvgRGBA(220, 220, 220, 255),
    443 			       nvgRGBA(128, 128, 128, 255));
    444 	nvgBeginPath(vg);
    445 	nvgEllipse(vg, lx, ly, ex, ey);
    446 	nvgEllipse(vg, rx, ry, ex, ey);
    447 	nvgFillPaint(vg, bg);
    448 	nvgFill(vg);
    449 
    450 	dx = (mx - rx) / (ex * 10);
    451 	dy = (my - ry) / (ey * 10);
    452 	d = sqrtf(dx * dx + dy * dy);
    453 	if (d > 1.0f) {
    454 		dx /= d;
    455 		dy /= d;
    456 	}
    457 	dx *= ex * 0.4f;
    458 	dy *= ey * 0.5f;
    459 	nvgBeginPath(vg);
    460 	nvgEllipse(vg, lx + dx, ly + dy + ey * 0.25f * (1 - blink), br,
    461 		   br * blink);
    462 	nvgFillColor(vg, nvgRGBA(32, 32, 32, 255));
    463 	nvgFill(vg);
    464 
    465 	dx = (mx - rx) / (ex * 10);
    466 	dy = (my - ry) / (ey * 10);
    467 	d = sqrtf(dx * dx + dy * dy);
    468 	if (d > 1.0f) {
    469 		dx /= d;
    470 		dy /= d;
    471 	}
    472 	dx *= ex * 0.4f;
    473 	dy *= ey * 0.5f;
    474 	nvgBeginPath(vg);
    475 	nvgEllipse(vg, rx + dx, ry + dy + ey * 0.25f * (1 - blink), br,
    476 		   br * blink);
    477 	nvgFillColor(vg, nvgRGBA(32, 32, 32, 255));
    478 	nvgFill(vg);
    479 
    480 	gloss = nvgRadialGradient(vg, lx - ex * 0.25f, ly - ey * 0.5f,
    481 				  ex * 0.1f, ex * 0.75f,
    482 				  nvgRGBA(255, 255, 255, 128),
    483 				  nvgRGBA(255, 255, 255, 0));
    484 	nvgBeginPath(vg);
    485 	nvgEllipse(vg, lx, ly, ex, ey);
    486 	nvgFillPaint(vg, gloss);
    487 	nvgFill(vg);
    488 
    489 	gloss = nvgRadialGradient(vg, rx - ex * 0.25f, ry - ey * 0.5f,
    490 				  ex * 0.1f, ex * 0.75f,
    491 				  nvgRGBA(255, 255, 255, 128),
    492 				  nvgRGBA(255, 255, 255, 0));
    493 	nvgBeginPath(vg);
    494 	nvgEllipse(vg, rx, ry, ex, ey);
    495 	nvgFillPaint(vg, gloss);
    496 	nvgFill(vg);
    497 }
    498 
    499 void drawGraph(NVGcontext *vg, float x, float y, float w, float h, float t)
    500 {
    501 	NVGpaint bg;
    502 	float samples[6];
    503 	float sx[6], sy[6];
    504 	float dx = w / 5.0f;
    505 	int i;
    506 
    507 	samples[0] =
    508 		(1 + sinf(t * 1.2345f + cosf(t * 0.33457f) * 0.44f)) * 0.5f;
    509 	samples[1] = (1 + sinf(t * 0.68363f + cosf(t * 1.3f) * 1.55f)) * 0.5f;
    510 	samples[2] = (1 + sinf(t * 1.1642f + cosf(t * 0.33457) * 1.24f)) * 0.5f;
    511 	samples[3] = (1 + sinf(t * 0.56345f + cosf(t * 1.63f) * 0.14f)) * 0.5f;
    512 	samples[4] = (1 + sinf(t * 1.6245f + cosf(t * 0.254f) * 0.3f)) * 0.5f;
    513 	samples[5] = (1 + sinf(t * 0.345f + cosf(t * 0.03f) * 0.6f)) * 0.5f;
    514 
    515 	for (i = 0; i < 6; i++) {
    516 		sx[i] = x + i * dx;
    517 		sy[i] = y + h * samples[i] * 0.8f;
    518 	}
    519 
    520 	// Graph background
    521 	bg = nvgLinearGradient(vg, x, y, x, y + h, nvgRGBA(0, 160, 192, 0),
    522 			       nvgRGBA(0, 160, 192, 64));
    523 	nvgBeginPath(vg);
    524 	nvgMoveTo(vg, sx[0], sy[0]);
    525 	for (i = 1; i < 6; i++)
    526 		nvgBezierTo(vg, sx[i - 1] + dx * 0.5f, sy[i - 1],
    527 			    sx[i] - dx * 0.5f, sy[i], sx[i], sy[i]);
    528 	nvgLineTo(vg, x + w, y + h);
    529 	nvgLineTo(vg, x, y + h);
    530 	nvgFillPaint(vg, bg);
    531 	nvgFill(vg);
    532 
    533 	// Graph line
    534 	nvgBeginPath(vg);
    535 	nvgMoveTo(vg, sx[0], sy[0] + 2);
    536 	for (i = 1; i < 6; i++)
    537 		nvgBezierTo(vg, sx[i - 1] + dx * 0.5f, sy[i - 1] + 2,
    538 			    sx[i] - dx * 0.5f, sy[i] + 2, sx[i], sy[i] + 2);
    539 	nvgStrokeColor(vg, nvgRGBA(0, 0, 0, 32));
    540 	nvgStrokeWidth(vg, 3.0f);
    541 	nvgStroke(vg);
    542 
    543 	nvgBeginPath(vg);
    544 	nvgMoveTo(vg, sx[0], sy[0]);
    545 	for (i = 1; i < 6; i++)
    546 		nvgBezierTo(vg, sx[i - 1] + dx * 0.5f, sy[i - 1],
    547 			    sx[i] - dx * 0.5f, sy[i], sx[i], sy[i]);
    548 	nvgStrokeColor(vg, nvgRGBA(0, 160, 192, 255));
    549 	nvgStrokeWidth(vg, 3.0f);
    550 	nvgStroke(vg);
    551 
    552 	// Graph sample pos
    553 	for (i = 0; i < 6; i++) {
    554 		bg = nvgRadialGradient(vg, sx[i], sy[i] + 2, 3.0f, 8.0f,
    555 				       nvgRGBA(0, 0, 0, 32),
    556 				       nvgRGBA(0, 0, 0, 0));
    557 		nvgBeginPath(vg);
    558 		nvgRect(vg, sx[i] - 10, sy[i] - 10 + 2, 20, 20);
    559 		nvgFillPaint(vg, bg);
    560 		nvgFill(vg);
    561 	}
    562 
    563 	nvgBeginPath(vg);
    564 	for (i = 0; i < 6; i++)
    565 		nvgCircle(vg, sx[i], sy[i], 4.0f);
    566 	nvgFillColor(vg, nvgRGBA(0, 160, 192, 255));
    567 	nvgFill(vg);
    568 	nvgBeginPath(vg);
    569 	for (i = 0; i < 6; i++)
    570 		nvgCircle(vg, sx[i], sy[i], 2.0f);
    571 	nvgFillColor(vg, nvgRGBA(220, 220, 220, 255));
    572 	nvgFill(vg);
    573 
    574 	nvgStrokeWidth(vg, 1.0f);
    575 }
    576 
    577 void drawSpinner(NVGcontext *vg, float cx, float cy, float r, float t)
    578 {
    579 	float a0 = 0.0f + t * 6;
    580 	float a1 = NVG_PI + t * 6;
    581 	float r0 = r;
    582 	float r1 = r * 0.75f;
    583 	float ax, ay, bx, by;
    584 	NVGpaint paint;
    585 
    586 	nvgSave(vg);
    587 
    588 	nvgBeginPath(vg);
    589 	nvgArc(vg, cx, cy, r0, a0, a1, NVG_CW);
    590 	nvgArc(vg, cx, cy, r1, a1, a0, NVG_CCW);
    591 	nvgClosePath(vg);
    592 	ax = cx + cosf(a0) * (r0 + r1) * 0.5f;
    593 	ay = cy + sinf(a0) * (r0 + r1) * 0.5f;
    594 	bx = cx + cosf(a1) * (r0 + r1) * 0.5f;
    595 	by = cy + sinf(a1) * (r0 + r1) * 0.5f;
    596 	paint = nvgLinearGradient(vg, ax, ay, bx, by, nvgRGBA(0, 0, 0, 0),
    597 				  nvgRGBA(0, 0, 0, 128));
    598 	nvgFillPaint(vg, paint);
    599 	nvgFill(vg);
    600 
    601 	nvgRestore(vg);
    602 }
    603 
    604 void drawThumbnails(NVGcontext *vg, float x, float y, float w, float h,
    605 		    const int *images, int nimages, float t)
    606 {
    607 	float cornerRadius = 3.0f;
    608 	NVGpaint shadowPaint, imgPaint, fadePaint;
    609 	float ix, iy, iw, ih;
    610 	float thumb = 60.0f;
    611 	float arry = 30.5f;
    612 	int imgw, imgh;
    613 	float stackh = (nimages / 2) * (thumb + 10) + 10;
    614 	int i;
    615 	float u = (1 + cosf(t * 0.5f)) * 0.5f;
    616 	float u2 = (1 - cosf(t * 0.2f)) * 0.5f;
    617 	float scrollh, dv;
    618 
    619 	nvgSave(vg);
    620 	//	nvgClearState(vg);
    621 
    622 	// Drop shadow
    623 	shadowPaint =
    624 		nvgBoxGradient(vg, x, y + 4, w, h, cornerRadius * 2, 20,
    625 			       nvgRGBA(0, 0, 0, 128), nvgRGBA(0, 0, 0, 0));
    626 	nvgBeginPath(vg);
    627 	nvgRect(vg, x - 10, y - 10, w + 20, h + 30);
    628 	nvgRoundedRect(vg, x, y, w, h, cornerRadius);
    629 	nvgPathWinding(vg, NVG_HOLE);
    630 	nvgFillPaint(vg, shadowPaint);
    631 	nvgFill(vg);
    632 
    633 	// Window
    634 	nvgBeginPath(vg);
    635 	nvgRoundedRect(vg, x, y, w, h, cornerRadius);
    636 	nvgMoveTo(vg, x - 10, y + arry);
    637 	nvgLineTo(vg, x + 1, y + arry - 11);
    638 	nvgLineTo(vg, x + 1, y + arry + 11);
    639 	nvgFillColor(vg, nvgRGBA(200, 200, 200, 255));
    640 	nvgFill(vg);
    641 
    642 	nvgSave(vg);
    643 	nvgScissor(vg, x, y, w, h);
    644 	nvgTranslate(vg, 0, -(stackh - h) * u);
    645 
    646 	dv = 1.0f / (float)(nimages - 1);
    647 
    648 	for (i = 0; i < nimages; i++) {
    649 		float tx, ty, v, a;
    650 		tx = x + 10;
    651 		ty = y + 10;
    652 		tx += (i % 2) * (thumb + 10);
    653 		ty += (i / 2) * (thumb + 10);
    654 		nvgImageSize(vg, images[i], &imgw, &imgh);
    655 		if (imgw < imgh) {
    656 			iw = thumb;
    657 			ih = iw * (float)imgh / (float)imgw;
    658 			ix = 0;
    659 			iy = -(ih - thumb) * 0.5f;
    660 		} else {
    661 			ih = thumb;
    662 			iw = ih * (float)imgw / (float)imgh;
    663 			ix = -(iw - thumb) * 0.5f;
    664 			iy = 0;
    665 		}
    666 
    667 		v = i * dv;
    668 		a = clampf((u2 - v) / dv, 0, 1);
    669 
    670 		if (a < 1.0f)
    671 			drawSpinner(vg, tx + thumb / 2, ty + thumb / 2,
    672 				    thumb * 0.25f, t);
    673 
    674 		imgPaint =
    675 			nvgImagePattern(vg, tx + ix, ty + iy, iw, ih,
    676 					0.0f / 180.0f * NVG_PI, images[i], a);
    677 		nvgBeginPath(vg);
    678 		nvgRoundedRect(vg, tx, ty, thumb, thumb, 5);
    679 		nvgFillPaint(vg, imgPaint);
    680 		nvgFill(vg);
    681 
    682 		shadowPaint =
    683 			nvgBoxGradient(vg, tx - 1, ty, thumb + 2, thumb + 2, 5,
    684 				       3, nvgRGBA(0, 0, 0, 128),
    685 				       nvgRGBA(0, 0, 0, 0));
    686 		nvgBeginPath(vg);
    687 		nvgRect(vg, tx - 5, ty - 5, thumb + 10, thumb + 10);
    688 		nvgRoundedRect(vg, tx, ty, thumb, thumb, 6);
    689 		nvgPathWinding(vg, NVG_HOLE);
    690 		nvgFillPaint(vg, shadowPaint);
    691 		nvgFill(vg);
    692 
    693 		nvgBeginPath(vg);
    694 		nvgRoundedRect(vg, tx + 0.5f, ty + 0.5f, thumb - 1, thumb - 1,
    695 			       4 - 0.5f);
    696 		nvgStrokeWidth(vg, 1.0f);
    697 		nvgStrokeColor(vg, nvgRGBA(255, 255, 255, 192));
    698 		nvgStroke(vg);
    699 	}
    700 	nvgRestore(vg);
    701 
    702 	// Hide fades
    703 	fadePaint = nvgLinearGradient(vg, x, y, x, y + 6,
    704 				      nvgRGBA(200, 200, 200, 255),
    705 				      nvgRGBA(200, 200, 200, 0));
    706 	nvgBeginPath(vg);
    707 	nvgRect(vg, x + 4, y, w - 8, 6);
    708 	nvgFillPaint(vg, fadePaint);
    709 	nvgFill(vg);
    710 
    711 	fadePaint = nvgLinearGradient(vg, x, y + h, x, y + h - 6,
    712 				      nvgRGBA(200, 200, 200, 255),
    713 				      nvgRGBA(200, 200, 200, 0));
    714 	nvgBeginPath(vg);
    715 	nvgRect(vg, x + 4, y + h - 6, w - 8, 6);
    716 	nvgFillPaint(vg, fadePaint);
    717 	nvgFill(vg);
    718 
    719 	// Scroll bar
    720 	shadowPaint =
    721 		nvgBoxGradient(vg, x + w - 12 + 1, y + 4 + 1, 8, h - 8, 3, 4,
    722 			       nvgRGBA(0, 0, 0, 32), nvgRGBA(0, 0, 0, 92));
    723 	nvgBeginPath(vg);
    724 	nvgRoundedRect(vg, x + w - 12, y + 4, 8, h - 8, 3);
    725 	nvgFillPaint(vg, shadowPaint);
    726 	//	nvgFillColor(vg, nvgRGBA(255,0,0,128));
    727 	nvgFill(vg);
    728 
    729 	scrollh = (h / stackh) * (h - 8);
    730 	shadowPaint = nvgBoxGradient(vg, x + w - 12 - 1,
    731 				     y + 4 + (h - 8 - scrollh) * u - 1, 8,
    732 				     scrollh, 3, 4, nvgRGBA(220, 220, 220, 255),
    733 				     nvgRGBA(128, 128, 128, 255));
    734 	nvgBeginPath(vg);
    735 	nvgRoundedRect(vg, x + w - 12 + 1, y + 4 + 1 + (h - 8 - scrollh) * u,
    736 		       8 - 2, scrollh - 2, 2);
    737 	nvgFillPaint(vg, shadowPaint);
    738 	//	nvgFillColor(vg, nvgRGBA(0,0,0,128));
    739 	nvgFill(vg);
    740 
    741 	nvgRestore(vg);
    742 }
    743 
    744 void drawColorwheel(NVGcontext *vg, float x, float y, float w, float h, float t)
    745 {
    746 	int i;
    747 	float r0, r1, ax, ay, bx, by, cx, cy, aeps, r;
    748 	float hue = sinf(t * 0.12f);
    749 	NVGpaint paint;
    750 
    751 	nvgSave(vg);
    752 
    753 	/*	nvgBeginPath(vg);
    754 	nvgRect(vg, x,y,w,h);
    755 	nvgFillColor(vg, nvgRGBA(255,0,0,128));
    756 	nvgFill(vg);*/
    757 
    758 	cx = x + w * 0.5f;
    759 	cy = y + h * 0.5f;
    760 	r1 = (w < h ? w : h) * 0.5f - 5.0f;
    761 	r0 = r1 - 20.0f;
    762 	aeps = 0.5f /
    763 	       r1; // half a pixel arc length in radians (2pi cancels out).
    764 
    765 	for (i = 0; i < 6; i++) {
    766 		float a0 = (float)i / 6.0f * NVG_PI * 2.0f - aeps;
    767 		float a1 = (float)(i + 1.0f) / 6.0f * NVG_PI * 2.0f + aeps;
    768 		nvgBeginPath(vg);
    769 		nvgArc(vg, cx, cy, r0, a0, a1, NVG_CW);
    770 		nvgArc(vg, cx, cy, r1, a1, a0, NVG_CCW);
    771 		nvgClosePath(vg);
    772 		ax = cx + cosf(a0) * (r0 + r1) * 0.5f;
    773 		ay = cy + sinf(a0) * (r0 + r1) * 0.5f;
    774 		bx = cx + cosf(a1) * (r0 + r1) * 0.5f;
    775 		by = cy + sinf(a1) * (r0 + r1) * 0.5f;
    776 		paint = nvgLinearGradient(
    777 			vg, ax, ay, bx, by,
    778 			nvgHSLA(a0 / (NVG_PI * 2), 1.0f, 0.55f, 255),
    779 			nvgHSLA(a1 / (NVG_PI * 2), 1.0f, 0.55f, 255));
    780 		nvgFillPaint(vg, paint);
    781 		nvgFill(vg);
    782 	}
    783 
    784 	nvgBeginPath(vg);
    785 	nvgCircle(vg, cx, cy, r0 - 0.5f);
    786 	nvgCircle(vg, cx, cy, r1 + 0.5f);
    787 	nvgStrokeColor(vg, nvgRGBA(0, 0, 0, 64));
    788 	nvgStrokeWidth(vg, 1.0f);
    789 	nvgStroke(vg);
    790 
    791 	// Selector
    792 	nvgSave(vg);
    793 	nvgTranslate(vg, cx, cy);
    794 	nvgRotate(vg, hue * NVG_PI * 2);
    795 
    796 	// Marker on
    797 	nvgStrokeWidth(vg, 2.0f);
    798 	nvgBeginPath(vg);
    799 	nvgRect(vg, r0 - 1, -3, r1 - r0 + 2, 6);
    800 	nvgStrokeColor(vg, nvgRGBA(255, 255, 255, 192));
    801 	nvgStroke(vg);
    802 
    803 	paint = nvgBoxGradient(vg, r0 - 3, -5, r1 - r0 + 6, 10, 2, 4,
    804 			       nvgRGBA(0, 0, 0, 128), nvgRGBA(0, 0, 0, 0));
    805 	nvgBeginPath(vg);
    806 	nvgRect(vg, r0 - 2 - 10, -4 - 10, r1 - r0 + 4 + 20, 8 + 20);
    807 	nvgRect(vg, r0 - 2, -4, r1 - r0 + 4, 8);
    808 	nvgPathWinding(vg, NVG_HOLE);
    809 	nvgFillPaint(vg, paint);
    810 	nvgFill(vg);
    811 
    812 	// Center triangle
    813 	r = r0 - 6;
    814 	ax = cosf(120.0f / 180.0f * NVG_PI) * r;
    815 	ay = sinf(120.0f / 180.0f * NVG_PI) * r;
    816 	bx = cosf(-120.0f / 180.0f * NVG_PI) * r;
    817 	by = sinf(-120.0f / 180.0f * NVG_PI) * r;
    818 	nvgBeginPath(vg);
    819 	nvgMoveTo(vg, r, 0);
    820 	nvgLineTo(vg, ax, ay);
    821 	nvgLineTo(vg, bx, by);
    822 	nvgClosePath(vg);
    823 	paint = nvgLinearGradient(vg, r, 0, ax, ay,
    824 				  nvgHSLA(hue, 1.0f, 0.5f, 255),
    825 				  nvgRGBA(255, 255, 255, 255));
    826 	nvgFillPaint(vg, paint);
    827 	nvgFill(vg);
    828 	paint = nvgLinearGradient(vg, (r + ax) * 0.5f, (0 + ay) * 0.5f, bx, by,
    829 				  nvgRGBA(0, 0, 0, 0), nvgRGBA(0, 0, 0, 255));
    830 	nvgFillPaint(vg, paint);
    831 	nvgFill(vg);
    832 	nvgStrokeColor(vg, nvgRGBA(0, 0, 0, 64));
    833 	nvgStroke(vg);
    834 
    835 	// Select circle on triangle
    836 	ax = cosf(120.0f / 180.0f * NVG_PI) * r * 0.3f;
    837 	ay = sinf(120.0f / 180.0f * NVG_PI) * r * 0.4f;
    838 	nvgStrokeWidth(vg, 2.0f);
    839 	nvgBeginPath(vg);
    840 	nvgCircle(vg, ax, ay, 5);
    841 	nvgStrokeColor(vg, nvgRGBA(255, 255, 255, 192));
    842 	nvgStroke(vg);
    843 
    844 	paint = nvgRadialGradient(vg, ax, ay, 7, 9, nvgRGBA(0, 0, 0, 64),
    845 				  nvgRGBA(0, 0, 0, 0));
    846 	nvgBeginPath(vg);
    847 	nvgRect(vg, ax - 20, ay - 20, 40, 40);
    848 	nvgCircle(vg, ax, ay, 7);
    849 	nvgPathWinding(vg, NVG_HOLE);
    850 	nvgFillPaint(vg, paint);
    851 	nvgFill(vg);
    852 
    853 	nvgRestore(vg);
    854 
    855 	nvgRestore(vg);
    856 }
    857 
    858 void drawLines(NVGcontext *vg, float x, float y, float w, float h, float t)
    859 {
    860 	int i, j;
    861 	float pad = 5.0f, s = w / 9.0f - pad * 2;
    862 	float pts[4 * 2], fx, fy;
    863 	int joins[3] = { NVG_MITER, NVG_ROUND, NVG_BEVEL };
    864 	int caps[3] = { NVG_BUTT, NVG_ROUND, NVG_SQUARE };
    865 	NVG_NOTUSED(h);
    866 
    867 	nvgSave(vg);
    868 	pts[0] = -s * 0.25f + cosf(t * 0.3f) * s * 0.5f;
    869 	pts[1] = sinf(t * 0.3f) * s * 0.5f;
    870 	pts[2] = -s * 0.25;
    871 	pts[3] = 0;
    872 	pts[4] = s * 0.25f;
    873 	pts[5] = 0;
    874 	pts[6] = s * 0.25f + cosf(-t * 0.3f) * s * 0.5f;
    875 	pts[7] = sinf(-t * 0.3f) * s * 0.5f;
    876 
    877 	for (i = 0; i < 3; i++) {
    878 		for (j = 0; j < 3; j++) {
    879 			fx = x + s * 0.5f + (i * 3 + j) / 9.0f * w + pad;
    880 			fy = y - s * 0.5f + pad;
    881 
    882 			nvgLineCap(vg, caps[i]);
    883 			nvgLineJoin(vg, joins[j]);
    884 
    885 			nvgStrokeWidth(vg, s * 0.3f);
    886 			nvgStrokeColor(vg, nvgRGBA(0, 0, 0, 160));
    887 			nvgBeginPath(vg);
    888 			nvgMoveTo(vg, fx + pts[0], fy + pts[1]);
    889 			nvgLineTo(vg, fx + pts[2], fy + pts[3]);
    890 			nvgLineTo(vg, fx + pts[4], fy + pts[5]);
    891 			nvgLineTo(vg, fx + pts[6], fy + pts[7]);
    892 			nvgStroke(vg);
    893 
    894 			nvgLineCap(vg, NVG_BUTT);
    895 			nvgLineJoin(vg, NVG_BEVEL);
    896 
    897 			nvgStrokeWidth(vg, 1.0f);
    898 			nvgStrokeColor(vg, nvgRGBA(0, 192, 255, 255));
    899 			nvgBeginPath(vg);
    900 			nvgMoveTo(vg, fx + pts[0], fy + pts[1]);
    901 			nvgLineTo(vg, fx + pts[2], fy + pts[3]);
    902 			nvgLineTo(vg, fx + pts[4], fy + pts[5]);
    903 			nvgLineTo(vg, fx + pts[6], fy + pts[7]);
    904 			nvgStroke(vg);
    905 		}
    906 	}
    907 
    908 	nvgRestore(vg);
    909 }
    910 
    911 int loadDemoData(NVGcontext *vg, DemoData *data)
    912 {
    913 	int i;
    914 
    915 	if (vg == NULL)
    916 		return -1;
    917 
    918 	for (i = 0; i < 12; i++) {
    919 		char file[128];
    920 		snprintf(file, 128, "res/images/image%d.jpg", i + 1);
    921 		data->images[i] = nvgCreateImage(vg, file, 0);
    922 		if (data->images[i] == 0) {
    923 			printf("Could not load %s.\n", file);
    924 			return -1;
    925 		}
    926 	}
    927 
    928 	data->fontIcons = nvgCreateFont(vg, "icons", "res/fonts/entypo.ttf");
    929 	if (data->fontIcons == -1) {
    930 		printf("Could not add font icons.\n");
    931 		return -1;
    932 	}
    933 	data->fontNormal =
    934 		nvgCreateFont(vg, "sans", "res/fonts/Roboto-Regular.ttf");
    935 	if (data->fontNormal == -1) {
    936 		printf("Could not add font italic.\n");
    937 		return -1;
    938 	}
    939 	data->fontBold =
    940 		nvgCreateFont(vg, "sans-bold", "res/fonts/Roboto-Bold.ttf");
    941 	if (data->fontBold == -1) {
    942 		printf("Could not add font bold.\n");
    943 		return -1;
    944 	}
    945 	data->fontEmoji =
    946 		nvgCreateFont(vg, "emoji", "res/fonts/NotoEmoji-Regular.ttf");
    947 	if (data->fontEmoji == -1) {
    948 		printf("Could not add font emoji.\n");
    949 		return -1;
    950 	}
    951 	nvgAddFallbackFontId(vg, data->fontNormal, data->fontEmoji);
    952 	nvgAddFallbackFontId(vg, data->fontBold, data->fontEmoji);
    953 
    954 	return 0;
    955 }
    956 
    957 void freeDemoData(NVGcontext *vg, DemoData *data)
    958 {
    959 	int i;
    960 
    961 	if (vg == NULL)
    962 		return;
    963 
    964 	for (i = 0; i < 12; i++)
    965 		nvgDeleteImage(vg, data->images[i]);
    966 }
    967 
    968 void drawParagraph(NVGcontext *vg, float x, float y, float width, float height,
    969 		   float mx, float my)
    970 {
    971 	NVGtextRow rows[3];
    972 	NVGglyphPosition glyphs[100];
    973 	const char *text =
    974 		"This is longer chunk of text.\n  \n  Would have used lorem ipsum but she    was busy jumping over the lazy dog with the fox and all the men who came to the aid of the party.🎉";
    975 	const char *start;
    976 	const char *end;
    977 	int nrows, i, nglyphs, j, lnum = 0;
    978 	float lineh;
    979 	float caretx, px;
    980 	float bounds[4];
    981 	float a;
    982 	float gx, gy;
    983 	int gutter = 0;
    984 	NVG_NOTUSED(height);
    985 
    986 	nvgSave(vg);
    987 
    988 	nvgFontSize(vg, 18.0f);
    989 	nvgFontFace(vg, "sans");
    990 	nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_TOP);
    991 	nvgTextMetrics(vg, NULL, NULL, &lineh);
    992 
    993 	// The text break API can be used to fill a large buffer of rows,
    994 	// or to iterate over the text just few lines (or just one) at a time.
    995 	// The "next" variable of the last returned item tells where to continue.
    996 	start = text;
    997 	end = text + strlen(text);
    998 	while ((nrows = nvgTextBreakLines(vg, start, end, width, rows, 3))) {
    999 		for (i = 0; i < nrows; i++) {
   1000 			NVGtextRow *row = &rows[i];
   1001 			int hit = mx > x && mx < (x + width) && my >= y &&
   1002 				  my < (y + lineh);
   1003 
   1004 			nvgBeginPath(vg);
   1005 			nvgFillColor(vg, nvgRGBA(255, 255, 255, hit ? 64 : 16));
   1006 			nvgRect(vg, x, y, row->width, lineh);
   1007 			nvgFill(vg);
   1008 
   1009 			nvgFillColor(vg, nvgRGBA(255, 255, 255, 255));
   1010 			nvgText(vg, x, y, row->start, row->end);
   1011 
   1012 			if (hit) {
   1013 				caretx = (mx < x + row->width / 2) ?
   1014 						 x :
   1015 						 x + row->width;
   1016 				px = x;
   1017 				nglyphs = nvgTextGlyphPositions(vg, x, y,
   1018 								row->start,
   1019 								row->end,
   1020 								glyphs, 100);
   1021 				for (j = 0; j < nglyphs; j++) {
   1022 					float x0 = glyphs[j].x;
   1023 					float x1 = (j + 1 < nglyphs) ?
   1024 							   glyphs[j + 1].x :
   1025 							   x + row->width;
   1026 					float gx = x0 * 0.3f + x1 * 0.7f;
   1027 					if (mx >= px && mx < gx)
   1028 						caretx = glyphs[j].x;
   1029 					px = gx;
   1030 				}
   1031 				nvgBeginPath(vg);
   1032 				nvgFillColor(vg, nvgRGBA(255, 192, 0, 255));
   1033 				nvgRect(vg, caretx, y, 1, lineh);
   1034 				nvgFill(vg);
   1035 
   1036 				gutter = lnum + 1;
   1037 				gx = x - 10;
   1038 				gy = y + lineh / 2;
   1039 			}
   1040 			lnum++;
   1041 			y += lineh;
   1042 		}
   1043 		// Keep going...
   1044 		start = rows[nrows - 1].next;
   1045 	}
   1046 
   1047 	if (gutter) {
   1048 		char txt[16];
   1049 		snprintf(txt, sizeof(txt), "%d", gutter);
   1050 		nvgFontSize(vg, 13.0f);
   1051 		nvgTextAlign(vg, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE);
   1052 
   1053 		nvgTextBounds(vg, gx, gy, txt, NULL, bounds);
   1054 
   1055 		nvgBeginPath(vg);
   1056 		nvgFillColor(vg, nvgRGBA(255, 192, 0, 255));
   1057 		nvgRoundedRect(vg, (int)bounds[0] - 4, (int)bounds[1] - 2,
   1058 			       (int)(bounds[2] - bounds[0]) + 8,
   1059 			       (int)(bounds[3] - bounds[1]) + 4,
   1060 			       ((int)(bounds[3] - bounds[1]) + 4) / 2 - 1);
   1061 		nvgFill(vg);
   1062 
   1063 		nvgFillColor(vg, nvgRGBA(32, 32, 32, 255));
   1064 		nvgText(vg, gx, gy, txt, NULL);
   1065 	}
   1066 
   1067 	y += 20.0f;
   1068 
   1069 	nvgFontSize(vg, 13.0f);
   1070 	nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_TOP);
   1071 	nvgTextLineHeight(vg, 1.2f);
   1072 
   1073 	nvgTextBoxBounds(
   1074 		vg, x, y, 150,
   1075 		"Hover your mouse over the text to see calculated caret position.",
   1076 		NULL, bounds);
   1077 
   1078 	// Fade the tooltip out when close to it.
   1079 	gx = fabsf((mx - (bounds[0] + bounds[2]) * 0.5f) /
   1080 		   (bounds[0] - bounds[2]));
   1081 	gy = fabsf((my - (bounds[1] + bounds[3]) * 0.5f) /
   1082 		   (bounds[1] - bounds[3]));
   1083 	a = maxf(gx, gy) - 0.5f;
   1084 	a = clampf(a, 0, 1);
   1085 	nvgGlobalAlpha(vg, a);
   1086 
   1087 	nvgBeginPath(vg);
   1088 	nvgFillColor(vg, nvgRGBA(220, 220, 220, 255));
   1089 	nvgRoundedRect(vg, bounds[0] - 2, bounds[1] - 2,
   1090 		       (int)(bounds[2] - bounds[0]) + 4,
   1091 		       (int)(bounds[3] - bounds[1]) + 4, 3);
   1092 	px = (int)((bounds[2] + bounds[0]) / 2);
   1093 	nvgMoveTo(vg, px, bounds[1] - 10);
   1094 	nvgLineTo(vg, px + 7, bounds[1] + 1);
   1095 	nvgLineTo(vg, px - 7, bounds[1] + 1);
   1096 	nvgFill(vg);
   1097 
   1098 	nvgFillColor(vg, nvgRGBA(0, 0, 0, 220));
   1099 	nvgTextBox(
   1100 		vg, x, y, 150,
   1101 		"Hover your mouse over the text to see calculated caret position.",
   1102 		NULL);
   1103 
   1104 	nvgRestore(vg);
   1105 }
   1106 
   1107 void drawWidths(NVGcontext *vg, float x, float y, float width)
   1108 {
   1109 	int i;
   1110 
   1111 	nvgSave(vg);
   1112 
   1113 	nvgStrokeColor(vg, nvgRGBA(0, 0, 0, 255));
   1114 
   1115 	for (i = 0; i < 20; i++) {
   1116 		float w = (i + 0.5f) * 0.1f;
   1117 		nvgStrokeWidth(vg, w);
   1118 		nvgBeginPath(vg);
   1119 		nvgMoveTo(vg, x, y);
   1120 		nvgLineTo(vg, x + width, y + width * 0.3f);
   1121 		nvgStroke(vg);
   1122 		y += 10;
   1123 	}
   1124 
   1125 	nvgRestore(vg);
   1126 }
   1127 
   1128 void drawCaps(NVGcontext *vg, float x, float y, float width)
   1129 {
   1130 	int i;
   1131 	int caps[3] = { NVG_BUTT, NVG_ROUND, NVG_SQUARE };
   1132 	float lineWidth = 8.0f;
   1133 
   1134 	nvgSave(vg);
   1135 
   1136 	nvgBeginPath(vg);
   1137 	nvgRect(vg, x - lineWidth / 2, y, width + lineWidth, 40);
   1138 	nvgFillColor(vg, nvgRGBA(255, 255, 255, 32));
   1139 	nvgFill(vg);
   1140 
   1141 	nvgBeginPath(vg);
   1142 	nvgRect(vg, x, y, width, 40);
   1143 	nvgFillColor(vg, nvgRGBA(255, 255, 255, 32));
   1144 	nvgFill(vg);
   1145 
   1146 	nvgStrokeWidth(vg, lineWidth);
   1147 	for (i = 0; i < 3; i++) {
   1148 		nvgLineCap(vg, caps[i]);
   1149 		nvgStrokeColor(vg, nvgRGBA(0, 0, 0, 255));
   1150 		nvgBeginPath(vg);
   1151 		nvgMoveTo(vg, x, y + i * 10 + 5);
   1152 		nvgLineTo(vg, x + width, y + i * 10 + 5);
   1153 		nvgStroke(vg);
   1154 	}
   1155 
   1156 	nvgRestore(vg);
   1157 }
   1158 
   1159 void drawScissor(NVGcontext *vg, float x, float y, float t)
   1160 {
   1161 	nvgSave(vg);
   1162 
   1163 	// Draw first rect and set scissor to it's area.
   1164 	nvgTranslate(vg, x, y);
   1165 	nvgRotate(vg, nvgDegToRad(5));
   1166 	nvgBeginPath(vg);
   1167 	nvgRect(vg, -20, -20, 60, 40);
   1168 	nvgFillColor(vg, nvgRGBA(255, 0, 0, 255));
   1169 	nvgFill(vg);
   1170 	nvgScissor(vg, -20, -20, 60, 40);
   1171 
   1172 	// Draw second rectangle with offset and rotation.
   1173 	nvgTranslate(vg, 40, 0);
   1174 	nvgRotate(vg, t);
   1175 
   1176 	// Draw the intended second rectangle without any scissoring.
   1177 	nvgSave(vg);
   1178 	nvgResetScissor(vg);
   1179 	nvgBeginPath(vg);
   1180 	nvgRect(vg, -20, -10, 60, 30);
   1181 	nvgFillColor(vg, nvgRGBA(255, 128, 0, 64));
   1182 	nvgFill(vg);
   1183 	nvgRestore(vg);
   1184 
   1185 	// Draw second rectangle with combined scissoring.
   1186 	nvgIntersectScissor(vg, -20, -10, 60, 30);
   1187 	nvgBeginPath(vg);
   1188 	nvgRect(vg, -20, -10, 60, 30);
   1189 	nvgFillColor(vg, nvgRGBA(255, 128, 0, 255));
   1190 	nvgFill(vg);
   1191 
   1192 	nvgRestore(vg);
   1193 }
   1194 
   1195 void renderDemo(NVGcontext *vg, float mx, float my, float width, float height,
   1196 		float t, int blowup, DemoData *data)
   1197 {
   1198 	float x, y, popy;
   1199 
   1200 	drawEyes(vg, width - 250, 50, 150, 100, mx, my, t);
   1201 	drawParagraph(vg, width - 450, 50, 150, 100, mx, my);
   1202 	drawGraph(vg, 0, height / 2, width, height / 2, t);
   1203 	drawColorwheel(vg, width - 300, height - 300, 250.0f, 250.0f, t);
   1204 
   1205 	// Line joints
   1206 	drawLines(vg, 120, height - 50, 600, 50, t);
   1207 
   1208 	// Line caps
   1209 	drawWidths(vg, 10, 50, 30);
   1210 
   1211 	// Line caps
   1212 	drawCaps(vg, 10, 300, 30);
   1213 
   1214 	drawScissor(vg, 50, height - 80, t);
   1215 
   1216 	nvgSave(vg);
   1217 	if (blowup) {
   1218 		nvgRotate(vg, sinf(t * 0.3f) * 5.0f / 180.0f * NVG_PI);
   1219 		nvgScale(vg, 2.0f, 2.0f);
   1220 	}
   1221 
   1222 	// Widgets
   1223 	drawWindow(vg, "Widgets `n Stuff", 50, 50, 300, 400);
   1224 	x = 60;
   1225 	y = 95;
   1226 	drawSearchBox(vg, "Search", x, y, 280, 25);
   1227 	y += 40;
   1228 	drawDropDown(vg, "Effects", x, y, 280, 28);
   1229 	popy = y + 14;
   1230 	y += 45;
   1231 
   1232 	// Form
   1233 	drawLabel(vg, "Login", x, y, 280, 20);
   1234 	y += 25;
   1235 	drawEditBox(vg, "Email", x, y, 280, 28);
   1236 	y += 35;
   1237 	drawEditBox(vg, "Password", x, y, 280, 28);
   1238 	y += 38;
   1239 	drawCheckBox(vg, "Remember me", x, y, 140, 28);
   1240 	drawButton(vg, ICON_LOGIN, "Sign in", x + 138, y, 140, 28,
   1241 		   nvgRGBA(0, 96, 128, 255));
   1242 	y += 45;
   1243 
   1244 	// Slider
   1245 	drawLabel(vg, "Diameter", x, y, 280, 20);
   1246 	y += 25;
   1247 	drawEditBoxNum(vg, "123.00", "px", x + 180, y, 100, 28);
   1248 	drawSlider(vg, 0.4f, x, y, 170, 28);
   1249 	y += 55;
   1250 
   1251 	drawButton(vg, ICON_TRASH, "Delete", x, y, 160, 28,
   1252 		   nvgRGBA(128, 16, 8, 255));
   1253 	drawButton(vg, 0, "Cancel", x + 170, y, 110, 28, nvgRGBA(0, 0, 0, 0));
   1254 
   1255 	// Thumbnails box
   1256 	drawThumbnails(vg, 365, popy - 30, 160, 300, data->images, 12, t);
   1257 
   1258 	nvgRestore(vg);
   1259 }
   1260