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