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