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.

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