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