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.

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