The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
animated.tpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2004 by Philippe Plantier <[email protected]>
3  Copyright (C) 2005 - 2016 by Guillaume Melquiond <[email protected]>
4  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License version 2
8  or at your option any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * @file animated.tpp
17  * Templates related to animations.
18  */
19 
20 #include "global.hpp"
21 
22 #include <climits>
23 
24 #include <SDL.h>
25 #include "animated.hpp"
26 
27 template<typename T, typename T_void_value>
28 const T animated<T,T_void_value>::void_value_ = T_void_value()();
29 
30 template<typename T, typename T_void_value>
31 inline animated<T,T_void_value>::animated(int start_time) :
32  starting_frame_time_(start_time),
33  does_not_change_(true),
34  started_(false),
35  force_next_update_(false),
36  frames_(),
37  start_tick_(0),
38  cycles_(false),
39  acceleration_(1),
40  last_update_tick_(0),
41  current_frame_key_(0)
42 {
43 }
44 
45 template<typename T, typename T_void_value>
46 inline animated<T,T_void_value>::animated(const std::vector<std::pair<int,T> > &cfg, int start_time, bool force_change ):
47  starting_frame_time_(start_time),
48  does_not_change_(true),
49  started_(false),
50  force_next_update_(false),
51  frames_(),
52  start_tick_(0),
53  cycles_(false),
54  acceleration_(1),
55  last_update_tick_(0),
56  current_frame_key_(0)
57 {
58  typename std::vector< std::pair<int,T> >::const_iterator itor = cfg.begin();
59  for (; itor != cfg.end(); ++itor) {
60  add_frame(itor->first,itor->second,force_change);
61  }
62 }
63 
64 template<typename T, typename T_void_value>
65 inline void animated<T,T_void_value>::add_frame(int duration, const T& value,bool force_change)
66 {
67  if (frames_.empty() ) {
68  does_not_change_=!force_change;
69  frames_.push_back( frame(duration,value,starting_frame_time_));
70  } else {
71  does_not_change_=false;
72  frames_.push_back( frame(duration,value,frames_.back().start_time_+frames_.back().duration_));
73  }
74 }
75 
76 template<typename T, typename T_void_value>
77 inline void animated<T,T_void_value>::start_animation(int start_time, bool cycles)
78 {
79  started_ = true;
80  last_update_tick_ = get_current_animation_tick();
81  acceleration_ = 1.0; //assume acceleration is 1, this will be fixed at first update_last_draw_time
82  start_tick_ = last_update_tick_ +
83  static_cast<int>(( starting_frame_time_ - start_time)/acceleration_);
84 
85  cycles_ = cycles;
86  if (acceleration_ <= 0) {
87  acceleration_ = 1;
88  }
89  current_frame_key_= 0;
90  force_next_update_ = !frames_.empty();
91 }
92 
93 template<typename T, typename T_void_value>
94 inline void animated<T,T_void_value>::update_last_draw_time(double acceleration)
95 {
96  if (acceleration > 0 && acceleration_ != acceleration) {
97  int tmp = tick_to_time(last_update_tick_);
98  acceleration_ = acceleration;
99  start_tick_ = last_update_tick_ +
100  static_cast<int>(( starting_frame_time_ - tmp)/acceleration_);
101  }
102  if (!started_ && start_tick_ != 0) {
103  // animation is paused
104  start_tick_ += get_current_animation_tick() - last_update_tick_;
105  }
106  last_update_tick_ = get_current_animation_tick();
107  if (force_next_update_) {
108  force_next_update_ = false;
109  return;
110  }
111  if (does_not_change_) {
112  return;
113  }
114 
115  // Always update last_update_tick_, for the animation_time functions to work.
116  if (!started_) {
117  return;
118  }
119 
120  if (frames_.empty()) {
121  does_not_change_ = true;
122  return;
123  }
124  if (cycles_) {
125  while(get_animation_time() > get_end_time()){ // cut extra time
126  start_tick_ += std::max<int>(static_cast<int>(get_animation_duration()/acceleration_),1);
127  current_frame_key_ = 0;
128  }
129  }
130  if (get_current_frame_end_time() < get_animation_time() && // catch up
131  get_current_frame_end_time() < get_end_time()) {// don't go after the end
132  current_frame_key_++;
133  }
134 }
135 
136 template<typename T, typename T_void_value>
137 inline bool animated<T,T_void_value>::need_update() const
138 {
139  if (force_next_update_) {
140  return true;
141  }
142  if (does_not_change_) {
143  return false;
144  }
145  if (frames_.empty()) {
146  return false;
147  }
148  if (!started_ && start_tick_ == 0) {
149  return false;
150  }
151  if (get_current_animation_tick() >
152  static_cast<int>(get_current_frame_end_time() /
153  acceleration_ + start_tick_)) {
154  return true;
155  }
156  return false;
157 }
158 
159 template<typename T, typename T_void_value>
160 inline bool animated<T,T_void_value>::animation_finished_potential() const
161 {
162  if (frames_.empty()) {
163  return true;
164  }
165  if (!started_ && start_tick_ == 0) {
166  return true;
167  }
168  if (cycles_ ) {
169  return true;
170  }
171  if (tick_to_time(get_current_animation_tick()) > get_end_time()) {
172  return true;
173  }
174 
175  return false;
176 }
177 
178 template<typename T, typename T_void_value>
179 inline bool animated<T,T_void_value>::animation_finished() const
180 {
181  if (frames_.empty()) {
182  return true;
183  }
184  if (!started_ && start_tick_ == 0) {
185  return true;
186  }
187  if (cycles_) {
188  return true;
189  }
190  if (get_animation_time() > get_end_time()) {
191  return true;
192  }
193 
194  return false;
195 }
196 
197 template<typename T, typename T_void_value>
198 inline int animated<T,T_void_value>::get_animation_time_potential() const
199 {
200  if (!started_ && start_tick_ == 0 ) {
201  return starting_frame_time_;
202  }
203 
204  return tick_to_time(get_current_animation_tick());
205 }
206 
207 template<typename T, typename T_void_value>
208 inline int animated<T,T_void_value>::get_animation_time() const
209 {
210  if (!started_ && start_tick_ == 0 ) {
211  return starting_frame_time_;
212  }
213 
214  return tick_to_time(last_update_tick_);
215 }
216 
217 template<typename T, typename T_void_value>
218 inline void animated<T,T_void_value>::set_animation_time(int time)
219 {
220  start_tick_ = last_update_tick_ +
221  static_cast<int>((starting_frame_time_ - time) / acceleration_);
222 
223  current_frame_key_= 0;
224  force_next_update_ = true;
225 }
226 
227 template<typename T, typename T_void_value>
228 inline int animated<T,T_void_value>::get_animation_duration() const
229 {
230  return get_end_time() - get_begin_time();
231 }
232 
233 template<typename T, typename T_void_value>
234 inline const T& animated<T,T_void_value>::get_current_frame() const
235 {
236  if (frames_.empty()) {
237  return void_value_;
238  }
239  return frames_[current_frame_key_].value_;
240 }
241 
242 template<typename T, typename T_void_value>
243 inline int animated<T,T_void_value>::get_current_frame_begin_time() const
244 {
245  if (frames_.empty()) {
246  return starting_frame_time_;
247  }
248  return frames_[current_frame_key_].start_time_;
249 }
250 
251 template<typename T, typename T_void_value>
252 inline int animated<T,T_void_value>::get_current_frame_end_time() const
253 {
254  if (frames_.empty()) {
255  return starting_frame_time_;
256  }
257  return get_current_frame_begin_time() +get_current_frame_duration();
258 }
259 
260 template<typename T, typename T_void_value>
261 inline int animated<T,T_void_value>::get_current_frame_duration() const
262 {
263  if (frames_.empty()) {
264  return 0;
265  }
266  return frames_[current_frame_key_].duration_;
267 }
268 
269 template<typename T, typename T_void_value>
270 inline int animated<T,T_void_value>::get_current_frame_time() const
271 {
272  if (frames_.empty()) {
273  return 0;
274  }
275  //FIXME: get_animation_time() use acceleration but get_current_frame_begin_time() doesn't ?
276  return std::max<int>(0,get_animation_time() - get_current_frame_begin_time());
277 }
278 
279 template<typename T, typename T_void_value>
280 inline const T& animated<T,T_void_value>::get_first_frame() const
281 {
282  if (frames_.empty()) {
283  return void_value_;
284  }
285  return frames_[0].value_;
286 }
287 
288 template<typename T, typename T_void_value>
289 inline const T& animated<T,T_void_value>::get_frame(size_t n) const
290 {
291  if (n >= frames_.size()) {
292  return void_value_;
293  }
294  return frames_[n].value_;
295 }
296 
297 template<typename T, typename T_void_value>
298 inline const T& animated<T,T_void_value>::get_last_frame() const
299 {
300  if (frames_.empty()) {
301  return void_value_;
302  }
303  return frames_.back().value_;
304 }
305 
306 template<typename T, typename T_void_value>
307 inline size_t animated<T,T_void_value>::get_frames_count() const
308 {
309  return frames_.size();
310 }
311 
312 template<typename T, typename T_void_value>
313 inline int animated<T,T_void_value>::get_begin_time() const
314 {
315  return starting_frame_time_;
316 }
317 
318 template<typename T, typename T_void_value>
319 inline int animated<T,T_void_value>::time_to_tick(int animation_time) const
320 {
321  if (!started_ && start_tick_ == 0) {
322  return 0;
323  }
324  return start_tick_ + static_cast<int>((animation_time-starting_frame_time_) / acceleration_);
325 }
326 
327 template<typename T, typename T_void_value>
328 inline int animated<T,T_void_value>::tick_to_time(int animation_tick) const
329 {
330  if (!started_ && start_tick_ == 0) {
331  return 0;
332  }
333  return static_cast<int>(
334  (static_cast<double>(animation_tick - start_tick_) *
335  acceleration_) + starting_frame_time_);
336 }
337 
338 template<typename T, typename T_void_value>
339 inline int animated<T,T_void_value>::get_end_time() const
340 {
341  if (frames_.empty()) {
342  return starting_frame_time_;
343  }
344  return frames_.back().start_time_ + frames_.back().duration_;
345 }
346 
347 template<typename T, typename T_void_value>
348 void animated<T,T_void_value>::remove_frames_until(int new_starting_time)
349 {
350  while (starting_frame_time_ < new_starting_time && !frames_.empty()) {
351  starting_frame_time_ += frames_[0].duration_;
352  frames_.erase(frames_.begin());
353  }
354 }
355 
356 template<typename T, typename T_void_value>
357 inline void animated<T,T_void_value>::set_end_time(int new_ending_time)
358 {
359  int last_start_time = starting_frame_time_;
360  typename std::vector<frame>::iterator current_frame = frames_.begin();
361  while (last_start_time < new_ending_time && current_frame != frames_.end()) {
362  last_start_time += current_frame->duration_;
363  ++current_frame;
364  }
365  // at this point last_start_time is set to the beginning of the first frame past the end
366  // or set to frames_.end()
367  frames_.erase(current_frame,frames_.end());
368  frames_.back().duration_ += new_ending_time - last_start_time;
369 }
370 
371 template<typename T, typename T_void_value>
372 inline void animated<T,T_void_value>::set_begin_time(int new_begin_time)
373 {
374  const int variation = new_begin_time - starting_frame_time_;
375  starting_frame_time_ += variation;
376  for (typename std::vector<frame>::iterator itor = frames_.begin(); itor != frames_.end() ; ++itor) {
377  itor->start_time_ += variation;
378  }
379 }
380