The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
frame.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2016 by Jeremy Rosen <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (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 /** @file */
16 
17 #include "global.hpp"
18 
19 #include "game_display.hpp"
20 #include "halo.hpp"
21 #include "sound.hpp"
22 #include "units/frame.hpp"
23 
24 
26  data_(),
27  input_(data)
28 {
29  const std::vector<std::string> first_pass = utils::square_parenthetical_split(data);
30  int time_chunk = std::max<int>(duration, 1);
31  std::vector<std::string>::const_iterator tmp;
32 
33  if (duration > 1 && first_pass.size() > 0) {
34  // If duration specified, divide evenly the time for items with unspecified times
35  int total_specified_time = 0;
36  for(tmp=first_pass.begin(); tmp != first_pass.end(); ++tmp) {
37  std::vector<std::string> second_pass = utils::split(*tmp,':');
38  if(second_pass.size() > 1) {
39  total_specified_time += std::stoi(second_pass[1]);
40  }
41  }
42  time_chunk = std::max<int>((duration - total_specified_time) / first_pass.size(), 1);
43  }
44 
45  for(tmp=first_pass.begin(); tmp != first_pass.end(); ++tmp) {
46  std::vector<std::string> second_pass = utils::split(*tmp,':');
47  if(second_pass.size() > 1) {
48  data_.push_back(std::pair<std::string,int>(second_pass[0],std::stoi(second_pass[1])));
49  } else {
50  data_.push_back(std::pair<std::string,int>(second_pass[0],time_chunk));
51  }
52  }
53 }
55 {
56  int total =0;
57  std::vector<std::pair<std::string,int> >::const_iterator cur_halo;
58  for(cur_halo = data_.begin() ; cur_halo != data_.end() ; ++cur_halo) {
59  total += cur_halo->second;
60  }
61  return total;
62 }
63 
65  data_(),
66  input_(data)
67 {
68  const std::vector<std::string> first_pass = utils::square_parenthetical_split(data);
69  int time_chunk = std::max<int>(duration, 1);
70  std::vector<std::string>::const_iterator tmp;
71 
72  if (duration > 1 && first_pass.size() > 0) {
73  // If duration specified, divide evenly the time for images with unspecified times
74  int total_specified_time = 0;
75  for(tmp=first_pass.begin(); tmp != first_pass.end(); ++tmp) {
76  std::vector<std::string> second_pass = utils::split(*tmp,':');
77  if(second_pass.size() > 1) {
78  total_specified_time += std::stoi(second_pass[1]);
79  }
80  }
81  time_chunk = std::max<int>((duration - total_specified_time) / first_pass.size(), 1);
82  }
83 
84  for(tmp=first_pass.begin(); tmp != first_pass.end(); ++tmp) {
85  std::vector<std::string> second_pass = utils::split(*tmp,':');
86  if(second_pass.size() > 1) {
87  data_.push_back(std::pair<image::locator,int>(second_pass[0],std::stoi(second_pass[1])));
88  } else {
89  data_.push_back(std::pair<image::locator,int>(second_pass[0],time_chunk));
90  }
91  }
92 }
94 {
95  int total =0;
96  std::vector<std::pair<image::locator,int> >::const_iterator cur_halo;
97  for(cur_halo = data_.begin() ; cur_halo != data_.end() ; ++cur_halo) {
98  total += cur_halo->second;
99  }
100  return total;
101 }
102 
104 
106 {
107  int time = 0;
108  unsigned int sub_image = 0;
109  if(data_.empty()) return empty_image;
110  while(time < current_time&& sub_image < data_.size()) {
111  time += data_[sub_image].second;
112  ++sub_image;
113 
114  }
115  if(sub_image) sub_image--;
116  return data_[sub_image].first;
117 }
118 
120 
122 {
123  int time = 0;
124  unsigned int sub_halo = 0;
125  if(data_.empty()) return empty_string;
126  while(time < current_time&& sub_halo < data_.size()) {
127  time += data_[sub_halo].second;
128  ++sub_halo;
129 
130  }
131  if(sub_halo) sub_halo--;
132  return data_[sub_halo].first;
133 }
134 
135 template <class T>
137  data_(),
138  input_(data)
139 {
140  int split_flag = utils::REMOVE_EMPTY; // useless to strip spaces
141  const std::vector<std::string> comma_split = utils::split(data,',',split_flag);
142  const int time_chunk = std::max<int>(1, duration / std::max<int>(comma_split.size(),1));
143 
144  std::vector<std::string>::const_iterator com_it = comma_split.begin();
145  for(; com_it != comma_split.end(); ++com_it) {
146  std::vector<std::string> colon_split = utils::split(*com_it,':',split_flag);
147  int time = (colon_split.size() > 1) ? std::stoi(colon_split[1]) : time_chunk;
148 
149  std::vector<std::string> range = utils::split(colon_split[0],'~',split_flag);
150  T range0 = lexical_cast<T>(range[0]);
151  T range1 = (range.size() > 1) ? lexical_cast<T>(range[1]) : range0;
152  typedef std::pair<T,T> range_pair;
153  data_.push_back(std::pair<range_pair,int>(range_pair(range0, range1), time));
154  }
155 }
156 
157 template <class T>
158 const T progressive_<T>::get_current_element(int current_time, T default_val) const
159 {
160  int time = 0;
161  unsigned int sub_halo = 0;
162  int searched_time = current_time;
163  if(searched_time < 0) searched_time = 0;
164  if(searched_time > duration()) searched_time = duration();
165  if(data_.empty()) return default_val;
166  while(time < searched_time&& sub_halo < data_.size()) {
167  time += data_[sub_halo].second;
168  ++sub_halo;
169 
170  }
171  if(sub_halo != 0) {
172  sub_halo--;
173  time -= data_[sub_halo].second;
174  }
175 
176  const T first = data_[sub_halo].first.first;
177  const T second = data_[sub_halo].first.second;
178 
179  return T((static_cast<double>(searched_time - time) /
180  static_cast<double>(data_[sub_halo].second)) *
181  (second - first) + first);
182 }
183 
184 template<class T>
186 {
187  int total = 0;
188  typename std::vector<std::pair<std::pair<T, T>, int> >::const_iterator cur_halo;
189  for(cur_halo = data_.begin() ; cur_halo != data_.end() ; ++cur_halo) {
190  total += cur_halo->second;
191  }
192  return total;
193 
194 }
195 
196 template <class T>
198 {
199 return data_.empty() ||
200  ( data_.size() == 1 && data_[0].first.first == data_[0].first.second);
201 }
202 
203 // Force compilation of the following template instantiations
204 template class progressive_<int>;
205 template class progressive_<double>;
206 
207 bool tristate_to_bool(tristate tri, bool def)
208 {
209  switch(tri)
210  {
211  case(t_false):
212  return false;
213  case(t_true):
214  return true;
215  case(t_unset):
216  return def;
217  default:
218  throw "found unexpected tristate";
219  }
220 }
221 
223  duration(0),
224  image(),
225  image_diagonal(),
226  image_mod(""),
227  halo(""),
228  halo_x(0),
229  halo_y(0),
230  halo_mod(""),
231  sound(""),
232  text(""),
233  text_color(0),
234  blend_with(0),
235  blend_ratio(0.0),
236  highlight_ratio(1.0),
237  offset(0),
238  submerge(0.0),
239  x(0),
240  y(0),
241  directional_x(0),
242  directional_y(0),
243  auto_vflip(t_unset),
244  auto_hflip(t_unset),
245  primary_frame(t_unset),
246  drawing_layer(display::LAYER_UNIT_DEFAULT - display::LAYER_UNIT_FIRST)
247 {}
248 
250  duration_(1),
251  image_(),
252  image_diagonal_(),
253  image_mod_(""),
254  halo_(""),
255  halo_x_(""),
256  halo_y_(""),
257  halo_mod_(""),
258  sound_(""),
259  text_(""),
260  text_color_(0),
261  blend_with_(0),
262  blend_ratio_(""),
263  highlight_ratio_(""),
264  offset_(""),
265  submerge_(""),
266  x_(""),
267  y_(""),
268  directional_x_(""),
269  directional_y_(""),
270  auto_vflip_(t_unset),
271  auto_hflip_(t_unset),
272  primary_frame_(t_unset),
273  drawing_layer_(std::to_string(display::LAYER_UNIT_DEFAULT - display::LAYER_UNIT_FIRST))
274 {}
275 
276 frame_builder::frame_builder(const config& cfg,const std::string& frame_string) :
277  duration_(1),
278  image_(cfg[frame_string + "image"]),
279  image_diagonal_(cfg[frame_string + "image_diagonal"]),
280  image_mod_(cfg[frame_string + "image_mod"]),
281  halo_(cfg[frame_string + "halo"]),
282  halo_x_(cfg[frame_string + "halo_x"]),
283  halo_y_(cfg[frame_string + "halo_y"]),
284  halo_mod_(cfg[frame_string + "halo_mod"]),
285  sound_(cfg[frame_string + "sound"]),
286  text_(cfg[frame_string + "text"]),
287  text_color_(0),
288  blend_with_(0),
289  blend_ratio_(cfg[frame_string + "blend_ratio"]),
290  highlight_ratio_(cfg[frame_string + "alpha"]),
291  offset_(cfg[frame_string + "offset"]),
292  submerge_(cfg[frame_string + "submerge"]),
293  x_(cfg[frame_string + "x"]),
294  y_(cfg[frame_string + "y"]),
295  directional_x_(cfg[frame_string + "directional_x"]),
296  directional_y_(cfg[frame_string + "directional_y"]),
297  auto_vflip_(t_unset),
298  auto_hflip_(t_unset),
299  primary_frame_(t_unset),
300  drawing_layer_(cfg[frame_string + "layer"])
301 {
302  if(!cfg.has_attribute(frame_string + "auto_vflip")) {
304  } else if(cfg[frame_string + "auto_vflip"].to_bool()) {
306  } else {
308  }
309  if(!cfg.has_attribute(frame_string + "auto_hflip")) {
311  } else if(cfg[frame_string + "auto_hflip"].to_bool()) {
313  } else {
315  }
316  if(!cfg.has_attribute(frame_string + "primary")) {
318  } else if(cfg[frame_string + "primary"].to_bool()) {
320  } else {
322  }
323  std::vector<std::string> color = utils::split(cfg[frame_string + "text_color"]);
324  if (color.size() == 3) {
325  text_color_ = display::rgb(std::stoi(color[0]),
326  std::stoi(color[1]), std::stoi(color[2]));
327  }
328 
329  if (const config::attribute_value *v = cfg.get(frame_string + "duration")) {
330  duration(*v);
331  } else if (!cfg.get(frame_string + "end")) {
332  int halo_duration = (progressive_string(halo_,1)).duration();
333  int image_duration = (progressive_image(image_,1)).duration();
334  int image_diagonal_duration = (progressive_image(image_diagonal_,1)).duration();
335  duration(std::max(std::max(image_duration,image_diagonal_duration),halo_duration));
336 
337  } else {
338  duration(cfg[frame_string + "end"].to_int() - cfg[frame_string + "begin"].to_int());
339  }
340  duration_ = std::max(duration_,1);
341 
342  color = utils::split(cfg[frame_string + "blend_color"]);
343  if (color.size() == 3) {
344  blend_with_ = display::rgb(std::stoi(color[0]),
345  std::stoi(color[1]), std::stoi(color[2]));
346  }
347 }
348 
350 {
351  image_ = image;
352  image_mod_ = image_mod;
353  return *this;
354 }
355 frame_builder & frame_builder::image_diagonal(const std::string& image_diagonal,const std::string& image_mod)
356 {
358  image_mod_ = image_mod;
359  return *this;
360 }
362 {
363  sound_=sound;
364  return *this;
365 }
366 frame_builder & frame_builder::text(const std::string& text,const Uint32 text_color)
367 {
368  text_=text;
369  text_color_=text_color;
370  return *this;
371 }
372 frame_builder & frame_builder::halo(const std::string &halo, const std::string &halo_x, const std::string& halo_y,const std::string & halo_mod)
373 {
374  halo_ = halo;
375  halo_x_ = halo_x;
376  halo_y_ = halo_y;
377  halo_mod_= halo_mod;
378  return *this;
379 }
381 {
383  return *this;
384 }
385 frame_builder & frame_builder::blend(const std::string& blend_ratio,const Uint32 blend_color)
386 {
387  blend_with_=blend_color;
388  blend_ratio_=blend_ratio;
389  return *this;
390 }
392 {
394  return *this;
395 }
397 {
398  offset_=offset;
399  return *this;
400 }
402 {
404  return *this;
405 }
407 {
408  x_=x;
409  return *this;
410 }
412 {
413  y_=y;
414  return *this;
415 }
417 {
419  return *this;
420 }
422 {
424  return *this;
425 }
426 frame_builder & frame_builder::auto_vflip(const bool auto_vflip)
427 {
428  if(auto_vflip) auto_vflip_ = t_true;
429  else auto_vflip_ = t_false;
430  return *this;
431 }
432 frame_builder & frame_builder::auto_hflip(const bool auto_hflip)
433 {
434  if(auto_hflip) auto_hflip_ = t_true;
435  else auto_hflip_ = t_false;
436  return *this;
437 }
438 frame_builder & frame_builder::primary_frame(const bool primary_frame)
439 {
440  if(primary_frame) primary_frame_ = t_true;
441  else primary_frame_ = t_false;
442  return *this;
443 }
445 {
447  return *this;
448 }
449 
451  duration_(duration ? duration :builder.duration_),
452  image_(builder.image_,duration_),
453  image_diagonal_(builder.image_diagonal_,duration_),
454  image_mod_(builder.image_mod_),
455  halo_(builder.halo_,duration_),
456  halo_x_(builder.halo_x_,duration_),
457  halo_y_(builder.halo_y_,duration_),
458  halo_mod_(builder.halo_mod_),
459  sound_(builder.sound_),
460  text_(builder.text_),
461  text_color_(builder.text_color_),
462  blend_with_(builder.blend_with_),
463  blend_ratio_(builder.blend_ratio_,duration_),
464  highlight_ratio_(builder.highlight_ratio_,duration_),
465  offset_(builder.offset_,duration_),
466  submerge_(builder.submerge_,duration_),
467  x_(builder.x_,duration_),
468  y_(builder.y_,duration_),
469  directional_x_(builder.directional_x_,duration_),
470  directional_y_(builder.directional_y_,duration_),
471  auto_vflip_(builder.auto_vflip_),
472  auto_hflip_(builder.auto_hflip_),
473  primary_frame_(builder.primary_frame_),
474  drawing_layer_(builder.drawing_layer_,duration_)
475 {}
476 
477 
479 {
480  return image_.does_not_change() &&
489  x_.does_not_change() &&
490  y_.does_not_change() &&
494 }
496 {
497  if(!image_.does_not_change() ||
499  !halo_.does_not_change() ||
506  !x_.does_not_change() ||
507  !y_.does_not_change() ||
511  return true;
512  }
513  return false;
514 }
515 
517 {
519  result.duration = duration_;
520  result.image = image_.get_current_element(current_time);
521  result.image_diagonal = image_diagonal_.get_current_element(current_time);
522  result.image_mod = image_mod_;
523  result.halo = halo_.get_current_element(current_time);
524  result.halo_x = halo_x_.get_current_element(current_time);
525  result.halo_y = halo_y_.get_current_element(current_time);
526  result.halo_mod = halo_mod_;
527  result.sound = sound_;
528  result.text = text_;
529  result.text_color = text_color_;
530  result.blend_with = blend_with_;
531  result.blend_ratio = blend_ratio_.get_current_element(current_time);
532  result.highlight_ratio = highlight_ratio_.get_current_element(current_time,1.0);
533  result.offset = offset_.get_current_element(current_time,-1000);
534  result.submerge = submerge_.get_current_element(current_time);
535  result.x = x_.get_current_element(current_time);
536  result.y = y_.get_current_element(current_time);
537  result.directional_x = directional_x_.get_current_element(current_time);
538  result.directional_y = directional_y_.get_current_element(current_time);
539  result.auto_vflip = auto_vflip_;
540  result.auto_hflip = auto_hflip_;
541  result.primary_frame = primary_frame_;
543  return result;
544 }
545 
547  , const std::string& highlight
548  , const std::string& blend_ratio
549  , Uint32 blend_color
550  , const std::string& offset
551  , const std::string& layer
552  , const std::string& modifiers)
553 {
554  if(!highlight.empty()) {
555  highlight_ratio_ = progressive_double(highlight,duration);
556  } else if(duration != duration_){
558  }
559  if(!offset.empty()) {
560  offset_= progressive_double(offset,duration);
561  } else if(duration != duration_){
563  }
564  if(!blend_ratio.empty()) {
565  blend_ratio_ = progressive_double(blend_ratio,duration);
566  blend_with_ = blend_color;
567  } else if(duration != duration_){
569  }
570  if(!layer.empty()) {
571  drawing_layer_ = progressive_int(layer,duration);
572  } else if(duration != duration_){
574  }
575  if(!modifiers.empty()) {
576  image_mod_+=modifiers;
577  }
578 
579  if(duration != duration_) {
591  }
592 }
593 std::vector<std::string> frame_parsed_parameters::debug_strings() const {
594  std::vector<std::string> v;
595  if (duration_>0) v.push_back("duration="+utils::half_signed_value(duration_));
596  if (!image_.get_original().empty()) v.push_back("image="+image_.get_original());
597  if (!image_diagonal_.get_original().empty()) v.push_back("image_diagonal="+image_diagonal_.get_original());
598  if (!image_mod_.empty()) v.push_back("image_mod="+image_mod_);
599  if (!halo_.get_original().empty()) v.push_back("halo="+halo_.get_original());
600  if (!halo_x_.get_original().empty()) v.push_back("halo_x="+halo_x_.get_original());
601  if (!halo_y_.get_original().empty()) v.push_back("halo_y="+halo_y_.get_original());
602  if (!halo_mod_.empty()) v.push_back("halo_mod="+halo_mod_);
603  if (!sound_.empty()) v.push_back("sound="+sound_);
604  if (!text_.empty()) {
605  v.push_back("text="+text_);
606  v.push_back("text_color="+std::to_string(text_color_));
607  }
608  if (!blend_ratio_.get_original().empty()) {
609  v.push_back("blend_ratio="+blend_ratio_.get_original());
610  v.push_back("blend_with="+std::to_string(blend_with_));
611  }
612  if (!highlight_ratio_.get_original().empty()) v.push_back("highlight_ratio="+highlight_ratio_.get_original());
613  if (!offset_.get_original().empty()) v.push_back("offset="+offset_.get_original());
614  if (!submerge_.get_original().empty()) v.push_back("submerge="+submerge_.get_original());
615  if (!x_.get_original().empty()) v.push_back("x="+x_.get_original());
616  if (!y_.get_original().empty()) v.push_back("y="+y_.get_original());
617  if (!directional_x_.get_original().empty()) v.push_back("directional_x="+directional_x_.get_original());
618  if (!directional_y_.get_original().empty()) v.push_back("directional_y="+directional_y_.get_original());
619  if (auto_vflip_ == t_true) v.push_back("auto_vflip=true");
620  if (auto_vflip_ == t_false) v.push_back("auto_vflip=false");
621  if (auto_hflip_ == t_true) v.push_back("auto_hflip=true");
622  if (auto_hflip_ == t_false) v.push_back("auto_hflip=false");
623  if (primary_frame_ == t_true) v.push_back("primary_frame=true");
624  if (primary_frame_ == t_false) v.push_back("primary_frame=false");
625  if (!drawing_layer_.get_original().empty()) v.push_back("drawing_layer="+drawing_layer_.get_original());
626  return v;
627 }
628 
629 
630 void unit_frame::redraw(const int frame_time,bool on_start_time,bool in_scope_of_frame,const map_location & src,const map_location & dst,halo::handle & halo_id,halo::manager & halo_man, const frame_parameters & animation_val,const frame_parameters & engine_val)const
631 {
632  const int xsrc = game_display::get_singleton()->get_location_x(src);
633  const int ysrc = game_display::get_singleton()->get_location_y(src);
634  const int xdst = game_display::get_singleton()->get_location_x(dst);
635  const int ydst = game_display::get_singleton()->get_location_y(dst);
636  const map_location::DIRECTION direction = src.get_relative_dir(dst);
637 
638  const frame_parameters current_data = merge_parameters(frame_time,animation_val,engine_val);
639  double tmp_offset = current_data.offset;
640 
641  // debug code allowing to see the number of frames and their position
642  // you need to add a '/n'
643  // if (tmp_offset) std::cout << (int)(tmp_offset*100) << ",";
644 
645  int d2 = display::get_singleton()->hex_size() / 2;
646  if(on_start_time ) {
647  // stuff that should be done only once per frame
648  if(!current_data.sound.empty() ) {
649  sound::play_sound(current_data.sound);
650  }
651  if(!current_data.text.empty() ) {
652  game_display::get_singleton()->float_label(src, current_data.text,
653  int_to_color(current_data.text_color));
654  }
655  }
656  image::locator image_loc;
657  if(direction != map_location::NORTH && direction != map_location::SOUTH) {
658  image_loc = image::locator(current_data.image_diagonal,current_data.image_mod);
659  }
660  if(image_loc.is_void() || image_loc.get_filename() == "") { // invalid diag image, or not diagonal
661  image_loc = image::locator(current_data.image,current_data.image_mod);
662  }
663 
664  surface image;
665  if(!image_loc.is_void() && image_loc.get_filename() != "") { // invalid diag image, or not diagonal
666  image=image::get_image(image_loc, image::SCALED_TO_ZOOM);
667  }
668  const int x = static_cast<int>(tmp_offset * xdst + (1.0-tmp_offset) * xsrc) + d2;
669  const int y = static_cast<int>(tmp_offset * ydst + (1.0-tmp_offset) * ysrc) + d2;
670  if (image != nullptr) {
671 #ifdef LOW_MEM
672  bool facing_west = false;
673 #else
674  bool facing_west = direction == map_location::NORTH_WEST || direction == map_location::SOUTH_WEST;
675 #endif
676  bool facing_north = direction == map_location::NORTH_WEST || direction == map_location::NORTH || direction == map_location::NORTH_EAST;
677  if(!current_data.auto_hflip) facing_west = false;
678  if(!current_data.auto_vflip) facing_north = true;
679  int my_x = x + current_data.x- image->w/2;
680  int my_y = y + current_data.y- image->h/2;
681  if(facing_west) {
682  my_x -= current_data.directional_x;
683  } else {
684  my_x += current_data.directional_x;
685  }
686  if(facing_north) {
687  my_y += current_data.directional_y;
688  } else {
689  my_y -= current_data.directional_y;
690  }
691 
693  static_cast<display::tdrawing_layer>(display::LAYER_UNIT_FIRST+current_data.drawing_layer),
694  src, image, facing_west, false,
695  ftofxp(current_data.highlight_ratio), current_data.blend_with,
696  current_data.blend_ratio,current_data.submerge,!facing_north);
697  }
698  halo_id = halo::handle(); //halo::NO_HALO;
699 
700  if (!in_scope_of_frame) { //check after frame as first/last frame image used in defense/attack anims
701  return;
702  }
703 
704  if(!current_data.halo.empty()) {
705  halo::ORIENTATION orientation;
706  switch(direction)
707  {
708  case map_location::NORTH:
710  orientation = halo::NORMAL;
711  break;
713  case map_location::SOUTH:
714  if(!current_data.auto_vflip) {
715  orientation = halo::NORMAL;
716  } else {
717  orientation = halo::VREVERSE;
718  }
719  break;
721  if(!current_data.auto_vflip) {
722  orientation = halo::HREVERSE;
723  } else {
724  orientation = halo::HVREVERSE;
725  }
726  break;
728  orientation = halo::HREVERSE;
729  break;
731  default:
732  orientation = halo::NORMAL;
733  break;
734  }
735 
736  if(direction != map_location::SOUTH_WEST && direction != map_location::NORTH_WEST) {
737  halo_id = halo_man.add(static_cast<int>(x+current_data.halo_x* game_display::get_singleton()->get_zoom_factor()),
738  static_cast<int>(y+current_data.halo_y* game_display::get_singleton()->get_zoom_factor()),
739  current_data.halo + current_data.halo_mod,
740  map_location(-1, -1),
741  orientation);
742  } else {
743  halo_id = halo_man.add(static_cast<int>(x-current_data.halo_x* game_display::get_singleton()->get_zoom_factor()),
744  static_cast<int>(y+current_data.halo_y* game_display::get_singleton()->get_zoom_factor()),
745  current_data.halo + current_data.halo_mod,
746  map_location(-1, -1),
747  orientation);
748  }
749  }
750 }
751 std::set<map_location> unit_frame::get_overlaped_hex(const int frame_time,const map_location & src,const map_location & dst,const frame_parameters & animation_val,const frame_parameters & engine_val) const
752 {
754  const int xsrc = disp->get_location_x(src);
755  const int ysrc = disp->get_location_y(src);
756  const int xdst = disp->get_location_x(dst);
757  const int ydst = disp->get_location_y(dst);
758  const map_location::DIRECTION direction = src.get_relative_dir(dst);
759 
760  const frame_parameters current_data = merge_parameters(frame_time,animation_val,engine_val);
761  double tmp_offset = current_data.offset;
762  int d2 = game_display::get_singleton()->hex_size() / 2;
763 
764  image::locator image_loc;
765  if(direction != map_location::NORTH && direction != map_location::SOUTH) {
766  image_loc = image::locator(current_data.image_diagonal,current_data.image_mod);
767  }
768  if(image_loc.is_void() || image_loc.get_filename() == "") { // invalid diag image, or not diagonal
769  image_loc = image::locator(current_data.image,current_data.image_mod);
770  }
771 
772  // we always invalidate our own hex because we need to be called at redraw time even
773  // if we don't draw anything in the hex itself
774  std::set<map_location> result;
775  if(tmp_offset==0 && current_data.x == 0 && current_data.directional_x == 0 && image::is_in_hex(image_loc)) {
776  result.insert(src);
777  int my_y = current_data.y;
778  bool facing_north = direction == map_location::NORTH_WEST || direction == map_location::NORTH || direction == map_location::NORTH_EAST;
779  if(!current_data.auto_vflip) facing_north = true;
780  if(facing_north) {
781  my_y += current_data.directional_y;
782  } else {
783  my_y -= current_data.directional_y;
784  }
785  if(my_y < 0) {
786  result.insert(src.get_direction(map_location::NORTH));
787  result.insert(src.get_direction(map_location::NORTH_EAST));
788  result.insert(src.get_direction(map_location::NORTH_WEST));
789  } else if(my_y > 0) {
790  result.insert(src.get_direction(map_location::SOUTH));
791  result.insert(src.get_direction(map_location::SOUTH_EAST));
792  result.insert(src.get_direction(map_location::SOUTH_WEST));
793  }
794  } else {
795  int w=0;
796  int h =0;
797 #ifdef _OPENMP
798 #pragma omp critical(frame_surface) // with the way surfaces work it's hard to lock the refcount within sdl_utils
799 #endif //_OPENMP
800  {
801  surface image;
802  if(!image_loc.is_void() && image_loc.get_filename() != "") { // invalid diag image, or not diagonal
803  image=image::get_image(image_loc,
805  );
806  }
807  if(image != nullptr) {
808  w = image->w;
809  h = image->h;
810  }
811  }
812  if (w != 0 || h != 0) {
813  const int x = static_cast<int>(tmp_offset * xdst + (1.0-tmp_offset) * xsrc);
814  const int y = static_cast<int>(tmp_offset * ydst + (1.0-tmp_offset) * ysrc);
815 #ifdef LOW_MEM
816  bool facing_west = false;
817 #else
818  bool facing_west = direction == map_location::NORTH_WEST || direction == map_location::SOUTH_WEST;
819 #endif
820  bool facing_north = direction == map_location::NORTH_WEST || direction == map_location::NORTH || direction == map_location::NORTH_EAST;
821  if(!current_data.auto_vflip) facing_north = true;
822  if(!current_data.auto_hflip) facing_west = false;
823  int my_x = x +current_data.x+d2- w/2;
824  int my_y = y +current_data.y+d2- h/2;
825  if(facing_west) {
826  my_x += current_data.directional_x;
827  } else {
828  my_x -= current_data.directional_x;
829  }
830  if(facing_north) {
831  my_y += current_data.directional_y;
832  } else {
833  my_y -= current_data.directional_y;
834  }
835 
836  const SDL_Rect r = sdl::create_rect(my_x, my_y, w, h);
837  // check if our underlying hexes are invalidated
838  // if we need to update ourselves because we changed, invalidate our hexes
839  // and return whether or not our hexes was invalidated
840  // invalidate ourself to be called at redraw time
841  result.insert(src);
842  display::rect_of_hexes underlying_hex = disp->hexes_under_rect(r);
843  result.insert(underlying_hex.begin(),underlying_hex.end());
844  } else {
845  // we have no "redraw surface" but we still need to invalidate our own hex
846  // in case we have a halo and/or sound that needs a redraw
847  // invalidate ourself to be called at redraw time
848  result.insert(src);
849  result.insert(dst);
850  }
851  }
852  return result;
853 }
854 
855 
856 
857 const frame_parameters unit_frame::merge_parameters(int current_time,const frame_parameters & animation_val,const frame_parameters & engine_val) const
858 {
859  /**
860  * this function merges the value provided by
861  * * the frame
862  * * the engine (poison, flying unit...)
863  * * the animation as a whole
864  * there is no absolute rule for merging, so creativity is the rule
865  * if a value is never provided by the engine, assert. (this way if it becomes used, people will easily find the right place to look)
866  *
867  */
869  const frame_parameters & current_val = builder_.parameters(current_time);
870 
871  result.primary_frame = engine_val.primary_frame;
872  if(animation_val.primary_frame != t_unset) result.primary_frame = animation_val.primary_frame;
873  if(current_val.primary_frame != t_unset) result.primary_frame = current_val.primary_frame;
874  const bool primary = tristate_to_bool(result.primary_frame, true);
875 
876  /** engine provides a default image to use for the unit when none is available */
877  result.image = current_val.image.is_void() || current_val.image.get_filename() == ""?animation_val.image:current_val.image;
878  if(primary && ( result.image.is_void() || result.image.get_filename().empty())) {
879  result.image = engine_val.image;
880  }
881 
882  /** engine provides a default image to use for the unit when none is available */
883  result.image_diagonal = current_val.image_diagonal.is_void() || current_val.image_diagonal.get_filename() == ""?animation_val.image_diagonal:current_val.image_diagonal;
884  if(primary && ( result.image_diagonal.is_void() || result.image_diagonal.get_filename().empty())) {
885  result.image_diagonal = engine_val.image_diagonal;
886  }
887 
888  /** engine provides a string for "petrified" and "team color" modifications
889  note that image_mod is the complete modification and halo_mod is only the TC part
890  see unit.cpp, we know that and use it*/
891  result.image_mod = current_val.image_mod +animation_val.image_mod;
892  if(primary) {
893  result.image_mod += engine_val.image_mod;
894  } else {
895  result.image_mod += engine_val.halo_mod;
896  }
897 
898  assert(engine_val.halo.empty());
899  result.halo = current_val.halo.empty()?animation_val.halo:current_val.halo;
900 
901  assert(engine_val.halo_x == 0);
902  result.halo_x = current_val.halo_x?current_val.halo_x:animation_val.halo_x;
903 
904  /** the engine provide y modification for terrain with height adjust and flying units */
905  result.halo_y = current_val.halo_y?current_val.halo_y:animation_val.halo_y;
906  result.halo_y += engine_val.halo_y;
907 
908  result.halo_mod = current_val.halo_mod +animation_val.halo_mod;
909  result.halo_mod += engine_val.halo_mod;
910 
911  assert(engine_val.duration == 0);
912  result.duration = current_val.duration;
913 
914  assert(engine_val.sound.empty());
915  result.sound = current_val.sound.empty()?animation_val.sound:current_val.sound;
916 
917  assert(engine_val.text.empty());
918  result.text = current_val.text.empty()?animation_val.text:current_val.text;
919 
920  assert(engine_val.text_color == 0);
921  result.text_color = current_val.text_color?current_val.text_color:animation_val.text_color;
922 
923  /** engine provide a blend color for poisoned units */
924  result.blend_with = current_val.blend_with?current_val.blend_with:animation_val.blend_with;
925  if(primary&& engine_val.blend_with) result.blend_with = display::max_rgb(engine_val.blend_with,result.blend_with);
926 
927  /** engine provide a blend color for poisoned units */
928  result.blend_ratio = current_val.blend_ratio?current_val.blend_ratio:animation_val.blend_ratio;
929  if(primary && engine_val.blend_ratio) {
930  result.blend_ratio = std::min(
931  result.blend_ratio + engine_val.blend_ratio
932  , 1.0);
933  }
934 
935  /** engine provide a highlight ratio for selected units and visible "invisible" units */
936  result.highlight_ratio = current_val.highlight_ratio!=1.0?current_val.highlight_ratio:animation_val.highlight_ratio;
937  if(primary && engine_val.highlight_ratio != 1.0) result.highlight_ratio = result.highlight_ratio +engine_val.highlight_ratio - 1.0; // selected unit
938 
939  assert(engine_val.offset == 0);
940  result.offset = (current_val.offset!=-1000)?current_val.offset:animation_val.offset;
941  if(result.offset == -1000) result.offset = 0.0;
942 
943  /** engine provides a submerge for units in water */
944  result.submerge = current_val.submerge?current_val.submerge:animation_val.submerge;
945  if(primary && engine_val.submerge && !result.submerge ) result.submerge = engine_val.submerge;
946 
947  assert(engine_val.x == 0);
948  result.x = current_val.x?current_val.x:animation_val.x;
949 
950  /** the engine provide y modification for terrain with height adjust and flying units */
951  result.y = current_val.y?current_val.y:animation_val.y;
952  result.y += engine_val.y;
953 
954  assert(engine_val.directional_x == 0);
955  result.directional_x = current_val.directional_x?current_val.directional_x:animation_val.directional_x;
956  assert(engine_val.directional_y == 0);
957  result.directional_y = current_val.directional_y?current_val.directional_y:animation_val.directional_y;
958 
961  current_val.drawing_layer:animation_val.drawing_layer;
962 
963  /** the engine provide us with default value to compare with, we update if different */
964  result.auto_hflip = engine_val.auto_hflip;
965  if(animation_val.auto_hflip != t_unset) result.auto_hflip = animation_val.auto_hflip;
966  if(current_val.auto_hflip != t_unset) result.auto_hflip = current_val.auto_hflip;
967  if(result.auto_hflip == t_unset) result.auto_hflip = t_true;
968 
969  result.auto_vflip = engine_val.auto_vflip;
970  if(animation_val.auto_vflip != t_unset) result.auto_vflip = animation_val.auto_vflip;
971  if(current_val.auto_vflip != t_unset) result.auto_vflip = current_val.auto_vflip;
972  if(result.auto_vflip == t_unset) {
973  if(primary) result.auto_vflip=t_false;
974  else result.auto_vflip = t_true;
975  }
976 #ifdef LOW_MEM
977  if(primary) {
978  result.image= engine_val.image;
979  result.image_diagonal= engine_val.image;
980  }
981 #endif
982  return result;
983 }
double highlight_ratio
Definition: frame.hpp:88
double blend_ratio
Definition: frame.hpp:87
bool does_not_change() const
Definition: frame.hpp:33
surface get_image(const image::locator &i_locator, TYPE type)
function to get the surface corresponding to an image.
Definition: image.cpp:878
tristate auto_vflip_
Definition: frame.hpp:150
int duration() const
Definition: frame.cpp:185
tformula< unsigned > x_
The x coordinate of the rectangle.
Definition: canvas.cpp:682
std::string image_
Definition: frame.hpp:131
std::string sound
Definition: frame.hpp:83
frame_builder & y(const std::string &y)
Definition: frame.cpp:411
const image::locator empty_image
Definition: frame.cpp:103
std::vector< std::pair< std::string, int > > data_
Definition: frame.hpp:36
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:88
progressive_int halo_x_
Definition: frame.hpp:183
bool is_void() const
Definition: image.hpp:96
progressive_double blend_ratio_
Definition: frame.hpp:190
frame_parsed_parameters(const frame_builder &builder=frame_builder(), int override_duration=0)
Definition: frame.cpp:450
iterator end() const
Definition: display.cpp:661
image::locator image
Definition: frame.hpp:76
std::string image_mod_
Definition: frame.hpp:181
progressive_image(const std::string &data="", int duration=0)
Definition: frame.cpp:64
GLenum GLint * range
Definition: glew.h:3025
std::string blend_ratio_
Definition: frame.hpp:142
std::string sound_
Definition: frame.hpp:186
bool does_not_change() const
Definition: frame.hpp:45
Uint32 text_color
Definition: frame.hpp:85
std::string directional_y_
Definition: frame.hpp:149
std::vector< std::string > debug_strings() const
Definition: frame.cpp:593
std::string text_
Definition: frame.hpp:139
SDL_Color int_to_color(const Uint32 rgb)
Definition: utils.cpp:63
Frame for unit's animation sequence.
frame_builder & drawing_layer(const std::string &drawing_layer)
Definition: frame.cpp:444
frame_builder & image_diagonal(const std::string &image_diagonal, const std::string &image_mod="")
Definition: frame.cpp:355
REMOVE_EMPTY : remove empty elements.
surface image_
The image is cached in this surface.
Definition: canvas.cpp:961
GLenum GLsizei GLenum GLenum const GLvoid * image
Definition: glew.h:3783
std::vector< std::pair< std::pair< T, T >, int > > data_
Definition: frame.hpp:55
void float_label(const map_location &loc, const std::string &text, const SDL_Color &color)
Function to float a label above a tile.
tristate
Definition: frame.hpp:68
tristate auto_hflip_
Definition: frame.hpp:151
std::string drawing_layer_
Definition: frame.hpp:153
STL namespace.
double get_zoom_factor() const
Returns the current zoom factor.
Definition: display.hpp:269
DIRECTION get_relative_dir(const map_location &loc, map_location::RELATIVE_DIR_MODE mode) const
Definition: location.cpp:220
int get_location_x(const map_location &loc) const
Functions to get the on-screen positions of hexes.
Definition: display.cpp:713
GLint GLint GLint GLint GLint GLint y
Definition: glew.h:1220
Audio output for sound and music.
Definition: sound.cpp:43
std::string halo_mod_
Definition: frame.hpp:137
double submerge
Definition: frame.hpp:90
GLenum src
Definition: glew.h:2392
image::locator image_diagonal
Definition: frame.hpp:77
Rectangular area of hexes, allowing to decide how the top and bottom edges handles the vertical shift...
Definition: display.hpp:309
std::string get_original() const
Definition: frame.hpp:62
All parameters from a frame at a given instant.
Definition: frame.hpp:71
frame_builder & directional_x(const std::string &directional_x)
Definition: frame.cpp:416
bool need_update() const
Definition: frame.cpp:495
std::string halo_y_
Definition: frame.hpp:136
GLint GLenum GLsizei GLint GLsizei const GLvoid * data
Definition: glew.h:1347
tristate auto_vflip
Definition: frame.hpp:95
To lexical_cast(From value)
Lexical cast converts one type to another.
tformula< t_string > text_
The text to draw.
Definition: canvas.cpp:1268
frame_builder & blend(const std::string &blend_ratio, const Uint32 blend_color)
Definition: frame.cpp:385
frame_builder & image(const std::string &image, const std::string &image_mod="")
Definition: frame.cpp:349
int duration() const
Definition: frame.cpp:54
const frame_parameters parameters(int current_time) const
getters for the different parameters
Definition: frame.cpp:516
Variant for storing WML attributes.
Definition: config.hpp:223
std::string halo_
Definition: frame.hpp:134
int get_location_y(const map_location &loc) const
Definition: display.cpp:718
void play_sound(const std::string &files, channel_group group, unsigned int repeats)
Definition: sound.cpp:818
frame_builder & submerge(const std::string &submerge)
Definition: frame.cpp:401
frame_parsed_parameters builder_
Definition: frame.hpp:219
static const std::string empty_string
Definition: frame.cpp:119
double offset
Definition: frame.hpp:89
const frame_parameters merge_parameters(int current_time, const frame_parameters &animation_val, const frame_parameters &engine_val=frame_parameters()) const
Definition: frame.cpp:857
GLintptr offset
Definition: glew.h:1650
frame_builder & auto_hflip(const bool auto_hflip)
Definition: frame.cpp:432
tristate primary_frame_
Definition: frame.hpp:200
std::set< map_location > get_overlaped_hex(const int frame_time, const map_location &src, const map_location &dst, const frame_parameters &animation_val, const frame_parameters &engine_val) const
Definition: frame.cpp:751
std::string half_signed_value(int val)
Sign with Unicode "−" if negative.
frame_builder & sound(const std::string &sound)
Definition: frame.cpp:361
GLuint64EXT * result
Definition: glew.h:10727
std::string get_original() const
Definition: frame.hpp:34
bool does_not_change() const
Definition: frame.cpp:197
GLenum GLenum GLuint GLint GLint layer
Definition: glew.h:3455
progressive_image image_diagonal_
Definition: frame.hpp:180
std::string highlight_ratio_
Definition: frame.hpp:143
GLubyte GLubyte GLubyte GLubyte w
Definition: glew.h:1858
tristate auto_hflip
Definition: frame.hpp:96
const GLdouble * v
Definition: glew.h:1359
GLenum GLenum dst
Definition: glew.h:2392
std::string halo_mod
Definition: frame.hpp:82
progressive_int x_
Definition: frame.hpp:194
std::string text_
Definition: frame.hpp:187
progressive_(const std::string &data="", int duration=0)
Definition: frame.cpp:136
void render_image(int x, int y, const display::tdrawing_layer drawing_layer, const map_location &loc, surface image, bool hreverse=false, bool greyscale=false, fixed_t alpha=ftofxp(1.0), Uint32 blendto=0, double blend_ratio=0, double submerged=0.0, bool vreverse=false)
Draw an image at a certain location.
Definition: display.cpp:1724
int duration() const
Definition: frame.hpp:173
frame_builder & auto_vflip(const bool auto_vflip)
Definition: frame.cpp:426
progressive_image image_
Definition: frame.hpp:179
progressive_double highlight_ratio_
Definition: frame.hpp:191
std::string y_
Definition: frame.hpp:147
progressive_int halo_y_
Definition: frame.hpp:184
std::string text
Definition: frame.hpp:84
int drawing_layer
Definition: frame.hpp:98
std::vector< std::pair< image::locator, int > > data_
Definition: frame.hpp:48
GLuint color
Definition: glew.h:5801
std::string directional_x_
Definition: frame.hpp:148
progressive_int drawing_layer_
Definition: frame.hpp:201
handle add(int x, int y, const std::string &image, const map_location &loc, halo::ORIENTATION orientation=NORMAL, bool infinite=true)
Add a haloing effect using 'image centered on (x,y).
Definition: halo.cpp:478
progressive_int directional_x_
Definition: frame.hpp:196
Encapsulates the map of the game.
Definition: location.hpp:38
std::string get_original() const
Definition: frame.hpp:46
const std::string & get_filename() const
Definition: image.hpp:86
Reserve layers to be selected for WML.
Definition: display.hpp:873
default layer for drawing units
Definition: display.hpp:875
const T get_current_element(int time, T default_val=0) const
Definition: frame.cpp:158
frame_builder & text(const std::string &text, const Uint32 text_color)
Definition: frame.cpp:366
const image::locator & get_current_element(int time) const
Definition: frame.cpp:105
Uint32 text_color_
Definition: frame.hpp:140
static Uint32 rgb(Uint8 red, Uint8 green, Uint8 blue)
Definition: display.hpp:176
std::string image_mod
Definition: frame.hpp:78
static Uint32 max_rgb(Uint32 first, Uint32 second)
Definition: display.hpp:184
int directional_y
Definition: frame.hpp:94
Uint32 blend_with_
Definition: frame.hpp:141
int duration_
Definition: frame.hpp:130
progressive_< int > progressive_int
Definition: frame.hpp:65
GLfloat GLfloat GLfloat GLfloat h
Definition: glew.h:5910
frame_builder & offset(const std::string &offset)
Definition: frame.cpp:396
GLint GLint GLint GLint GLint x
Definition: glew.h:1220
frame_builder & x(const std::string &x)
Definition: frame.cpp:406
std::string offset_
Definition: frame.hpp:144
DIRECTION
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:40
bool does_not_change() const
Definition: frame.cpp:478
tformula< unsigned > y_
The y coordinate of the rectangle.
Definition: canvas.cpp:682
GLdouble GLdouble GLdouble r
Definition: glew.h:1374
frame_builder & primary_frame(const bool primary_frame)
Definition: frame.cpp:438
bool is_in_hex(const locator &i_locator)
function to check if an image fit into an hex return false if the image has not the standard size...
Definition: image.cpp:1121
frame_builder & directional_y(const std::string &directional_y)
Definition: frame.cpp:421
const rect_of_hexes hexes_under_rect(const SDL_Rect &r) const
Return the rectangular area of hexes overlapped by r (r is in screen coordinates) ...
Definition: display.cpp:666
tristate primary_frame_
Definition: frame.hpp:152
progressive_double submerge_
Definition: frame.hpp:193
const attribute_value * get(const std::string &key) const
Returns a pointer to the attribute with the given key or nullptr if it does not exist.
Definition: config.cpp:935
SDL_Rect create_rect(const int x, const int y, const int w, const int h)
Creates an empty SDL_Rect.
Definition: rect.cpp:28
std::string halo
Definition: frame.hpp:79
int duration() const
Definition: frame.cpp:93
Definition: display.hpp:43
ORIENTATION
Definition: halo.hpp:38
bool has_attribute(const std::string &key) const
Definition: config.cpp:514
void override(int duration, const std::string &highlight="", const std::string &blend_ratio="", Uint32 blend_color=0, const std::string &offset="", const std::string &layer="", const std::string &modifiers="")
allow easy chained modifications will raised assert if used after initialization
Definition: frame.cpp:546
progressive_int directional_y_
Definition: frame.hpp:197
tristate primary_frame
Definition: frame.hpp:97
Uint32 blend_with
Definition: frame.hpp:86
this module manages the cache of images.
Definition: image.cpp:75
progressive_< double > progressive_double
Definition: frame.hpp:66
std::string halo_mod_
Definition: frame.hpp:185
std::string image_diagonal_
Definition: frame.hpp:132
frame_builder & duration(const int duration)
allow easy chained modifications will raised assert if used after initialization
Definition: frame.cpp:380
GLint * first
Definition: glew.h:1496
Definition: frame.hpp:68
map_location get_direction(DIRECTION d, unsigned int n=1u) const
Definition: location.hpp:232
std::vector< std::string > split(std::string const &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
progressive_double offset_
Definition: frame.hpp:192
frame_builder & highlight(const std::string &highlight)
Definition: frame.cpp:391
std::string halo_x_
Definition: frame.hpp:135
std::string x_
Definition: frame.hpp:146
bool tristate_to_bool(tristate tri, bool def)
Definition: frame.cpp:207
progressive_string halo_
Definition: frame.hpp:182
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
progressive_int y_
Definition: frame.hpp:195
int hex_size() const
Function which returns the size of a hex in pixels (from top tip to bottom tip or left edge to right ...
Definition: display.hpp:266
std::string image_mod_
Definition: frame.hpp:133
iterator begin() const
Definition: display.cpp:657
const std::string & get_current_element(int time) const
Definition: frame.cpp:121
std::vector< std::string > square_parenthetical_split(std::string const &val, const char separator, std::string const &left, std::string const &right, const int flags)
Similar to parenthetical_split, but also expands embedded square brackets.
GLsizei const GLcharARB ** string
Definition: glew.h:4503
void redraw(const int frame_time, bool on_start_time, bool in_scope_of_frame, const map_location &src, const map_location &dst, halo::handle &halo_id, halo::manager &halo_man, const frame_parameters &animation_val, const frame_parameters &engine_val) const
Definition: frame.cpp:630
frame_builder & halo(const std::string &halo, const std::string &halo_x, const std::string &halo_y, const std::string &halo_mod)
Definition: frame.cpp:372
#define ftofxp(x)
IN: float or int - OUT: fixed_t.
Definition: util.hpp:503
progressive_string(const std::string &data="", int duration=0)
Definition: frame.cpp:25
static game_display * get_singleton()
std::string submerge_
Definition: frame.hpp:145
boost::shared_ptr< halo_record > handle
Definition: halo.hpp:34
std::string sound_
Definition: frame.hpp:138
int directional_x
Definition: frame.hpp:93