1 /**
2  * Simple turtle graphics API
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.turtle;
15 
16 import std.math;
17 
18 import ae.utils.graphics.draw;
19 import ae.utils.graphics.view;
20 
21 struct Turtle(View)
22 	if (isWritableView!View)
23 {
24 	alias Color = ViewColor!View;
25 
26 	/// View to draw on. This will usually be a reference.
27 	View view;
28 
29 	/// How many pixels is one unit (as used by `forward`).
30 	float scale;
31 
32 	/// Current turtle coordinates.
33 	float x = 0, y = 0;
34 
35 	/// Current turtle orientation (in degrees).
36 	/// Initially, the turtle is facing upwards.
37 	float orientation = 270;
38 
39 	/// Current turtle color.
40 	Color color;
41 
42 	/// Is the pen currently down?
43 	bool penActive = false;
44 
45 	/// Put the pen up or down.
46 	void penUp  () { penActive = false; }
47 	void penDown() { penActive = true;  } /// ditto
48 
49 	/// Change the turtle orientation by the given number of degrees.
50 	void turnLeft (float deg) { orientation -= deg; }
51 	void turnRight(float deg) { orientation += deg; } /// ditto
52 	void turnAround() { orientation += 180; }
53 
54 	/// Move the turtle forward by the given number of units.
55 	/// If the pen is down, draw a line with the configured color.
56 	void forward(float distance)
57 	{
58 		// Angle in radians.
59 		float rad = orientation / 180 * PI;
60 
61 		// Convert distance from units to pixels.
62 		distance *= scale;
63 
64 		// Endpoint coordinates.
65 		float x0 = this.x;
66 		float y0 = this.y;
67 		float x1 = x0 + distance * cos(rad);
68 		float y1 = y0 + distance * sin(rad);
69 
70 		// Draw a line if needed.
71 		if (penActive)
72 			view.aaLine(x0, y0, x1, y1, color);
73 
74 		// Update coordinates.
75 		this.x = x1;
76 		this.y = y1;
77 	}
78 }
79 
80 auto turtle(View)(ref View view)
81 	if (isWritableView!View)
82 {
83 	import std.typecons;
84 	alias R = NullableRef!View;
85 	R r = R(&view);
86 	return Turtle!R(r);
87 }