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 }