1 #include "demo.h"
2 #include <stdio.h>
3 #include <string.h>
4 #include <math.h>
5 #ifdef NANOVG_GLEW
6 # include <GL/glew.h>
7 #endif
8 #include <GLFW/glfw3.h>
9 #include "nanovg.h"
10 #define STB_IMAGE_WRITE_IMPLEMENTATION
11 #include "stb_image_write.h"
12
13
14 #ifdef _MSC_VER
15 #define snprintf _snprintf
16 #elif !defined(__MINGW32__)
17 #include <iconv.h>
18 #endif
19
20 #define ICON_SEARCH 0x1F50D
21 #define ICON_CIRCLED_CROSS 0x2716
22 #define ICON_CHEVRON_RIGHT 0xE75E
23 #define ICON_CHECK 0x2713
24 #define ICON_LOGIN 0xE740
25 #define ICON_TRASH 0xE729
26
27 //static float minf(float a, float b) { return a < b ? a : b; }
maxf(float a,float b)28 static float maxf(float a, float b) { return a > b ? a : b; }
29 //static float absf(float a) { return a >= 0.0f ? a : -a; }
clampf(float a,float mn,float mx)30 static float clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); }
31
32 // Returns 1 if col.rgba is 0.0f,0.0f,0.0f,0.0f, 0 otherwise
isBlack(NVGcolor col)33 int isBlack(NVGcolor col)
34 {
35 if( col.r == 0.0f && col.g == 0.0f && col.b == 0.0f && col.a == 0.0f )
36 {
37 return 1;
38 }
39 return 0;
40 }
41
cpToUTF8(int cp,char * str)42 static char* cpToUTF8(int cp, char* str)
43 {
44 int n = 0;
45 if (cp < 0x80) n = 1;
46 else if (cp < 0x800) n = 2;
47 else if (cp < 0x10000) n = 3;
48 else if (cp < 0x200000) n = 4;
49 else if (cp < 0x4000000) n = 5;
50 else if (cp <= 0x7fffffff) n = 6;
51 str[n] = '\0';
52 switch (n) {
53 case 6: str[5] = 0x80 | (cp & 0x3f); cp = cp >> 6; cp |= 0x4000000;
54 case 5: str[4] = 0x80 | (cp & 0x3f); cp = cp >> 6; cp |= 0x200000;
55 case 4: str[3] = 0x80 | (cp & 0x3f); cp = cp >> 6; cp |= 0x10000;
56 case 3: str[2] = 0x80 | (cp & 0x3f); cp = cp >> 6; cp |= 0x800;
57 case 2: str[1] = 0x80 | (cp & 0x3f); cp = cp >> 6; cp |= 0xc0;
58 case 1: str[0] = cp;
59 }
60 return str;
61 }
62
63
drawWindow(NVGcontext * vg,const char * title,float x,float y,float w,float h)64 void drawWindow(NVGcontext* vg, const char* title, float x, float y, float w, float h)
65 {
66 float cornerRadius = 3.0f;
67 NVGpaint shadowPaint;
68 NVGpaint headerPaint;
69
70 nvgSave(vg);
71 // nvgClearState(vg);
72
73 // Window
74 nvgBeginPath(vg);
75 nvgRoundedRect(vg, x,y, w,h, cornerRadius);
76 nvgFillColor(vg, nvgRGBA(28,30,34,192));
77 // nvgFillColor(vg, nvgRGBA(0,0,0,128));
78 nvgFill(vg);
79
80 // Drop shadow
81 shadowPaint = nvgBoxGradient(vg, x,y+2, w,h, cornerRadius*2, 10, nvgRGBA(0,0,0,128), nvgRGBA(0,0,0,0));
82 nvgBeginPath(vg);
83 nvgRect(vg, x-10,y-10, w+20,h+30);
84 nvgRoundedRect(vg, x,y, w,h, cornerRadius);
85 nvgPathWinding(vg, NVG_HOLE);
86 nvgFillPaint(vg, shadowPaint);
87 nvgFill(vg);
88
89 // Header
90 headerPaint = nvgLinearGradient(vg, x,y,x,y+15, nvgRGBA(255,255,255,8), nvgRGBA(0,0,0,16));
91 nvgBeginPath(vg);
92 nvgRoundedRect(vg, x+1,y+1, w-2,30, cornerRadius-1);
93 nvgFillPaint(vg, headerPaint);
94 nvgFill(vg);
95 nvgBeginPath(vg);
96 nvgMoveTo(vg, x+0.5f, y+0.5f+30);
97 nvgLineTo(vg, x+0.5f+w-1, y+0.5f+30);
98 nvgStrokeColor(vg, nvgRGBA(0,0,0,32));
99 nvgStroke(vg);
100
101 nvgFontSize(vg, 18.0f);
102 nvgFontFace(vg, "sans-bold");
103 nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
104
105 nvgFontBlur(vg,2);
106 nvgFillColor(vg, nvgRGBA(0,0,0,128));
107 nvgText(vg, x+w/2,y+16+1, title, NULL);
108
109 nvgFontBlur(vg,0);
110 nvgFillColor(vg, nvgRGBA(220,220,220,160));
111 nvgText(vg, x+w/2,y+16, title, NULL);
112
113 nvgRestore(vg);
114 }
115
drawSearchBox(NVGcontext * vg,const char * text,float x,float y,float w,float h)116 void drawSearchBox(NVGcontext* vg, const char* text, float x, float y, float w, float h)
117 {
118 NVGpaint bg;
119 char icon[8];
120 float cornerRadius = h/2-1;
121
122 // Edit
123 bg = nvgBoxGradient(vg, x,y+1.5f, w,h, h/2,5, nvgRGBA(0,0,0,16), nvgRGBA(0,0,0,92));
124 nvgBeginPath(vg);
125 nvgRoundedRect(vg, x,y, w,h, cornerRadius);
126 nvgFillPaint(vg, bg);
127 nvgFill(vg);
128
129 /* nvgBeginPath(vg);
130 nvgRoundedRect(vg, x+0.5f,y+0.5f, w-1,h-1, cornerRadius-0.5f);
131 nvgStrokeColor(vg, nvgRGBA(0,0,0,48));
132 nvgStroke(vg);*/
133
134 nvgFontSize(vg, h*1.3f);
135 nvgFontFace(vg, "icons");
136 nvgFillColor(vg, nvgRGBA(255,255,255,64));
137 nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
138 nvgText(vg, x+h*0.55f, y+h*0.55f, cpToUTF8(ICON_SEARCH,icon), NULL);
139
140 nvgFontSize(vg, 20.0f);
141 nvgFontFace(vg, "sans");
142 nvgFillColor(vg, nvgRGBA(255,255,255,32));
143
144 nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
145 nvgText(vg, x+h*1.05f,y+h*0.5f,text, NULL);
146
147 nvgFontSize(vg, h*1.3f);
148 nvgFontFace(vg, "icons");
149 nvgFillColor(vg, nvgRGBA(255,255,255,32));
150 nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
151 nvgText(vg, x+w-h*0.55f, y+h*0.55f, cpToUTF8(ICON_CIRCLED_CROSS,icon), NULL);
152 }
153
drawDropDown(NVGcontext * vg,const char * text,float x,float y,float w,float h)154 void drawDropDown(NVGcontext* vg, const char* text, float x, float y, float w, float h)
155 {
156 NVGpaint bg;
157 char icon[8];
158 float cornerRadius = 4.0f;
159
160 bg = nvgLinearGradient(vg, x,y,x,y+h, nvgRGBA(255,255,255,16), nvgRGBA(0,0,0,16));
161 nvgBeginPath(vg);
162 nvgRoundedRect(vg, x+1,y+1, w-2,h-2, cornerRadius-1);
163 nvgFillPaint(vg, bg);
164 nvgFill(vg);
165
166 nvgBeginPath(vg);
167 nvgRoundedRect(vg, x+0.5f,y+0.5f, w-1,h-1, cornerRadius-0.5f);
168 nvgStrokeColor(vg, nvgRGBA(0,0,0,48));
169 nvgStroke(vg);
170
171 nvgFontSize(vg, 20.0f);
172 nvgFontFace(vg, "sans");
173 nvgFillColor(vg, nvgRGBA(255,255,255,160));
174 nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
175 nvgText(vg, x+h*0.3f,y+h*0.5f,text, NULL);
176
177 nvgFontSize(vg, h*1.3f);
178 nvgFontFace(vg, "icons");
179 nvgFillColor(vg, nvgRGBA(255,255,255,64));
180 nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
181 nvgText(vg, x+w-h*0.5f, y+h*0.5f, cpToUTF8(ICON_CHEVRON_RIGHT,icon), NULL);
182 }
183
drawLabel(NVGcontext * vg,const char * text,float x,float y,float w,float h)184 void drawLabel(NVGcontext* vg, const char* text, float x, float y, float w, float h)
185 {
186 NVG_NOTUSED(w);
187
188 nvgFontSize(vg, 18.0f);
189 nvgFontFace(vg, "sans");
190 nvgFillColor(vg, nvgRGBA(255,255,255,128));
191
192 nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
193 nvgText(vg, x,y+h*0.5f,text, NULL);
194 }
195
drawEditBoxBase(NVGcontext * vg,float x,float y,float w,float h)196 void drawEditBoxBase(NVGcontext* vg, float x, float y, float w, float h)
197 {
198 NVGpaint bg;
199 // Edit
200 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));
201 nvgBeginPath(vg);
202 nvgRoundedRect(vg, x+1,y+1, w-2,h-2, 4-1);
203 nvgFillPaint(vg, bg);
204 nvgFill(vg);
205
206 nvgBeginPath(vg);
207 nvgRoundedRect(vg, x+0.5f,y+0.5f, w-1,h-1, 4-0.5f);
208 nvgStrokeColor(vg, nvgRGBA(0,0,0,48));
209 nvgStroke(vg);
210 }
211
drawEditBox(NVGcontext * vg,const char * text,float x,float y,float w,float h)212 void drawEditBox(NVGcontext* vg, const char* text, float x, float y, float w, float h)
213 {
214
215 drawEditBoxBase(vg, x,y, w,h);
216
217 nvgFontSize(vg, 20.0f);
218 nvgFontFace(vg, "sans");
219 nvgFillColor(vg, nvgRGBA(255,255,255,64));
220 nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
221 nvgText(vg, x+h*0.3f,y+h*0.5f,text, NULL);
222 }
223
drawEditBoxNum(NVGcontext * vg,const char * text,const char * units,float x,float y,float w,float h)224 void drawEditBoxNum(NVGcontext* vg,
225 const char* text, const char* units, float x, float y, float w, float h)
226 {
227 float uw;
228
229 drawEditBoxBase(vg, x,y, w,h);
230
231 uw = nvgTextBounds(vg, 0,0, units, NULL, NULL);
232
233 nvgFontSize(vg, 18.0f);
234 nvgFontFace(vg, "sans");
235 nvgFillColor(vg, nvgRGBA(255,255,255,64));
236 nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_MIDDLE);
237 nvgText(vg, x+w-h*0.3f,y+h*0.5f,units, NULL);
238
239 nvgFontSize(vg, 20.0f);
240 nvgFontFace(vg, "sans");
241 nvgFillColor(vg, nvgRGBA(255,255,255,128));
242 nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_MIDDLE);
243 nvgText(vg, x+w-uw-h*0.5f,y+h*0.5f,text, NULL);
244 }
245
drawCheckBox(NVGcontext * vg,const char * text,float x,float y,float w,float h)246 void drawCheckBox(NVGcontext* vg, const char* text, float x, float y, float w, float h)
247 {
248 NVGpaint bg;
249 char icon[8];
250 NVG_NOTUSED(w);
251
252 nvgFontSize(vg, 18.0f);
253 nvgFontFace(vg, "sans");
254 nvgFillColor(vg, nvgRGBA(255,255,255,160));
255
256 nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
257 nvgText(vg, x+28,y+h*0.5f,text, NULL);
258
259 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));
260 nvgBeginPath(vg);
261 nvgRoundedRect(vg, x+1,y+(int)(h*0.5f)-9, 18,18, 3);
262 nvgFillPaint(vg, bg);
263 nvgFill(vg);
264
265 nvgFontSize(vg, 40);
266 nvgFontFace(vg, "icons");
267 nvgFillColor(vg, nvgRGBA(255,255,255,128));
268 nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE);
269 nvgText(vg, x+9+2, y+h*0.5f, cpToUTF8(ICON_CHECK,icon), NULL);
270 }
271
drawButton(NVGcontext * vg,int preicon,const char * text,float x,float y,float w,float h,NVGcolor col)272 void drawButton(NVGcontext* vg, int preicon, const char* text, float x, float y, float w, float h, NVGcolor col)
273 {
274 NVGpaint bg;
275 char icon[8];
276 float cornerRadius = 4.0f;
277 float tw = 0, iw = 0;
278
279 bg = nvgLinearGradient(vg, x,y,x,y+h, nvgRGBA(255,255,255,isBlack(col)?16:32), nvgRGBA(0,0,0,isBlack(col)?16:32));
280 nvgBeginPath(vg);
281 nvgRoundedRect(vg, x+1,y+1, w-2,h-2, cornerRadius-1);
282 if (!isBlack(col)) {
283 nvgFillColor(vg, col);
284 nvgFill(vg);
285 }
286 nvgFillPaint(vg, bg);
287 nvgFill(vg);
288
289 nvgBeginPath(vg);
290 nvgRoundedRect(vg, x+0.5f,y+0.5f, w-1,h-1, cornerRadius-0.5f);
291 nvgStrokeColor(vg, nvgRGBA(0,0,0,48));
292 nvgStroke(vg);
293
294 nvgFontSize(vg, 20.0f);
295 nvgFontFace(vg, "sans-bold");
296 tw = nvgTextBounds(vg, 0,0, text, NULL, NULL);
297 if (preicon != 0) {
298 nvgFontSize(vg, h*1.3f);
299 nvgFontFace(vg, "icons");
300 iw = nvgTextBounds(vg, 0,0, cpToUTF8(preicon,icon), NULL, NULL);
301 iw += h*0.15f;
302 }
303
304 if (preicon != 0) {
305 nvgFontSize(vg, h*1.3f);
306 nvgFontFace(vg, "icons");
307 nvgFillColor(vg, nvgRGBA(255,255,255,96));
308 nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
309 nvgText(vg, x+w*0.5f-tw*0.5f-iw*0.75f, y+h*0.5f, cpToUTF8(preicon,icon), NULL);
310 }
311
312 nvgFontSize(vg, 20.0f);
313 nvgFontFace(vg, "sans-bold");
314 nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
315 nvgFillColor(vg, nvgRGBA(0,0,0,160));
316 nvgText(vg, x+w*0.5f-tw*0.5f+iw*0.25f,y+h*0.5f-1,text, NULL);
317 nvgFillColor(vg, nvgRGBA(255,255,255,160));
318 nvgText(vg, x+w*0.5f-tw*0.5f+iw*0.25f,y+h*0.5f,text, NULL);
319 }
320
drawSlider(NVGcontext * vg,float pos,float x,float y,float w,float h)321 void drawSlider(NVGcontext* vg, float pos, float x, float y, float w, float h)
322 {
323 NVGpaint bg, knob;
324 float cy = y+(int)(h*0.5f);
325 float kr = (int)(h*0.25f);
326
327 nvgSave(vg);
328 // nvgClearState(vg);
329
330 // Slot
331 bg = nvgBoxGradient(vg, x,cy-2+1, w,4, 2,2, nvgRGBA(0,0,0,32), nvgRGBA(0,0,0,128));
332 nvgBeginPath(vg);
333 nvgRoundedRect(vg, x,cy-2, w,4, 2);
334 nvgFillPaint(vg, bg);
335 nvgFill(vg);
336
337 // Knob Shadow
338 bg = nvgRadialGradient(vg, x+(int)(pos*w),cy+1, kr-3,kr+3, nvgRGBA(0,0,0,64), nvgRGBA(0,0,0,0));
339 nvgBeginPath(vg);
340 nvgRect(vg, x+(int)(pos*w)-kr-5,cy-kr-5,kr*2+5+5,kr*2+5+5+3);
341 nvgCircle(vg, x+(int)(pos*w),cy, kr);
342 nvgPathWinding(vg, NVG_HOLE);
343 nvgFillPaint(vg, bg);
344 nvgFill(vg);
345
346 // Knob
347 knob = nvgLinearGradient(vg, x,cy-kr,x,cy+kr, nvgRGBA(255,255,255,16), nvgRGBA(0,0,0,16));
348 nvgBeginPath(vg);
349 nvgCircle(vg, x+(int)(pos*w),cy, kr-1);
350 nvgFillColor(vg, nvgRGBA(40,43,48,255));
351 nvgFill(vg);
352 nvgFillPaint(vg, knob);
353 nvgFill(vg);
354
355 nvgBeginPath(vg);
356 nvgCircle(vg, x+(int)(pos*w),cy, kr-0.5f);
357 nvgStrokeColor(vg, nvgRGBA(0,0,0,92));
358 nvgStroke(vg);
359
360 nvgRestore(vg);
361 }
362
drawEyes(NVGcontext * vg,float x,float y,float w,float h,float mx,float my,float t)363 void drawEyes(NVGcontext* vg, float x, float y, float w, float h, float mx, float my, float t)
364 {
365 NVGpaint gloss, bg;
366 float ex = w *0.23f;
367 float ey = h * 0.5f;
368 float lx = x + ex;
369 float ly = y + ey;
370 float rx = x + w - ex;
371 float ry = y + ey;
372 float dx,dy,d;
373 float br = (ex < ey ? ex : ey) * 0.5f;
374 float blink = 1 - pow(sinf(t*0.5f),200)*0.8f;
375
376 bg = nvgLinearGradient(vg, x,y+h*0.5f,x+w*0.1f,y+h, nvgRGBA(0,0,0,32), nvgRGBA(0,0,0,16));
377 nvgBeginPath(vg);
378 nvgEllipse(vg, lx+3.0f,ly+16.0f, ex,ey);
379 nvgEllipse(vg, rx+3.0f,ry+16.0f, ex,ey);
380 nvgFillPaint(vg, bg);
381 nvgFill(vg);
382
383 bg = nvgLinearGradient(vg, x,y+h*0.25f,x+w*0.1f,y+h, nvgRGBA(220,220,220,255), nvgRGBA(128,128,128,255));
384 nvgBeginPath(vg);
385 nvgEllipse(vg, lx,ly, ex,ey);
386 nvgEllipse(vg, rx,ry, ex,ey);
387 nvgFillPaint(vg, bg);
388 nvgFill(vg);
389
390 dx = (mx - rx) / (ex * 10);
391 dy = (my - ry) / (ey * 10);
392 d = sqrtf(dx*dx+dy*dy);
393 if (d > 1.0f) {
394 dx /= d; dy /= d;
395 }
396 dx *= ex*0.4f;
397 dy *= ey*0.5f;
398 nvgBeginPath(vg);
399 nvgEllipse(vg, lx+dx,ly+dy+ey*0.25f*(1-blink), br,br*blink);
400 nvgFillColor(vg, nvgRGBA(32,32,32,255));
401 nvgFill(vg);
402
403 dx = (mx - rx) / (ex * 10);
404 dy = (my - ry) / (ey * 10);
405 d = sqrtf(dx*dx+dy*dy);
406 if (d > 1.0f) {
407 dx /= d; dy /= d;
408 }
409 dx *= ex*0.4f;
410 dy *= ey*0.5f;
411 nvgBeginPath(vg);
412 nvgEllipse(vg, rx+dx,ry+dy+ey*0.25f*(1-blink), br,br*blink);
413 nvgFillColor(vg, nvgRGBA(32,32,32,255));
414 nvgFill(vg);
415
416 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));
417 nvgBeginPath(vg);
418 nvgEllipse(vg, lx,ly, ex,ey);
419 nvgFillPaint(vg, gloss);
420 nvgFill(vg);
421
422 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));
423 nvgBeginPath(vg);
424 nvgEllipse(vg, rx,ry, ex,ey);
425 nvgFillPaint(vg, gloss);
426 nvgFill(vg);
427 }
428
drawGraph(NVGcontext * vg,float x,float y,float w,float h,float t)429 void drawGraph(NVGcontext* vg, float x, float y, float w, float h, float t)
430 {
431 NVGpaint bg;
432 float samples[6];
433 float sx[6], sy[6];
434 float dx = w/5.0f;
435 int i;
436
437 samples[0] = (1+sinf(t*1.2345f+cosf(t*0.33457f)*0.44f))*0.5f;
438 samples[1] = (1+sinf(t*0.68363f+cosf(t*1.3f)*1.55f))*0.5f;
439 samples[2] = (1+sinf(t*1.1642f+cosf(t*0.33457)*1.24f))*0.5f;
440 samples[3] = (1+sinf(t*0.56345f+cosf(t*1.63f)*0.14f))*0.5f;
441 samples[4] = (1+sinf(t*1.6245f+cosf(t*0.254f)*0.3f))*0.5f;
442 samples[5] = (1+sinf(t*0.345f+cosf(t*0.03f)*0.6f))*0.5f;
443
444 for (i = 0; i < 6; i++) {
445 sx[i] = x+i*dx;
446 sy[i] = y+h*samples[i]*0.8f;
447 }
448
449 // Graph background
450 bg = nvgLinearGradient(vg, x,y,x,y+h, nvgRGBA(0,160,192,0), nvgRGBA(0,160,192,64));
451 nvgBeginPath(vg);
452 nvgMoveTo(vg, sx[0], sy[0]);
453 for (i = 1; i < 6; i++)
454 nvgBezierTo(vg, sx[i-1]+dx*0.5f,sy[i-1], sx[i]-dx*0.5f,sy[i], sx[i],sy[i]);
455 nvgLineTo(vg, x+w, y+h);
456 nvgLineTo(vg, x, y+h);
457 nvgFillPaint(vg, bg);
458 nvgFill(vg);
459
460 // Graph line
461 nvgBeginPath(vg);
462 nvgMoveTo(vg, sx[0], sy[0]+2);
463 for (i = 1; i < 6; i++)
464 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);
465 nvgStrokeColor(vg, nvgRGBA(0,0,0,32));
466 nvgStrokeWidth(vg, 3.0f);
467 nvgStroke(vg);
468
469 nvgBeginPath(vg);
470 nvgMoveTo(vg, sx[0], sy[0]);
471 for (i = 1; i < 6; i++)
472 nvgBezierTo(vg, sx[i-1]+dx*0.5f,sy[i-1], sx[i]-dx*0.5f,sy[i], sx[i],sy[i]);
473 nvgStrokeColor(vg, nvgRGBA(0,160,192,255));
474 nvgStrokeWidth(vg, 3.0f);
475 nvgStroke(vg);
476
477 // Graph sample pos
478 for (i = 0; i < 6; i++) {
479 bg = nvgRadialGradient(vg, sx[i],sy[i]+2, 3.0f,8.0f, nvgRGBA(0,0,0,32), nvgRGBA(0,0,0,0));
480 nvgBeginPath(vg);
481 nvgRect(vg, sx[i]-10, sy[i]-10+2, 20,20);
482 nvgFillPaint(vg, bg);
483 nvgFill(vg);
484 }
485
486 nvgBeginPath(vg);
487 for (i = 0; i < 6; i++)
488 nvgCircle(vg, sx[i], sy[i], 4.0f);
489 nvgFillColor(vg, nvgRGBA(0,160,192,255));
490 nvgFill(vg);
491 nvgBeginPath(vg);
492 for (i = 0; i < 6; i++)
493 nvgCircle(vg, sx[i], sy[i], 2.0f);
494 nvgFillColor(vg, nvgRGBA(220,220,220,255));
495 nvgFill(vg);
496
497 nvgStrokeWidth(vg, 1.0f);
498 }
499
drawSpinner(NVGcontext * vg,float cx,float cy,float r,float t)500 void drawSpinner(NVGcontext* vg, float cx, float cy, float r, float t)
501 {
502 float a0 = 0.0f + t*6;
503 float a1 = NVG_PI + t*6;
504 float r0 = r;
505 float r1 = r * 0.75f;
506 float ax,ay, bx,by;
507 NVGpaint paint;
508
509 nvgSave(vg);
510
511 nvgBeginPath(vg);
512 nvgArc(vg, cx,cy, r0, a0, a1, NVG_CW);
513 nvgArc(vg, cx,cy, r1, a1, a0, NVG_CCW);
514 nvgClosePath(vg);
515 ax = cx + cosf(a0) * (r0+r1)*0.5f;
516 ay = cy + sinf(a0) * (r0+r1)*0.5f;
517 bx = cx + cosf(a1) * (r0+r1)*0.5f;
518 by = cy + sinf(a1) * (r0+r1)*0.5f;
519 paint = nvgLinearGradient(vg, ax,ay, bx,by, nvgRGBA(0,0,0,0), nvgRGBA(0,0,0,128));
520 nvgFillPaint(vg, paint);
521 nvgFill(vg);
522
523 nvgRestore(vg);
524 }
525
drawThumbnails(NVGcontext * vg,float x,float y,float w,float h,const int * images,int nimages,float t)526 void drawThumbnails(NVGcontext* vg, float x, float y, float w, float h, const int* images, int nimages, float t)
527 {
528 float cornerRadius = 3.0f;
529 NVGpaint shadowPaint, imgPaint, fadePaint;
530 float ix,iy,iw,ih;
531 float thumb = 60.0f;
532 float arry = 30.5f;
533 int imgw, imgh;
534 float stackh = (nimages/2) * (thumb+10) + 10;
535 int i;
536 float u = (1+cosf(t*0.5f))*0.5f;
537 float u2 = (1-cosf(t*0.2f))*0.5f;
538 float scrollh, dv;
539
540 nvgSave(vg);
541 // nvgClearState(vg);
542
543 // Drop shadow
544 shadowPaint = nvgBoxGradient(vg, x,y+4, w,h, cornerRadius*2, 20, nvgRGBA(0,0,0,128), nvgRGBA(0,0,0,0));
545 nvgBeginPath(vg);
546 nvgRect(vg, x-10,y-10, w+20,h+30);
547 nvgRoundedRect(vg, x,y, w,h, cornerRadius);
548 nvgPathWinding(vg, NVG_HOLE);
549 nvgFillPaint(vg, shadowPaint);
550 nvgFill(vg);
551
552 // Window
553 nvgBeginPath(vg);
554 nvgRoundedRect(vg, x,y, w,h, cornerRadius);
555 nvgMoveTo(vg, x-10,y+arry);
556 nvgLineTo(vg, x+1,y+arry-11);
557 nvgLineTo(vg, x+1,y+arry+11);
558 nvgFillColor(vg, nvgRGBA(200,200,200,255));
559 nvgFill(vg);
560
561 nvgSave(vg);
562 nvgScissor(vg, x,y,w,h);
563 nvgTranslate(vg, 0, -(stackh - h)*u);
564
565 dv = 1.0f / (float)(nimages-1);
566
567 for (i = 0; i < nimages; i++) {
568 float tx, ty, v, a;
569 tx = x+10;
570 ty = y+10;
571 tx += (i%2) * (thumb+10);
572 ty += (i/2) * (thumb+10);
573 nvgImageSize(vg, images[i], &imgw, &imgh);
574 if (imgw < imgh) {
575 iw = thumb;
576 ih = iw * (float)imgh/(float)imgw;
577 ix = 0;
578 iy = -(ih-thumb)*0.5f;
579 } else {
580 ih = thumb;
581 iw = ih * (float)imgw/(float)imgh;
582 ix = -(iw-thumb)*0.5f;
583 iy = 0;
584 }
585
586 v = i * dv;
587 a = clampf((u2-v) / dv, 0, 1);
588
589 if (a < 1.0f)
590 drawSpinner(vg, tx+thumb/2,ty+thumb/2, thumb*0.25f, t);
591
592 imgPaint = nvgImagePattern(vg, tx+ix, ty+iy, iw,ih, 0.0f/180.0f*NVG_PI, images[i], a);
593 nvgBeginPath(vg);
594 nvgRoundedRect(vg, tx,ty, thumb,thumb, 5);
595 nvgFillPaint(vg, imgPaint);
596 nvgFill(vg);
597
598 shadowPaint = nvgBoxGradient(vg, tx-1,ty, thumb+2,thumb+2, 5, 3, nvgRGBA(0,0,0,128), nvgRGBA(0,0,0,0));
599 nvgBeginPath(vg);
600 nvgRect(vg, tx-5,ty-5, thumb+10,thumb+10);
601 nvgRoundedRect(vg, tx,ty, thumb,thumb, 6);
602 nvgPathWinding(vg, NVG_HOLE);
603 nvgFillPaint(vg, shadowPaint);
604 nvgFill(vg);
605
606 nvgBeginPath(vg);
607 nvgRoundedRect(vg, tx+0.5f,ty+0.5f, thumb-1,thumb-1, 4-0.5f);
608 nvgStrokeWidth(vg,1.0f);
609 nvgStrokeColor(vg, nvgRGBA(255,255,255,192));
610 nvgStroke(vg);
611 }
612 nvgRestore(vg);
613
614 // Hide fades
615 fadePaint = nvgLinearGradient(vg, x,y,x,y+6, nvgRGBA(200,200,200,255), nvgRGBA(200,200,200,0));
616 nvgBeginPath(vg);
617 nvgRect(vg, x+4,y,w-8,6);
618 nvgFillPaint(vg, fadePaint);
619 nvgFill(vg);
620
621 fadePaint = nvgLinearGradient(vg, x,y+h,x,y+h-6, nvgRGBA(200,200,200,255), nvgRGBA(200,200,200,0));
622 nvgBeginPath(vg);
623 nvgRect(vg, x+4,y+h-6,w-8,6);
624 nvgFillPaint(vg, fadePaint);
625 nvgFill(vg);
626
627 // Scroll bar
628 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));
629 nvgBeginPath(vg);
630 nvgRoundedRect(vg, x+w-12,y+4, 8,h-8, 3);
631 nvgFillPaint(vg, shadowPaint);
632 // nvgFillColor(vg, nvgRGBA(255,0,0,128));
633 nvgFill(vg);
634
635 scrollh = (h/stackh) * (h-8);
636 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));
637 nvgBeginPath(vg);
638 nvgRoundedRect(vg, x+w-12+1,y+4+1 + (h-8-scrollh)*u, 8-2,scrollh-2, 2);
639 nvgFillPaint(vg, shadowPaint);
640 // nvgFillColor(vg, nvgRGBA(0,0,0,128));
641 nvgFill(vg);
642
643 nvgRestore(vg);
644 }
645
drawColorwheel(NVGcontext * vg,float x,float y,float w,float h,float t)646 void drawColorwheel(NVGcontext* vg, float x, float y, float w, float h, float t)
647 {
648 int i;
649 float r0, r1, ax,ay, bx,by, cx,cy, aeps, r;
650 float hue = sinf(t * 0.12f);
651 NVGpaint paint;
652
653 nvgSave(vg);
654
655 /* nvgBeginPath(vg);
656 nvgRect(vg, x,y,w,h);
657 nvgFillColor(vg, nvgRGBA(255,0,0,128));
658 nvgFill(vg);*/
659
660 cx = x + w*0.5f;
661 cy = y + h*0.5f;
662 r1 = (w < h ? w : h) * 0.5f - 5.0f;
663 r0 = r1 - 20.0f;
664 aeps = 0.5f / r1; // half a pixel arc length in radians (2pi cancels out).
665
666 for (i = 0; i < 6; i++) {
667 float a0 = (float)i / 6.0f * NVG_PI * 2.0f - aeps;
668 float a1 = (float)(i+1.0f) / 6.0f * NVG_PI * 2.0f + aeps;
669 nvgBeginPath(vg);
670 nvgArc(vg, cx,cy, r0, a0, a1, NVG_CW);
671 nvgArc(vg, cx,cy, r1, a1, a0, NVG_CCW);
672 nvgClosePath(vg);
673 ax = cx + cosf(a0) * (r0+r1)*0.5f;
674 ay = cy + sinf(a0) * (r0+r1)*0.5f;
675 bx = cx + cosf(a1) * (r0+r1)*0.5f;
676 by = cy + sinf(a1) * (r0+r1)*0.5f;
677 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));
678 nvgFillPaint(vg, paint);
679 nvgFill(vg);
680 }
681
682 nvgBeginPath(vg);
683 nvgCircle(vg, cx,cy, r0-0.5f);
684 nvgCircle(vg, cx,cy, r1+0.5f);
685 nvgStrokeColor(vg, nvgRGBA(0,0,0,64));
686 nvgStrokeWidth(vg, 1.0f);
687 nvgStroke(vg);
688
689 // Selector
690 nvgSave(vg);
691 nvgTranslate(vg, cx,cy);
692 nvgRotate(vg, hue*NVG_PI*2);
693
694 // Marker on
695 nvgStrokeWidth(vg, 2.0f);
696 nvgBeginPath(vg);
697 nvgRect(vg, r0-1,-3,r1-r0+2,6);
698 nvgStrokeColor(vg, nvgRGBA(255,255,255,192));
699 nvgStroke(vg);
700
701 paint = nvgBoxGradient(vg, r0-3,-5,r1-r0+6,10, 2,4, nvgRGBA(0,0,0,128), nvgRGBA(0,0,0,0));
702 nvgBeginPath(vg);
703 nvgRect(vg, r0-2-10,-4-10,r1-r0+4+20,8+20);
704 nvgRect(vg, r0-2,-4,r1-r0+4,8);
705 nvgPathWinding(vg, NVG_HOLE);
706 nvgFillPaint(vg, paint);
707 nvgFill(vg);
708
709 // Center triangle
710 r = r0 - 6;
711 ax = cosf(120.0f/180.0f*NVG_PI) * r;
712 ay = sinf(120.0f/180.0f*NVG_PI) * r;
713 bx = cosf(-120.0f/180.0f*NVG_PI) * r;
714 by = sinf(-120.0f/180.0f*NVG_PI) * r;
715 nvgBeginPath(vg);
716 nvgMoveTo(vg, r,0);
717 nvgLineTo(vg, ax,ay);
718 nvgLineTo(vg, bx,by);
719 nvgClosePath(vg);
720 paint = nvgLinearGradient(vg, r,0, ax,ay, nvgHSLA(hue,1.0f,0.5f,255), nvgRGBA(255,255,255,255));
721 nvgFillPaint(vg, paint);
722 nvgFill(vg);
723 paint = nvgLinearGradient(vg, (r+ax)*0.5f,(0+ay)*0.5f, bx,by, nvgRGBA(0,0,0,0), nvgRGBA(0,0,0,255));
724 nvgFillPaint(vg, paint);
725 nvgFill(vg);
726 nvgStrokeColor(vg, nvgRGBA(0,0,0,64));
727 nvgStroke(vg);
728
729 // Select circle on triangle
730 ax = cosf(120.0f/180.0f*NVG_PI) * r*0.3f;
731 ay = sinf(120.0f/180.0f*NVG_PI) * r*0.4f;
732 nvgStrokeWidth(vg, 2.0f);
733 nvgBeginPath(vg);
734 nvgCircle(vg, ax,ay,5);
735 nvgStrokeColor(vg, nvgRGBA(255,255,255,192));
736 nvgStroke(vg);
737
738 paint = nvgRadialGradient(vg, ax,ay, 7,9, nvgRGBA(0,0,0,64), nvgRGBA(0,0,0,0));
739 nvgBeginPath(vg);
740 nvgRect(vg, ax-20,ay-20,40,40);
741 nvgCircle(vg, ax,ay,7);
742 nvgPathWinding(vg, NVG_HOLE);
743 nvgFillPaint(vg, paint);
744 nvgFill(vg);
745
746 nvgRestore(vg);
747
748 nvgRestore(vg);
749 }
750
drawLines(NVGcontext * vg,float x,float y,float w,float h,float t)751 void drawLines(NVGcontext* vg, float x, float y, float w, float h, float t)
752 {
753 int i, j;
754 float pad = 5.0f, s = w/9.0f - pad*2;
755 float pts[4*2], fx, fy;
756 int joins[3] = {NVG_MITER, NVG_ROUND, NVG_BEVEL};
757 int caps[3] = {NVG_BUTT, NVG_ROUND, NVG_SQUARE};
758 NVG_NOTUSED(h);
759
760 nvgSave(vg);
761 pts[0] = -s*0.25f + cosf(t*0.3f) * s*0.5f;
762 pts[1] = sinf(t*0.3f) * s*0.5f;
763 pts[2] = -s*0.25;
764 pts[3] = 0;
765 pts[4] = s*0.25f;
766 pts[5] = 0;
767 pts[6] = s*0.25f + cosf(-t*0.3f) * s*0.5f;
768 pts[7] = sinf(-t*0.3f) * s*0.5f;
769
770 for (i = 0; i < 3; i++) {
771 for (j = 0; j < 3; j++) {
772 fx = x + s*0.5f + (i*3+j)/9.0f*w + pad;
773 fy = y - s*0.5f + pad;
774
775 nvgLineCap(vg, caps[i]);
776 nvgLineJoin(vg, joins[j]);
777
778 nvgStrokeWidth(vg, s*0.3f);
779 nvgStrokeColor(vg, nvgRGBA(0,0,0,160));
780 nvgBeginPath(vg);
781 nvgMoveTo(vg, fx+pts[0], fy+pts[1]);
782 nvgLineTo(vg, fx+pts[2], fy+pts[3]);
783 nvgLineTo(vg, fx+pts[4], fy+pts[5]);
784 nvgLineTo(vg, fx+pts[6], fy+pts[7]);
785 nvgStroke(vg);
786
787 nvgLineCap(vg, NVG_BUTT);
788 nvgLineJoin(vg, NVG_BEVEL);
789
790 nvgStrokeWidth(vg, 1.0f);
791 nvgStrokeColor(vg, nvgRGBA(0,192,255,255));
792 nvgBeginPath(vg);
793 nvgMoveTo(vg, fx+pts[0], fy+pts[1]);
794 nvgLineTo(vg, fx+pts[2], fy+pts[3]);
795 nvgLineTo(vg, fx+pts[4], fy+pts[5]);
796 nvgLineTo(vg, fx+pts[6], fy+pts[7]);
797 nvgStroke(vg);
798 }
799 }
800
801
802 nvgRestore(vg);
803 }
804
loadDemoData(NVGcontext * vg,DemoData * data)805 int loadDemoData(NVGcontext* vg, DemoData* data)
806 {
807 int i;
808
809 if (vg == NULL)
810 return -1;
811
812 for (i = 0; i < 12; i++) {
813 char file[128];
814 snprintf(file, 128, "../example/images/image%d.jpg", i+1);
815 data->images[i] = nvgCreateImage(vg, file, 0);
816 if (data->images[i] == 0) {
817 printf("Could not load %s.\n", file);
818 return -1;
819 }
820 }
821
822 data->fontIcons = nvgCreateFont(vg, "icons", "../example/entypo.ttf");
823 if (data->fontIcons == -1) {
824 printf("Could not add font icons.\n");
825 return -1;
826 }
827 data->fontNormal = nvgCreateFont(vg, "sans", "../example/Roboto-Regular.ttf");
828 if (data->fontNormal == -1) {
829 printf("Could not add font italic.\n");
830 return -1;
831 }
832 data->fontBold = nvgCreateFont(vg, "sans-bold", "../example/Roboto-Bold.ttf");
833 if (data->fontBold == -1) {
834 printf("Could not add font bold.\n");
835 return -1;
836 }
837 data->fontEmoji = nvgCreateFont(vg, "emoji", "../example/NotoEmoji-Regular.ttf");
838 if (data->fontEmoji == -1) {
839 printf("Could not add font emoji.\n");
840 return -1;
841 }
842 nvgAddFallbackFontId(vg, data->fontNormal, data->fontEmoji);
843 nvgAddFallbackFontId(vg, data->fontBold, data->fontEmoji);
844
845 return 0;
846 }
847
freeDemoData(NVGcontext * vg,DemoData * data)848 void freeDemoData(NVGcontext* vg, DemoData* data)
849 {
850 int i;
851
852 if (vg == NULL)
853 return;
854
855 for (i = 0; i < 12; i++)
856 nvgDeleteImage(vg, data->images[i]);
857 }
858
drawParagraph(NVGcontext * vg,float x,float y,float width,float height,float mx,float my)859 void drawParagraph(NVGcontext* vg, float x, float y, float width, float height, float mx, float my)
860 {
861 NVGtextRow rows[3];
862 NVGglyphPosition glyphs[100];
863 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.";
864 const char* start;
865 const char* end;
866 int nrows, i, nglyphs, j, lnum = 0;
867 float lineh;
868 float caretx, px;
869 float bounds[4];
870 float a;
871 float gx,gy;
872 int gutter = 0;
873 NVG_NOTUSED(height);
874
875 nvgSave(vg);
876
877 nvgFontSize(vg, 18.0f);
878 nvgFontFace(vg, "sans");
879 nvgTextAlign(vg, NVG_ALIGN_LEFT|NVG_ALIGN_TOP);
880 nvgTextMetrics(vg, NULL, NULL, &lineh);
881
882 // The text break API can be used to fill a large buffer of rows,
883 // or to iterate over the text just few lines (or just one) at a time.
884 // The "next" variable of the last returned item tells where to continue.
885 start = text;
886 end = text + strlen(text);
887 while ((nrows = nvgTextBreakLines(vg, start, end, width, rows, 3))) {
888 for (i = 0; i < nrows; i++) {
889 NVGtextRow* row = &rows[i];
890 int hit = mx > x && mx < (x+width) && my >= y && my < (y+lineh);
891
892 nvgBeginPath(vg);
893 nvgFillColor(vg, nvgRGBA(255,255,255,hit?64:16));
894 nvgRect(vg, x, y, row->width, lineh);
895 nvgFill(vg);
896
897 nvgFillColor(vg, nvgRGBA(255,255,255,255));
898 nvgText(vg, x, y, row->start, row->end);
899
900 if (hit) {
901 caretx = (mx < x+row->width/2) ? x : x+row->width;
902 px = x;
903 nglyphs = nvgTextGlyphPositions(vg, x, y, row->start, row->end, glyphs, 100);
904 for (j = 0; j < nglyphs; j++) {
905 float x0 = glyphs[j].x;
906 float x1 = (j+1 < nglyphs) ? glyphs[j+1].x : x+row->width;
907 float gx = x0 * 0.3f + x1 * 0.7f;
908 if (mx >= px && mx < gx)
909 caretx = glyphs[j].x;
910 px = gx;
911 }
912 nvgBeginPath(vg);
913 nvgFillColor(vg, nvgRGBA(255,192,0,255));
914 nvgRect(vg, caretx, y, 1, lineh);
915 nvgFill(vg);
916
917 gutter = lnum+1;
918 gx = x - 10;
919 gy = y + lineh/2;
920 }
921 lnum++;
922 y += lineh;
923 }
924 // Keep going...
925 start = rows[nrows-1].next;
926 }
927
928 if (gutter) {
929 char txt[16];
930 snprintf(txt, sizeof(txt), "%d", gutter);
931 nvgFontSize(vg, 13.0f);
932 nvgTextAlign(vg, NVG_ALIGN_RIGHT|NVG_ALIGN_MIDDLE);
933
934 nvgTextBounds(vg, gx,gy, txt, NULL, bounds);
935
936 nvgBeginPath(vg);
937 nvgFillColor(vg, nvgRGBA(255,192,0,255));
938 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);
939 nvgFill(vg);
940
941 nvgFillColor(vg, nvgRGBA(32,32,32,255));
942 nvgText(vg, gx,gy, txt, NULL);
943 }
944
945 y += 20.0f;
946
947 nvgFontSize(vg, 13.0f);
948 nvgTextAlign(vg, NVG_ALIGN_LEFT|NVG_ALIGN_TOP);
949 nvgTextLineHeight(vg, 1.2f);
950
951 nvgTextBoxBounds(vg, x,y, 150, "Hover your mouse over the text to see calculated caret position.", NULL, bounds);
952
953 // Fade the tooltip out when close to it.
954 gx = fabsf((mx - (bounds[0]+bounds[2])*0.5f) / (bounds[0] - bounds[2]));
955 gy = fabsf((my - (bounds[1]+bounds[3])*0.5f) / (bounds[1] - bounds[3]));
956 a = maxf(gx, gy) - 0.5f;
957 a = clampf(a, 0, 1);
958 nvgGlobalAlpha(vg, a);
959
960 nvgBeginPath(vg);
961 nvgFillColor(vg, nvgRGBA(220,220,220,255));
962 nvgRoundedRect(vg, bounds[0]-2,bounds[1]-2, (int)(bounds[2]-bounds[0])+4, (int)(bounds[3]-bounds[1])+4, 3);
963 px = (int)((bounds[2]+bounds[0])/2);
964 nvgMoveTo(vg, px,bounds[1] - 10);
965 nvgLineTo(vg, px+7,bounds[1]+1);
966 nvgLineTo(vg, px-7,bounds[1]+1);
967 nvgFill(vg);
968
969 nvgFillColor(vg, nvgRGBA(0,0,0,220));
970 nvgTextBox(vg, x,y, 150, "Hover your mouse over the text to see calculated caret position.", NULL);
971
972 nvgRestore(vg);
973 }
974
drawWidths(NVGcontext * vg,float x,float y,float width)975 void drawWidths(NVGcontext* vg, float x, float y, float width)
976 {
977 int i;
978
979 nvgSave(vg);
980
981 nvgStrokeColor(vg, nvgRGBA(0,0,0,255));
982
983 for (i = 0; i < 20; i++) {
984 float w = (i+0.5f)*0.1f;
985 nvgStrokeWidth(vg, w);
986 nvgBeginPath(vg);
987 nvgMoveTo(vg, x,y);
988 nvgLineTo(vg, x+width,y+width*0.3f);
989 nvgStroke(vg);
990 y += 10;
991 }
992
993 nvgRestore(vg);
994 }
995
drawCaps(NVGcontext * vg,float x,float y,float width)996 void drawCaps(NVGcontext* vg, float x, float y, float width)
997 {
998 int i;
999 int caps[3] = {NVG_BUTT, NVG_ROUND, NVG_SQUARE};
1000 float lineWidth = 8.0f;
1001
1002 nvgSave(vg);
1003
1004 nvgBeginPath(vg);
1005 nvgRect(vg, x-lineWidth/2, y, width+lineWidth, 40);
1006 nvgFillColor(vg, nvgRGBA(255,255,255,32));
1007 nvgFill(vg);
1008
1009 nvgBeginPath(vg);
1010 nvgRect(vg, x, y, width, 40);
1011 nvgFillColor(vg, nvgRGBA(255,255,255,32));
1012 nvgFill(vg);
1013
1014 nvgStrokeWidth(vg, lineWidth);
1015 for (i = 0; i < 3; i++) {
1016 nvgLineCap(vg, caps[i]);
1017 nvgStrokeColor(vg, nvgRGBA(0,0,0,255));
1018 nvgBeginPath(vg);
1019 nvgMoveTo(vg, x, y + i*10 + 5);
1020 nvgLineTo(vg, x+width, y + i*10 + 5);
1021 nvgStroke(vg);
1022 }
1023
1024 nvgRestore(vg);
1025 }
1026
drawScissor(NVGcontext * vg,float x,float y,float t)1027 void drawScissor(NVGcontext* vg, float x, float y, float t)
1028 {
1029 nvgSave(vg);
1030
1031 // Draw first rect and set scissor to it's area.
1032 nvgTranslate(vg, x, y);
1033 nvgRotate(vg, nvgDegToRad(5));
1034 nvgBeginPath(vg);
1035 nvgRect(vg, -20,-20,60,40);
1036 nvgFillColor(vg, nvgRGBA(255,0,0,255));
1037 nvgFill(vg);
1038 nvgScissor(vg, -20,-20,60,40);
1039
1040 // Draw second rectangle with offset and rotation.
1041 nvgTranslate(vg, 40,0);
1042 nvgRotate(vg, t);
1043
1044 // Draw the intended second rectangle without any scissoring.
1045 nvgSave(vg);
1046 nvgResetScissor(vg);
1047 nvgBeginPath(vg);
1048 nvgRect(vg, -20,-10,60,30);
1049 nvgFillColor(vg, nvgRGBA(255,128,0,64));
1050 nvgFill(vg);
1051 nvgRestore(vg);
1052
1053 // Draw second rectangle with combined scissoring.
1054 nvgIntersectScissor(vg, -20,-10,60,30);
1055 nvgBeginPath(vg);
1056 nvgRect(vg, -20,-10,60,30);
1057 nvgFillColor(vg, nvgRGBA(255,128,0,255));
1058 nvgFill(vg);
1059
1060 nvgRestore(vg);
1061 }
1062
renderDemo(NVGcontext * vg,float mx,float my,float width,float height,float t,int blowup,DemoData * data)1063 void renderDemo(NVGcontext* vg, float mx, float my, float width, float height,
1064 float t, int blowup, DemoData* data)
1065 {
1066 float x,y,popy;
1067
1068 drawEyes(vg, width - 250, 50, 150, 100, mx, my, t);
1069 drawParagraph(vg, width - 450, 50, 150, 100, mx, my);
1070 drawGraph(vg, 0, height/2, width, height/2, t);
1071 drawColorwheel(vg, width - 300, height - 300, 250.0f, 250.0f, t);
1072
1073 // Line joints
1074 drawLines(vg, 120, height-50, 600, 50, t);
1075
1076 // Line caps
1077 drawWidths(vg, 10, 50, 30);
1078
1079 // Line caps
1080 drawCaps(vg, 10, 300, 30);
1081
1082 drawScissor(vg, 50, height-80, t);
1083
1084 nvgSave(vg);
1085 if (blowup) {
1086 nvgRotate(vg, sinf(t*0.3f)*5.0f/180.0f*NVG_PI);
1087 nvgScale(vg, 2.0f, 2.0f);
1088 }
1089
1090 // Widgets
1091 drawWindow(vg, "Widgets `n Stuff", 50, 50, 300, 400);
1092 x = 60; y = 95;
1093 drawSearchBox(vg, "Search", x,y,280,25);
1094 y += 40;
1095 drawDropDown(vg, "Effects", x,y,280,28);
1096 popy = y + 14;
1097 y += 45;
1098
1099 // Form
1100 drawLabel(vg, "Login", x,y, 280,20);
1101 y += 25;
1102 drawEditBox(vg, "Email", x,y, 280,28);
1103 y += 35;
1104 drawEditBox(vg, "Password", x,y, 280,28);
1105 y += 38;
1106 drawCheckBox(vg, "Remember me", x,y, 140,28);
1107 drawButton(vg, ICON_LOGIN, "Sign in", x+138, y, 140, 28, nvgRGBA(0,96,128,255));
1108 y += 45;
1109
1110 // Slider
1111 drawLabel(vg, "Diameter", x,y, 280,20);
1112 y += 25;
1113 drawEditBoxNum(vg, "123.00", "px", x+180,y, 100,28);
1114 drawSlider(vg, 0.4f, x,y, 170,28);
1115 y += 55;
1116
1117 drawButton(vg, ICON_TRASH, "Delete", x, y, 160, 28, nvgRGBA(128,16,8,255));
1118 drawButton(vg, 0, "Cancel", x+170, y, 110, 28, nvgRGBA(0,0,0,0));
1119
1120 // Thumbnails box
1121 drawThumbnails(vg, 365, popy-30, 160, 300, data->images, 12, t);
1122
1123 nvgRestore(vg);
1124 }
1125
mini(int a,int b)1126 static int mini(int a, int b) { return a < b ? a : b; }
1127
unpremultiplyAlpha(unsigned char * image,int w,int h,int stride)1128 static void unpremultiplyAlpha(unsigned char* image, int w, int h, int stride)
1129 {
1130 int x,y;
1131
1132 // Unpremultiply
1133 for (y = 0; y < h; y++) {
1134 unsigned char *row = &image[y*stride];
1135 for (x = 0; x < w; x++) {
1136 int r = row[0], g = row[1], b = row[2], a = row[3];
1137 if (a != 0) {
1138 row[0] = (int)mini(r*255/a, 255);
1139 row[1] = (int)mini(g*255/a, 255);
1140 row[2] = (int)mini(b*255/a, 255);
1141 }
1142 row += 4;
1143 }
1144 }
1145
1146 // Defringe
1147 for (y = 0; y < h; y++) {
1148 unsigned char *row = &image[y*stride];
1149 for (x = 0; x < w; x++) {
1150 int r = 0, g = 0, b = 0, a = row[3], n = 0;
1151 if (a == 0) {
1152 if (x-1 > 0 && row[-1] != 0) {
1153 r += row[-4];
1154 g += row[-3];
1155 b += row[-2];
1156 n++;
1157 }
1158 if (x+1 < w && row[7] != 0) {
1159 r += row[4];
1160 g += row[5];
1161 b += row[6];
1162 n++;
1163 }
1164 if (y-1 > 0 && row[-stride+3] != 0) {
1165 r += row[-stride];
1166 g += row[-stride+1];
1167 b += row[-stride+2];
1168 n++;
1169 }
1170 if (y+1 < h && row[stride+3] != 0) {
1171 r += row[stride];
1172 g += row[stride+1];
1173 b += row[stride+2];
1174 n++;
1175 }
1176 if (n > 0) {
1177 row[0] = r/n;
1178 row[1] = g/n;
1179 row[2] = b/n;
1180 }
1181 }
1182 row += 4;
1183 }
1184 }
1185 }
1186
setAlpha(unsigned char * image,int w,int h,int stride,unsigned char a)1187 static void setAlpha(unsigned char* image, int w, int h, int stride, unsigned char a)
1188 {
1189 int x, y;
1190 for (y = 0; y < h; y++) {
1191 unsigned char* row = &image[y*stride];
1192 for (x = 0; x < w; x++)
1193 row[x*4+3] = a;
1194 }
1195 }
1196
flipHorizontal(unsigned char * image,int w,int h,int stride)1197 static void flipHorizontal(unsigned char* image, int w, int h, int stride)
1198 {
1199 int i = 0, j = h-1, k;
1200 while (i < j) {
1201 unsigned char* ri = &image[i * stride];
1202 unsigned char* rj = &image[j * stride];
1203 for (k = 0; k < w*4; k++) {
1204 unsigned char t = ri[k];
1205 ri[k] = rj[k];
1206 rj[k] = t;
1207 }
1208 i++;
1209 j--;
1210 }
1211 }
1212
saveScreenShot(int w,int h,int premult,const char * name)1213 void saveScreenShot(int w, int h, int premult, const char* name)
1214 {
1215 unsigned char* image = (unsigned char*)malloc(w*h*4);
1216 if (image == NULL)
1217 return;
1218 glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, image);
1219 if (premult)
1220 unpremultiplyAlpha(image, w, h, w*4);
1221 else
1222 setAlpha(image, w, h, w*4, 255);
1223 flipHorizontal(image, w, h, w*4);
1224 stbi_write_png(name, w, h, 4, image, w*4);
1225 free(image);
1226 }
1227