The Battle for Wesnoth  1.15.2+dev
frame_private.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2018 by Jeremy Rosen <jeremy.rosen@enst-bretagne.fr>
3  Part of the Battle for Wesnoth Project https://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 #pragma once
16 
17 #include "lexical_cast.hpp"
19 #include "utils/general.hpp"
20 
21 #include <vector>
22 
23 namespace image { class locator; }
24 
25 template<typename T, typename D>
27 {
28 public:
29  using data_t = std::vector<std::pair<D, int>>;
30 
31  progressive_base(const std::string& input)
32  : data_()
33  , input_(input)
34  {}
35 
36  virtual const T get_current_element(int current_time, T default_val) const = 0;
37 
38  virtual bool does_not_change() const
39  {
40  return data_.size() <= 1;
41  }
42 
43  int duration() const
44  {
45  int total = 0;
46  for(const auto& entry : data_) {
47  total += entry.second;
48  }
49 
50  return total;
51  }
52 
53  std::string get_original() const
54  {
55  return input_;
56  }
57 
59  {
60  return data_;
61  }
62 
63  const data_t& data() const
64  {
65  return data_;
66  }
67 
68  virtual ~progressive_base() {}
69 
70 private:
72  std::string input_;
73 };
74 
75 template<typename T>
76 class progressive_pair : public progressive_base<T, std::pair<T, T>>
77 {
78 public:
79  progressive_pair(const std::string& input = "", int duration = 0)
80  : progressive_base<T, std::pair<T, T>>(input)
81  {
82  auto& base_data = progressive_pair_base_type::data();
83 
84  const int split_flag = utils::REMOVE_EMPTY; // useless to strip spaces
85 
86  const std::vector<std::string> comma_split = utils::split(input, ',', split_flag);
87  const int time_chunk = std::max<int>(1, duration / std::max<int>(comma_split.size(), 1));
88 
89  for(const auto& entry : comma_split) {
90  std::vector<std::string> colon_split = utils::split(entry, ':', split_flag);
91  int time = 0;
92 
93  try {
94  time = (colon_split.size() > 1) ? std::stoi(colon_split[1]) : time_chunk;
95  } catch(const std::invalid_argument&) {
96  //ERR_NG << "Invalid time in unit animation: " << colon_split[1] << "\n";
97  }
98 
99  try {
100  std::vector<std::string> range = utils::split(colon_split[0],'~',split_flag);
101  T range0 = lexical_cast<T>(range[0]);
102  T range1 = (range.size() > 1) ? lexical_cast<T>(range[1]) : range0;
103 
104  base_data.push_back({{range0, range1}, time});
105  } catch(const bad_lexical_cast&) {}
106  }
107  }
108 
109  virtual const T get_current_element(int current_time, T default_val = T()) const override
110  {
111  const auto& base_data = progressive_pair_base_type::data();
112  const int& base_duration = progressive_pair_base_type::duration();
113 
114  if(base_data.empty()) {
115  return default_val;
116  }
117 
118  int time = 0;
119  unsigned int i = 0;
120  const int searched_time = utils::clamp(current_time, 0, base_duration);
121 
122  while(time < searched_time && i < base_data.size()) {
123  time += base_data[i].second;
124  ++i;
125  }
126 
127  if(i != 0) {
128  i--;
129  time -= base_data[i].second;
130  }
131 
132  const T first = base_data[i].first.first;
133  const T second = base_data[i].first.second;
134 
135  return T((
136  static_cast<double>(searched_time - time) /
137  static_cast<double>(base_data[i].second)
138  ) * (second - first) + first);
139  }
140 
141  bool does_not_change() const override
142  {
143  const auto& base_data = progressive_pair_base_type::data();
144  return base_data.empty() || (base_data.size() == 1 && base_data[0].first.first == base_data[0].first.second);
145  }
146 
147 private:
149 };
150 
151 template<typename T>
153 {
154 public:
155  progressive_single(const std::string& input = "", int duration = 0)
156  : progressive_base<T, T>(input)
157  {
158  auto& base_data = progressive_single_base_type::data();
159 
160  const std::vector<std::string> first_pass = utils::square_parenthetical_split(input);
161  int time_chunk = std::max<int>(duration, 1);
162 
163  if(duration > 1 && !first_pass.empty()) {
164  // If duration specified, divide evenly the time for items with unspecified times
165  int total_specified_time = 0;
166 
167  for(const std::string& fp_string : first_pass) {
168  std::vector<std::string> second_pass = utils::split(fp_string, ':');
169  if(second_pass.size() > 1) {
170  try {
171  total_specified_time += std::stoi(second_pass[1]);
172  } catch(const std::invalid_argument&) {
173  //ERR_NG << "Invalid time in unit animation: " << second_pass[1] << "\n";
174  }
175  }
176  }
177 
178  time_chunk = std::max<int>((duration - total_specified_time) / first_pass.size(), 1);
179  }
180 
181  for(const std::string& fp_string : first_pass) {
182  std::vector<std::string> second_pass = utils::split(fp_string, ':');
183  if(second_pass.size() > 1) {
184  try {
185  base_data.push_back({std::move(second_pass[0]), std::stoi(second_pass[1])});
186  } catch(const std::invalid_argument&) {
187  //ERR_NG << "Invalid time in unit animation: " << second_pass[1] << "\n";
188  }
189  } else {
190  base_data.push_back({std::move(second_pass[0]) ,time_chunk});
191  }
192  }
193  }
194 
195  virtual const T get_current_element(int current_time, T default_val = T()) const override
196  {
197  const auto& base_data = progressive_single_base_type::data();
198 
199  if(base_data.empty()) {
200  return default_val;
201  }
202 
203  int time = 0;
204  unsigned int i = 0;
205 
206  while(time < current_time && i < base_data.size()) {
207  time += base_data[i].second;
208  ++i;
209  }
210 
211  // TODO: what is this for?
212  if(i) {
213  i--;
214  }
215 
216  return base_data[i].first;
217  }
218 
219 private:
221 };
222 
223 // Common types used by the unit frame code.
226 
constexpr const T & clamp(const T &value, const T &min, const T &max)
Definition: general.hpp:31
virtual bool does_not_change() const
virtual const T get_current_element(int current_time, T default_val=T()) const override
progressive_base(const std::string &input)
New lexcical_cast header.
std::string get_original() const
STL namespace.
To lexical_cast(From value)
Lexical cast converts one type to another.
std::vector< std::string > split(const std::string &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
bool does_not_change() const override
virtual const T get_current_element(int current_time, T default_val=T()) const override
int duration() const
std::vector< std::pair< std::string, int > > data_t
virtual ~progressive_base()
progressive_pair(const std::string &input="", int duration=0)
std::string input_
progressive_single(const std::string &input="", int duration=0)
std::size_t i
Definition: function.cpp:933
this module manages the cache of images.
Thrown when a lexical_cast fails.
std::vector< std::string > square_parenthetical_split(const std::string &val, const char separator, const std::string &left, const std::string &right, const int flags)
Similar to parenthetical_split, but also expands embedded square brackets.
const data_t & data() const