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 <ae@cy.md>
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(xy_t w, xy_t 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 }