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 */