demo.c 32 KB

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