DPF OpenGL examples
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.

1217 lines
31KB

  1. #include "demo.h"
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <math.h>
  5. #include "nanovg.h"
  6. #define STB_IMAGE_WRITE_IMPLEMENTATION
  7. #include "stb_image_write.h"
  8. #ifdef _MSC_VER
  9. #define snprintf _snprintf
  10. #elif !defined(__MINGW32__)
  11. #include <iconv.h>
  12. #endif
  13. #define ICON_SEARCH 0x1F50D
  14. #define ICON_CIRCLED_CROSS 0x2716
  15. #define ICON_CHEVRON_RIGHT 0xE75E
  16. #define ICON_CHECK 0x2713
  17. #define ICON_LOGIN 0xE740
  18. #define ICON_TRASH 0xE729
  19. //static float minf(float a, float b) { return a < b ? a : b; }
  20. static float maxf(float a, float b) { return a > b ? a : b; }
  21. //static float absf(float a) { return a >= 0.0f ? a : -a; }
  22. static float clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); }
  23. // Returns 1 if col.rgba is 0.0f,0.0f,0.0f,0.0f, 0 otherwise
  24. int isBlack(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(NVGcontext* vg, const char* title, float x, float y, float w, float h)
  53. {
  54. float cornerRadius = 3.0f;
  55. NVGpaint shadowPaint;
  56. 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(NVGcontext* vg, const char* text, float x, float y, float w, float h)
  96. {
  97. 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(NVGcontext* vg, const char* text, float x, float y, float w, float h)
  127. {
  128. 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(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(NVGcontext* vg, float x, float y, float w, float h)
  161. {
  162. 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(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(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, 0,0, 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(NVGcontext* vg, const char* text, float x, float y, float w, float h)
  201. {
  202. 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(NVGcontext* vg, int preicon, const char* text, float x, float y, float w, float h, NVGcolor col)
  222. {
  223. 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, 0,0, text, NULL, NULL);
  243. if (preicon != 0) {
  244. nvgFontSize(vg, h*1.3f);
  245. nvgFontFace(vg, "icons");
  246. iw = nvgTextBounds(vg, 0,0, 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(NVGcontext* vg, float pos, float x, float y, float w, float h)
  265. {
  266. 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(NVGcontext* vg, float x, float y, float w, float h, float mx, float my, float t)
  300. {
  301. 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(NVGcontext* vg, float x, float y, float w, float h, float t)
  359. {
  360. 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 drawSpinner(NVGcontext* vg, float cx, float cy, float r, float t)
  421. {
  422. float a0 = 0.0f + t*6;
  423. float a1 = NVG_PI + t*6;
  424. float r0 = r;
  425. float r1 = r * 0.75f;
  426. float ax,ay, bx,by;
  427. NVGpaint paint;
  428. nvgSave(vg);
  429. nvgBeginPath(vg);
  430. nvgArc(vg, cx,cy, r0, a0, a1, NVG_CW);
  431. nvgArc(vg, cx,cy, r1, a1, a0, NVG_CCW);
  432. nvgClosePath(vg);
  433. ax = cx + cosf(a0) * (r0+r1)*0.5f;
  434. ay = cy + sinf(a0) * (r0+r1)*0.5f;
  435. bx = cx + cosf(a1) * (r0+r1)*0.5f;
  436. by = cy + sinf(a1) * (r0+r1)*0.5f;
  437. paint = nvgLinearGradient(vg, ax,ay, bx,by, nvgRGBA(0,0,0,0), nvgRGBA(0,0,0,128));
  438. nvgFillPaint(vg, paint);
  439. nvgFill(vg);
  440. nvgRestore(vg);
  441. }
  442. void drawThumbnails(NVGcontext* vg, float x, float y, float w, float h, const int* images, int nimages, float t)
  443. {
  444. float cornerRadius = 3.0f;
  445. NVGpaint shadowPaint, imgPaint, fadePaint;
  446. float ix,iy,iw,ih;
  447. float thumb = 60.0f;
  448. float arry = 30.5f;
  449. int imgw, imgh;
  450. float stackh = (nimages/2) * (thumb+10) + 10;
  451. int i;
  452. float u = (1+cosf(t*0.5f))*0.5f;
  453. float u2 = (1-cosf(t*0.2f))*0.5f;
  454. float scrollh, dv;
  455. nvgSave(vg);
  456. // nvgClearState(vg);
  457. // Drop shadow
  458. shadowPaint = nvgBoxGradient(vg, x,y+4, w,h, cornerRadius*2, 20, nvgRGBA(0,0,0,128), nvgRGBA(0,0,0,0));
  459. nvgBeginPath(vg);
  460. nvgRect(vg, x-10,y-10, w+20,h+30);
  461. nvgRoundedRect(vg, x,y, w,h, cornerRadius);
  462. nvgPathWinding(vg, NVG_HOLE);
  463. nvgFillPaint(vg, shadowPaint);
  464. nvgFill(vg);
  465. // Window
  466. nvgBeginPath(vg);
  467. nvgRoundedRect(vg, x,y, w,h, cornerRadius);
  468. nvgMoveTo(vg, x-10,y+arry);
  469. nvgLineTo(vg, x+1,y+arry-11);
  470. nvgLineTo(vg, x+1,y+arry+11);
  471. nvgFillColor(vg, nvgRGBA(200,200,200,255));
  472. nvgFill(vg);
  473. nvgSave(vg);
  474. nvgScissor(vg, x,y,w,h);
  475. nvgTranslate(vg, 0, -(stackh - h)*u);
  476. dv = 1.0f / (float)(nimages-1);
  477. for (i = 0; i < nimages; i++) {
  478. float tx, ty, v, a;
  479. tx = x+10;
  480. ty = y+10;
  481. tx += (i%2) * (thumb+10);
  482. ty += (i/2) * (thumb+10);
  483. nvgImageSize(vg, images[i], &imgw, &imgh);
  484. if (imgw < imgh) {
  485. iw = thumb;
  486. ih = iw * (float)imgh/(float)imgw;
  487. ix = 0;
  488. iy = -(ih-thumb)*0.5f;
  489. } else {
  490. ih = thumb;
  491. iw = ih * (float)imgw/(float)imgh;
  492. ix = -(iw-thumb)*0.5f;
  493. iy = 0;
  494. }
  495. v = i * dv;
  496. a = clampf((u2-v) / dv, 0, 1);
  497. if (a < 1.0f)
  498. drawSpinner(vg, tx+thumb/2,ty+thumb/2, thumb*0.25f, t);
  499. imgPaint = nvgImagePattern(vg, tx+ix, ty+iy, iw,ih, 0.0f/180.0f*NVG_PI, images[i], a);
  500. nvgBeginPath(vg);
  501. nvgRoundedRect(vg, tx,ty, thumb,thumb, 5);
  502. nvgFillPaint(vg, imgPaint);
  503. nvgFill(vg);
  504. shadowPaint = nvgBoxGradient(vg, tx-1,ty, thumb+2,thumb+2, 5, 3, nvgRGBA(0,0,0,128), nvgRGBA(0,0,0,0));
  505. nvgBeginPath(vg);
  506. nvgRect(vg, tx-5,ty-5, thumb+10,thumb+10);
  507. nvgRoundedRect(vg, tx,ty, thumb,thumb, 6);
  508. nvgPathWinding(vg, NVG_HOLE);
  509. nvgFillPaint(vg, shadowPaint);
  510. nvgFill(vg);
  511. nvgBeginPath(vg);
  512. nvgRoundedRect(vg, tx+0.5f,ty+0.5f, thumb-1,thumb-1, 4-0.5f);
  513. nvgStrokeWidth(vg,1.0f);
  514. nvgStrokeColor(vg, nvgRGBA(255,255,255,192));
  515. nvgStroke(vg);
  516. }
  517. nvgRestore(vg);
  518. // Hide fades
  519. fadePaint = nvgLinearGradient(vg, x,y,x,y+6, nvgRGBA(200,200,200,255), nvgRGBA(200,200,200,0));
  520. nvgBeginPath(vg);
  521. nvgRect(vg, x+4,y,w-8,6);
  522. nvgFillPaint(vg, fadePaint);
  523. nvgFill(vg);
  524. fadePaint = nvgLinearGradient(vg, x,y+h,x,y+h-6, nvgRGBA(200,200,200,255), nvgRGBA(200,200,200,0));
  525. nvgBeginPath(vg);
  526. nvgRect(vg, x+4,y+h-6,w-8,6);
  527. nvgFillPaint(vg, fadePaint);
  528. nvgFill(vg);
  529. // Scroll bar
  530. 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));
  531. nvgBeginPath(vg);
  532. nvgRoundedRect(vg, x+w-12,y+4, 8,h-8, 3);
  533. nvgFillPaint(vg, shadowPaint);
  534. // nvgFillColor(vg, nvgRGBA(255,0,0,128));
  535. nvgFill(vg);
  536. scrollh = (h/stackh) * (h-8);
  537. 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));
  538. nvgBeginPath(vg);
  539. nvgRoundedRect(vg, x+w-12+1,y+4+1 + (h-8-scrollh)*u, 8-2,scrollh-2, 2);
  540. nvgFillPaint(vg, shadowPaint);
  541. // nvgFillColor(vg, nvgRGBA(0,0,0,128));
  542. nvgFill(vg);
  543. nvgRestore(vg);
  544. }
  545. void drawColorwheel(NVGcontext* vg, float x, float y, float w, float h, float t)
  546. {
  547. int i;
  548. float r0, r1, ax,ay, bx,by, cx,cy, aeps, r;
  549. float hue = sinf(t * 0.12f);
  550. NVGpaint paint;
  551. nvgSave(vg);
  552. /* nvgBeginPath(vg);
  553. nvgRect(vg, x,y,w,h);
  554. nvgFillColor(vg, nvgRGBA(255,0,0,128));
  555. nvgFill(vg);*/
  556. cx = x + w*0.5f;
  557. cy = y + h*0.5f;
  558. r1 = (w < h ? w : h) * 0.5f - 5.0f;
  559. r0 = r1 - 20.0f;
  560. aeps = 0.5f / r1; // half a pixel arc length in radians (2pi cancels out).
  561. for (i = 0; i < 6; i++) {
  562. float a0 = (float)i / 6.0f * NVG_PI * 2.0f - aeps;
  563. float a1 = (float)(i+1.0f) / 6.0f * NVG_PI * 2.0f + aeps;
  564. nvgBeginPath(vg);
  565. nvgArc(vg, cx,cy, r0, a0, a1, NVG_CW);
  566. nvgArc(vg, cx,cy, r1, a1, a0, NVG_CCW);
  567. nvgClosePath(vg);
  568. ax = cx + cosf(a0) * (r0+r1)*0.5f;
  569. ay = cy + sinf(a0) * (r0+r1)*0.5f;
  570. bx = cx + cosf(a1) * (r0+r1)*0.5f;
  571. by = cy + sinf(a1) * (r0+r1)*0.5f;
  572. 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));
  573. nvgFillPaint(vg, paint);
  574. nvgFill(vg);
  575. }
  576. nvgBeginPath(vg);
  577. nvgCircle(vg, cx,cy, r0-0.5f);
  578. nvgCircle(vg, cx,cy, r1+0.5f);
  579. nvgStrokeColor(vg, nvgRGBA(0,0,0,64));
  580. nvgStrokeWidth(vg, 1.0f);
  581. nvgStroke(vg);
  582. // Selector
  583. nvgSave(vg);
  584. nvgTranslate(vg, cx,cy);
  585. nvgRotate(vg, hue*NVG_PI*2);
  586. // Marker on
  587. nvgStrokeWidth(vg, 2.0f);
  588. nvgBeginPath(vg);
  589. nvgRect(vg, r0-1,-3,r1-r0+2,6);
  590. nvgStrokeColor(vg, nvgRGBA(255,255,255,192));
  591. nvgStroke(vg);
  592. paint = nvgBoxGradient(vg, r0-3,-5,r1-r0+6,10, 2,4, nvgRGBA(0,0,0,128), nvgRGBA(0,0,0,0));
  593. nvgBeginPath(vg);
  594. nvgRect(vg, r0-2-10,-4-10,r1-r0+4+20,8+20);
  595. nvgRect(vg, r0-2,-4,r1-r0+4,8);
  596. nvgPathWinding(vg, NVG_HOLE);
  597. nvgFillPaint(vg, paint);
  598. nvgFill(vg);
  599. // Center triangle
  600. r = r0 - 6;
  601. ax = cosf(120.0f/180.0f*NVG_PI) * r;
  602. ay = sinf(120.0f/180.0f*NVG_PI) * r;
  603. bx = cosf(-120.0f/180.0f*NVG_PI) * r;
  604. by = sinf(-120.0f/180.0f*NVG_PI) * r;
  605. nvgBeginPath(vg);
  606. nvgMoveTo(vg, r,0);
  607. nvgLineTo(vg, ax,ay);
  608. nvgLineTo(vg, bx,by);
  609. nvgClosePath(vg);
  610. paint = nvgLinearGradient(vg, r,0, ax,ay, nvgHSLA(hue,1.0f,0.5f,255), nvgRGBA(255,255,255,255));
  611. nvgFillPaint(vg, paint);
  612. nvgFill(vg);
  613. paint = nvgLinearGradient(vg, (r+ax)*0.5f,(0+ay)*0.5f, bx,by, nvgRGBA(0,0,0,0), nvgRGBA(0,0,0,255));
  614. nvgFillPaint(vg, paint);
  615. nvgFill(vg);
  616. nvgStrokeColor(vg, nvgRGBA(0,0,0,64));
  617. nvgStroke(vg);
  618. // Select circle on triangle
  619. ax = cosf(120.0f/180.0f*NVG_PI) * r*0.3f;
  620. ay = sinf(120.0f/180.0f*NVG_PI) * r*0.4f;
  621. nvgStrokeWidth(vg, 2.0f);
  622. nvgBeginPath(vg);
  623. nvgCircle(vg, ax,ay,5);
  624. nvgStrokeColor(vg, nvgRGBA(255,255,255,192));
  625. nvgStroke(vg);
  626. paint = nvgRadialGradient(vg, ax,ay, 7,9, nvgRGBA(0,0,0,64), nvgRGBA(0,0,0,0));
  627. nvgBeginPath(vg);
  628. nvgRect(vg, ax-20,ay-20,40,40);
  629. nvgCircle(vg, ax,ay,7);
  630. nvgPathWinding(vg, NVG_HOLE);
  631. nvgFillPaint(vg, paint);
  632. nvgFill(vg);
  633. nvgRestore(vg);
  634. nvgRestore(vg);
  635. }
  636. void drawLines(NVGcontext* vg, float x, float y, float w, float h, float t)
  637. {
  638. int i, j;
  639. float pad = 5.0f, s = w/9.0f - pad*2;
  640. float pts[4*2], fx, fy;
  641. int joins[3] = {NVG_MITER, NVG_ROUND, NVG_BEVEL};
  642. int caps[3] = {NVG_BUTT, NVG_ROUND, NVG_SQUARE};
  643. NVG_NOTUSED(h);
  644. nvgSave(vg);
  645. pts[0] = -s*0.25f + cosf(t*0.3f) * s*0.5f;
  646. pts[1] = sinf(t*0.3f) * s*0.5f;
  647. pts[2] = -s*0.25;
  648. pts[3] = 0;
  649. pts[4] = s*0.25f;
  650. pts[5] = 0;
  651. pts[6] = s*0.25f + cosf(-t*0.3f) * s*0.5f;
  652. pts[7] = sinf(-t*0.3f) * s*0.5f;
  653. for (i = 0; i < 3; i++) {
  654. for (j = 0; j < 3; j++) {
  655. fx = x + s*0.5f + (i*3+j)/9.0f*w + pad;
  656. fy = y - s*0.5f + pad;
  657. nvgLineCap(vg, caps[i]);
  658. nvgLineJoin(vg, joins[j]);
  659. nvgStrokeWidth(vg, s*0.3f);
  660. nvgStrokeColor(vg, nvgRGBA(0,0,0,160));
  661. nvgBeginPath(vg);
  662. nvgMoveTo(vg, fx+pts[0], fy+pts[1]);
  663. nvgLineTo(vg, fx+pts[2], fy+pts[3]);
  664. nvgLineTo(vg, fx+pts[4], fy+pts[5]);
  665. nvgLineTo(vg, fx+pts[6], fy+pts[7]);
  666. nvgStroke(vg);
  667. nvgLineCap(vg, NVG_BUTT);
  668. nvgLineJoin(vg, NVG_BEVEL);
  669. nvgStrokeWidth(vg, 1.0f);
  670. nvgStrokeColor(vg, nvgRGBA(0,192,255,255));
  671. nvgBeginPath(vg);
  672. nvgMoveTo(vg, fx+pts[0], fy+pts[1]);
  673. nvgLineTo(vg, fx+pts[2], fy+pts[3]);
  674. nvgLineTo(vg, fx+pts[4], fy+pts[5]);
  675. nvgLineTo(vg, fx+pts[6], fy+pts[7]);
  676. nvgStroke(vg);
  677. }
  678. }
  679. nvgRestore(vg);
  680. }
  681. int loadDemoData(NVGcontext* vg, DemoData* data)
  682. {
  683. int i;
  684. if (vg == NULL)
  685. return -1;
  686. for (i = 0; i < 12; i++) {
  687. char file[128];
  688. snprintf(file, 128, "./nanovg_res/images/image%d.jpg", i+1);
  689. data->images[i] = nvgCreateImage(vg, file, 0);
  690. if (data->images[i] == 0) {
  691. printf("Could not load %s.\n", file);
  692. return -1;
  693. }
  694. }
  695. data->fontIcons = nvgCreateFont(vg, "icons", "./nanovg_res/entypo.ttf");
  696. if (data->fontIcons == -1) {
  697. printf("Could not add font icons.\n");
  698. return -1;
  699. }
  700. data->fontNormal = nvgCreateFont(vg, "sans", "./nanovg_res/Roboto-Regular.ttf");
  701. if (data->fontNormal == -1) {
  702. printf("Could not add font italic.\n");
  703. return -1;
  704. }
  705. data->fontBold = nvgCreateFont(vg, "sans-bold", "./nanovg_res/Roboto-Bold.ttf");
  706. if (data->fontBold == -1) {
  707. printf("Could not add font bold.\n");
  708. return -1;
  709. }
  710. return 0;
  711. }
  712. void freeDemoData(NVGcontext* vg, DemoData* data)
  713. {
  714. int i;
  715. if (vg == NULL)
  716. return;
  717. for (i = 0; i < 12; i++)
  718. nvgDeleteImage(vg, data->images[i]);
  719. }
  720. void drawParagraph(NVGcontext* vg, float x, float y, float width, float height, float mx, float my)
  721. {
  722. NVGtextRow rows[3];
  723. NVGglyphPosition glyphs[100];
  724. const char* text = "This is longer chunk of text.\n \n Would have used lorem ipsum but she was busy jumping over the lazy dog with the fox and all the men who came to the aid of the party.";
  725. const char* start;
  726. const char* end;
  727. int nrows, i, nglyphs, j, lnum = 0;
  728. float lineh;
  729. float caretx, px;
  730. float bounds[4];
  731. float a;
  732. float gx,gy;
  733. int gutter = 0;
  734. NVG_NOTUSED(height);
  735. nvgSave(vg);
  736. nvgFontSize(vg, 18.0f);
  737. nvgFontFace(vg, "sans");
  738. nvgTextAlign(vg, NVG_ALIGN_LEFT|NVG_ALIGN_TOP);
  739. nvgTextMetrics(vg, NULL, NULL, &lineh);
  740. // The text break API can be used to fill a large buffer of rows,
  741. // or to iterate over the text just few lines (or just one) at a time.
  742. // The "next" variable of the last returned item tells where to continue.
  743. start = text;
  744. end = text + strlen(text);
  745. while ((nrows = nvgTextBreakLines(vg, start, end, width, rows, 3))) {
  746. for (i = 0; i < nrows; i++) {
  747. NVGtextRow* row = &rows[i];
  748. int hit = mx > x && mx < (x+width) && my >= y && my < (y+lineh);
  749. nvgBeginPath(vg);
  750. nvgFillColor(vg, nvgRGBA(255,255,255,hit?64:16));
  751. nvgRect(vg, x, y, row->width, lineh);
  752. nvgFill(vg);
  753. nvgFillColor(vg, nvgRGBA(255,255,255,255));
  754. nvgText(vg, x, y, row->start, row->end);
  755. if (hit) {
  756. caretx = (mx < x+row->width/2) ? x : x+row->width;
  757. px = x;
  758. nglyphs = nvgTextGlyphPositions(vg, x, y, row->start, row->end, glyphs, 100);
  759. for (j = 0; j < nglyphs; j++) {
  760. float x0 = glyphs[j].x;
  761. float x1 = (j+1 < nglyphs) ? glyphs[j+1].x : x+row->width;
  762. float gx = x0 * 0.3f + x1 * 0.7f;
  763. if (mx >= px && mx < gx)
  764. caretx = glyphs[j].x;
  765. px = gx;
  766. }
  767. nvgBeginPath(vg);
  768. nvgFillColor(vg, nvgRGBA(255,192,0,255));
  769. nvgRect(vg, caretx, y, 1, lineh);
  770. nvgFill(vg);
  771. gutter = lnum+1;
  772. gx = x - 10;
  773. gy = y + lineh/2;
  774. }
  775. lnum++;
  776. y += lineh;
  777. }
  778. // Keep going...
  779. start = rows[nrows-1].next;
  780. }
  781. if (gutter) {
  782. char txt[16];
  783. snprintf(txt, sizeof(txt), "%d", gutter);
  784. nvgFontSize(vg, 13.0f);
  785. nvgTextAlign(vg, NVG_ALIGN_RIGHT|NVG_ALIGN_MIDDLE);
  786. nvgTextBounds(vg, gx,gy, txt, NULL, bounds);
  787. nvgBeginPath(vg);
  788. nvgFillColor(vg, nvgRGBA(255,192,0,255));
  789. nvgRoundedRect(vg, (int)bounds[0]-4,(int)bounds[1]-2, (int)(bounds[2]-bounds[0])+8, (int)(bounds[3]-bounds[1])+4, ((int)(bounds[3]-bounds[1])+4)/2-1);
  790. nvgFill(vg);
  791. nvgFillColor(vg, nvgRGBA(32,32,32,255));
  792. nvgText(vg, gx,gy, txt, NULL);
  793. }
  794. y += 20.0f;
  795. nvgFontSize(vg, 13.0f);
  796. nvgTextAlign(vg, NVG_ALIGN_LEFT|NVG_ALIGN_TOP);
  797. nvgTextLineHeight(vg, 1.2f);
  798. nvgTextBoxBounds(vg, x,y, 150, "Hover your mouse over the text to see calculated caret position.", NULL, bounds);
  799. // Fade the tooltip out when close to it.
  800. gx = fabsf((mx - (bounds[0]+bounds[2])*0.5f) / (bounds[0] - bounds[2]));
  801. gy = fabsf((my - (bounds[1]+bounds[3])*0.5f) / (bounds[1] - bounds[3]));
  802. a = maxf(gx, gy) - 0.5f;
  803. a = clampf(a, 0, 1);
  804. nvgGlobalAlpha(vg, a);
  805. nvgBeginPath(vg);
  806. nvgFillColor(vg, nvgRGBA(220,220,220,255));
  807. nvgRoundedRect(vg, bounds[0]-2,bounds[1]-2, (int)(bounds[2]-bounds[0])+4, (int)(bounds[3]-bounds[1])+4, 3);
  808. px = (int)((bounds[2]+bounds[0])/2);
  809. nvgMoveTo(vg, px,bounds[1] - 10);
  810. nvgLineTo(vg, px+7,bounds[1]+1);
  811. nvgLineTo(vg, px-7,bounds[1]+1);
  812. nvgFill(vg);
  813. nvgFillColor(vg, nvgRGBA(0,0,0,220));
  814. nvgTextBox(vg, x,y, 150, "Hover your mouse over the text to see calculated caret position.", NULL);
  815. nvgRestore(vg);
  816. }
  817. void drawWidths(NVGcontext* vg, float x, float y, float width)
  818. {
  819. int i;
  820. nvgSave(vg);
  821. nvgStrokeColor(vg, nvgRGBA(0,0,0,255));
  822. for (i = 0; i < 20; i++) {
  823. float w = (i+0.5f)*0.1f;
  824. nvgStrokeWidth(vg, w);
  825. nvgBeginPath(vg);
  826. nvgMoveTo(vg, x,y);
  827. nvgLineTo(vg, x+width,y+width*0.3f);
  828. nvgStroke(vg);
  829. y += 10;
  830. }
  831. nvgRestore(vg);
  832. }
  833. void drawCaps(NVGcontext* vg, float x, float y, float width)
  834. {
  835. int i;
  836. int caps[3] = {NVG_BUTT, NVG_ROUND, NVG_SQUARE};
  837. float lineWidth = 8.0f;
  838. nvgSave(vg);
  839. nvgBeginPath(vg);
  840. nvgRect(vg, x-lineWidth/2, y, width+lineWidth, 40);
  841. nvgFillColor(vg, nvgRGBA(255,255,255,32));
  842. nvgFill(vg);
  843. nvgBeginPath(vg);
  844. nvgRect(vg, x, y, width, 40);
  845. nvgFillColor(vg, nvgRGBA(255,255,255,32));
  846. nvgFill(vg);
  847. nvgStrokeWidth(vg, lineWidth);
  848. for (i = 0; i < 3; i++) {
  849. nvgLineCap(vg, caps[i]);
  850. nvgStrokeColor(vg, nvgRGBA(0,0,0,255));
  851. nvgBeginPath(vg);
  852. nvgMoveTo(vg, x, y + i*10 + 5);
  853. nvgLineTo(vg, x+width, y + i*10 + 5);
  854. nvgStroke(vg);
  855. }
  856. nvgRestore(vg);
  857. }
  858. void drawScissor(NVGcontext* vg, float x, float y, float t)
  859. {
  860. nvgSave(vg);
  861. // Draw first rect and set scissor to it's area.
  862. nvgTranslate(vg, x, y);
  863. nvgRotate(vg, nvgDegToRad(5));
  864. nvgBeginPath(vg);
  865. nvgRect(vg, -20,-20,60,40);
  866. nvgFillColor(vg, nvgRGBA(255,0,0,255));
  867. nvgFill(vg);
  868. nvgScissor(vg, -20,-20,60,40);
  869. // Draw second rectangle with offset and rotation.
  870. nvgTranslate(vg, 40,0);
  871. nvgRotate(vg, t);
  872. // Draw the intended second rectangle without any scissoring.
  873. nvgSave(vg);
  874. nvgResetScissor(vg);
  875. nvgBeginPath(vg);
  876. nvgRect(vg, -20,-10,60,30);
  877. nvgFillColor(vg, nvgRGBA(255,128,0,64));
  878. nvgFill(vg);
  879. nvgRestore(vg);
  880. // Draw second rectangle with combined scissoring.
  881. nvgIntersectScissor(vg, -20,-10,60,30);
  882. nvgBeginPath(vg);
  883. nvgRect(vg, -20,-10,60,30);
  884. nvgFillColor(vg, nvgRGBA(255,128,0,255));
  885. nvgFill(vg);
  886. nvgRestore(vg);
  887. }
  888. void renderDemo(NVGcontext* vg, float mx, float my, float width, float height,
  889. float t, int blowup, DemoData* data)
  890. {
  891. float x,y,popy;
  892. drawEyes(vg, width - 250, 50, 150, 100, mx, my, t);
  893. drawParagraph(vg, width - 450, 50, 150, 100, mx, my);
  894. drawGraph(vg, 0, height/2, width, height/2, t);
  895. drawColorwheel(vg, width - 300, height - 300, 250.0f, 250.0f, t);
  896. // Line joints
  897. drawLines(vg, 120, height-50, 600, 50, t);
  898. // Line caps
  899. drawWidths(vg, 10, 50, 30);
  900. // Line caps
  901. drawCaps(vg, 10, 300, 30);
  902. drawScissor(vg, 50, height-80, t);
  903. nvgSave(vg);
  904. if (blowup) {
  905. nvgRotate(vg, sinf(t*0.3f)*5.0f/180.0f*NVG_PI);
  906. nvgScale(vg, 2.0f, 2.0f);
  907. }
  908. // Widgets
  909. drawWindow(vg, "Widgets `n Stuff", 50, 50, 300, 400);
  910. x = 60; y = 95;
  911. drawSearchBox(vg, "Search", x,y,280,25);
  912. y += 40;
  913. drawDropDown(vg, "Effects", x,y,280,28);
  914. popy = y + 14;
  915. y += 45;
  916. // Form
  917. drawLabel(vg, "Login", x,y, 280,20);
  918. y += 25;
  919. drawEditBox(vg, "Email", x,y, 280,28);
  920. y += 35;
  921. drawEditBox(vg, "Password", x,y, 280,28);
  922. y += 38;
  923. drawCheckBox(vg, "Remember me", x,y, 140,28);
  924. drawButton(vg, ICON_LOGIN, "Sign in", x+138, y, 140, 28, nvgRGBA(0,96,128,255));
  925. y += 45;
  926. // Slider
  927. drawLabel(vg, "Diameter", x,y, 280,20);
  928. y += 25;
  929. drawEditBoxNum(vg, "123.00", "px", x+180,y, 100,28);
  930. drawSlider(vg, 0.4f, x,y, 170,28);
  931. y += 55;
  932. drawButton(vg, ICON_TRASH, "Delete", x, y, 160, 28, nvgRGBA(128,16,8,255));
  933. drawButton(vg, 0, "Cancel", x+170, y, 110, 28, nvgRGBA(0,0,0,0));
  934. // Thumbnails box
  935. drawThumbnails(vg, 365, popy-30, 160, 300, data->images, 12, t);
  936. nvgRestore(vg);
  937. }
  938. static int mini(int a, int b) { return a < b ? a : b; }
  939. static void unpremultiplyAlpha(unsigned char* image, int w, int h, int stride)
  940. {
  941. int x,y;
  942. // Unpremultiply
  943. for (y = 0; y < h; y++) {
  944. unsigned char *row = &image[y*stride];
  945. for (x = 0; x < w; x++) {
  946. int r = row[0], g = row[1], b = row[2], a = row[3];
  947. if (a != 0) {
  948. row[0] = (int)mini(r*255/a, 255);
  949. row[1] = (int)mini(g*255/a, 255);
  950. row[2] = (int)mini(b*255/a, 255);
  951. }
  952. row += 4;
  953. }
  954. }
  955. // Defringe
  956. for (y = 0; y < h; y++) {
  957. unsigned char *row = &image[y*stride];
  958. for (x = 0; x < w; x++) {
  959. int r = 0, g = 0, b = 0, a = row[3], n = 0;
  960. if (a == 0) {
  961. if (x-1 > 0 && row[-1] != 0) {
  962. r += row[-4];
  963. g += row[-3];
  964. b += row[-2];
  965. n++;
  966. }
  967. if (x+1 < w && row[7] != 0) {
  968. r += row[4];
  969. g += row[5];
  970. b += row[6];
  971. n++;
  972. }
  973. if (y-1 > 0 && row[-stride+3] != 0) {
  974. r += row[-stride];
  975. g += row[-stride+1];
  976. b += row[-stride+2];
  977. n++;
  978. }
  979. if (y+1 < h && row[stride+3] != 0) {
  980. r += row[stride];
  981. g += row[stride+1];
  982. b += row[stride+2];
  983. n++;
  984. }
  985. if (n > 0) {
  986. row[0] = r/n;
  987. row[1] = g/n;
  988. row[2] = b/n;
  989. }
  990. }
  991. row += 4;
  992. }
  993. }
  994. }
  995. static void setAlpha(unsigned char* image, int w, int h, int stride, unsigned char a)
  996. {
  997. int x, y;
  998. for (y = 0; y < h; y++) {
  999. unsigned char* row = &image[y*stride];
  1000. for (x = 0; x < w; x++)
  1001. row[x*4+3] = a;
  1002. }
  1003. }
  1004. static void flipHorizontal(unsigned char* image, int w, int h, int stride)
  1005. {
  1006. int i = 0, j = h-1, k;
  1007. while (i < j) {
  1008. unsigned char* ri = &image[i * stride];
  1009. unsigned char* rj = &image[j * stride];
  1010. for (k = 0; k < w*4; k++) {
  1011. unsigned char t = ri[k];
  1012. ri[k] = rj[k];
  1013. rj[k] = t;
  1014. }
  1015. i++;
  1016. j--;
  1017. }
  1018. }
  1019. void saveScreenShot(int w, int h, int premult, const char* name)
  1020. {
  1021. unsigned char* image = (unsigned char*)malloc(w*h*4);
  1022. if (image == NULL)
  1023. return;
  1024. glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, image);
  1025. if (premult)
  1026. unpremultiplyAlpha(image, w, h, w*4);
  1027. else
  1028. setAlpha(image, w, h, w*4, 255);
  1029. flipHorizontal(image, w, h, w*4);
  1030. stbi_write_png(name, w, h, 4, image, w*4);
  1031. free(image);
  1032. }