/* $Id$ */ /* Copyright (C) 2004 by Philippe Plantier Copyright (C) 2005 - 2012 by Guillaume Melquiond Part of the Battle for Wesnoth Project http://www.wesnoth.org/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 or at your option any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. See the COPYING file for more details. */ /** * @file animated.i * Templates related to animations. */ #include "global.hpp" #include #include "SDL.h" #include "animated.hpp" namespace { int current_ticks = 0; } void new_animation_frame() { current_ticks = SDL_GetTicks(); } int get_current_animation_tick() { return current_ticks; } template const T animated::void_value_ = T_void_value()(); template animated::animated(int start_time) : starting_frame_time_(start_time), does_not_change_(true), started_(false), force_next_update_(false), frames_(), start_tick_(0), cycles_(false), acceleration_(1), last_update_tick_(0), current_frame_key_(0) { } template animated::animated(const std::vector > &cfg, int start_time, bool force_change ): starting_frame_time_(start_time), does_not_change_(true), started_(false), force_next_update_(false), frames_(), start_tick_(0), cycles_(false), acceleration_(1), last_update_tick_(0), current_frame_key_(0) { typename std::vector< std::pair >::const_iterator itor = cfg.begin(); for(; itor != cfg.end(); ++itor) { add_frame(itor->first,itor->second,force_change); } } template void animated::add_frame(int duration, const T& value,bool force_change) { if(frames_.empty() ) { does_not_change_=!force_change; frames_.push_back( frame(duration,value,starting_frame_time_)); } else { does_not_change_=false; frames_.push_back( frame(duration,value,frames_.back().start_time_+frames_.back().duration_)); } } template void animated::start_animation(int start_time, bool cycles) { started_ = true; last_update_tick_ = current_ticks; acceleration_ = 1.0; //assume acceleration is 1, this will be fixed at first update_last_draw_time start_tick_ = last_update_tick_ + static_cast(( starting_frame_time_ - start_time)/acceleration_); cycles_ = cycles; if(acceleration_ <=0) acceleration_ = 1; current_frame_key_= 0; force_next_update_ = !frames_.empty(); } template void animated::update_last_draw_time(double acceleration) { if (acceleration > 0 && acceleration_ != acceleration) { int tmp = tick_to_time(last_update_tick_); acceleration_ = acceleration; start_tick_ = last_update_tick_ + static_cast(( starting_frame_time_ - tmp)/acceleration_); } if(!started_ && start_tick_ != 0) { // animation is paused start_tick_ +=current_ticks -last_update_tick_; } last_update_tick_ = current_ticks; if (force_next_update_) { force_next_update_ = false; return; } if(does_not_change_) return; // Always update last_update_tick_, for the animation_time functions to work. if(!started_) { return; } if(frames_.empty()) { does_not_change_ = true; return; } if(cycles_) { while(get_animation_time() > get_end_time()){ // cut extra time start_tick_ += std::max(static_cast(get_animation_duration()/acceleration_),1); current_frame_key_ = 0; } } if(get_current_frame_end_time() < get_animation_time() && // catch up get_current_frame_end_time() < get_end_time()) {// don't go after the end current_frame_key_++; } } template bool animated::need_update() const { if(force_next_update_) { return true; } if(does_not_change_) { return false; } if(frames_.empty()) { return false; } if(!started_ && start_tick_ == 0) { return false; } if(current_ticks > static_cast(get_current_frame_end_time() / acceleration_+start_tick_)){ return true; } return false; } template bool animated::animation_finished_potential() const { if(frames_.empty()) return true; if(!started_ && start_tick_ == 0) return true; if(cycles_ ) return true; if(tick_to_time(current_ticks) > get_end_time()) return true; return false; } template bool animated::animation_finished() const { if(frames_.empty()) return true; if(!started_ && start_tick_ == 0) return true; if(cycles_) return true; if(get_animation_time() > get_end_time()) return true; return false; } template int animated::get_animation_time_potential() const { if(!started_ && start_tick_ == 0 ) return starting_frame_time_; return tick_to_time(current_ticks); } template int animated::get_animation_time() const { if(!started_ && start_tick_ == 0 ) return starting_frame_time_; return tick_to_time(last_update_tick_); } template void animated::set_animation_time(int time) { start_tick_ = last_update_tick_ + static_cast(( starting_frame_time_ - time)/acceleration_); current_frame_key_= 0; force_next_update_ = true; } template int animated::get_animation_duration() const { return get_end_time() - get_begin_time(); } template const T& animated::get_current_frame() const { if(frames_.empty() ) return void_value_; return frames_[current_frame_key_].value_; } template int animated::get_current_frame_begin_time() const { if(frames_.empty() ) return starting_frame_time_; return frames_[current_frame_key_].start_time_; } template int animated::get_current_frame_end_time() const { if(frames_.empty() ) return starting_frame_time_; return get_current_frame_begin_time() +get_current_frame_duration(); } template int animated::get_current_frame_duration() const { if(frames_.empty() ) return 0; return frames_[current_frame_key_].duration_; } template int animated::get_current_frame_time() const { if(frames_.empty() ) return 0; //FIXME: get_animation_time() use acceleration but get_current_frame_begin_time() doesn't ? return std::max(0,get_animation_time() - get_current_frame_begin_time()); } template const T& animated::get_first_frame() const { if(frames_.empty() ) return void_value_; return frames_[0].value_; } template const T& animated::get_frame(size_t n) const { if(n >= frames_.size()) return void_value_; return frames_[n].value_; } template const T& animated::get_last_frame() const { if(frames_.empty() ) return void_value_; return frames_.back().value_; } template size_t animated::get_frames_count() const { return frames_.size(); } template int animated::get_begin_time() const { return starting_frame_time_; } template int animated::time_to_tick(int animation_time) const { if(!started_ && start_tick_ == 0) return 0; return start_tick_ + static_cast((animation_time-starting_frame_time_)/acceleration_); } template int animated::tick_to_time(int animation_tick) const { if(!started_ && start_tick_ == 0) return 0; return static_cast( (static_cast(animation_tick - start_tick_) * acceleration_) + starting_frame_time_); } template int animated::get_end_time() const { if(frames_.empty()) return starting_frame_time_; return frames_.back().start_time_ + frames_.back().duration_; } template void animated::remove_frames_until(int new_starting_time) { while (starting_frame_time_ < new_starting_time && !frames_.empty() ) { starting_frame_time_ += frames_[0].duration_; frames_.erase(frames_.begin()); } } template void animated::set_end_time(int new_ending_time) { int last_start_time = starting_frame_time_; typename std::vector::iterator current_frame = frames_.begin(); while (last_start_time < new_ending_time && current_frame != frames_.end()) { last_start_time += current_frame->duration_; current_frame++; } // at this point last_start_time is set to the beginning of the first frame past the end // or set to frames_.end() frames_.erase(current_frame,frames_.end()); frames_.back().duration_ += new_ending_time - last_start_time; } template void animated::set_begin_time(int new_begin_time) { const int variation = new_begin_time - starting_frame_time_; starting_frame_time_ += variation; for(typename std::vector::iterator itor = frames_.begin(); itor != frames_.end() ; ++itor) { itor->start_time_ += variation; } }