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

967 lines
25KB

  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. #else
  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. // Returns 1 if col.rgba is 0.0f,0.0f,0.0f,0.0f, 0 otherwise
  24. int isBlack( struct NVGcolor col )
  25. {
  26. if( col.r == 0.0f && col.g == 0.0f && col.b == 0.0f && col.a == 0.0f )
  27. {
  28. return 1;
  29. }
  30. return 0;
  31. }
  32. static char* cpToUTF8(int cp, char* str)
  33. {
  34. int n = 0;
  35. if (cp < 0x80) n = 1;
  36. else if (cp < 0x800) n = 2;
  37. else if (cp < 0x10000) n = 3;
  38. else if (cp < 0x200000) n = 4;
  39. else if (cp < 0x4000000) n = 5;
  40. else if (cp <= 0x7fffffff) n = 6;
  41. str[n] = '\0';
  42. switch (n) {
  43. case 6: str[5] = 0x80 | (cp & 0x3f); cp = cp >> 6; cp |= 0x4000000;
  44. case 5: str[4] = 0x80 | (cp & 0x3f); cp = cp >> 6; cp |= 0x200000;
  45. case 4: str[3] = 0x80 | (cp & 0x3f); cp = cp >> 6; cp |= 0x10000;
  46. case 3: str[2] = 0x80 | (cp & 0x3f); cp = cp >> 6; cp |= 0x800;
  47. case 2: str[1] = 0x80 | (cp & 0x3f); cp = cp >> 6; cp |= 0xc0;
  48. case 1: str[0] = cp;
  49. }
  50. return str;
  51. }
  52. void drawWindow(struct NVGcontext* vg, const char* title, float x, float y, float w, float h)
  53. {
  54. float cornerRadius = 3.0f;
  55. struct NVGpaint shadowPaint;
  56. struct NVGpaint headerPaint;
  57. nvgSave(vg);
  58. // nvgClearState(vg);
  59. // Window
  60. nvgBeginPath(vg);
  61. nvgRoundedRect(vg, x,y, w,h, cornerRadius);
  62. nvgFillColor(vg, nvgRGBA(28,30,34,192));
  63. // nvgFillColor(vg, nvgRGBA(0,0,0,128));
  64. nvgFill(vg);
  65. // Drop shadow
  66. shadowPaint = nvgBoxGradient(vg, x,y+2, w,h, cornerRadius*2, 10, nvgRGBA(0,0,0,128), nvgRGBA(0,0,0,0));
  67. nvgBeginPath(vg);
  68. nvgRect(vg, x-10,y-10, w+20,h+30);
  69. nvgRoundedRect(vg, x,y, w,h, cornerRadius);
  70. nvgPathWinding(vg, NVG_HOLE);
  71. nvgFillPaint(vg, shadowPaint);
  72. nvgFill(vg);
  73. // Header
  74. headerPaint = nvgLinearGradient(vg, x,y,x,y+15, nvgRGBA(255,255,255,8), nvgRGBA(0,0,0,16));
  75. nvgBeginPath(vg);
  76. nvgRoundedRect(vg, x+1,y+1, w-2,30, cornerRadius-1);
  77. nvgFillPaint(vg, headerPaint);
  78. nvgFill(vg);
  79. nvgBeginPath(vg);
  80. nvgMoveTo(vg, x+0.5f, y+0.5f+30);
  81. nvgLineTo(vg, x+0.5f+w-1, y+0.5f+30);
  82. nvgStrokeColor(vg, nvgRGBA(0,0,0,32));
  83. nvgStroke(vg);
  84. nvgFontSize(vg, 18.0f);
  85. nvgFontFace(vg, "sans-bold");
  86. nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
  87. nvgFontBlur(vg,2);
  88. nvgFillColor(vg, nvgRGBA(0,0,0,128));
  89. nvgText(vg, x+w/2,y+16+1, title, NULL);
  90. nvgFontBlur(vg,0);
  91. nvgFillColor(vg, nvgRGBA(220,220,220,160));
  92. nvgText(vg, x+w/2,y+16, title, NULL);
  93. nvgRestore(vg);
  94. }
  95. void drawSearchBox(struct NVGcontext* vg, const char* text, float x, float y, float w, float h)
  96. {
  97. struct NVGpaint bg;
  98. char icon[8];
  99. float cornerRadius = h/2-1;
  100. // Edit
  101. bg = nvgBoxGradient(vg, x,y+1.5f, w,h, h/2,5, nvgRGBA(0,0,0,16), nvgRGBA(0,0,0,92));
  102. nvgBeginPath(vg);
  103. nvgRoundedRect(vg, x,y, w,h, cornerRadius);
  104. nvgFillPaint(vg, bg);
  105. nvgFill(vg);
  106. /* nvgBeginPath(vg);
  107. nvgRoundedRect(vg, x+0.5f,y+0.5f, w-1,h-1, cornerRadius-0.5f);
  108. nvgStrokeColor(vg, nvgRGBA(0,0,0,48));
  109. nvgStroke(vg);*/
  110. nvgFontSize(vg, h*1.3f);
  111. nvgFontFace(vg, "icons");
  112. nvgFillColor(vg, nvgRGBA(255,255,255,64));
  113. nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
  114. nvgText(vg, x+h*0.55f, y+h*0.55f, cpToUTF8(ICON_SEARCH,icon), NULL);
  115. nvgFontSize(vg, 20.0f);
  116. nvgFontFace(vg, "sans");
  117. nvgFillColor(vg, nvgRGBA(255,255,255,32));
  118. nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
  119. nvgText(vg, x+h*1.05f,y+h*0.5f,text, NULL);
  120. nvgFontSize(vg, h*1.3f);
  121. nvgFontFace(vg, "icons");
  122. nvgFillColor(vg, nvgRGBA(255,255,255,32));
  123. nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
  124. nvgText(vg, x+w-h*0.55f, y+h*0.55f, cpToUTF8(ICON_CIRCLED_CROSS,icon), NULL);
  125. }
  126. void drawDropDown(struct NVGcontext* vg, const char* text, float x, float y, float w, float h)
  127. {
  128. struct NVGpaint bg;
  129. char icon[8];
  130. float cornerRadius = 4.0f;
  131. bg = nvgLinearGradient(vg, x,y,x,y+h, nvgRGBA(255,255,255,16), nvgRGBA(0,0,0,16));
  132. nvgBeginPath(vg);
  133. nvgRoundedRect(vg, x+1,y+1, w-2,h-2, cornerRadius-1);
  134. nvgFillPaint(vg, bg);
  135. nvgFill(vg);
  136. nvgBeginPath(vg);
  137. nvgRoundedRect(vg, x+0.5f,y+0.5f, w-1,h-1, cornerRadius-0.5f);
  138. nvgStrokeColor(vg, nvgRGBA(0,0,0,48));
  139. nvgStroke(vg);
  140. nvgFontSize(vg, 20.0f);
  141. nvgFontFace(vg, "sans");
  142. nvgFillColor(vg, nvgRGBA(255,255,255,160));
  143. nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
  144. nvgText(vg, x+h*0.3f,y+h*0.5f,text, NULL);
  145. nvgFontSize(vg, h*1.3f);
  146. nvgFontFace(vg, "icons");
  147. nvgFillColor(vg, nvgRGBA(255,255,255,64));
  148. nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
  149. nvgText(vg, x+w-h*0.5f, y+h*0.5f, cpToUTF8(ICON_CHEVRON_RIGHT,icon), NULL);
  150. }
  151. void drawLabel(struct NVGcontext* vg, const char* text, float x, float y, float w, float h)
  152. {
  153. NVG_NOTUSED(w);
  154. nvgFontSize(vg, 18.0f);
  155. nvgFontFace(vg, "sans");
  156. nvgFillColor(vg, nvgRGBA(255,255,255,128));
  157. nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
  158. nvgText(vg, x,y+h*0.5f,text, NULL);
  159. }
  160. void drawEditBoxBase(struct NVGcontext* vg, float x, float y, float w, float h)
  161. {
  162. struct NVGpaint bg;
  163. // Edit
  164. 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));
  165. nvgBeginPath(vg);
  166. nvgRoundedRect(vg, x+1,y+1, w-2,h-2, 4-1);
  167. nvgFillPaint(vg, bg);
  168. nvgFill(vg);
  169. nvgBeginPath(vg);
  170. nvgRoundedRect(vg, x+0.5f,y+0.5f, w-1,h-1, 4-0.5f);
  171. nvgStrokeColor(vg, nvgRGBA(0,0,0,48));
  172. nvgStroke(vg);
  173. }
  174. void drawEditBox(struct NVGcontext* vg, const char* text, float x, float y, float w, float h)
  175. {
  176. drawEditBoxBase(vg, x,y, w,h);
  177. nvgFontSize(vg, 20.0f);
  178. nvgFontFace(vg, "sans");
  179. nvgFillColor(vg, nvgRGBA(255,255,255,64));
  180. nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
  181. nvgText(vg, x+h*0.3f,y+h*0.5f,text, NULL);
  182. }
  183. void drawEditBoxNum(struct NVGcontext* vg,
  184. const char* text, const char* units, float x, float y, float w, float h)
  185. {
  186. float uw;
  187. drawEditBoxBase(vg, x,y, w,h);
  188. uw = nvgTextBounds(vg, units, NULL, NULL);
  189. nvgFontSize(vg, 18.0f);
  190. nvgFontFace(vg, "sans");
  191. nvgFillColor(vg, nvgRGBA(255,255,255,64));
  192. nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_MIDDLE);
  193. nvgText(vg, x+w-h*0.3f,y+h*0.5f,units, NULL);
  194. nvgFontSize(vg, 20.0f);
  195. nvgFontFace(vg, "sans");
  196. nvgFillColor(vg, nvgRGBA(255,255,255,128));
  197. nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_MIDDLE);
  198. nvgText(vg, x+w-uw-h*0.5f,y+h*0.5f,text, NULL);
  199. }
  200. void drawCheckBox(struct NVGcontext* vg, const char* text, float x, float y, float w, float h)
  201. {
  202. struct NVGpaint bg;
  203. char icon[8];
  204. NVG_NOTUSED(w);
  205. nvgFontSize(vg, 18.0f);
  206. nvgFontFace(vg, "sans");
  207. nvgFillColor(vg, nvgRGBA(255,255,255,160));
  208. nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
  209. nvgText(vg, x+28,y+h*0.5f,text, NULL);
  210. 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));
  211. nvgBeginPath(vg);
  212. nvgRoundedRect(vg, x+1,y+(int)(h*0.5f)-9, 18,18, 3);
  213. nvgFillPaint(vg, bg);
  214. nvgFill(vg);
  215. nvgFontSize(vg, 40);
  216. nvgFontFace(vg, "icons");
  217. nvgFillColor(vg, nvgRGBA(255,255,255,128));
  218. nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
  219. nvgText(vg, x+9+2, y+h*0.5f, cpToUTF8(ICON_CHECK,icon), NULL);
  220. }
  221. void drawButton(struct NVGcontext* vg, int preicon, const char* text, float x, float y, float w, float h, struct NVGcolor col)
  222. {
  223. struct NVGpaint bg;
  224. char icon[8];
  225. float cornerRadius = 4.0f;
  226. float tw = 0, iw = 0;
  227. bg = nvgLinearGradient(vg, x,y,x,y+h, nvgRGBA(255,255,255,isBlack(col)?16:32), nvgRGBA(0,0,0,isBlack(col)?16:32));
  228. nvgBeginPath(vg);
  229. nvgRoundedRect(vg, x+1,y+1, w-2,h-2, cornerRadius-1);
  230. if (!isBlack(col)) {
  231. nvgFillColor(vg, col);
  232. nvgFill(vg);
  233. }
  234. nvgFillPaint(vg, bg);
  235. nvgFill(vg);
  236. nvgBeginPath(vg);
  237. nvgRoundedRect(vg, x+0.5f,y+0.5f, w-1,h-1, cornerRadius-0.5f);
  238. nvgStrokeColor(vg, nvgRGBA(0,0,0,48));
  239. nvgStroke(vg);
  240. nvgFontSize(vg, 20.0f);
  241. nvgFontFace(vg, "sans-bold");
  242. tw = nvgTextBounds(vg, text, NULL, NULL);
  243. if (preicon != 0) {
  244. nvgFontSize(vg, h*1.3f);
  245. nvgFontFace(vg, "icons");
  246. iw = nvgTextBounds(vg, cpToUTF8(preicon,icon), NULL, NULL);
  247. iw += h*0.15f;
  248. }
  249. if (preicon != 0) {
  250. nvgFontSize(vg, h*1.3f);
  251. nvgFontFace(vg, "icons");
  252. nvgFillColor(vg, nvgRGBA(255,255,255,96));
  253. nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
  254. nvgText(vg, x+w*0.5f-tw*0.5f-iw*0.75f, y+h*0.5f, cpToUTF8(preicon,icon), NULL);
  255. }
  256. nvgFontSize(vg, 20.0f);
  257. nvgFontFace(vg, "sans-bold");
  258. nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
  259. nvgFillColor(vg, nvgRGBA(0,0,0,160));
  260. nvgText(vg, x+w*0.5f-tw*0.5f+iw*0.25f,y+h*0.5f-1,text, NULL);
  261. nvgFillColor(vg, nvgRGBA(255,255,255,160));
  262. nvgText(vg, x+w*0.5f-tw*0.5f+iw*0.25f,y+h*0.5f,text, NULL);
  263. }
  264. void drawSlider(struct NVGcontext* vg, float pos, float x, float y, float w, float h)
  265. {
  266. struct NVGpaint bg, knob;
  267. float cy = y+(int)(h*0.5f);
  268. float kr = (int)(h*0.25f);
  269. nvgSave(vg);
  270. // nvgClearState(vg);
  271. // Slot
  272. bg = nvgBoxGradient(vg, x,cy-2+1, w,4, 2,2, nvgRGBA(0,0,0,32), nvgRGBA(0,0,0,128));
  273. nvgBeginPath(vg);
  274. nvgRoundedRect(vg, x,cy-2, w,4, 2);
  275. nvgFillPaint(vg, bg);
  276. nvgFill(vg);
  277. // Knob Shadow
  278. bg = nvgRadialGradient(vg, x+(int)(pos*w),cy+1, kr-3,kr+3, nvgRGBA(0,0,0,64), nvgRGBA(0,0,0,0));
  279. nvgBeginPath(vg);
  280. nvgRect(vg, x+(int)(pos*w)-kr-5,cy-kr-5,kr*2+5+5,kr*2+5+5+3);
  281. nvgCircle(vg, x+(int)(pos*w),cy, kr);
  282. nvgPathWinding(vg, NVG_HOLE);
  283. nvgFillPaint(vg, bg);
  284. nvgFill(vg);
  285. // Knob
  286. knob = nvgLinearGradient(vg, x,cy-kr,x,cy+kr, nvgRGBA(255,255,255,16), nvgRGBA(0,0,0,16));
  287. nvgBeginPath(vg);
  288. nvgCircle(vg, x+(int)(pos*w),cy, kr-1);
  289. nvgFillColor(vg, nvgRGBA(40,43,48,255));
  290. nvgFill(vg);
  291. nvgFillPaint(vg, knob);
  292. nvgFill(vg);
  293. nvgBeginPath(vg);
  294. nvgCircle(vg, x+(int)(pos*w),cy, kr-0.5f);
  295. nvgStrokeColor(vg, nvgRGBA(0,0,0,92));
  296. nvgStroke(vg);
  297. nvgRestore(vg);
  298. }
  299. void drawEyes(struct NVGcontext* vg, float x, float y, float w, float h, float mx, float my, float t)
  300. {
  301. struct NVGpaint gloss, bg;
  302. float ex = w *0.23f;
  303. float ey = h * 0.5f;
  304. float lx = x + ex;
  305. float ly = y + ey;
  306. float rx = x + w - ex;
  307. float ry = y + ey;
  308. float dx,dy,d;
  309. float br = (ex < ey ? ex : ey) * 0.5f;
  310. float blink = 1 - pow(sinf(t*0.5f),200)*0.8f;
  311. bg = nvgLinearGradient(vg, x,y+h*0.5f,x+w*0.1f,y+h, nvgRGBA(0,0,0,32), nvgRGBA(0,0,0,16));
  312. nvgBeginPath(vg);
  313. nvgEllipse(vg, lx+3.0f,ly+16.0f, ex,ey);
  314. nvgEllipse(vg, rx+3.0f,ry+16.0f, ex,ey);
  315. nvgFillPaint(vg, bg);
  316. nvgFill(vg);
  317. bg = nvgLinearGradient(vg, x,y+h*0.25f,x+w*0.1f,y+h, nvgRGBA(220,220,220,255), nvgRGBA(128,128,128,255));
  318. nvgBeginPath(vg);
  319. nvgEllipse(vg, lx,ly, ex,ey);
  320. nvgEllipse(vg, rx,ry, ex,ey);
  321. nvgFillPaint(vg, bg);
  322. nvgFill(vg);
  323. dx = (mx - rx) / (ex * 10);
  324. dy = (my - ry) / (ey * 10);
  325. d = sqrtf(dx*dx+dy*dy);
  326. if (d > 1.0f) {
  327. dx /= d; dy /= d;
  328. }
  329. dx *= ex*0.4f;
  330. dy *= ey*0.5f;
  331. nvgBeginPath(vg);
  332. nvgEllipse(vg, lx+dx,ly+dy+ey*0.25f*(1-blink), br,br*blink);
  333. nvgFillColor(vg, nvgRGBA(32,32,32,255));
  334. nvgFill(vg);
  335. dx = (mx - rx) / (ex * 10);
  336. dy = (my - ry) / (ey * 10);
  337. d = sqrtf(dx*dx+dy*dy);
  338. if (d > 1.0f) {
  339. dx /= d; dy /= d;
  340. }
  341. dx *= ex*0.4f;
  342. dy *= ey*0.5f;
  343. nvgBeginPath(vg);
  344. nvgEllipse(vg, rx+dx,ry+dy+ey*0.25f*(1-blink), br,br*blink);
  345. nvgFillColor(vg, nvgRGBA(32,32,32,255));
  346. nvgFill(vg);
  347. 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));
  348. nvgBeginPath(vg);
  349. nvgEllipse(vg, lx,ly, ex,ey);
  350. nvgFillPaint(vg, gloss);
  351. nvgFill(vg);
  352. 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));
  353. nvgBeginPath(vg);
  354. nvgEllipse(vg, rx,ry, ex,ey);
  355. nvgFillPaint(vg, gloss);
  356. nvgFill(vg);
  357. }
  358. void drawGraph(struct NVGcontext* vg, float x, float y, float w, float h, float t)
  359. {
  360. struct NVGpaint bg;
  361. float samples[6];
  362. float sx[6], sy[6];
  363. float dx = w/5.0f;
  364. int i;
  365. samples[0] = (1+sinf(t*1.2345f+cosf(t*0.33457f)*0.44f))*0.5f;
  366. samples[1] = (1+sinf(t*0.68363f+cosf(t*1.3f)*1.55f))*0.5f;
  367. samples[2] = (1+sinf(t*1.1642f+cosf(t*0.33457)*1.24f))*0.5f;
  368. samples[3] = (1+sinf(t*0.56345f+cosf(t*1.63f)*0.14f))*0.5f;
  369. samples[4] = (1+sinf(t*1.6245f+cosf(t*0.254f)*0.3f))*0.5f;
  370. samples[5] = (1+sinf(t*0.345f+cosf(t*0.03f)*0.6f))*0.5f;
  371. for (i = 0; i < 6; i++) {
  372. sx[i] = x+i*dx;
  373. sy[i] = y+h*samples[i]*0.8f;
  374. }
  375. // Graph background
  376. bg = nvgLinearGradient(vg, x,y,x,y+h, nvgRGBA(0,160,192,0), nvgRGBA(0,160,192,64));
  377. nvgBeginPath(vg);
  378. nvgMoveTo(vg, sx[0], sy[0]);
  379. for (i = 1; i < 6; i++)
  380. nvgBezierTo(vg, sx[i-1]+dx*0.5f,sy[i-1], sx[i]-dx*0.5f,sy[i], sx[i],sy[i]);
  381. nvgLineTo(vg, x+w, y+h);
  382. nvgLineTo(vg, x, y+h);
  383. nvgFillPaint(vg, bg);
  384. nvgFill(vg);
  385. // Graph line
  386. nvgBeginPath(vg);
  387. nvgMoveTo(vg, sx[0], sy[0]+2);
  388. for (i = 1; i < 6; i++)
  389. 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);
  390. nvgStrokeColor(vg, nvgRGBA(0,0,0,32));
  391. nvgStrokeWidth(vg, 3.0f);
  392. nvgStroke(vg);
  393. nvgBeginPath(vg);
  394. nvgMoveTo(vg, sx[0], sy[0]);
  395. for (i = 1; i < 6; i++)
  396. nvgBezierTo(vg, sx[i-1]+dx*0.5f,sy[i-1], sx[i]-dx*0.5f,sy[i], sx[i],sy[i]);
  397. nvgStrokeColor(vg, nvgRGBA(0,160,192,255));
  398. nvgStrokeWidth(vg, 3.0f);
  399. nvgStroke(vg);
  400. // Graph sample pos
  401. for (i = 0; i < 6; i++) {
  402. bg = nvgRadialGradient(vg, sx[i],sy[i]+2, 3.0f,8.0f, nvgRGBA(0,0,0,32), nvgRGBA(0,0,0,0));
  403. nvgBeginPath(vg);
  404. nvgRect(vg, sx[i]-10, sy[i]-10+2, 20,20);
  405. nvgFillPaint(vg, bg);
  406. nvgFill(vg);
  407. }
  408. nvgBeginPath(vg);
  409. for (i = 0; i < 6; i++)
  410. nvgCircle(vg, sx[i], sy[i], 4.0f);
  411. nvgFillColor(vg, nvgRGBA(0,160,192,255));
  412. nvgFill(vg);
  413. nvgBeginPath(vg);
  414. for (i = 0; i < 6; i++)
  415. nvgCircle(vg, sx[i], sy[i], 2.0f);
  416. nvgFillColor(vg, nvgRGBA(220,220,220,255));
  417. nvgFill(vg);
  418. nvgStrokeWidth(vg, 1.0f);
  419. }
  420. void drawThumbnails(struct NVGcontext* vg, float x, float y, float w, float h, const int* images, int nimages, float t)
  421. {
  422. float cornerRadius = 3.0f;
  423. struct NVGpaint shadowPaint, imgPaint, fadePaint;
  424. float ix,iy,iw,ih;
  425. float thumb = 60.0f;
  426. float arry = 30.5f;
  427. int imgw, imgh;
  428. float stackh = (nimages/2) * (thumb+10) + 10;
  429. int i;
  430. float u = (1+cosf(t*0.5f))*0.5f;
  431. float scrollh;
  432. nvgSave(vg);
  433. // nvgClearState(vg);
  434. // Drop shadow
  435. shadowPaint = nvgBoxGradient(vg, x,y+4, w,h, cornerRadius*2, 20, nvgRGBA(0,0,0,128), nvgRGBA(0,0,0,0));
  436. nvgBeginPath(vg);
  437. nvgRect(vg, x-10,y-10, w+20,h+30);
  438. nvgRoundedRect(vg, x,y, w,h, cornerRadius);
  439. nvgPathWinding(vg, NVG_HOLE);
  440. nvgFillPaint(vg, shadowPaint);
  441. nvgFill(vg);
  442. // Window
  443. nvgBeginPath(vg);
  444. nvgRoundedRect(vg, x,y, w,h, cornerRadius);
  445. nvgMoveTo(vg, x-10,y+arry);
  446. nvgLineTo(vg, x+1,y+arry-11);
  447. nvgLineTo(vg, x+1,y+arry+11);
  448. nvgFillColor(vg, nvgRGBA(200,200,200,255));
  449. nvgFill(vg);
  450. nvgSave(vg);
  451. nvgScissor(vg, x,y,w,h);
  452. nvgTranslate(vg, 0, -(stackh - h)*u);
  453. for (i = 0; i < nimages; i++) {
  454. float tx, ty;
  455. tx = x+10;
  456. ty = y+10;
  457. tx += (i%2) * (thumb+10);
  458. ty += (i/2) * (thumb+10);
  459. nvgImageSize(vg, images[i], &imgw, &imgh);
  460. if (imgw < imgh) {
  461. iw = thumb;
  462. ih = iw * (float)imgh/(float)imgw;
  463. ix = 0;
  464. iy = -(ih-thumb)*0.5f;
  465. } else {
  466. ih = thumb;
  467. iw = ih * (float)imgw/(float)imgh;
  468. ix = -(iw-thumb)*0.5f;
  469. iy = 0;
  470. }
  471. imgPaint = nvgImagePattern(vg, tx+ix, ty+iy, iw,ih, 0.0f/180.0f*NVG_PI, images[i], 0);
  472. nvgBeginPath(vg);
  473. nvgRoundedRect(vg, tx,ty, thumb,thumb, 5);
  474. nvgFillPaint(vg, imgPaint);
  475. nvgFill(vg);
  476. shadowPaint = nvgBoxGradient(vg, tx-1,ty, thumb+2,thumb+2, 5, 3, nvgRGBA(0,0,0,128), nvgRGBA(0,0,0,0));
  477. nvgBeginPath(vg);
  478. nvgRect(vg, tx-5,ty-5, thumb+10,thumb+10);
  479. nvgRoundedRect(vg, tx,ty, thumb,thumb, 6);
  480. nvgPathWinding(vg, NVG_HOLE);
  481. nvgFillPaint(vg, shadowPaint);
  482. nvgFill(vg);
  483. nvgBeginPath(vg);
  484. nvgRoundedRect(vg, tx+0.5f,ty+0.5f, thumb-1,thumb-1, 4-0.5f);
  485. nvgStrokeWidth(vg,1.0f);
  486. nvgStrokeColor(vg, nvgRGBA(255,255,255,192));
  487. nvgStroke(vg);
  488. }
  489. nvgRestore(vg);
  490. // Hide fades
  491. fadePaint = nvgLinearGradient(vg, x,y,x,y+6, nvgRGBA(200,200,200,255), nvgRGBA(200,200,200,0));
  492. nvgBeginPath(vg);
  493. nvgRect(vg, x+4,y,w-8,6);
  494. nvgFillPaint(vg, fadePaint);
  495. nvgFill(vg);
  496. fadePaint = nvgLinearGradient(vg, x,y+h,x,y+h-6, nvgRGBA(200,200,200,255), nvgRGBA(200,200,200,0));
  497. nvgBeginPath(vg);
  498. nvgRect(vg, x+4,y+h-6,w-8,6);
  499. nvgFillPaint(vg, fadePaint);
  500. nvgFill(vg);
  501. // Scroll bar
  502. 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));
  503. nvgBeginPath(vg);
  504. nvgRoundedRect(vg, x+w-12,y+4, 8,h-8, 3);
  505. nvgFillPaint(vg, shadowPaint);
  506. // nvgFillColor(vg, nvgRGBA(255,0,0,128));
  507. nvgFill(vg);
  508. scrollh = (h/stackh) * (h-8);
  509. 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));
  510. nvgBeginPath(vg);
  511. nvgRoundedRect(vg, x+w-12+1,y+4+1 + (h-8-scrollh)*u, 8-2,scrollh-2, 2);
  512. nvgFillPaint(vg, shadowPaint);
  513. // nvgFillColor(vg, nvgRGBA(0,0,0,128));
  514. nvgFill(vg);
  515. nvgRestore(vg);
  516. }
  517. void drawColorwheel(struct NVGcontext* vg, float x, float y, float w, float h, float t)
  518. {
  519. int i;
  520. float r0, r1, ax,ay, bx,by, cx,cy, aeps, r;
  521. float hue = sinf(t * 0.12f);
  522. struct NVGpaint paint;
  523. nvgSave(vg);
  524. /* nvgBeginPath(vg);
  525. nvgRect(vg, x,y,w,h);
  526. nvgFillColor(vg, nvgRGBA(255,0,0,128));
  527. nvgFill(vg);*/
  528. cx = x + w*0.5f;
  529. cy = y + h*0.5f;
  530. r1 = (w < h ? w : h) * 0.5f - 5.0f;
  531. r0 = r1 - 20.0f;
  532. aeps = 0.5f / r1; // half a pixel arc length in radians (2pi cancels out).
  533. for (i = 0; i < 6; i++) {
  534. float a0 = (float)i / 6.0f * NVG_PI * 2.0f - aeps;
  535. float a1 = (float)(i+1.0f) / 6.0f * NVG_PI * 2.0f + aeps;
  536. nvgBeginPath(vg);
  537. nvgArc(vg, cx,cy, r0, a0, a1, NVG_CW);
  538. nvgArc(vg, cx,cy, r1, a1, a0, NVG_CCW);
  539. nvgClosePath(vg);
  540. ax = cx + cosf(a0) * (r0+r1)*0.5f;
  541. ay = cy + sinf(a0) * (r0+r1)*0.5f;
  542. bx = cx + cosf(a1) * (r0+r1)*0.5f;
  543. by = cy + sinf(a1) * (r0+r1)*0.5f;
  544. 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));
  545. nvgFillPaint(vg, paint);
  546. nvgFill(vg);
  547. }
  548. nvgBeginPath(vg);
  549. nvgCircle(vg, cx,cy, r0-0.5f);
  550. nvgCircle(vg, cx,cy, r1+0.5f);
  551. nvgStrokeColor(vg, nvgRGBA(0,0,0,64));
  552. nvgStrokeWidth(vg, 1.0f);
  553. nvgStroke(vg);
  554. // Selector
  555. nvgSave(vg);
  556. nvgTranslate(vg, cx,cy);
  557. nvgRotate(vg, hue*NVG_PI*2);
  558. // Marker on
  559. nvgStrokeWidth(vg, 2.0f);
  560. nvgBeginPath(vg);
  561. nvgRect(vg, r0-1,-3,r1-r0+2,6);
  562. nvgStrokeColor(vg, nvgRGBA(255,255,255,192));
  563. nvgStroke(vg);
  564. paint = nvgBoxGradient(vg, r0-3,-5,r1-r0+6,10, 2,4, nvgRGBA(0,0,0,128), nvgRGBA(0,0,0,0));
  565. nvgBeginPath(vg);
  566. nvgRect(vg, r0-2-10,-4-10,r1-r0+4+20,8+20);
  567. nvgRect(vg, r0-2,-4,r1-r0+4,8);
  568. nvgPathWinding(vg, NVG_HOLE);
  569. nvgFillPaint(vg, paint);
  570. nvgFill(vg);
  571. // Center triangle
  572. r = r0 - 6;
  573. ax = cosf(120.0f/180.0f*NVG_PI) * r;
  574. ay = sinf(120.0f/180.0f*NVG_PI) * r;
  575. bx = cosf(-120.0f/180.0f*NVG_PI) * r;
  576. by = sinf(-120.0f/180.0f*NVG_PI) * r;
  577. nvgBeginPath(vg);
  578. nvgMoveTo(vg, r,0);
  579. nvgLineTo(vg, ax,ay);
  580. nvgLineTo(vg, bx,by);
  581. nvgClosePath(vg);
  582. paint = nvgLinearGradient(vg, r,0, ax,ay, nvgHSLA(hue,1.0f,0.5f,255), nvgRGBA(255,255,255,255));
  583. nvgFillPaint(vg, paint);
  584. nvgFill(vg);
  585. paint = nvgLinearGradient(vg, (r+ax)*0.5f,(0+ay)*0.5f, bx,by, nvgRGBA(0,0,0,0), nvgRGBA(0,0,0,255));
  586. nvgFillPaint(vg, paint);
  587. nvgFill(vg);
  588. nvgStrokeColor(vg, nvgRGBA(0,0,0,64));
  589. nvgStroke(vg);
  590. // Select circle on triangle
  591. ax = cosf(120.0f/180.0f*NVG_PI) * r*0.3f;
  592. ay = sinf(120.0f/180.0f*NVG_PI) * r*0.4f;
  593. nvgStrokeWidth(vg, 2.0f);
  594. nvgBeginPath(vg);
  595. nvgCircle(vg, ax,ay,5);
  596. nvgStrokeColor(vg, nvgRGBA(255,255,255,192));
  597. nvgStroke(vg);
  598. paint = nvgRadialGradient(vg, ax,ay, 7,9, nvgRGBA(0,0,0,64), nvgRGBA(0,0,0,0));
  599. nvgBeginPath(vg);
  600. nvgRect(vg, ax-20,ay-20,40,40);
  601. nvgCircle(vg, ax,ay,7);
  602. nvgPathWinding(vg, NVG_HOLE);
  603. nvgFillPaint(vg, paint);
  604. nvgFill(vg);
  605. nvgRestore(vg);
  606. nvgRestore(vg);
  607. }
  608. void drawLines(struct NVGcontext* vg, float x, float y, float w, float h, float t)
  609. {
  610. int i, j;
  611. float pad = 5.0f, s = w/9.0f - pad*2;
  612. float pts[4*2], fx, fy;
  613. int joins[3] = {NVG_MITER, NVG_ROUND, NVG_BEVEL};
  614. int caps[3] = {NVG_BUTT, NVG_ROUND, NVG_SQUARE};
  615. NVG_NOTUSED(h);
  616. nvgSave(vg);
  617. pts[0] = -s*0.25f + cosf(t*0.3f) * s*0.5f;
  618. pts[1] = sinf(t*0.3f) * s*0.5f;
  619. pts[2] = -s*0.25;
  620. pts[3] = 0;
  621. pts[4] = s*0.25f;
  622. pts[5] = 0;
  623. pts[6] = s*0.25f + cosf(-t*0.3f) * s*0.5f;
  624. pts[7] = sinf(-t*0.3f) * s*0.5f;
  625. for (i = 0; i < 3; i++) {
  626. for (j = 0; j < 3; j++) {
  627. fx = x + s*0.5f + (i*3+j)/9.0f*w + pad;
  628. fy = y - s*0.5f + pad;
  629. nvgLineCap(vg, caps[i]);
  630. nvgLineJoin(vg, joins[j]);
  631. nvgStrokeWidth(vg, s*0.3f);
  632. nvgStrokeColor(vg, nvgRGBA(0,0,0,160));
  633. nvgBeginPath(vg);
  634. nvgMoveTo(vg, fx+pts[0], fy+pts[1]);
  635. nvgLineTo(vg, fx+pts[2], fy+pts[3]);
  636. nvgLineTo(vg, fx+pts[4], fy+pts[5]);
  637. nvgLineTo(vg, fx+pts[6], fy+pts[7]);
  638. nvgStroke(vg);
  639. nvgLineCap(vg, NVG_BUTT);
  640. nvgLineJoin(vg, NVG_BEVEL);
  641. nvgStrokeWidth(vg, 1.0f);
  642. nvgStrokeColor(vg, nvgRGBA(0,192,255,255));
  643. nvgBeginPath(vg);
  644. nvgMoveTo(vg, fx+pts[0], fy+pts[1]);
  645. nvgLineTo(vg, fx+pts[2], fy+pts[3]);
  646. nvgLineTo(vg, fx+pts[4], fy+pts[5]);
  647. nvgLineTo(vg, fx+pts[6], fy+pts[7]);
  648. nvgStroke(vg);
  649. }
  650. }
  651. nvgRestore(vg);
  652. }
  653. int loadDemoData(struct NVGcontext* vg, struct DemoData* data)
  654. {
  655. int i;
  656. if (vg == NULL)
  657. return -1;
  658. for (i = 0; i < 12; i++) {
  659. char file[128];
  660. snprintf(file, 128, "../example/images/image%d.jpg", i+1);
  661. data->images[i] = nvgCreateImage(vg, file);
  662. if (data->images[i] == 0) {
  663. printf("Could not load %s.\n", file);
  664. return -1;
  665. }
  666. }
  667. data->fontIcons = nvgCreateFont(vg, "icons", "../example/entypo.ttf");
  668. if (data->fontIcons == -1) {
  669. printf("Could not add font icons.\n");
  670. return -1;
  671. }
  672. data->fontNormal = nvgCreateFont(vg, "sans", "../example/Roboto-Regular.ttf");
  673. if (data->fontNormal == -1) {
  674. printf("Could not add font italic.\n");
  675. return -1;
  676. }
  677. data->fontBold = nvgCreateFont(vg, "sans-bold", "../example/Roboto-Bold.ttf");
  678. if (data->fontBold == -1) {
  679. printf("Could not add font bold.\n");
  680. return -1;
  681. }
  682. return 0;
  683. }
  684. void freeDemoData(struct NVGcontext* vg, struct DemoData* data)
  685. {
  686. int i;
  687. if (vg == NULL)
  688. return;
  689. for (i = 0; i < 12; i++)
  690. nvgDeleteImage(vg, data->images[i]);
  691. }
  692. void renderDemo(struct NVGcontext* vg, float mx, float my, float width, float height,
  693. float t, int blowup, struct DemoData* data)
  694. {
  695. float x,y,popy;
  696. drawEyes(vg, width - 250, 50, 150, 100, mx, my, t);
  697. drawGraph(vg, 0, height/2, width, height/2, t);
  698. drawColorwheel(vg, width - 300, height - 300, 250.0f, 250.0f, t);
  699. // Line joints
  700. drawLines(vg, 50, height-50, 600, 50, t);
  701. nvgSave(vg);
  702. if (blowup) {
  703. nvgRotate(vg, sinf(t*0.3f)*5.0f/180.0f*NVG_PI);
  704. nvgScale(vg, 2.0f, 2.0f);
  705. }
  706. // Widgets
  707. drawWindow(vg, "Widgets `n Stuff", 50, 50, 300, 400);
  708. x = 60; y = 95;
  709. drawSearchBox(vg, "Search", x,y,280,25);
  710. y += 40;
  711. drawDropDown(vg, "Effects", x,y,280,28);
  712. popy = y + 14;
  713. y += 45;
  714. // Form
  715. drawLabel(vg, "Login", x,y, 280,20);
  716. y += 25;
  717. drawEditBox(vg, "Email", x,y, 280,28);
  718. y += 35;
  719. drawEditBox(vg, "Password", x,y, 280,28);
  720. y += 38;
  721. drawCheckBox(vg, "Remember me", x,y, 140,28);
  722. drawButton(vg, ICON_LOGIN, "Sign in", x+138, y, 140, 28, nvgRGBA(0,96,128,255));
  723. y += 45;
  724. // Slider
  725. drawLabel(vg, "Diameter", x,y, 280,20);
  726. y += 25;
  727. drawEditBoxNum(vg, "123.00", "px", x+180,y, 100,28);
  728. drawSlider(vg, 0.4f, x,y, 170,28);
  729. y += 55;
  730. drawButton(vg, ICON_TRASH, "Delete", x, y, 160, 28, nvgRGBA(128,16,8,255));
  731. drawButton(vg, 0, "Cancel", x+170, y, 110, 28, nvgRGBA(0,0,0,0));
  732. // Thumbnails box
  733. drawThumbnails(vg, 365, popy-30, 160, 300, data->images, 12, t);
  734. nvgRestore(vg);
  735. }
  736. static int mini(int a, int b) { return a < b ? a : b; }
  737. static void unpremultiplyAlpha(unsigned char* image, int w, int h, int stride)
  738. {
  739. int x,y;
  740. // Unpremultiply
  741. for (y = 0; y < h; y++) {
  742. unsigned char *row = &image[y*stride];
  743. for (x = 0; x < w; x++) {
  744. int r = row[0], g = row[1], b = row[2], a = row[3];
  745. if (a != 0) {
  746. row[0] = (int)mini(r*255/a, 255);
  747. row[1] = (int)mini(g*255/a, 255);
  748. row[2] = (int)mini(b*255/a, 255);
  749. }
  750. row += 4;
  751. }
  752. }
  753. // Defringe
  754. for (y = 0; y < h; y++) {
  755. unsigned char *row = &image[y*stride];
  756. for (x = 0; x < w; x++) {
  757. int r = 0, g = 0, b = 0, a = row[3], n = 0;
  758. if (a == 0) {
  759. if (x-1 > 0 && row[-1] != 0) {
  760. r += row[-4];
  761. g += row[-3];
  762. b += row[-2];
  763. n++;
  764. }
  765. if (x+1 < w && row[7] != 0) {
  766. r += row[4];
  767. g += row[5];
  768. b += row[6];
  769. n++;
  770. }
  771. if (y-1 > 0 && row[-stride+3] != 0) {
  772. r += row[-stride];
  773. g += row[-stride+1];
  774. b += row[-stride+2];
  775. n++;
  776. }
  777. if (y+1 < h && row[stride+3] != 0) {
  778. r += row[stride];
  779. g += row[stride+1];
  780. b += row[stride+2];
  781. n++;
  782. }
  783. if (n > 0) {
  784. row[0] = r/n;
  785. row[1] = g/n;
  786. row[2] = b/n;
  787. }
  788. }
  789. row += 4;
  790. }
  791. }
  792. }
  793. static void setAlpha(unsigned char* image, int w, int h, int stride, unsigned char a)
  794. {
  795. int x, y;
  796. for (y = 0; y < h; y++) {
  797. unsigned char* row = &image[y*stride];
  798. for (x = 0; x < w; x++)
  799. row[x*4+3] = a;
  800. }
  801. }
  802. static void flipHorizontal(unsigned char* image, int w, int h, int stride)
  803. {
  804. int i = 0, j = h-1, k;
  805. while (i < j) {
  806. unsigned char* ri = &image[i * stride];
  807. unsigned char* rj = &image[j * stride];
  808. for (k = 0; k < w*4; k++) {
  809. unsigned char t = ri[k];
  810. ri[k] = rj[k];
  811. rj[k] = t;
  812. }
  813. i++;
  814. j--;
  815. }
  816. }
  817. void saveScreenShot(int w, int h, int premult, const char* name)
  818. {
  819. unsigned char* image = (unsigned char*)malloc(w*h*4);
  820. if (image == NULL)
  821. return;
  822. glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, image);
  823. if (premult)
  824. unpremultiplyAlpha(image, w, h, w*4);
  825. else
  826. setAlpha(image, w, h, w*4, 255);
  827. flipHorizontal(image, w, h, w*4);
  828. stbi_write_png(name, w, h, 4, image, w*4);
  829. free(image);
  830. }