1 /** 2 * Simple turtle graphics demo 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <vladimir@thecybershadow.net> 12 */ 13 14 module ae.demo.turtle.main; 15 16 import std.algorithm.comparison; 17 import std.math; 18 19 import ae.demo.turtle.turtle; 20 import ae.ui.app.application; 21 import ae.ui.app.main; 22 import ae.ui.shell.shell; 23 import ae.ui.shell.sdl2.shell; 24 import ae.ui.video.video; 25 import ae.ui.video.sdl2.video; 26 import ae.ui.video.renderer; 27 import ae.utils.graphics.draw; 28 29 final class MyApplication : Application 30 { 31 override string getName() { return "Demo/Turtle"; } 32 override string getCompanyName() { return "CyberShadow"; } 33 34 Shell shell; 35 36 alias Color = Renderer.COLOR; 37 38 Image!Color image; 39 int demoIndex; 40 41 override void render(Renderer s) 42 { 43 auto canvas = s.lock(); 44 scope(exit) s.unlock(); 45 46 if (image.w != canvas.w || image.h != canvas.h) 47 renderImage(canvas.w, canvas.h); 48 image.blitTo(canvas); 49 } 50 51 override void handleMouseDown(uint x, uint y, MouseButton button) 52 { 53 demoIndex++; 54 image = image.init; // Force redraw next frame 55 } 56 57 void renderImage(int w, int h) 58 { 59 image.size(w, h); 60 image.fill(Color.init); 61 62 auto t = image.turtle(); 63 t.x = w/2; 64 t.y = h/2; 65 t.scale = min(w, h) * 0.75f; 66 t.color = Color.white; 67 68 switch (demoIndex % 4) 69 { 70 case 0: 71 shell.setCaption("Square"); 72 // Move to the corner 73 t.turnLeft(90); 74 t.forward(0.5); 75 t.turnLeft(90); 76 t.forward(0.5); 77 t.turnAround(); 78 // Draw a square 79 t.penDown(); 80 foreach (n; 0..4) 81 { 82 t.forward(1.0); 83 t.turnRight(90); 84 } 85 break; 86 87 case 1: 88 shell.setCaption("Plus"); 89 // Draw a spoke, turn left, repeat 4 times 90 t.penDown(); 91 foreach (n; 0..4) 92 { 93 t.forward(0.5); 94 t.turnAround(); 95 t.forward(0.5); 96 t.turnLeft(90); 97 } 98 break; 99 100 case 2: 101 // Function to draw an arbitrary regular convex polygon. 102 void drawPolygon(int sides) 103 { 104 t.forward(0.5); 105 t.turnRight(90 + 180f / sides); 106 t.penDown(); 107 auto sideAngle = 360f / sides; 108 auto sideLength = sin(sideAngle / 180 * PI) * 0.5; 109 foreach (n; 0..sides) 110 { 111 t.forward(sideLength); 112 t.turnRight(sideAngle); 113 } 114 return; 115 } 116 117 shell.setCaption("Octagon"); 118 drawPolygon(8); 119 break; 120 121 case 3: 122 { 123 shell.setCaption("Koch snowflake"); 124 enum maxDepth = 6; 125 126 // Recursive function used to draw one segment. 127 void drawSegment(float scale, int depth) 128 { 129 if (depth == maxDepth) 130 t.forward(scale); 131 else 132 { 133 drawSegment(scale/3, depth+1); 134 t.turnLeft(60); 135 drawSegment(scale/3, depth+1); 136 t.turnRight(120); 137 drawSegment(scale/3, depth+1); 138 t.turnLeft(60); 139 drawSegment(scale/3, depth+1); 140 } 141 } 142 143 t.forward(0.5); 144 t.turnRight(120); 145 t.penDown(); 146 foreach (n; 0..6) 147 { 148 drawSegment(0.5, 0); 149 t.turnRight(60); 150 } 151 break; 152 } 153 154 default: 155 assert(false); 156 } 157 } 158 159 override int run(string[] args) 160 { 161 shell = new SDL2Shell(this); 162 shell.video = new SDL2SoftwareVideo(); 163 shell.run(); 164 shell.video.shutdown(); 165 return 0; 166 } 167 168 override void handleQuit() 169 { 170 shell.quit(); 171 } 172 } 173 174 shared static this() 175 { 176 createApplication!MyApplication(); 177 }