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.

883 lines
24KB

  1. //
  2. // Copyright (c) 2013 Mikko Mononen memon@inside.org
  3. //
  4. // This software is provided 'as-is', without any express or implied
  5. // warranty. In no event will the authors be held liable for any damages
  6. // arising from the use of this software.
  7. // Permission is granted to anyone to use this software for any purpose,
  8. // including commercial applications, and to alter it and redistribute it
  9. // freely, subject to the following restrictions:
  10. // 1. The origin of this software must not be misrepresented; you must not
  11. // claim that you wrote the original software. If you use this software
  12. // in a product, an acknowledgment in the product documentation would be
  13. // appreciated but is not required.
  14. // 2. Altered source versions must be plainly marked as such, and must not be
  15. // misrepresented as being the original software.
  16. // 3. This notice may not be removed or altered from any source distribution.
  17. //
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <iconv.h>
  21. #include <math.h>
  22. #ifdef NANOVG_GLEW
  23. # include <GL/glew.h>
  24. #endif
  25. #include <GLFW/glfw3.h>
  26. #include "nanovg.h"
  27. #define GLNANOVG_IMPLEMENTATION
  28. #include "glnanovg.h"
  29. #define ICON_SEARCH 0x1F50D
  30. #define ICON_CIRCLED_CROSS 0x2716
  31. #define ICON_CHEVRON_RIGHT 0xE75E
  32. #define ICON_CHECK 0x2713
  33. #define ICON_LOGIN 0xE740
  34. #define ICON_TRASH 0xE729
  35. static char* cpToUTF8(int cp, char* str)
  36. {
  37. int n = 0;
  38. if (cp < 0x80) n = 1;
  39. else if (cp < 0x800) n = 2;
  40. else if (cp < 0x10000) n = 3;
  41. else if (cp < 0x200000) n = 4;
  42. else if (cp < 0x4000000) n = 5;
  43. else if (cp <= 0x7fffffff) n = 6;
  44. str[n] = '\0';
  45. switch (n) {
  46. case 6: str[5] = 0x80 | (cp & 0x3f); cp = cp >> 6; cp |= 0x4000000;
  47. case 5: str[4] = 0x80 | (cp & 0x3f); cp = cp >> 6; cp |= 0x200000;
  48. case 4: str[3] = 0x80 | (cp & 0x3f); cp = cp >> 6; cp |= 0x10000;
  49. case 3: str[2] = 0x80 | (cp & 0x3f); cp = cp >> 6; cp |= 0x800;
  50. case 2: str[1] = 0x80 | (cp & 0x3f); cp = cp >> 6; cp |= 0xc0;
  51. case 1: str[0] = cp;
  52. }
  53. return str;
  54. }
  55. void drawWindow(struct NVGcontext* vg, const char* title, float x, float y, float w, float h)
  56. {
  57. float cornerRadius = 3.0f;
  58. struct NVGpaint shadowPaint;
  59. struct NVGpaint headerPaint;
  60. nvgSave(vg);
  61. // nvgClearState(vg);
  62. // Window
  63. nvgBeginPath(vg);
  64. nvgRoundedRect(vg, x,y, w,h, cornerRadius);
  65. nvgFillColor(vg, nvgRGBA(28,30,34,192));
  66. // nvgFillColor(vg, nvgRGBA(0,0,0,128));
  67. nvgFill(vg);
  68. // Drop shadow
  69. shadowPaint = nvgBoxGradient(vg, x,y+2, w,h, cornerRadius*2, 10, nvgRGBA(0,0,0,128), nvgRGBA(0,0,0,0));
  70. nvgBeginPath(vg);
  71. nvgRect(vg, x-10,y-10, w+20,h+30);
  72. nvgRoundedRect(vg, x,y, w,h, cornerRadius);
  73. nvgPathWinding(vg, NVG_HOLE);
  74. nvgFillPaint(vg, shadowPaint);
  75. nvgFill(vg);
  76. // Header
  77. headerPaint = nvgLinearGradient(vg, x,y,x,y+15, nvgRGBA(255,255,255,8), nvgRGBA(0,0,0,16));
  78. nvgBeginPath(vg);
  79. nvgRoundedRect(vg, x+1,y+1, w-2,30, cornerRadius-1);
  80. nvgFillPaint(vg, headerPaint);
  81. nvgFill(vg);
  82. nvgBeginPath(vg);
  83. nvgMoveTo(vg, x+0.5f, y+0.5f+30);
  84. nvgLineTo(vg, x+0.5f+w-1, y+0.5f+30);
  85. nvgStrokeColor(vg, nvgRGBA(0,0,0,32));
  86. nvgStroke(vg);
  87. nvgFontSize(vg, 18.0f);
  88. nvgFontFace(vg, "sans-bold");
  89. nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
  90. nvgFontBlur(vg,2);
  91. nvgFillColor(vg, nvgRGBA(0,0,0,128));
  92. nvgText(vg, x+w/2,y+16+1, title, NULL);
  93. nvgFontBlur(vg,0);
  94. nvgFillColor(vg, nvgRGBA(220,220,220,160));
  95. nvgText(vg, x+w/2,y+16, title, NULL);
  96. nvgRestore(vg);
  97. }
  98. void drawSearchBox(struct NVGcontext* vg, const char* text, float x, float y, float w, float h)
  99. {
  100. struct NVGpaint bg;
  101. char icon[8];
  102. float cornerRadius = h/2-1;
  103. // Edit
  104. bg = nvgBoxGradient(vg, x,y+1.5f, w,h, h/2,5, nvgRGBA(0,0,0,16), nvgRGBA(0,0,0,92));
  105. nvgBeginPath(vg);
  106. nvgRoundedRect(vg, x,y, w,h, cornerRadius);
  107. nvgFillPaint(vg, bg);
  108. nvgFill(vg);
  109. /* nvgBeginPath(vg);
  110. nvgRoundedRect(vg, x+0.5f,y+0.5f, w-1,h-1, cornerRadius-0.5f);
  111. nvgStrokeColor(vg, nvgRGBA(0,0,0,48));
  112. nvgStroke(vg);*/
  113. nvgFontSize(vg, h*1.3f);
  114. nvgFontFace(vg, "icons");
  115. nvgFillColor(vg, nvgRGBA(255,255,255,64));
  116. nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
  117. nvgText(vg, x+h*0.55f, y+h*0.55f, cpToUTF8(ICON_SEARCH,icon), NULL);
  118. nvgFontSize(vg, 20.0f);
  119. nvgFontFace(vg, "sans");
  120. nvgFillColor(vg, nvgRGBA(255,255,255,32));
  121. nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
  122. nvgText(vg, x+h*1.05f,y+h*0.5f,text, NULL);
  123. nvgFontSize(vg, h*1.3f);
  124. nvgFontFace(vg, "icons");
  125. nvgFillColor(vg, nvgRGBA(255,255,255,32));
  126. nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
  127. nvgText(vg, x+w-h*0.55f, y+h*0.55f, cpToUTF8(ICON_CIRCLED_CROSS,icon), NULL);
  128. }
  129. void drawDropDown(struct NVGcontext* vg, const char* text, float x, float y, float w, float h)
  130. {
  131. struct NVGpaint bg;
  132. char icon[8];
  133. float cornerRadius = 4.0f;
  134. bg = nvgLinearGradient(vg, x,y,x,y+h, nvgRGBA(255,255,255,16), nvgRGBA(0,0,0,16));
  135. nvgBeginPath(vg);
  136. nvgRoundedRect(vg, x+1,y+1, w-2,h-2, cornerRadius-1);
  137. nvgFillPaint(vg, bg);
  138. nvgFill(vg);
  139. nvgBeginPath(vg);
  140. nvgRoundedRect(vg, x+0.5f,y+0.5f, w-1,h-1, cornerRadius-0.5f);
  141. nvgStrokeColor(vg, nvgRGBA(0,0,0,48));
  142. nvgStroke(vg);
  143. nvgFontSize(vg, 20.0f);
  144. nvgFontFace(vg, "sans");
  145. nvgFillColor(vg, nvgRGBA(255,255,255,160));
  146. nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
  147. nvgText(vg, x+h*0.3f,y+h*0.5f,text, NULL);
  148. nvgFontSize(vg, h*1.3f);
  149. nvgFontFace(vg, "icons");
  150. nvgFillColor(vg, nvgRGBA(255,255,255,64));
  151. nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
  152. nvgText(vg, x+w-h*0.5f, y+h*0.5f, cpToUTF8(ICON_CHEVRON_RIGHT,icon), NULL);
  153. }
  154. void drawLabel(struct NVGcontext* vg, const char* text, float x, float y, float w, float h)
  155. {
  156. nvgFontSize(vg, 18.0f);
  157. nvgFontFace(vg, "sans");
  158. nvgFillColor(vg, nvgRGBA(255,255,255,128));
  159. nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
  160. nvgText(vg, x,y+h*0.5f,text, NULL);
  161. }
  162. void drawEditBoxBase(struct NVGcontext* vg, float x, float y, float w, float h)
  163. {
  164. struct NVGpaint bg;
  165. // Edit
  166. 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));
  167. nvgBeginPath(vg);
  168. nvgRoundedRect(vg, x+1,y+1, w-2,h-2, 4-1);
  169. nvgFillPaint(vg, bg);
  170. nvgFill(vg);
  171. nvgBeginPath(vg);
  172. nvgRoundedRect(vg, x+0.5f,y+0.5f, w-1,h-1, 4-0.5f);
  173. nvgStrokeColor(vg, nvgRGBA(0,0,0,48));
  174. nvgStroke(vg);
  175. }
  176. void drawEditBox(struct NVGcontext* vg, const char* text, float x, float y, float w, float h)
  177. {
  178. drawEditBoxBase(vg, x,y, w,h);
  179. nvgFontSize(vg, 20.0f);
  180. nvgFontFace(vg, "sans");
  181. nvgFillColor(vg, nvgRGBA(255,255,255,64));
  182. nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
  183. nvgText(vg, x+h*0.3f,y+h*0.5f,text, NULL);
  184. }
  185. void drawEditBoxNum(struct NVGcontext* vg,
  186. const char* text, const char* units, float x, float y, float w, float h)
  187. {
  188. float uw;
  189. drawEditBoxBase(vg, x,y, w,h);
  190. uw = nvgTextBounds(vg, units, NULL, NULL);
  191. nvgFontSize(vg, 18.0f);
  192. nvgFontFace(vg, "sans");
  193. nvgFillColor(vg, nvgRGBA(255,255,255,64));
  194. nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_MIDDLE);
  195. nvgText(vg, x+w-h*0.3f,y+h*0.5f,units, NULL);
  196. nvgFontSize(vg, 20.0f);
  197. nvgFontFace(vg, "sans");
  198. nvgFillColor(vg, nvgRGBA(255,255,255,128));
  199. nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_MIDDLE);
  200. nvgText(vg, x+w-uw-h*0.5f,y+h*0.5f,text, NULL);
  201. }
  202. void drawCheckBox(struct NVGcontext* vg, const char* text, float x, float y, float w, float h)
  203. {
  204. struct NVGpaint bg;
  205. char icon[8];
  206. nvgFontSize(vg, 18.0f);
  207. nvgFontFace(vg, "sans");
  208. nvgFillColor(vg, nvgRGBA(255,255,255,160));
  209. nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
  210. nvgText(vg, x+28,y+h*0.5f,text, NULL);
  211. 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));
  212. nvgBeginPath(vg);
  213. nvgRoundedRect(vg, x+1,y+(int)(h*0.5f)-9, 18,18, 3);
  214. nvgFillPaint(vg, bg);
  215. nvgFill(vg);
  216. nvgFontSize(vg, 40);
  217. nvgFontFace(vg, "icons");
  218. nvgFillColor(vg, nvgRGBA(255,255,255,128));
  219. nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
  220. nvgText(vg, x+9+2, y+h*0.5f, cpToUTF8(ICON_CHECK,icon), NULL);
  221. }
  222. void drawButton(struct NVGcontext* vg, int preicon, const char* text, float x, float y, float w, float h, unsigned int col)
  223. {
  224. struct NVGpaint bg;
  225. char icon[8];
  226. float cornerRadius = 4.0f;
  227. float tw = 0, iw = 0;
  228. bg = nvgLinearGradient(vg, x,y,x,y+h, nvgRGBA(255,255,255,col==0?16:32), nvgRGBA(0,0,0,col==0?16:32));
  229. nvgBeginPath(vg);
  230. nvgRoundedRect(vg, x+1,y+1, w-2,h-2, cornerRadius-1);
  231. if (col != 0) {
  232. nvgFillColor(vg, col);
  233. nvgFill(vg);
  234. }
  235. nvgFillPaint(vg, bg);
  236. nvgFill(vg);
  237. nvgBeginPath(vg);
  238. nvgRoundedRect(vg, x+0.5f,y+0.5f, w-1,h-1, cornerRadius-0.5f);
  239. nvgStrokeColor(vg, nvgRGBA(0,0,0,48));
  240. nvgStroke(vg);
  241. nvgFontSize(vg, 20.0f);
  242. nvgFontFace(vg, "sans-bold");
  243. tw = nvgTextBounds(vg, text, NULL, NULL);
  244. if (preicon != 0) {
  245. nvgFontSize(vg, h*1.3f);
  246. nvgFontFace(vg, "icons");
  247. iw = nvgTextBounds(vg, cpToUTF8(preicon,icon), NULL, NULL);
  248. iw += h*0.15f;
  249. }
  250. if (preicon != 0) {
  251. nvgFontSize(vg, h*1.3f);
  252. nvgFontFace(vg, "icons");
  253. nvgFillColor(vg, nvgRGBA(255,255,255,96));
  254. nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
  255. nvgText(vg, x+w*0.5f-tw*0.5f-iw*0.75f, y+h*0.5f, cpToUTF8(preicon,icon), NULL);
  256. }
  257. nvgFontSize(vg, 20.0f);
  258. nvgFontFace(vg, "sans-bold");
  259. nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
  260. nvgFillColor(vg, nvgRGBA(0,0,0,160));
  261. nvgText(vg, x+w*0.5f-tw*0.5f+iw*0.25f,y+h*0.5f-1,text, NULL);
  262. nvgFillColor(vg, nvgRGBA(255,255,255,160));
  263. nvgText(vg, x+w*0.5f-tw*0.5f+iw*0.25f,y+h*0.5f,text, NULL);
  264. }
  265. void drawSlider(struct NVGcontext* vg, float pos, float x, float y, float w, float h)
  266. {
  267. struct NVGpaint bg, knob;
  268. float cy = y+(int)(h*0.5f);
  269. float kr = (int)(h*0.25f);
  270. nvgSave(vg);
  271. // nvgClearState(vg);
  272. // Slot
  273. bg = nvgBoxGradient(vg, x,cy-2+1, w,4, 2,2, nvgRGBA(0,0,0,32), nvgRGBA(0,0,0,128));
  274. nvgBeginPath(vg);
  275. nvgRoundedRect(vg, x,cy-2, w,4, 2);
  276. nvgFillPaint(vg, bg);
  277. nvgFill(vg);
  278. // Knob Shadow
  279. bg = nvgRadialGradient(vg, x+(int)(pos*w),cy+1, kr-3,kr+3, nvgRGBA(0,0,0,64), nvgRGBA(0,0,0,0));
  280. nvgBeginPath(vg);
  281. nvgRect(vg, x+(int)(pos*w)-kr-5,cy-kr-5,kr*2+5+5,kr*2+5+5+3);
  282. nvgCircle(vg, x+(int)(pos*w),cy, kr);
  283. nvgPathWinding(vg, NVG_HOLE);
  284. nvgFillPaint(vg, bg);
  285. nvgFill(vg);
  286. // Knob
  287. knob = nvgLinearGradient(vg, x,cy-kr,x,cy+kr, nvgRGBA(255,255,255,16), nvgRGBA(0,0,0,16));
  288. nvgBeginPath(vg);
  289. nvgCircle(vg, x+(int)(pos*w),cy, kr-1);
  290. nvgFillColor(vg, nvgRGBA(40,43,48,255));
  291. nvgFill(vg);
  292. nvgFillPaint(vg, knob);
  293. nvgFill(vg);
  294. nvgBeginPath(vg);
  295. nvgCircle(vg, x+(int)(pos*w),cy, kr-0.5f);
  296. nvgStrokeColor(vg, nvgRGBA(0,0,0,92));
  297. nvgStroke(vg);
  298. nvgRestore(vg);
  299. }
  300. void drawEyes(struct NVGcontext* vg, float x, float y, float w, float h, float mx, float my, float t)
  301. {
  302. struct NVGpaint gloss, bg;
  303. float ex = w *0.23f;
  304. float ey = h * 0.5f;
  305. float lx = x + ex;
  306. float ly = y + ey;
  307. float rx = x + w - ex;
  308. float ry = y + ey;
  309. float dx,dy,d;
  310. float br = (ex < ey ? ex : ey) * 0.5f;
  311. float blink = 1 - pow(sinf(t*0.5f),200)*0.8f;
  312. bg = nvgLinearGradient(vg, x,y+h*0.5f,x+w*0.1f,y+h, nvgRGBA(0,0,0,32), nvgRGBA(0,0,0,16));
  313. nvgBeginPath(vg);
  314. nvgEllipse(vg, lx+3.0f,ly+16.0f, ex,ey);
  315. nvgEllipse(vg, rx+3.0f,ry+16.0f, ex,ey);
  316. nvgFillPaint(vg, bg);
  317. nvgFill(vg);
  318. bg = nvgLinearGradient(vg, x,y+h*0.25f,x+w*0.1f,y+h, nvgRGBA(220,220,220,255), nvgRGBA(128,128,128,255));
  319. nvgBeginPath(vg);
  320. nvgEllipse(vg, lx,ly, ex,ey);
  321. nvgEllipse(vg, rx,ry, ex,ey);
  322. nvgFillPaint(vg, bg);
  323. nvgFill(vg);
  324. dx = (mx - rx) / (ex * 10);
  325. dy = (my - ry) / (ey * 10);
  326. d = sqrtf(dx*dx+dy*dy);
  327. if (d > 1.0f) {
  328. dx /= d; dy /= d;
  329. }
  330. dx *= ex*0.4f;
  331. dy *= ey*0.5f;
  332. nvgBeginPath(vg);
  333. nvgEllipse(vg, lx+dx,ly+dy+ey*0.25f*(1-blink), br,br*blink);
  334. nvgFillColor(vg, nvgRGBA(32,32,32,255));
  335. nvgFill(vg);
  336. dx = (mx - rx) / (ex * 10);
  337. dy = (my - ry) / (ey * 10);
  338. d = sqrtf(dx*dx+dy*dy);
  339. if (d > 1.0f) {
  340. dx /= d; dy /= d;
  341. }
  342. dx *= ex*0.4f;
  343. dy *= ey*0.5f;
  344. nvgBeginPath(vg);
  345. nvgEllipse(vg, rx+dx,ry+dy+ey*0.25f*(1-blink), br,br*blink);
  346. nvgFillColor(vg, nvgRGBA(32,32,32,255));
  347. nvgFill(vg);
  348. 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));
  349. nvgBeginPath(vg);
  350. nvgEllipse(vg, lx,ly, ex,ey);
  351. nvgFillPaint(vg, gloss);
  352. nvgFill(vg);
  353. 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));
  354. nvgBeginPath(vg);
  355. nvgEllipse(vg, rx,ry, ex,ey);
  356. nvgFillPaint(vg, gloss);
  357. nvgFill(vg);
  358. }
  359. void drawGraph(struct NVGcontext* vg, float x, float y, float w, float h, float t)
  360. {
  361. struct NVGpaint bg;
  362. float samples[6];
  363. float sx[6], sy[6];
  364. float dx = w/5.0f;
  365. int i;
  366. samples[0] = (1+sinf(t*1.2345f+cosf(t*0.33457f)*0.44f))*0.5f;
  367. samples[1] = (1+sinf(t*0.68363f+cosf(t*1.3f)*1.55f))*0.5f;
  368. samples[2] = (1+sinf(t*1.1642f+cosf(t*0.33457)*1.24f))*0.5f;
  369. samples[3] = (1+sinf(t*0.56345f+cosf(t*1.63f)*0.14f))*0.5f;
  370. samples[4] = (1+sinf(t*1.6245f+cosf(t*0.254f)*0.3f))*0.5f;
  371. samples[5] = (1+sinf(t*0.345f+cosf(t*0.03f)*0.6f))*0.5f;
  372. for (i = 0; i < 6; i++) {
  373. sx[i] = x+i*dx;
  374. sy[i] = y+h*samples[i]*0.8f;
  375. }
  376. // Graph background
  377. bg = nvgLinearGradient(vg, x,y,x,y+h, nvgRGBA(0,160,192,0), nvgRGBA(0,160,192,64));
  378. nvgBeginPath(vg);
  379. nvgMoveTo(vg, sx[0], sy[0]);
  380. for (i = 1; i < 6; i++)
  381. nvgBezierTo(vg, sx[i-1]+dx*0.5f,sy[i-1], sx[i]-dx*0.5f,sy[i], sx[i],sy[i]);
  382. nvgLineTo(vg, x+w, y+h);
  383. nvgLineTo(vg, x, y+h);
  384. nvgFillPaint(vg, bg);
  385. nvgFill(vg);
  386. // Graph line
  387. nvgBeginPath(vg);
  388. nvgMoveTo(vg, sx[0], sy[0]+2);
  389. for (i = 1; i < 6; i++)
  390. 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);
  391. nvgStrokeColor(vg, nvgRGBA(0,0,0,32));
  392. nvgStrokeWidth(vg, 3.0f);
  393. nvgStroke(vg);
  394. nvgBeginPath(vg);
  395. nvgMoveTo(vg, sx[0], sy[0]);
  396. for (i = 1; i < 6; i++)
  397. nvgBezierTo(vg, sx[i-1]+dx*0.5f,sy[i-1], sx[i]-dx*0.5f,sy[i], sx[i],sy[i]);
  398. nvgStrokeColor(vg, nvgRGBA(0,160,192,255));
  399. nvgStrokeWidth(vg, 3.0f);
  400. nvgStroke(vg);
  401. // Graph sample pos
  402. for (i = 0; i < 6; i++) {
  403. bg = nvgRadialGradient(vg, sx[i],sy[i]+2, 3.0f,8.0f, nvgRGBA(0,0,0,32), nvgRGBA(0,0,0,0));
  404. nvgBeginPath(vg);
  405. nvgRect(vg, sx[i]-10, sy[i]-10+2, 20,20);
  406. nvgFillPaint(vg, bg);
  407. nvgFill(vg);
  408. }
  409. nvgBeginPath(vg);
  410. for (i = 0; i < 6; i++)
  411. nvgCircle(vg, sx[i], sy[i], 4.0f);
  412. nvgFillColor(vg, nvgRGBA(0,160,192,255));
  413. nvgFill(vg);
  414. nvgBeginPath(vg);
  415. for (i = 0; i < 6; i++)
  416. nvgCircle(vg, sx[i], sy[i], 2.0f);
  417. nvgFillColor(vg, nvgRGBA(220,220,220,255));
  418. nvgFill(vg);
  419. nvgStrokeWidth(vg, 1.0f);
  420. }
  421. void drawThumbnails(struct NVGcontext* vg, float x, float y, float w, float h, const int* images, int nimages, float t)
  422. {
  423. float cornerRadius = 3.0f;
  424. struct NVGpaint shadowPaint, imgPaint, fadePaint;
  425. float ix,iy,iw,ih;
  426. float thumb = 60.0f;
  427. float arry = 30.5f;
  428. int imgw, imgh;
  429. float stackh = (nimages/2) * (thumb+10) + 10;
  430. int i;
  431. float u = (1+cosf(t*0.5f))*0.5f;
  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. float 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-1);
  550. nvgCircle(vg, cx,cy, r1+1);
  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-3-10,-5-10,r1-r0+6+20,10+20);
  567. nvgRect(vg, r0-3,-5,r1-r0+6,10);
  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 errorcb(int error, const char* desc)
  609. {
  610. printf("GLFW error: %s\n", desc);
  611. }
  612. int blowup = 0;
  613. static void key(GLFWwindow* window, int key, int scancode, int action, int mods)
  614. {
  615. if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
  616. glfwSetWindowShouldClose(window, GL_TRUE);
  617. if (key == GLFW_KEY_SPACE && action == GLFW_PRESS)
  618. blowup = !blowup;
  619. }
  620. int main()
  621. {
  622. GLFWwindow* window;
  623. int fontNormal = -1, fontBold = -1, fontIcons = -1;
  624. struct NVGcontext* vg = NULL;
  625. int images[12];
  626. int i;
  627. if (!glfwInit()) {
  628. printf("Failed to init GLFW.");
  629. return -1;
  630. }
  631. glfwSetErrorCallback(errorcb);
  632. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
  633. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
  634. window = glfwCreateWindow(1000, 600, "NanoVG", NULL, NULL);
  635. if (!window) {
  636. glfwTerminate();
  637. return -1;
  638. }
  639. glfwSetKeyCallback(window, key);
  640. glfwMakeContextCurrent(window);
  641. #ifdef NANOVG_GLEW
  642. if(glewInit() != GLEW_OK) {
  643. printf("Could not init glew.\n");
  644. return -1;
  645. }
  646. #endif
  647. vg = glnvgCreate(512,512);
  648. if (vg == NULL) {
  649. printf("Could not init nanovg.\n");
  650. return -1;
  651. }
  652. for (i = 0; i < 12; i++) {
  653. char file[128];
  654. snprintf(file, 128, "../example/images/image%d.jpg", i+1);
  655. images[i] = nvgCreateImage(vg, file);
  656. if (images[i] == 0) {
  657. printf("Could not load %s.\n", file);
  658. return -1;
  659. }
  660. }
  661. fontIcons = nvgCreateFont(vg, "icons", "../example/entypo.ttf");
  662. if (fontIcons == -1) {
  663. printf("Could not add font icons.\n");
  664. return -1;
  665. }
  666. fontNormal = nvgCreateFont(vg, "sans", "../example/Roboto-Regular.ttf");
  667. // fontNormal = nvgAddFont(vg, "sans", "../example/FiraSans-Regular.ttf");
  668. if (fontNormal == -1) {
  669. printf("Could not add font italic.\n");
  670. return -1;
  671. }
  672. fontBold = nvgCreateFont(vg, "sans-bold", "../example/Roboto-Bold.ttf");
  673. // fontBold = nvgAddFont(vg, "sans-bold", "../example/FiraSans-Bold.ttf");
  674. if (fontBold == -1) {
  675. printf("Could not add font bold.\n");
  676. return -1;
  677. }
  678. glfwSetTime(0);
  679. while (!glfwWindowShouldClose(window))
  680. {
  681. // float sx, sy, dx, dy, lh = 0;
  682. double mx, my;
  683. int width, height;
  684. glfwGetCursorPos(window, &mx, &my);
  685. glfwGetFramebufferSize(window, &width, &height);
  686. // Update and render
  687. glViewport(0, 0, width, height);
  688. glClearColor(0.3f, 0.3f, 0.32f, 1.0f);
  689. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
  690. glEnable(GL_BLEND);
  691. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  692. glEnable(GL_CULL_FACE);
  693. glDisable(GL_TEXTURE_2D);
  694. glMatrixMode(GL_PROJECTION);
  695. glLoadIdentity();
  696. glOrtho(0,width,height,0,-1,1);
  697. glMatrixMode(GL_MODELVIEW);
  698. glLoadIdentity();
  699. glDisable(GL_DEPTH_TEST);
  700. glColor4ub(255,255,255,255);
  701. glEnable(GL_BLEND);
  702. glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
  703. float t = glfwGetTime();
  704. float x,y,popy;
  705. nvgBeginFrame(vg);
  706. drawEyes(vg, width - 250, 50, 150, 100, mx, my, t);
  707. drawGraph(vg, 0, height/2, width, height/2, t);
  708. drawColorwheel(vg, width - 300, height - 300, 250.0f, 250.0f, t);
  709. nvgSave(vg);
  710. if (blowup) {
  711. // nvgRotate(vg, 3.0f/180.0f*NVG_PI);
  712. nvgScale(vg, 2.0f, 2.0f);
  713. }
  714. // Widgets
  715. drawWindow(vg, "Widgets `n Stuff", 50, 50, 300, 400);
  716. x = 60; y = 95;
  717. drawSearchBox(vg, "Search", x,y,280,25);
  718. y += 40;
  719. drawDropDown(vg, "Effects", x,y,280,28);
  720. popy = y + 14;
  721. y += 45;
  722. // Form
  723. drawLabel(vg, "Login", x,y, 280,20);
  724. y += 25;
  725. drawEditBox(vg, "Email", x,y, 280,28);
  726. y += 35;
  727. drawEditBox(vg, "Password", x,y, 280,28);
  728. y += 38;
  729. drawCheckBox(vg, "Remember me", x,y, 140,28);
  730. drawButton(vg, ICON_LOGIN, "Sign in", x+138, y, 140, 28, nvgRGBA(0,96,128,255));
  731. y += 45;
  732. // Slider
  733. drawLabel(vg, "Diameter", x,y, 280,20);
  734. y += 25;
  735. drawEditBoxNum(vg, "123.00", "px", x+180,y, 100,28);
  736. drawSlider(vg, 0.4f, x,y, 170,28);
  737. y += 55;
  738. drawButton(vg, ICON_TRASH, "Delete", x, y, 160, 28, nvgRGBA(128,16,8,255));
  739. drawButton(vg, 0, "Cancel", x+170, y, 110, 28, nvgRGBA(0,0,0,0));
  740. // Thumbnails box
  741. drawThumbnails(vg, 365, popy-30, 160, 300, images, 12, t);
  742. nvgRestore(vg);
  743. glEnable(GL_DEPTH_TEST);
  744. glfwSwapBuffers(window);
  745. glfwPollEvents();
  746. }
  747. for (i = 0; i < 12; i++)
  748. nvgDeleteImage(vg, images[i]);
  749. glnvgDelete(vg);
  750. glfwTerminate();
  751. return 0;
  752. }