The Battle for Wesnoth  1.15.0-dev
halo.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2017 by David White <dave@whitevine.net>
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 /**
16  * @file
17  * Maintain halo-effects for units and items.
18  * Examples: white mage, lighthouse.
19  */
20 
21 #include "halo.hpp"
22 #include "animated.hpp"
23 #include "display.hpp"
24 #include "log.hpp"
25 #include "preferences/game.hpp"
26 #include "sdl/texture.hpp"
28 
29 #include <iostream>
30 
31 static lg::log_domain log_display("display");
32 #define ERR_DP LOG_STREAM(err, log_display)
33 
34 namespace halo
35 {
36 class halo_impl
37 {
38 public:
40  : halos()
41  , halo_id(1)
42  {
43  }
44 
45  int add(int x,
46  int y,
47  const std::string& image,
48  const map_location& loc,
49  ORIENTATION orientation = NORMAL,
50  bool infinite = true);
51 
52  /** Set the position of an existing haloing effect, according to its handle. */
53  void set_location(int handle, int x, int y);
54 
55  /** Remove the halo with the given handle. */
56  void remove(int handle);
57 
58  /**
59  * Render halos.
60  *
61  * Which halos are rendered is determined by invalidated_locations and the
62  * internal state in the control sets (in halo.cpp).
63  */
64  void render();
65 
66 private:
67  /** Encapsulates the drawing of a single halo effect. */
68  class effect
69  {
70  public:
71  effect(int xpos,
72  int ypos,
74  const map_location& loc,
76  bool infinite);
77 
78  void set_location(int x, int y);
79 
80  bool render();
81 
82  bool expired() const
83  {
85  }
86 
87  bool need_update() const
88  {
89  return images_.need_update();
90  }
91 
92  bool does_change() const
93  {
94  return !images_.does_not_change();
95  }
96 
97  private:
99  {
100  return images_.get_current_frame();
101  }
102 
104 
106 
107  int x_, y_;
108 
110 
111  /** The location of the center of the halo. */
113 
115  };
116 
117  std::map<int, effect> halos;
118 
119  int halo_id;
120 };
121 
123  int xpos,
124  int ypos,
126  const map_location& loc,
127  ORIENTATION orientation,
128  bool infinite)
129  : images_(img)
130  , orientation_(orientation)
131  , x_(0)
132  , y_(0)
133  , texture_(nullptr)
134  , loc_(loc)
135  , disp(display::get_singleton())
136 {
137  assert(disp != nullptr);
138 
139  set_location(xpos, ypos);
140 
141  images_.start_animation(0, infinite);
142 }
143 
145 {
146  int new_x = x - disp->get_location_x(map_location::ZERO());
147  int new_y = y - disp->get_location_y(map_location::ZERO());
148 
149  if(new_x != x_ || new_y != y_) {
150  x_ = new_x;
151  y_ = new_y;
152  }
153 }
154 
156 {
157  if(disp == nullptr) {
158  return false;
159  }
160 
161  if(loc_.x != -1 && loc_.y != -1) {
162  if(disp->shrouded(loc_)) {
163  return false;
164  } else {
165  // The location of a halo is an x,y value and not a map location.
166  // This means when a map is zoomed, the halo's won't move,
167  // This glitch is most visible on [item] halos.
168  // This workaround always recalculates the location of the halo
169  // (item halos have a location parameter to hide them under the shroud)
170  // and reapplies that location.
171  // It might be optimized by storing and comparing the zoom value.
172  set_location(
173  disp->get_location_x(loc_) + disp->hex_size() / 2,
175  );
176  }
177  }
178 
180 
181  texture_ = image::get_texture(current_image() /*, image::SCALED_TO_ZOOM*/);
182  if(texture_ == nullptr) {
183  return false;
184  }
185 
186  const int screenx = disp->get_location_x(map_location::ZERO());
187  const int screeny = disp->get_location_y(map_location::ZERO());
188 
189  texture::info t_info = texture_.get_info();
190 
191  const double zoom_factor = disp->get_zoom_factor();
192 
193  const int xpos = x_ + screenx - (t_info.w / 2) * zoom_factor;
194  const int ypos = y_ + screeny - (t_info.h / 2) * zoom_factor;
195 
196  // TODO: decide if I need this
197  // SDL_Rect clip_rect = disp->map_outside_area();
198  // const clip_rect_setter clip_setter(screen, &clip_rect);
199 
200  const bool h_flip = orientation_ == HREVERSE || orientation_ == HVREVERSE;
201  const bool v_flip = orientation_ == VREVERSE || orientation_ == HVREVERSE;
202 
203  disp->render_scaled_to_zoom(texture_, xpos, ypos, h_flip, v_flip);
204 
205  return true;
206 }
207 
208 
209 //
210 // HALO IMPL =========================================================================
211 //
212 
214  int x, int y, const std::string& image, const map_location& loc, ORIENTATION orientation, bool infinite)
215 {
216  const int id = halo_id++;
217 
219 
220  for(const std::string& item : utils::square_parenthetical_split(image, ',')) {
221  const std::vector<std::string>& sub_items = utils::split(item, ':');
222 
223  std::string str = item;
224  int time = 100;
225 
226  if(sub_items.size() > 1) {
227  str = sub_items.front();
228  try {
229  time = std::stoi(sub_items.back());
230  } catch(const std::invalid_argument) {
231  ERR_DP << "Invalid time value found when constructing halo: " << sub_items.back() << "\n";
232  }
233  }
234 
235  image_vector.emplace_back(time, image::locator(str));
236  }
237 
238  halos.emplace(id, effect(x, y, image_vector, loc, orientation, infinite));
239 
240  return id;
241 }
242 
243 void halo_impl::set_location(int handle, int x, int y)
244 {
245  const auto itor = halos.find(handle);
246  if(itor != halos.end()) {
247  itor->second.set_location(x, y);
248  }
249 }
250 
252 {
253  // Silently ignore invalid halos. This happens when Wesnoth is being terminated as well.
254  if(handle == NO_HALO || halos.find(handle) == halos.end()) {
255  return;
256  }
257 
258  auto itor = halos.find(handle);
259  if(itor != halos.end()) {
260  halos.erase(itor);
261  }
262 }
263 
265 {
266  if(!preferences::show_haloes() || halos.empty()) {
267  return;
268  }
269 
270  //
271  // Clean up expired halos.
272  //
273  for(auto itor = halos.begin(); itor != halos.end(); /* Handle increment in loop*/) {
274  if(itor->second.expired()) {
275  halos.erase(itor++);
276  } else {
277  ++itor;
278  }
279  }
280 
281  //
282  // Render the halos.
283  //
284  for(auto& halo : halos) {
285  halo.second.render();
286  }
287 }
288 
289 
290 //
291 // HALO MANAGER =========================================================================
292 //
293 
295  : impl_(new halo_impl())
296 {
297 }
298 
300  int x, int y, const std::string& image, const map_location& loc, ORIENTATION orientation, bool infinite)
301 {
302  int new_halo = impl_->add(x, y, image, loc, orientation, infinite);
303  return handle(new halo_record(new_halo, impl_));
304 }
305 
306 void manager::set_location(const handle& h, int x, int y)
307 {
308  impl_->set_location(h->id_, x, y);
309 }
310 
312 {
313  impl_->remove(h->id_);
314  h->id_ = NO_HALO;
315 }
316 
318 {
319  impl_->render();
320 }
321 
322 
323 //
324 // HALO RECORD =========================================================================
325 //
326 
328  : id_(NO_HALO) // halo::NO_HALO
329  , my_manager_()
330 {
331 }
332 
333 halo_record::halo_record(int id, const std::shared_ptr<halo_impl>& my_manager)
334  : id_(id)
335  , my_manager_(my_manager)
336 {
337 }
338 
340 {
341  if(!valid()) {
342  return;
343  }
344 
345  std::shared_ptr<halo_impl> man = my_manager_.lock();
346 
347  if(man) {
348  man->remove(id_);
349  }
350 }
351 
352 } // end namespace halo
Encapsulates the drawing of a single halo effect.
Definition: halo.cpp:68
static int hex_size()
Function which returns the size of a hex in pixels (from top tip to bottom tip or left edge to right ...
Definition: display.hpp:321
bool cycles() const
Definition: animated.hpp:71
static const map_location & ZERO()
Definition: location.hpp:79
animated< image::locator > images_
Definition: halo.cpp:103
bool need_update() const
map_location loc_
The location of the center of the halo.
Definition: halo.cpp:112
const int NO_HALO
Definition: halo.hpp:37
bool valid() const
Definition: halo.hpp:82
#define h
bool need_update() const
Definition: halo.cpp:87
std::weak_ptr< halo_impl > my_manager_
Definition: halo.hpp:89
static lg::log_domain log_display("display")
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.
Wrapper class to encapsulate creation and management of an SDL_Texture.
Definition: texture.hpp:26
#define ERR_DP
Definition: halo.cpp:32
bool show_haloes()
Definition: game.cpp:861
Animate units.
ORIENTATION orientation_
Definition: halo.cpp:105
bool does_not_change() const
Definition: animated.hpp:100
map_display and display: classes which take care of displaying the map and game-data on the screen...
effect(int xpos, int ypos, const animated< image::locator >::anim_description &img, const map_location &loc, ORIENTATION, bool infinite)
Definition: halo.cpp:122
void render()
Render halos.
Definition: halo.cpp:264
void remove(int handle)
Remove the halo with the given handle.
Definition: halo.cpp:251
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 &#39;image centered on (x,y).
Definition: halo.cpp:299
Encapsulates the map of the game.
Definition: location.hpp:42
bool shrouded(const map_location &loc) const
Returns true if location (x,y) is covered in shroud.
Definition: display.cpp:611
int add(int x, int y, const std::string &image, const map_location &loc, ORIENTATION orientation=NORMAL, bool infinite=true)
Definition: halo.cpp:213
const T & get_current_frame() const
std::shared_ptr< halo_impl > impl_
Definition: halo.hpp:66
void update_last_draw_time(double acceleration=0)
void render_scaled_to_zoom(const texture &tex, const int x_pos, const int y_pos, T &&... extra_args) const
Renders a texture directly to the screen (or current rendering target) scaled to the current zoom fac...
Definition: display.hpp:766
bool expired() const
Definition: halo.cpp:82
pump_impl & impl_
Definition: pump.cpp:138
int get_location_y(const map_location &loc) const
Definition: display.cpp:626
void start_animation(int start_time, bool cycles=false)
Starts an animation cycle.
std::map< int, effect > halos
Definition: halo.cpp:117
void set_location(int x, int y)
Definition: halo.cpp:144
double get_zoom_factor() const
Returns the current zoom factor.
Definition: display.hpp:327
const info get_info() const
Queries metadata about the texture, such as its dimensions.
Definition: texture.hpp:55
void set_location(const handle &h, int x, int y)
Set the position of an existing haloing effect, according to its handle.
Definition: halo.cpp:306
void render()
Render managed halos.
Definition: halo.cpp:317
Definition: display.hpp:44
int get_location_x(const map_location &loc) const
Functions to get the on-screen positions of hexes.
Definition: display.cpp:621
ORIENTATION
Definition: halo.hpp:35
this module manages the cache of images.
Definition: image.cpp:102
Standard logging facilities (interface).
RAII object which manages a halo.
Definition: halo.hpp:72
const image::locator & current_image() const
Definition: halo.cpp:98
void set_location(int handle, int x, int y)
Set the position of an existing haloing effect, according to its handle.
Definition: halo.cpp:243
std::shared_ptr< halo_record > handle
Definition: halo.hpp:31
bool does_change() const
Definition: halo.cpp:92
bool animation_finished() const
Returns true if the current animation was finished.
Small wrapper that queries metadata about the provided texture.
Definition: texture.hpp:44
texture get_texture(const image::locator &i_locator, TYPE type)
Definition: image.cpp:1483
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.
void remove(const handle &h)
Remove the halo with the given handle.
Definition: halo.cpp:311