1 /**
2 Grimoire
3 Copyright (c) 2017 Enalye
4 
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising
7 from the use of this software.
8 
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute
11 it freely, subject to the following restrictions:
12 
13 	1. The origin of this software must not be misrepresented;
14 	   you must not claim that you wrote the original software.
15 	   If you use this software in a product, an acknowledgment
16 	   in the product documentation would be appreciated but
17 	   is not required.
18 
19 	2. Altered source versions must be plainly marked as such,
20 	   and must not be misrepresented as being the original software.
21 
22 	3. This notice may not be removed or altered from any source distribution.
23 */
24 
25 module core.tween;
26 
27 import std.math;
28 
29 import common.all;
30 import core.util;
31 
32 enum TimeMode {
33 	Stopped,
34 	Once,
35 	Loop,
36 	Bounce
37 }
38 
39 struct Timer {
40 	private {
41 		float _time = 0f, _speed = 0f;
42 		bool _isReversed = false;
43 	}
44 
45 	TimeMode mode = TimeMode.Stopped;
46 
47 	@property {
48 		float time() const { return _time; }
49 
50 		float duration() const { return _speed * nominalFps; }
51 		float duration(float newDuration) {
52 			if(newDuration <= 0f) {
53 				_speed = 0f;
54 				_time = 1f;
55 			}
56 			else
57 				_speed = 1f / (nominalFps * newDuration);
58 			return newDuration;
59 		}
60 
61 		bool isRunning() const { return (mode != TimeMode.Stopped); }
62 
63 		bool isReversed() const { return _isReversed; }
64 		bool isReversed(bool newIsReversed) { return _isReversed = newIsReversed; }
65 	}
66 	
67 	void start(float newDuration, TimeMode newTimeMode = TimeMode.Once) {
68 		_time = 0f;
69 		_isReversed = false;
70 		duration(newDuration);
71 		mode = newTimeMode;
72 	}
73 
74 	void startReverse(float newDuration, TimeMode newTimeMode = TimeMode.Once) {
75 		_time = 1f;
76 		_isReversed = true;
77 		duration(newDuration);
78 		mode = newTimeMode;
79 	}
80 
81     void stop() {
82         mode = TimeMode.Stopped;
83     }
84 
85 	void update(float deltaTime) {
86 		switch(mode) with(TimeMode) {
87 		case Stopped:
88 			break;
89 		case Once:
90 			if(_isReversed) {
91 				if(_time > 0f)
92 					_time -= _speed * deltaTime;
93 				if(_time < 0f) {
94 					_time = 0f;
95 					mode = TimeMode.Stopped;
96 				}
97 			}
98 			else {
99 				if(_time < 1f)
100 					_time += _speed * deltaTime;
101 				if(_time > 1f) {
102 					_time = 1f;
103 					mode = TimeMode.Stopped;
104 				}
105 			}
106 			break;
107 		case Loop:
108 			if(_time < 1f)
109 				_time += _speed * deltaTime;
110 			if(_time > 1f)
111 				_time = (_time - 1f) + (_speed * deltaTime);
112 			break;
113 		case Bounce:
114 			if(_isReversed) {
115 				if(_time > 0f)
116 					_time -= _speed * deltaTime;
117 				if(_time < 0f) {
118 					_time = -(_time - (_speed * deltaTime));
119 					_isReversed = false;
120 				}
121 			}
122 			else {
123 				if(_time < 1f)
124 					_time += _speed * deltaTime;
125 				if(_time > 1f) {
126 					_time = 1f - ((_time - 1f) + (_speed * deltaTime));
127 					_isReversed = true;
128 				}
129 			}
130 			break;
131 		default:
132 			throw new Exception("Invalid time mode");
133 		}
134 	}
135 }
136 
137 //Sine
138 float easeInSine(float t) {
139 	return sin((t - 1f) * PI_2) + 1f;
140 }
141 
142 float easeOutSine(float t) {
143 	return sin(t * PI_2);
144 }
145 
146 float easeInOutSine(float t) {
147 	return (1f - cos(t * PI)) / 2f;
148 }
149 
150 //Quad
151 float easeInQuad(float t) {
152 	return t * t;
153 }
154 
155 float easeOutQuad(float t) {
156 	return -(t * (t - 2));
157 }
158 
159 float easeInOutQuad(float t) {
160 	if(t < .5f)
161 		return 2f * t * t;
162 	else
163 		return (-2f * t * t) + (4f * t) - 1f;
164 }
165 
166 //Cubic
167 float easeInCubic(float t) {
168 	return t * t * t;
169 }
170 
171 float easeOutCubic(float t) {
172 	t = (t - 1f);
173 	t = (t * t * t + 1f);
174 	return t;
175 }
176 
177 float easeInOutCubic(float t) {
178 	if(t < .5f)
179 		return 4f * t * t * t;
180 	else {
181 		float f = ((2f * t) - 2f);
182 		return .5f * f * f * f + 1f;
183 	}
184 }
185 
186 //Quart
187 float easeInQuart(float t) {
188 	return t * t * t * t;
189 }
190 
191 float easeOutQuart(float t) {
192 	float f = (t - 1f);
193 	return f * f * f * (1f - t) + 1f;
194 }
195 
196 float easeInOutQuart(float t) {
197 	if(t < .5f)
198 		return 8f * t * t * t * t;
199 	else {
200 		float f = (t - 1f);
201 		return -8f * f * f * f * f + 1f;
202 	}
203 }
204 
205 //Quint
206 float easeInQuint(float t) {
207 	return t * t * t * t * t;
208 }
209 
210 float easeOutQuint(float t) {
211 	float f = (t - 1f);
212 	return f * f * f * f * f + 1f;
213 }
214 
215 float easeInOutQuint(float t) {
216 	if(t < .5f)
217 		return 16f * t * t * t * t * t;
218 	else {
219 		float f = ((2f * t) - 2f);
220 		return  .5f * f * f * f * f * f + 1f;
221 	}
222 }
223 
224 //Exp
225 float easeInExp(float t) {
226 	return (t == 0f) ? t : pow(2f, 10f * (t - 1f));
227 }
228 
229 float easeOutExp(float t) {
230 	return (t == 1f) ? t : 1f - pow(2f, -10f * t);
231 }
232 
233 float easeInOutExp(float t) {
234 	if(t == 0f || t == 1f)
235 		return t;
236 	if(t < .5f)
237 		return .5f * pow(2f, (20f * t) - 10f);
238 	else
239 		return -.5f * pow(2f, (-20f * t) + 10f) + 1f;
240 }
241 
242 //Circ
243 float easeInCirc(float t) {
244 	return 1f - sqrt(1f - (t * t));
245 }
246 
247 float easeOutCirc(float t) {
248 	return sqrt((2f - t) * t);
249 }
250 
251 float easeInOutCirc(float t) {
252 	if(t < .5f)
253 		return .5f * (1f - sqrt(1f - 4f * (t * t)));
254 	else
255 		return .5f * (sqrt(-((2f * t) - 3f) * ((2f * t) - 1f)) + 1f);
256 }
257 
258 //Back
259 float easeInBack(float t) {
260 	return t * t * t - t * sin(t * PI);
261 }
262 
263 float easeOutBack(float t) {
264 	float f = (1f - t);
265 	return 1f - (f * f * f - f * sin(f * PI));
266 }
267 
268 float easeInOutBack(float t) {
269 	if(t < .5f) {
270 		t *= 2f;
271 		return (t * t * t - t * sin(t * PI)) / 2f;
272 	}
273 	t = (1f - (2f*t - 1f));
274 	return (1f - (t * t * t - t * sin(t * PI))) / 2f + .5f;
275 }
276 
277 //Elastic
278 float easeInElastic(float t) {
279 	return sin(13f * PI_2 * t) * pow(2f, 10f * (t - 1f));
280 }
281 
282 float easeOutElastic(float t) {
283 	return sin(-13f * PI_2 * (t + 1)) * pow(2f, -10f * t) + 1f;
284 }
285 
286 float easeInOutElastic(float t) {
287 	if(t < .5f)
288 		return .5f * sin(13f * PI_2 * (2f * t)) * pow(2f, 10f * ((2f * t) - 1f));
289 	else
290 		return .5f * (sin(-13f * PI_2 * ((2f * t - 1f) + 1f)) * pow(2f, -10f * (2f * t - 1f)) + 2f);
291 }
292 
293 //Bounce
294 float easeInBounce(float t) {
295 	return 1f - easeOutBounce(1f - t);
296 }
297 
298 float easeOutBounce(float t) {
299 	if(t < 4f/11f)
300 		return (121f * t * t)/16f;
301 	else if(t < 8f/11f)
302 		return (363f/40f * t * t) - (99f/10f * t) + 17f/5f;
303 	else if(t < 9f/10f)
304 		return (4356f/361f * t * t) - (35442f/1805f * t) + 16061f/1805f;
305 	return (54f/5f * t * t) - (513f/25f * t) + 268f/25f;
306 }
307 
308 float easeInOutBounce(float t) {
309 	if(t < .5f)
310 		return easeInBounce(t * 2f) / 2f;
311 	else
312 		return easeOutBounce(t * 2f - 1f) / 2f + .5f;
313 }