1 /++
2 Module for animation of movement / frames and others. Contains a mutating
3 variable and a function that depends on it.
4 
5 See_Also:
6 	$(HREF https://github.com/ai/easings.net, Easing open source)
7 
8 Macros:
9     LREF = <a href="#$1">$1</a>
10     HREF = <a href="$1">$2</a>
11     PHOBREF = <a href="https://dlang.org/phobos/$1.html#$2">$2</a>
12 
13 Authors: $(HREF https://github.com/TodNaz,TodNaz)
14 Copyright: Copyright (c) 2020 - 2021, TodNaz.
15 License: $(HREF https://github.com/TodNaz/Tida/blob/master/LICENSE,MIT)
16 +/
17 module tida.animobj;
18 
19 /++
20 Object animation interface.
21 +/
22 interface IAnimated
23 {
24 @safe:
25 	/++
26 	Object animation function. Through such a call and a coefficient argument, 
27 	an animation is produced.
28 	
29 	Params:
30 		k = Animation step. Its range is from zero to one.
31 	+/
32     void animation(float k);
33 }
34 
35 /// Ease in sine animation
36 void easeInSine(ref float step, const(float) k) @safe nothrow pure
37 {
38 	import std.math : cos, PI;
39 
40 	step = 1 - cos((k * PI) / 2);
41 }
42 
43 /// Ease out sine animation
44 void easeOutSine(ref float step, const(float) k) @safe nothrow pure
45 {
46 	import std.math : sin, PI;
47 	
48 	step = sin((k * PI) / 2);
49 }
50 
51 /// Ease in out sine animation
52 void easeInOutSine(ref float step, const(float) k) @safe nothrow pure
53 {
54 	import std.math : cos, PI;
55 	
56 	step = -(cos(PI * k) - 1) / 2;
57 }
58 
59 /// Ease in degree animation
60 void easeIn(int degree)(ref float step, const(float) k) @safe nothrow pure
61 {
62 	import std.math : pow;
63 	
64 	step = pow(k, degree);
65 }
66 
67 /// Ease out degree animation
68 void easeOut(int degree)(ref float step, const(float) k) @safe nothrow pure
69 {
70 	import std.math : pow;
71 
72 	step = 1 - pow((1 - k), degree);
73 }
74 
75 /// Ease in out degree animation
76 void easeInOut(int degree)(ref float step, const(float) k) @safe nothrow pure
77 {
78 	import std.math : pow;
79 	
80 	step = k < 0.5f ? (2 * degree) * pow(k, degree) : 1 - pow(-2 * k + 2, degree) / 2;
81 }
82 
83 /// Ease in expo animation
84 void easeInExpo(ref float step, const(float) k) @safe nothrow pure
85 {
86 	import std.math : pow;
87 
88 	step = k == 0 ? 0 : pow(2, 10 * k - 10);
89 }
90 
91 /// Ease out expo animation
92 void easeOutExpo(ref float step, const(float) k) @safe nothrow pure
93 {
94 	import std.math : pow;
95 	
96 	step = k == 1 ? 1 : 1 - pow(2, -10 * k);
97 }
98 
99 /// Ease in out expo
100 void easeInOutExpo(ref float step, const(float) k) @safe nothrow pure
101 {
102 	import std.math : sqrt, pow;
103 	
104 	step = k == 0
105 		? 0
106 		: k == 1
107 		? 1
108 		: k < 0.5f ? pow(2, 20 * k - 10) / 2
109 		: (2 - pow(2, -20 * k + 10)) / 2;
110 }
111 
112 /// Ease in circ animation
113 void easeInCirc(ref float step, const(float) k) @safe nothrow pure
114 {
115 	import std.math : sqrt, pow;
116 	
117 	step = 1 - sqrt(1 - pow(k, 2));
118 }
119 
120 /// Ease out circ animation
121 void easeOutCirc(ref float step, const(float) k) @safe nothrow pure
122 {
123 	import std.math : sqrt, pow;
124 	
125 	step = sqrt(1 - pow(k - 1, 2));
126 }
127 
128 /// Ease in out circ animation
129 void easeInOutCirc(ref float step, const(float) k) @safe nothrow pure
130 {
131 	import std.math : pow, sqrt;
132 	
133 	step = k < 0.5f
134 		? (1 - sqrt(1 - pow(2 * k, 2))) / 2
135 		: (sqrt(1 - pow(-2 * k + 2, 2)) + 1) / 2;
136 }
137 
138 /// Ease in back animation
139 void easeInBack(ref float step, const(float) k) @safe nothrow pure
140 {
141 	immutable c1 = 1.70158f;
142 	immutable c3 = c1 + 1.0f;
143 	
144 	step = c3 * k * k * k - c1 * k * k;
145 }
146 
147 /// Ease out back animation
148 void easeOutBack(ref float step, const(float) k) @safe nothrow pure
149 {
150 	import std.math : pow;
151 	
152 	immutable c1 = 1.70158f;
153 	immutable c3 = c1 + 1.0f;
154 	
155 	step = 1 + c3 * pow(k - 1, 3) + c1 * pow(k - 1, 2);
156 }
157 
158 /// Ease in out animation
159 void easeInOutBack(ref float step, const(float) k) @safe nothrow pure
160 {
161 	import std.math : pow;
162 
163 	immutable c1 = 1.70158f;
164 	immutable c2 = c1 * 1.525;
165 	
166 	step = k < 0.5f
167 		? (pow(2 * k, 2) * ((c2 + 1) * 2 * k - c2)) / 2
168 		: (pow(2 * k - 2, 2) * ((c2 + 1) * (k * 2 - 2) + c2) + 2) / 2;
169 }
170 
171 /++
172 An object of smooth movement of an object along a function in a template.
173 
174 The function should contain the parameters of the motion step and the animation 
175 step, for example:
176 ---
177 void moveFunction(ref float step, const float k) @safe nothrow pure;
178 ---
179 +/
180 class MoveAnimation(alias moveFunction) : IAnimated
181 {
182 	import tida.vector;
183 
184 private:
185 	Vecf* vector;
186 	Vecf begin;
187 	
188 public:
189 	float distance;
190 	Vecf direction; 
191 
192 	/++
193 	Animation constructor.
194 	
195 	Params:
196 		vec = The position to move smoothly.
197 	+/
198 	this(ref Vecf vec) @trusted
199 	{
200 		vector = &vec;
201 		begin = vec;
202 	}
203 	
204 override @safe:
205 	void animation(float k)
206 	{
207 		float step = 0.0f;
208 		moveFunction(step, k);
209 		
210 		*vector = begin + (direction * (distance * step));
211 	}
212 }
213 
214 /++
215 Animation object. Animates an object.
216 +/
217 class Animator
218 {
219 private:
220     float k = 0.0f;
221 
222 public:
223 	/// Speed animation.
224     float speed = 0.01f;
225 
226 @safe:
227 	void reset() @safe
228 	{
229 		k = 0.0f;
230 	}
231 
232 	/++
233 	Object animation function. The input object receives an animation step from
234 	which it can play any animation.
235 	
236 	Params:
237 		anim = Animation object.
238 	+/
239     void step(IAnimated anim)
240     {
241     	if (k > 1.0f)
242     		return;
243      
244     	k += speed;
245 
246 		anim.animation(k);
247     }
248     
249     /// ditto
250     void stepArray(IAnimated[] anim)
251     {
252     	if (k > 1.0f)
253     		return;
254     
255     	k += speed;
256     	
257     	foreach(a; anim)
258 			a.animation(k);
259     }
260 }