1 /*
2   Copyright Chris Jones 2020.
3   Distributed under the Boost Software License, Version 1.0.
4   See accompanying file Licence.txt or copy at...
5   https://www.boost.org/LICENSE_1_0.txt
6 */
7 
8 module app;
9 
10 import std.stdio;
11 import window;
12 import dg2d.canvas;
13 import dg2d.font;
14 
15 import dg2d;
16 import dg2d.misc;
17 
18 import demo.panels;
19 
20 void main()
21 {   
22     auto wnd = new Window();
23     wnd.addClient(new MainPanel());
24     wnd.createWindow(200,200,800,800,"graphics test");
25 	WindowsMessageLoop();
26 }
27 
28 class MainPanel : Widget
29 {
30     this()
31     {
32         super(0,0,800,800);
33 
34         import rawgfx;
35         font = loadFont(rawfont);
36         font.setSize(15);
37 
38         testcvs = new Canvas(800,800);
39 
40         panels ~= new SolidPanel1();
41         panels ~= new SolidPanel2();
42               
43         panels ~= new LinearPanel1();
44 
45         panels ~= new AngularPanel1();
46 
47         panels ~= new RadialPanel1();
48         panels ~= new RadialPanel2();
49         panels ~= new RadialPanel3();
50         addChild(panels[0]);
51 
52         infobtn = new Button(32,10,600,40,"",font);
53         infobtn.setOnClick(&clicked);
54         addChild(infobtn);
55     }
56 
57     override void onPaint(Canvas canvas)
58     {
59         canvas.fill(0xFF000000);
60     }
61     
62     override void onTimer()
63     {   
64         long t = profilePanel(panels[gfxidx],5);
65         timings[0..$-1] = timings[1..$];
66         timings[$-1] = getPerformanceFrequency() / (1.0*t);
67 
68         fps = 0;
69         foreach(f; timings) fps = max(fps,f);
70 
71         import std.conv;
72         infobtn.setText(panels[gfxidx].getInfo ~ ", FPS = " ~ to!string(fps));
73         repaint();
74     }
75 
76     void clicked()
77     {   
78         removeChild(panels[gfxidx]);
79         gfxidx = (gfxidx+1) % panels.length;
80         addChild(panels[gfxidx]);
81         addChild(infobtn);
82         timings = 0;
83         repaint();
84     }
85 
86     long profilePanel(GFXPanel panel, int runs = 1)
87     {
88         testcvs.fill(0xFF000000);
89         panel.onPaint(testcvs);
90         long best = long.max;
91         foreach(i; 0..runs)
92         {
93             testcvs.fill(0xFF000000);
94             long t = getPerformanceCounter();
95             panel.onPaint(testcvs);
96             t = getPerformanceCounter()-t;
97             best = min(best,t);
98         }
99         return best;
100     }
101 
102     size_t gfxidx = 0;
103     Font   font;
104     Button infobtn;
105     GFXPanel[] panels;
106     Canvas testcvs;
107     float fps = 0;
108     float[25] timings = 0;
109 }
110 
111 /*
112   Windows performance timer stuff
113 */
114 
115 long getPerformanceCounter()
116 {
117     import core.sys.windows.windows;
118     LARGE_INTEGER t;
119     QueryPerformanceCounter(&t);
120     return t.QuadPart;
121 }
122 
123 long getPerformanceFrequency()
124 {
125     import core.sys.windows.windows;
126     LARGE_INTEGER f;
127     QueryPerformanceFrequency(&f);
128     return f.QuadPart;
129 }
130 
131 
132 /*
133 class TestPanel : Widget
134 {
135     Path!float path;
136 
137     this()
138     {
139         super(200,200,800,800);
140         path.moveTo(-4.48518,1.69193).lineTo( 9.89451,0.150122).lineTo(-1.97198,1.42315).close();
141         path.moveTo(49.276596,11.177839).lineTo(12.747784,8.287876).lineTo(50.662491,11.286461).close();
142         path.moveTo(-4.820584,34.291153).lineTo(-2.890672,34.366234).lineTo(50.161381,36.457401).close();
143         path.moveTo(50.861496,20.968971).lineTo(-6.823852,26.630871).lineTo(46.685181,21.377645).close();
144         path.moveTo(46.575394,54.352577).lineTo(18.876856,48.298264).lineTo(-5.532673,42.964012).close();
145         path.moveTo(53.697834,37.919582).lineTo(16.089132,46.436161).lineTo(55.921280,37.421677).close();
146     }
147 
148 	override void onPaint(Canvas canvas)
149   	{
150         canvas.fill(0xFF000000);
151         canvas.draw(path,0xFFFFFFFF,WindingRule.EvenOdd);
152     }
153 }
154 */
155 /*
156   Test paths
157 */
158 /*
159 Path!float  gfx_area;
160 Path!float  gfx_borders;
161 Path!float  gfx_lines50;
162 Path!float  gfx_lines250;
163 Path!float  gfx_rects;
164 Path!float  gfx_text_l;
165 Path!float  gfx_text_s;
166 Gradient    gfx_grad1;
167 Gradient    gfx_grad2;
168 Gradient    gfx_grad3;
169 Font        gfx_font;
170 
171 static this()
172 {
173     import rawgfx;
174 
175     RoundRect!float rect = RoundRect!float(200,200,600,600,60,60);
176     
177     foreach(i; 0..36)
178     {
179         gfx_area.append(rect.asPath.scale(i*0.02,i*0.02,600,600).rotate(400,400,i*10));
180     }
181 
182     RoundRect!float[70] rrr;
183 
184     foreach(i; 0..rrr.length)
185     {
186         retry:
187             rrr[i] = randomRoundRect();
188             auto osr = rrr[i].outset(8,true);
189             foreach(q; 0..i)
190                 if (!intersect(osr,rrr[q]).isEmpty) goto retry; 
191         gfx_borders.append(rrr[i].asPath);
192         gfx_borders.append(rrr[i].inset(10,true).asPath.retro);
193     }
194 
195 //	gfx_borders = loadSvgPath(rawborders,1);
196 	gfx_lines50 = randomPath(50,1);
197 	gfx_lines250 = randomPath(250,20);
198 	gfx_rects = loadSvgPath(rawrects,1);
199 
200     gfx_font = loadFont(rawfont);
201 
202     gfx_font.setSize(40);
203     gfx_text_l = buildTextPath(gfx_font,loremIpsum);
204     gfx_font.setSize(14);
205     gfx_text_s = buildTextPath(gfx_font,loremIpsum);
206 
207     gfx_grad1 = new Gradient;
208     gfx_grad1.addStop(0,0x80fF0000).addStop(0.33,0xff00FF00).addStop(0.66,0xFF0000FF).addStop(1.0,0xFFFF0000);
209     gfx_grad2 = new Gradient;
210     //gfx_grad2.addStop(0,0xFFa72ac6).addStop(0.5,0x00004092).addStop(0.95,0xFFb0ae00).addStop(1,0xFFa72ac6);
211     gfx_grad2.addStop(0,0xFFff0000).addStop(0.5,0xff00ff00).addStop(1.0,0xff0000ff);
212 }
213 */
214 /*
215 long ProfileGFX(ref Path!float path)
216 {
217 		import core.sys.windows.windows;
218 		import std.conv;
219 
220         Canvas canvas = new Canvas(800,800);
221 
222 		long time = long.max;
223 
224 		foreach(i;0..50)
225 		{
226         //    canvas.setClip(100,100,700,700);
227 
228             canvas.fill(0xff274634);
229 
230             long t = readCycleCounter();
231  //           canvas.fill(path, 0xff00ff00, WindingRule.NonZero);
232             t = readCycleCounter()-t;
233             if (t < time) time = t;
234    	}       
235 		
236     return time;
237 }
238 */
239 
240 /*
241 void ProfileAll()
242 {
243 		writeln("area    : ",ProfileGFX(gfx_area));
244 		writeln("borders : ",ProfileGFX(gfx_borders));
245 		writeln("lines   : ",ProfileGFX(gfx_lines50));
246 		writeln("lines2  : ",ProfileGFX(gfx_lines250));
247 		writeln("rects   : ",ProfileGFX(gfx_rects));
248 		writeln("text_l  : ",ProfileGFX(gfx_text_l));
249 		writeln("text_s  : ",ProfileGFX(gfx_text_s));
250 }
251 */
252 // load an svg path string/
253 /*
254 Path!float loadSvgPath(string txt, float scale)
255 {
256 	import readpath;
257     import std.stdio;
258 
259 	Path!float path;
260     readPathData(txt,path);
261 
262 //    path.scale(scale,scale);
263 
264     path = path.scale(scale,scale);
265 
266 	return path;
267 }
268 */
269 // dump an svg path string 
270 /*
271 void dumpPath(ref Path!float path, string filename)
272 {
273     import std.stdio;
274     import std.conv;
275 
276     File file = File(filename, "w");
277     file.rawWrite("d=\"");
278 
279     foreach(i; 0..path.length)
280     {
281         if (path.cmd(i) == PathCmd.move)
282         {
283             file.rawWrite("M ");
284             file.rawWrite(to!string(path[i].x));
285             file.rawWrite(" ");
286             file.rawWrite(to!string(path[i].y));
287             file.rawWrite(" ");
288         }
289         if (path.cmd(i) == PathCmd.line)
290         {
291             file.rawWrite("L ");
292             file.rawWrite(to!string(path[i].x));
293             file.rawWrite(" ");
294             file.rawWrite(to!string(path[i].y));
295             file.rawWrite(" ");
296         }
297         if (path.cmd(i+1) == PathCmd.quad)
298         {
299             file.rawWrite("Q ");
300             file.rawWrite(to!string(path[i].x));
301             file.rawWrite(" ");
302             file.rawWrite(to!string(path[i].y));
303             file.rawWrite(" ");
304             file.rawWrite(to!string(path[i+1].x));
305             file.rawWrite(" ");
306             file.rawWrite(to!string(path[i+1].y));
307             file.rawWrite(" ");
308             i++;
309         }
310         if (path.cmd(i+1) == PathCmd.cubic)
311         {
312             file.rawWrite("C ");
313             file.rawWrite(to!string(path[i].x));
314             file.rawWrite(" ");
315             file.rawWrite(to!string(path[i].y));
316             file.rawWrite(" ");
317             file.rawWrite(to!string(path[i+1].x));
318             file.rawWrite(" ");
319             file.rawWrite(to!string(path[i+1].y));
320             file.rawWrite(" ");
321             file.rawWrite(to!string(path[i+2].x));
322             file.rawWrite(" ");
323             file.rawWrite(to!string(path[i+2].y));
324             file.rawWrite(" ");
325             i+=2;
326         }
327     }
328 
329     file.rawWrite("\" \n");
330 }
331 */
332 // generate random lines
333 /*
334 Path!float randomPath(int n, int seed)
335 {
336     import std.random;
337     
338     auto rnd = Random(seed);
339 
340     Path!float path;
341     path.moveTo(uniform(20.0f, 780.0f, rnd),uniform(20.0f, 780.0f, rnd));
342 
343     foreach(i; 0..n)
344     {
345         path.lineTo(uniform(20.0f, 780.0f, rnd),uniform(20.0f, 780.0f, rnd));
346     }
347     path.close();
348 
349     return path;
350 }
351 */
352 // generate random rounded rects
353 /*
354 Path!float randomRoundRect(int n, int seed)
355 {
356     import std.random;
357     
358     auto rnd = Random(seed);
359 
360     Path!float path;
361 
362     foreach(i; 0..n)
363     {
364         float x = uniform(20.0f, 580.0f, rnd);
365         float y = uniform(20.0f, 580.0f, rnd);
366         float w = uniform(20.0f, 200.0f, rnd);
367         float h = uniform(20.0f, 200.0f, rnd);
368         float c = uniform(2.0f, ((w<h) ? w : h)/3, rnd);
369         float lpc = c-c*0.55228;
370 
371         path.moveTo(x+c,y);
372         path.lineTo(x+w-c,y);
373         path.cubicTo(x+w-lpc,y,  x+w,y+lpc,  x+w,y+c);
374         path.lineTo(x+w,y+h-c);
375         path.cubicTo(x+w,y+h-lpc,  x+w-lpc,y+h,  x+w-c,y+h);
376         path.lineTo(x+c,y+h);
377         path.cubicTo(x+lpc,y+h,  x,y+h-lpc,  x,y+h-c);
378         path.lineTo(x,y+c);
379         path.cubicTo(x,y+lpc,  x+lpc,y,  x+c,y);
380     }
381     return path;
382 }
383 */
384 /*
385 RoundRect!float randomRoundRect()
386 {
387     import std.random;
388     static auto rnd = Random(123);
389 
390     float x = uniform(0, 600.0f, rnd);
391     float y = uniform(0, 600.0f, rnd);
392     float w = uniform(20, 200, rnd);
393     float h = uniform(20, 200, rnd);
394     float c = uniform(2.0f, ((w<h) ? w : h)/2, rnd);
395 
396     RoundRect!float rect = RoundRect!float(x,y,x+w,y+w,c,c);
397 
398     return rect;
399 }
400 */
401 
402 // build some text as a path
403 /*
404 Path!float buildTextPath(Font font, const char[] txt)
405 {
406     Path!float path;
407     float[] adv;
408     adv.length = txt.length;
409     font.getTextSpacing(txt,adv);
410 
411     int i;
412     int subi = 0;
413     float subx = 50, y = 50;
414     float pos = subx;
415 
416     for (i = 0; i < txt.length; i++)
417     {
418         if ((txt[i] == ' ') || (txt[i] == '\n'))
419         {
420             for (int k = subi; k <= i; k++)
421             {
422                 font.addChar(path, subx, y, txt[k]);
423                 subx += adv[k];
424             }
425             subi = i+1;
426         }
427 
428         if ((pos > 750) || (txt[i] == '\n'))
429         {
430             pos = 50+pos-subx;
431             subx = 50;
432             y += font.lineHeight();
433         }
434 
435         if (y > 750) return path;
436 
437         pos += adv[i];
438     }
439     return path;
440 }
441 */