The Battle for Wesnoth  1.15.0-dev
display.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 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  * Routines to set up the display, scroll and zoom the map.
18  */
19 
20 #include "display.hpp"
21 
22 #include "arrow.hpp"
23 #include "color.hpp"
24 #include "cursor.hpp"
25 #include "fake_unit_manager.hpp"
26 #include "floating_label.hpp"
27 #include "font/marked-up_text.hpp"
28 #include "font/text.hpp"
29 #include "gettext.hpp"
31 #include "halo.hpp"
33 #include "log.hpp"
34 #include "map/label.hpp"
35 #include "map/map.hpp"
36 #include "overlay.hpp"
37 #include "preferences/game.hpp"
38 #include "resources.hpp"
39 #include "sdl/render_utils.hpp"
40 #include "synced_context.hpp"
41 #include "team.hpp"
42 #include "terrain/builder.hpp"
43 #include "time_of_day.hpp"
44 #include "tooltips.hpp"
46 #include "units/drawer.hpp"
47 #include "units/unit.hpp"
48 #include "whiteboard/manager.hpp"
49 
50 #include <array>
51 #include <cmath>
52 #include <iomanip>
53 #include <utility>
54 
55 static lg::log_domain log_display("display");
56 #define ERR_DP LOG_STREAM(err, log_display)
57 #define LOG_DP LOG_STREAM(info, log_display)
58 #define DBG_DP LOG_STREAM(debug, log_display)
59 
60 // These are macros instead of proper constants so that they auto-update if the game config is reloaded.
61 #define zoom_levels (game_config::zoom_levels)
62 #define final_zoom_index (static_cast<int>(zoom_levels.size()) - 1)
63 #define DefaultZoom (game_config::tile_size)
64 #define SmallZoom (DefaultZoom / 2)
65 #define MinZoom (zoom_levels.front())
66 #define MaxZoom (zoom_levels.back())
67 
68 namespace
69 {
70 bool benchmark = false;
71 bool debug_foreground = false;
72 
73 int prevLabel = 0;
74 
75 // frametime is in milliseconds
76 static unsigned calculate_fps(unsigned frametime)
77 {
78  return frametime != 0u ? 1000u / frametime : 999u;
79 }
80 
81 } // end anon namespace
82 
83 unsigned int display::zoom_ = DefaultZoom;
84 unsigned int display::last_zoom_ = SmallZoom;
85 
87  std::weak_ptr<wb::manager> wb,
88  const config& theme_cfg,
89  const config& level,
90  bool auto_join)
91  : events::sdl_handler(auto_join)
92  , dc_(dc)
93  , halo_man_(new halo::manager())
94  , wb_(wb)
95  , exclusive_unit_draw_requests_()
96  , video_(CVideo::get_singleton())
97  , currentTeam_(0)
98  , dont_show_all_(false)
99  , xpos_(0)
100  , ypos_(0)
101  , view_locked_(false)
102  , theme_(theme_cfg, video().screen_area())
103  , zoom_index_(0)
104  , fake_unit_man_(new fake_unit_manager(*this))
105  , builder_(new terrain_builder(level, (dc_ ? &get_map() : nullptr), theme_.border().tile_image, theme_.border().show_border))
106  , minimap_location_(sdl::empty_rect)
107  , redrawMinimap_(false)
108  , grid_(false)
109  , diagnostic_label_(0)
110  , turbo_speed_(2)
111  , turbo_(false)
112  , map_labels_(new map_labels(nullptr))
113  , scroll_event_("scrolled")
114  , complete_redraw_event_("completely_redrawn")
115  , fps_counter_()
116  , fps_start_()
117  , fps_actual_()
118  , mouseover_hex_overlay_(nullptr)
119  , tod_hex_mask1(nullptr)
120  , tod_hex_mask2(nullptr)
121  , fog_images_()
122  , shroud_images_()
123  , selectedHex_()
124  , mouseoverHex_()
125  , keys_()
126  , animate_map_(true)
127  , animate_water_(true)
128  , flags_()
129  , activeTeam_(0)
130  , map_screenshot_(false)
131  , reach_map_()
132  , fps_handle_(0)
133  , drawn_hexes_(0)
134  , idle_anim_(preferences::idle_anim())
135  , idle_anim_rate_(1.0)
136  , draw_coordinates_(false)
137  , draw_terrain_codes_(false)
138  , draw_num_of_bitmaps_(false)
139  , arrows_map_()
140  , color_adjust_()
141 {
142  assert(singleton_ == nullptr);
143  singleton_ = this;
144 
146 
147  blindfold_ctr_ = 0;
148 
149  read(level.child_or_empty("display"));
150 
151  if(video_.non_interactive() && video_.faked()) {
152  video_.lock_updates(true);
153  }
154 
157 
159 
160  zoom_index_ = std::distance(zoom_levels.begin(), std::find(zoom_levels.begin(), zoom_levels.end(), zoom_));
161 
163 
164  init_flags();
165 }
166 
168 {
169  singleton_ = nullptr;
170  resources::fake_units = nullptr;
171 }
172 
173 void display::set_theme(config theme_cfg)
174 {
175  theme_ = theme(theme_cfg, video_.screen_area());
176 }
177 
179 {
180  flags_.clear();
181 
182  if(!dc_) {
183  return;
184  }
185 
186  flags_.resize(get_teams().size());
187 
188  for(std::size_t i = 0; i < get_teams().size(); ++i) {
189  init_flags(i);
190  }
191 }
192 
193 void display::init_flags(std::size_t side_index)
194 {
195  if(!dc_ || side_index >= dc_->teams().size()) {
196  ERR_DP << "Cannot build flag for nonexistent or unconfigured side " << (side_index + 1) << '\n';
197  return;
198  }
199 
200  const team& t = get_teams()[side_index];
201 
202  std::string flag = t.flag();
203  std::string old_rgb = game_config::flag_rgb;
204  std::string new_rgb = t.color();
205 
206  if(flag.empty()) {
208  }
209 
210  LOG_DP << "Adding flag for team " << t.side() << " from animation " << flag << "\n";
211 
212  // Must recolor flag image
213  animated<image::locator> temp_anim;
214 
215  std::vector<std::string> items = utils::square_parenthetical_split(flag);
216 
217  for(const std::string& item : items) {
218  const std::vector<std::string>& sub_items = utils::split(item, ':');
219  std::string str = item;
220  int time = 100;
221 
222  if(sub_items.size() > 1) {
223  str = sub_items.front();
224 
225  try {
226  time = std::max<int>(1, std::stoi(sub_items.back()));
227  } catch(const std::invalid_argument&) {
228  ERR_DP << "Invalid time value found when constructing flag for side " << t.side() << ": " << sub_items.back() << "\n";
229  }
230  }
231 
232  std::stringstream temp;
233  temp << str << "~RC(" << old_rgb << ">" << new_rgb << ")";
234  image::locator flag_image(temp.str());
235 
236  temp_anim.add_frame(time, flag_image);
237  }
238 
239  animated<image::locator>& f = flags_[side_index];
240  f = temp_anim;
241 
242  auto time = f.get_end_time();
243  if(time > 0) {
244  f.start_animation(randomness::rng::default_instance().get_random_int(0, time - 1), true);
245  } else {
246  // this can happen if both flag and game_config::images::flag are empty.
247  ERR_DP << "Missing flag for team" << t.side() << "\n";
248  }
249 }
250 
251 void display::set_team(std::size_t teamindex, bool show_everything)
252 {
253  assert(teamindex < get_teams().size());
254  currentTeam_ = teamindex;
255 
256  if(!show_everything) {
257  labels().set_team(&get_teams()[teamindex]);
258  dont_show_all_ = true;
259  } else {
260  labels().set_team(nullptr);
261  dont_show_all_ = false;
262  }
263 
265 
266  if(std::shared_ptr<wb::manager> w = wb_.lock()) {
267  w->on_viewer_change(teamindex);
268  }
269 }
270 
271 void display::set_playing_team(std::size_t teamindex)
272 {
273  assert(teamindex < get_teams().size());
274  activeTeam_ = teamindex;
275 }
276 
278  const std::string& img,
279  const std::string& halo,
280  const std::string& team_name,
281  const std::string& item_id,
282  bool visible_under_fog)
283 {
284  if(halo_man_) {
285  const halo::handle halo_handle = halo_man_->add(
286  get_location_x(loc) + hex_size() / 2,
287  get_location_y(loc) + hex_size() / 2, halo, loc
288  );
289 
290  get_overlays().emplace(loc, overlay(img, halo, halo_handle, team_name, item_id, visible_under_fog));
291  }
292 }
293 
295 {
296  get_overlays().erase(loc);
297 }
298 
299 void display::remove_single_overlay(const map_location& loc, const std::string& toDelete)
300 {
301  // Iterate through the values with key of loc
302  auto itors = get_overlays().equal_range(loc);
303 
304  while(itors.first != itors.second) {
305  const overlay& o = itors.first->second;
306 
307  if(o.image == toDelete || o.halo == toDelete || o.id == toDelete) {
308  get_overlays().erase(itors.first++);
309  } else {
310  ++itors.first;
311  }
312  }
313 }
314 
316 {
317  if(loc.valid() && exclusive_unit_draw_requests_.find(loc) == exclusive_unit_draw_requests_.end()) {
318  exclusive_unit_draw_requests_[loc] = unit.id();
319  return true;
320  } else {
321  return false;
322  }
323 }
324 
326 {
327  std::string id = "";
328  if(loc.valid()) {
330  // id will be set to the default "" string by the [] operator if the map doesn't have anything for that loc.
332  }
333 
334  return id;
335 }
336 
338 {
339  static time_of_day tod;
340  return tod;
341 }
342 
343 void display::update_tod(const time_of_day* tod_override)
344 {
345  const time_of_day* tod = tod_override;
346  if(tod == nullptr) {
347  tod = &get_time_of_day();
348  }
349 
350  const tod_color col = color_adjust_ + tod->color;
351  image::set_color_adjustment(col.r, col.g, col.b);
352 }
353 
354 void display::adjust_color_overlay(int r, int g, int b)
355 {
356  color_adjust_ = tod_color(r, g, b);
357  update_tod();
358 }
359 
360 void display::fill_images_list(const std::string& prefix, std::vector<std::string>& images)
361 {
362  if(prefix == "") {
363  return;
364  }
365 
366  // search prefix.png, prefix1.png, prefix2.png ...
367  for(int i = 0;; ++i) {
368  std::ostringstream s;
369  s << prefix;
370 
371  if(i != 0) {
372  s << i;
373  }
374 
375  s << ".png";
376 
377  if(image::exists(s.str())) {
378  images.push_back(s.str());
379  } else if(i > 0) {
380  break;
381  }
382  }
383 
384  if(images.empty()) {
385  images.emplace_back();
386  }
387 }
388 
389 const std::string& display::get_variant(const std::vector<std::string>& variants, const map_location& loc) const
390 {
391  // TODO use better noise function
392  return variants[std::abs(loc.x + loc.y) % variants.size()];
393 }
394 
396 {
397  builder_->rebuild_all();
398 }
399 
401 {
402  builder_->reload_map();
403 }
404 
406 {
407  dc_ = dc;
408  builder_->change_map(&get_map()); // TODO: Should display_context own and initialize the builder object?
409 }
410 
412 {
413  halo_man_.reset(new halo::manager());
414 }
415 
417 {
418  halo_man_.reset(&halo_man);
419 }
420 
421 void display::blindfold(bool value)
422 {
423  if(value == true) {
424  ++blindfold_ctr_;
425  } else {
426  --blindfold_ctr_;
427  }
428 }
429 
431 {
432  return blindfold_ctr_ > 0;
433 }
434 
435 const SDL_Rect& display::max_map_area() const
436 {
437  static SDL_Rect max_area {0, 0, 0, 0};
438 
439  // hex_size() is always a multiple of 4 and hex_width() a multiple of 3,
440  // so there shouldn't be off-by-one-errors due to rounding.
441  // To display a hex fully on screen, a little bit extra space is needed.
442  // Also added the border two times.
443  max_area.w = static_cast<int>((get_map().w() + 2 * theme_.border().size + 1.0 / 3.0) * hex_width());
444  max_area.h = static_cast<int>((get_map().h() + 2 * theme_.border().size + 0.5) * hex_size());
445 
446  return max_area;
447 }
448 
449 const SDL_Rect& display::map_area() const
450 {
451  static SDL_Rect max_area;
452  max_area = max_map_area();
453 
454  // if it's for map_screenshot, maximize and don't recenter
455  if(map_screenshot_) {
456  return max_area;
457  }
458 
459  static SDL_Rect res;
460  res = map_outside_area();
461 
462  // map is smaller, center
463  if(max_area.w < res.w) {
464  res.x += (res.w - max_area.w) / 2;
465  res.w = max_area.w;
466  }
467 
468  // map is smaller, center
469  if(max_area.h < res.h) {
470  res.y += (res.h - max_area.h) / 2;
471  res.h = max_area.h;
472  }
473 
474  return res;
475 }
476 
477 const SDL_Rect display::map_outside_area() const
478 {
480 }
481 
482 bool display::outside_area(const SDL_Rect& area, const int x, const int y)
483 {
484  const int x_thresh = hex_size();
485  const int y_thresh = hex_size();
486  return (x < area.x || x > area.x + area.w - x_thresh || y < area.y || y > area.y + area.h - y_thresh);
487 }
488 
489 // This function uses the screen as reference
490 const map_location display::hex_clicked_on(int xclick, int yclick) const
491 {
492  const SDL_Rect& rect = map_area();
493  if(sdl::point_in_rect(xclick, yclick, rect) == false) {
494  return map_location();
495  }
496 
497  xclick -= rect.x;
498  yclick -= rect.y;
499 
500  return pixel_position_to_hex(xpos_ + xclick, ypos_ + yclick);
501 }
502 
503 // This function uses the rect of map_area as reference
505 {
506  // adjust for the border
507  x -= static_cast<int>(theme_.border().size * hex_width());
508  y -= static_cast<int>(theme_.border().size * hex_size());
509 
510  // The editor can modify the border and this will result in a negative y
511  // value. Instead of adding extra cases we just shift the hex. Since the
512  // editor doesn't use the direction this is no problem.
513  const int offset = y < 0 ? 1 : 0;
514  if(offset) {
515  x += hex_width();
516  y += hex_size();
517  }
518 
519  const int s = hex_size();
520  const int tesselation_x_size = hex_width() * 2;
521  const int tesselation_y_size = s;
522  const int x_base = x / tesselation_x_size * 2;
523  const int x_mod = x % tesselation_x_size;
524  const int y_base = y / tesselation_y_size;
525  const int y_mod = y % tesselation_y_size;
526 
527  int x_modifier = 0;
528  int y_modifier = 0;
529 
530  if(y_mod < tesselation_y_size / 2) {
531  if((x_mod * 2 + y_mod) < (s / 2)) {
532  x_modifier = -1;
533  y_modifier = -1;
534  } else if((x_mod * 2 - y_mod) < (s * 3 / 2)) {
535  x_modifier = 0;
536  y_modifier = 0;
537  } else {
538  x_modifier = 1;
539  y_modifier = -1;
540  }
541  } else {
542  if((x_mod * 2 - (y_mod - s / 2)) < 0) {
543  x_modifier = -1;
544  y_modifier = 0;
545  } else if((x_mod * 2 + (y_mod - s / 2)) < s * 2) {
546  x_modifier = 0;
547  y_modifier = 0;
548  } else {
549  x_modifier = 1;
550  y_modifier = 0;
551  }
552  }
553 
554  return map_location(x_base + x_modifier - offset, y_base + y_modifier - offset);
555 }
556 
557 const rect_of_hexes display::hexes_under_rect(const SDL_Rect& r) const
558 {
559  rect_of_hexes res;
560 
561  if(r.w <= 0 || r.h <= 0) {
562  return res;
563  }
564 
565  SDL_Rect map_rect = map_area();
566 
567  // translate rect coordinates from screen-based to map_area-based
568  int x = xpos_ - map_rect.x + r.x;
569  int y = ypos_ - map_rect.y + r.y;
570 
571  // we use the "double" type to avoid important rounding error (size of an hex!)
572  // we will also need to use std::floor to avoid bad rounding at border (negative values)
573  double tile_width = hex_width();
574  double tile_size = hex_size();
575  double border = theme_.border().size;
576 
577  // we minus "0.(3)", for horizontal imbrication.
578  // reason is: two adjacent hexes each overlap 1/4 of their width, so for
579  // grid calculation 3/4 of tile width is used, which by default gives
580  // 18/54=0.(3). Note that, while tile_width is zoom dependent, 0.(3) is not.
581  res.left = static_cast<int>(std::floor(-border + x / tile_width - 0.3333333));
582 
583  // we remove 1 pixel of the rectangle dimensions
584  // (the rounded division take one pixel more than needed)
585  res.right = static_cast<int>(std::floor(-border + (x + r.w - 1) / tile_width));
586 
587  // for odd x, we must shift up one half-hex. Since x will vary along the edge,
588  // we store here the y values for even and odd x, respectively
589  res.top[0] = static_cast<int>(std::floor(-border + y / tile_size));
590  res.top[1] = static_cast<int>(std::floor(-border + y / tile_size - 0.5));
591  res.bottom[0] = static_cast<int>(std::floor(-border + (y + r.h - 1) / tile_size));
592  res.bottom[1] = static_cast<int>(std::floor(-border + (y + r.h - 1) / tile_size - 0.5));
593 
594  // TODO: in some rare cases (1/16), a corner of the big rect is on a tile
595  // (the 72x72 rectangle containing the hex) but not on the hex itself
596  // Can maybe be optimized by using pixel_position_to_hex
597 
598  return res;
599 }
600 
602 {
603  return hexes_under_rect(map_area());
604 }
605 
607 {
608  return currentTeam_ < get_teams().size();
609 }
610 
611 bool display::shrouded(const map_location& loc) const
612 {
613  return is_blindfolded() || (dont_show_all_ && get_teams()[currentTeam_].shrouded(loc));
614 }
615 
616 bool display::fogged(const map_location& loc) const
617 {
618  return is_blindfolded() || (dont_show_all_ && get_teams()[currentTeam_].fogged(loc));
619 }
620 
622 {
623  return static_cast<int>(map_area().x + (loc.x + theme_.border().size) * hex_width() - xpos_);
624 }
625 
627 {
628  return static_cast<int>(map_area().y + (loc.y + theme_.border().size) * zoom_ - ypos_ + (is_odd(loc.x) ? zoom_/2 : 0));
629 }
630 
632 {
633  return {
634  get_location_x(loc),
635  get_location_y(loc)
636  };
637 }
638 
640 {
641  // TODO: don't return location for this,
642  // instead directly scroll to the clicked pixel position
643 
644  if(!sdl::point_in_rect(x, y, minimap_area())) {
645  return map_location();
646  }
647 
648  // we transform the coordinates from minimap to the full map image
649  // probably more adjustments to do (border, minimap shift...)
650  // but the mouse and human capacity to evaluate the rectangle center
651  // is not pixel precise.
652  int px = (x - minimap_location_.x) * get_map().w() * hex_width() / std::max(minimap_location_.w, 1);
653  int py = (y - minimap_location_.y) * get_map().h() * hex_size() / std::max(minimap_location_.h, 1);
654 
655  map_location loc = pixel_position_to_hex(px, py);
656  loc.x = utils::clamp(loc.x, 0, get_map().w() - 1);
657  loc.y = utils::clamp(loc.x, 0, get_map().h() - 1);
658 
659  return loc;
660 }
661 
662 surface display::screenshot(bool map_screenshot)
663 {
664  if(!map_screenshot) {
665  // Use make_neutral_surface() to copy surface content
666  // TODO: convert to texture handling
667  //return make_neutral_surface(video_.getSurface());
668  return surface(nullptr);
669  }
670 
671  if(get_map().empty()) {
672  ERR_DP << "No map loaded, cannot create a map screenshot.\n";
673  return nullptr;
674  }
675 
676  const SDL_Rect area = max_map_area();
677  surface res = create_neutral_surface(area.w, area.h);
678 
679  // Memory problem?
680  if(res == nullptr) {
681  ERR_DP << "Could not create screenshot surface, try zooming out.\n";
682  return nullptr;
683  }
684 
685  // Back up the current map viewport position and move to top-left.
686  const int old_xpos = xpos_;
687  const int old_ypos = ypos_;
688  xpos_ = 0;
689  ypos_ = 0;
690 
691  // Reroute render output to a separate texture .
692  texture output_texture(area.w, area.h, SDL_TEXTUREACCESS_TARGET);
693  const render_target_setter target_setter(output_texture);
694 
695  map_screenshot_ = true;
696 
697  DBG_DP << "draw() call for map screenshot\n";
698  draw();
699 
700  map_screenshot_ = false;
701 
702  // Restore map viewport position
703  xpos_ = old_xpos;
704  ypos_ = old_ypos;
705 
706  // Copy the texture data to the output surface.
707  SDL_RenderReadPixels(video_.get_renderer(), &area, SDL_PIXELFORMAT_ARGB8888, res->pixels, res->pitch);
708  return res;
709 }
710 
711 static const std::string& get_direction(std::size_t n)
712 {
713  static const std::array<std::string, 6> dirs {{"-n", "-ne", "-se", "-s", "-sw", "-nw"}};
714  return dirs[n >= dirs.size() ? 0 : n];
715 }
716 
718 {
719  std::vector<std::string> names;
720 
721  adjacent_loc_array_t adjacent;
722  get_adjacent_tiles(loc, adjacent.data());
723 
724  enum visibility { FOG = 0, SHROUD = 1, CLEAR = 2 };
725  visibility tiles[6];
726 
727  const std::string* image_prefix[]{&game_config::fog_prefix, &game_config::shroud_prefix};
728 
729  for(int i = 0; i < 6; ++i) {
730  if(shrouded(adjacent[i])) {
731  tiles[i] = SHROUD;
732  } else if(!fogged(loc) && fogged(adjacent[i])) {
733  tiles[i] = FOG;
734  } else {
735  tiles[i] = CLEAR;
736  }
737  }
738 
739  for(int v = FOG; v != CLEAR; ++v) {
740  // Find somewhere that doesn't have overlap to use as a starting point
741  int start;
742  for(start = 0; start != 6; ++start) {
743  if(tiles[start] != v) {
744  break;
745  }
746  }
747 
748  if(start == 6) {
749  // Completely surrounded by fog or shroud. This might have a special graphic.
750  const std::string name = *image_prefix[v] + "-all.png";
751  if(image::exists(name)) {
752  names.push_back(name);
753  // Proceed to the next visibility (fog -> shroud -> clear).
754  continue;
755  }
756 
757  // No special graphic found. We'll just combine some other images
758  // and hope it works out.
759  start = 0;
760  }
761 
762  // Find all the directions overlap occurs from
763  for(int i = (start + 1) % 6, cap1 = 0; i != start && cap1 != 6; ++cap1) {
764  if(tiles[i] == v) {
765  std::ostringstream stream;
766  stream << *image_prefix[v];
767 
768  std::string name;
769  for(int cap2 = 0; v == tiles[i] && cap2 != 6; i = (i + 1) % 6, ++cap2) {
770  stream << get_direction(i);
771 
772  if(!image::exists(stream.str() + ".png")) {
773  // If we don't have any surface at all,
774  // then move onto the next overlapped area
775  if(name.empty()) {
776  i = (i + 1) % 6;
777  }
778  break;
779  } else {
780  name = stream.str();
781  }
782  }
783 
784  if(!name.empty()) {
785  names.push_back(name + ".png");
786  }
787  } else {
788  i = (i + 1) % 6;
789  }
790  }
791  }
792 
793  // Now render the images
794  for(std::string& name : names) {
795  render_scaled_to_zoom(image::get_texture(name), loc); // TODO: image_type
796  }
797 }
798 
800 {
801  benchmark = !benchmark;
802 }
803 
805 {
806  debug_foreground = !debug_foreground;
807 }
808 
810 {
811  if(video_.update_locked()) {
812  return;
813  }
814 
815  if(preferences::show_fps() || benchmark) {
816  static int frames = 0;
817  ++frames;
818 
819  const int sample_freq = 10;
820  if(frames == sample_freq) {
821  const auto minmax_it = std::minmax_element(frametimes_.begin(), frametimes_.end());
822  const unsigned render_avg = std::accumulate(frametimes_.begin(), frametimes_.end(), 0) / frametimes_.size();
823  const int avg_fps = calculate_fps(render_avg);
824  const int max_fps = calculate_fps(*minmax_it.first);
825  const int min_fps = calculate_fps(*minmax_it.second);
826  frames = 0;
827 
828  if(fps_handle_ != 0) {
830  fps_handle_ = 0;
831  }
832 
833  std::ostringstream stream;
834  stream << "<tt> min/avg/max/act</tt>\n";
835  stream << "<tt>FPS: " << std::setfill(' ') << std::setw(3) << min_fps << '/'<< std::setw(3) << avg_fps << '/' << std::setw(3) << max_fps << '/' << std::setw(3) << fps_actual_ << "</tt>\n";
836  stream << "<tt>Time: " << std::setfill(' ') << std::setw(3) << *minmax_it.first << '/' << std::setw(3) << render_avg << '/' << std::setw(3) << *minmax_it.second << " ms</tt>\n";
837  if(game_config::debug) {
838  stream << "\nhex: " << drawn_hexes_ * 1.0 / sample_freq;
839  }
840 
841  drawn_hexes_ = 0;
842 
843  font::floating_label flabel(stream.str());
844  flabel.set_font_size(12);
845  flabel.set_color(benchmark ? font::BAD_COLOR : font::NORMAL_COLOR);
846  flabel.set_position(10, 100);
847  flabel.set_alignment(font::LEFT_ALIGN);
848 
850  }
851  } else if(fps_handle_ != 0) {
853  fps_handle_ = 0;
854  drawn_hexes_ = 0;
855  }
856 }
857 
859 {
860  const std::string& image = theme_.border().background_image;
861  SDL_Rect area = map_outside_area();
862 
863  // No background image, just fill in black.
864  if(image.empty()) {
865  sdl::fill_rectangle(area, color_t(0, 0, 0));
866  return;
867  }
868 
869  const texture background(image::get_texture(image));
870  if(background.null()) {
871  return;
872  }
873 
874  // TODO: should probably tile this as before.
875  video_.render_copy(background, nullptr, &area);
876 }
877 
879  const std::string& text,
880  std::size_t font_size,
881  color_t color,
882  int fl_label_id,
883  double x_in_hex,
884  double y_in_hex)
885 {
886  if(text.empty()) {
887  return fl_label_id;
888  }
889 
890  const std::size_t font_sz = static_cast<std::size_t>(font_size * get_zoom_factor());
891 
892  const int x = get_location_x(loc) /*- text_surf->w / 2*/ + static_cast<int>(x_in_hex * hex_size());
893  const int y = get_location_y(loc) /*- text_surf->h / 2*/ + static_cast<int>(y_in_hex * hex_size());
894 
895  // We were given a label id, remove it.
896  if(fl_label_id != 0) {
897  font::remove_floating_label(fl_label_id);
898  }
899 
900  font::floating_label flabel(text);
901  flabel.set_font_size(font_sz);
902  flabel.set_color(color);
903  flabel.set_position(x, y);
906 
907  return font::add_floating_label(flabel);
908 }
909 
911 {
912  selectedHex_ = hex;
914 }
915 
917 {
918  mouseoverHex_ = hex;
919 }
920 
921 void display::set_diagnostic(const std::string& msg)
922 {
923  if(diagnostic_label_ != 0) {
925  diagnostic_label_ = 0;
926  }
927 
928  if(!msg.empty()) {
929  font::floating_label flabel(msg);
932  flabel.set_position(300, 50);
934 
936  }
937 }
938 
939 void display::announce(const std::string& message, const color_t& color, const announce_options& options)
940 {
941  if(options.discard_previous) {
942  font::remove_floating_label(prevLabel);
943  }
944 
945  font::floating_label flabel(message);
947  flabel.set_color(color);
948  flabel.set_position(map_outside_area().w / 2, map_outside_area().h / 3);
949  flabel.set_lifetime(options.lifetime);
951 
952  prevLabel = font::add_floating_label(flabel);
953 }
954 
955 bool display::scroll(int xmove, int ymove, bool force)
956 {
957  if(view_locked_ && !force) {
958  return false;
959  }
960 
961  // No move offset, do nothing.
962  if(xmove == 0 && ymove == 0) {
963  return false;
964  }
965 
966  int new_x = xpos_ + xmove;
967  int new_y = ypos_ + ymove;
968 
969  bounds_check_position(new_x, new_y);
970 
971  // Camera position doesn't change, exit.
972  if(xpos_ == new_x && ypos_ == new_y) {
973  return false;
974  }
975 
976  const int diff_x = xpos_ - new_x;
977  const int diff_y = ypos_ - new_y;
978 
979  xpos_ = new_x;
980  ypos_ = new_y;
981 
982  /* Adjust floating label positions. This only affects labels whose position is anchored
983  * to the map instead of the screen. In order to do that, we want to adjust their drawing
984  * coordinates in the opposite direction of the screen scroll.
985  *
986  * The check a few lines up prevents any scrolling from happening if the camera position
987  * doesn't change. Without that, the label still scroll even when the map edge is reached.
988  * If that's removed, the following formula should work instead:
989  *
990  * const int label_[x,y]_adjust = [x,y]pos_ - new_[x,y];
991  */
992  font::scroll_floating_labels(diff_x, diff_y);
993 
995 
997 
998  redrawMinimap_ = true;
999 
1000  return true;
1001 }
1002 
1004 {
1005  return zoom_ == MaxZoom;
1006 }
1007 
1009 {
1010  return zoom_ == MinZoom;
1011 }
1012 
1013 bool display::set_zoom(bool increase)
1014 {
1015  // Ensure we don't try to access nonexistent vector indices.
1016  zoom_index_ = utils::clamp(increase ? zoom_index_ + 1 : zoom_index_ - 1, 0, final_zoom_index);
1017 
1018  // No validation check is needed in the next step since we've already set the index here and
1019  // know the new zoom value is indeed valid.
1020  return set_zoom(zoom_levels[zoom_index_], false);
1021 }
1022 
1023 bool display::set_zoom(unsigned int amount, const bool validate_value_and_set_index)
1024 {
1025  unsigned int new_zoom = utils::clamp(amount, MinZoom, MaxZoom);
1026 
1027  LOG_DP << "new_zoom = " << new_zoom << std::endl;
1028 
1029  if(new_zoom == zoom_) {
1030  return false;
1031  }
1032 
1033  // Confirm this is indeed a valid zoom level.
1034  if(validate_value_and_set_index) {
1035  auto iter = std::lower_bound(zoom_levels.begin(), zoom_levels.end(), new_zoom);
1036 
1037  if(iter == zoom_levels.end()) {
1038  // This should never happen, since the value was already clamped earlier
1039  return false;
1040  } else if(iter != zoom_levels.begin()) {
1041  float diff = *iter - *(iter - 1);
1042  float lower = (new_zoom - *(iter - 1)) / diff;
1043  float upper = (*iter - new_zoom) / diff;
1044  if(lower < upper) {
1045  // It's actually closer to the previous element.
1046  iter--;
1047  }
1048  }
1049 
1050  new_zoom = *iter;
1051  zoom_index_ = std::distance(zoom_levels.begin(), iter);
1052  }
1053 
1054  const SDL_Rect& area = map_area();
1055 
1056  // Turn the zoom factor to a double in order to avoid rounding errors.
1057  double zoom_factor = static_cast<double>(new_zoom) / static_cast<double>(zoom_);
1058 
1059  xpos_ = std::round(((xpos_ + area.w / 2) * zoom_factor) - (area.w / 2));
1060  ypos_ = std::round(((ypos_ + area.h / 2) * zoom_factor) - (area.h / 2));
1061 
1062  zoom_ = new_zoom;
1064  if(zoom_ != DefaultZoom) {
1065  last_zoom_ = zoom_;
1066  }
1067 
1069 
1071 
1072  // Forces a redraw after zooming.
1073  // This prevents some graphic glitches from occurring.
1074  // draw();
1075 
1076  return true;
1077 }
1078 
1080 {
1081  if(zoom_ != DefaultZoom) {
1082  last_zoom_ = zoom_;
1084  } else {
1085  // When we are already at the default zoom,
1086  // switch to the last zoom used
1088  }
1089 }
1090 
1092 {
1093  int x = get_location_x(loc);
1094  int y = get_location_y(loc);
1095  return !outside_area(map_area(), x, y);
1096 }
1097 
1099 {
1100  int x = get_location_x(loc);
1101  int y = get_location_y(loc);
1102  const SDL_Rect& area = map_area();
1103  int hw = hex_width(), hs = hex_size();
1104  return x + hs >= area.x - hw && x < area.x + area.w + hw && y + hs >= area.y - hs && y < area.y + area.h + hs;
1105 }
1106 
1107 void display::scroll_to_xy(int screenxpos, int screenypos, SCROLL_TYPE scroll_type, bool force)
1108 {
1109  if(!force && (view_locked_ || !preferences::scroll_to_action())) {
1110  return;
1111  }
1112 
1113  if(video_.update_locked()) {
1114  return;
1115  }
1116 
1117  const SDL_Rect area = map_area();
1118  const int xmove_expected = screenxpos - (area.x + area.w / 2);
1119  const int ymove_expected = screenypos - (area.y + area.h / 2);
1120 
1121  int xpos = xpos_ + xmove_expected;
1122  int ypos = ypos_ + ymove_expected;
1123  bounds_check_position(xpos, ypos);
1124  int xmove = xpos - xpos_;
1125  int ymove = ypos - ypos_;
1126 
1127  if(scroll_type == WARP || scroll_type == ONSCREEN_WARP || turbo_speed() > 2.0 || preferences::scroll_speed() > 99) {
1128  scroll(xmove, ymove, true);
1129  // draw();
1130  return;
1131  }
1132 
1133  // Doing an animated scroll, with acceleration etc.
1134 
1135  int x_old = 0;
1136  int y_old = 0;
1137 
1138  const double dist_total = std::hypot(xmove, ymove);
1139  double dist_moved = 0.0;
1140 
1141  int t_prev = SDL_GetTicks();
1142 
1143  double velocity = 0.0;
1144  while(dist_moved < dist_total) {
1146 
1147  int t = SDL_GetTicks();
1148  double dt = (t - t_prev) / 1000.0;
1149  if(dt > 0.200) {
1150  // Do not skip too many frames on slow PCs
1151  dt = 0.200;
1152  }
1153  t_prev = t;
1154 
1155  const double accel_time = 0.3 / turbo_speed(); // seconds until full speed is reached
1156  const double decel_time = 0.4 / turbo_speed(); // seconds from full speed to stop
1157 
1158  double velocity_max = preferences::scroll_speed() * 60.0;
1159  velocity_max *= turbo_speed();
1160  double accel = velocity_max / accel_time;
1161  double decel = velocity_max / decel_time;
1162 
1163  // If we started to decelerate now, where would we stop?
1164  double stop_time = velocity / decel;
1165  double dist_stop = dist_moved + velocity * stop_time - 0.5 * decel * stop_time * stop_time;
1166 
1167  if(dist_stop > dist_total || velocity > velocity_max) {
1168  velocity -= decel * dt;
1169  if(velocity < 1.0) {
1170  velocity = 1.0;
1171  }
1172  } else {
1173  velocity += accel * dt;
1174  if(velocity > velocity_max) {
1175  velocity = velocity_max;
1176  }
1177  }
1178 
1179  dist_moved += velocity * dt;
1180  if(dist_moved > dist_total) {
1181  dist_moved = dist_total;
1182  }
1183 
1184  int x_new = std::round(xmove * dist_moved / dist_total);
1185  int y_new = std::round(ymove * dist_moved / dist_total);
1186 
1187  int dx = x_new - x_old;
1188  int dy = y_new - y_old;
1189 
1190  scroll(dx, dy, true);
1191  x_old += dx;
1192  y_old += dy;
1193  // draw();
1194  }
1195 }
1196 
1197 void display::scroll_to_tile(const map_location& loc, SCROLL_TYPE scroll_type, bool check_fogged, bool force)
1198 {
1199  if(get_map().on_board(loc) == false) {
1200  ERR_DP << "Tile at " << loc << " isn't on the map, can't scroll to the tile." << std::endl;
1201  return;
1202  }
1203 
1204  std::vector<map_location> locs;
1205  locs.push_back(loc);
1206 
1207  scroll_to_tiles(locs, scroll_type, check_fogged, false, 0.0, force);
1208 }
1209 
1211  map_location loc2,
1212  SCROLL_TYPE scroll_type,
1213  bool check_fogged,
1214  double add_spacing,
1215  bool force)
1216 {
1217  std::vector<map_location> locs;
1218  locs.push_back(loc1);
1219  locs.push_back(loc2);
1220  scroll_to_tiles(locs, scroll_type, check_fogged, false, add_spacing, force);
1221 }
1222 
1223 void display::scroll_to_tiles(const std::vector<map_location>::const_iterator& begin,
1224  const std::vector<map_location>::const_iterator& end,
1225  SCROLL_TYPE scroll_type,
1226  bool check_fogged,
1227  bool only_if_possible,
1228  double add_spacing,
1229  bool force)
1230 {
1231  // basically we calculate the min/max coordinates we want to have on-screen
1232  int minx = 0;
1233  int maxx = 0;
1234  int miny = 0;
1235  int maxy = 0;
1236  bool valid = false;
1237 
1238  for(std::vector<map_location>::const_iterator itor = begin; itor != end; ++itor) {
1239  if(get_map().on_board(*itor) == false)
1240  continue;
1241  if(check_fogged && fogged(*itor))
1242  continue;
1243 
1244  int x = get_location_x(*itor);
1245  int y = get_location_y(*itor);
1246 
1247  if(!valid) {
1248  minx = x;
1249  maxx = x;
1250  miny = y;
1251  maxy = y;
1252 
1253  valid = true;
1254  } else {
1255  int minx_new = std::min<int>(minx, x);
1256  int miny_new = std::min<int>(miny, y);
1257  int maxx_new = std::max<int>(maxx, x);
1258  int maxy_new = std::max<int>(maxy, y);
1259 
1260  SDL_Rect r = map_area();
1261  r.x = minx_new;
1262  r.y = miny_new;
1263 
1264  if(outside_area(r, maxx_new, maxy_new)) {
1265  // we cannot fit all locations to the screen
1266  if(only_if_possible) {
1267  return;
1268  }
1269 
1270  break;
1271  }
1272 
1273  minx = minx_new;
1274  miny = miny_new;
1275  maxx = maxx_new;
1276  maxy = maxy_new;
1277  }
1278  }
1279 
1280  // if everything is fogged or the location list is empty
1281  if(!valid) {
1282  return;
1283  }
1284 
1285  if(scroll_type == ONSCREEN || scroll_type == ONSCREEN_WARP) {
1286  SDL_Rect r = map_area();
1287  int spacing = std::round(add_spacing * hex_size());
1288  r.x += spacing;
1289  r.y += spacing;
1290  r.w -= 2 * spacing;
1291  r.h -= 2 * spacing;
1292 
1293  if(!outside_area(r, minx, miny) && !outside_area(r, maxx, maxy)) {
1294  return;
1295  }
1296  }
1297 
1298  // let's do "normal" rectangle math from now on
1299  SDL_Rect locs_bbox {
1300  minx,
1301  miny,
1302  maxx - minx + hex_size(),
1303  maxy - miny + hex_size()
1304  };
1305 
1306  // target the center
1307  int target_x = locs_bbox.x + locs_bbox.w / 2;
1308  int target_y = locs_bbox.y + locs_bbox.h / 2;
1309 
1310  if(scroll_type == ONSCREEN || scroll_type == ONSCREEN_WARP) {
1311  // when doing an ONSCREEN scroll we do not center the target unless needed
1312  SDL_Rect r = map_area();
1313  int map_center_x = r.x + r.w / 2;
1314  int map_center_y = r.y + r.h / 2;
1315 
1316  int h = r.h;
1317  int w = r.w;
1318 
1319  // we do not want to be only inside the screen rect, but center a bit more
1320  double inside_frac = 0.5; // 0.0 = always center the target, 1.0 = scroll the minimum distance
1321  w = static_cast<int>(w * inside_frac);
1322  h = static_cast<int>(h * inside_frac);
1323 
1324  // shrink the rectangle by the size of the locations rectangle we found
1325  // such that the new task to fit a point into a rectangle instead of rectangle into rectangle
1326  w -= locs_bbox.w;
1327  h -= locs_bbox.h;
1328 
1329  if (w < 1) w = 1;
1330  if (h < 1) h = 1;
1331 
1332  r.x = target_x - w / 2;
1333  r.y = target_y - h / 2;
1334  r.w = w;
1335  r.h = h;
1336 
1337  // now any point within r is a possible target to scroll to
1338  // we take the one with the minimum distance to map_center
1339  // which will always be at the border of r
1340 
1341  if(map_center_x < r.x) {
1342  target_x = r.x;
1343  target_y = utils::clamp(map_center_y, r.y, r.y + r.h - 1);
1344  } else if(map_center_x > r.x + r.w - 1) {
1345  target_x = r.x + r.w - 1;
1346  target_y = utils::clamp(map_center_y, r.y, r.y + r.h - 1);
1347  } else if(map_center_y < r.y) {
1348  target_y = r.y;
1349  target_x = utils::clamp(map_center_x, r.x, r.x + r.w - 1);
1350  } else if(map_center_y > r.y + r.h - 1) {
1351  target_y = r.y + r.h - 1;
1352  target_x = utils::clamp(map_center_x, r.x, r.x + r.w - 1);
1353  } else {
1354  ERR_DP << "Bug in the scrolling code? Looks like we would not need to scroll after all..." << std::endl;
1355  // keep the target at the center
1356  }
1357  }
1358 
1359  scroll_to_xy(target_x, target_y, scroll_type, force);
1360 }
1361 
1363 {
1364  const unsigned int orig_zoom = zoom_;
1365 
1367 
1369 
1370  if(zoom_ != orig_zoom) {
1372  }
1373 }
1374 
1375 void display::bounds_check_position(int& xpos, int& ypos) const
1376 {
1377  const int tile_width = hex_width();
1378 
1379  // Adjust for the border 2 times
1380  const int xend = static_cast<int>(tile_width * (get_map().w() + 2 * theme_.border().size) + tile_width / 3);
1381  const int yend = static_cast<int>(zoom_ * (get_map().h() + 2 * theme_.border().size) + zoom_ / 2);
1382 
1383  xpos = utils::clamp(xpos, 0, xend - map_area().w);
1384  ypos = utils::clamp(ypos, 0, yend - map_area().h);
1385 }
1386 
1387 double display::turbo_speed() const
1388 {
1389  bool res = turbo_;
1390  if(keys_[SDLK_LSHIFT] || keys_[SDLK_RSHIFT]) {
1391  res = !res;
1392  }
1393 
1394  res |= video_.faked();
1395  if(res) {
1396  return turbo_speed_;
1397  }
1398 
1399  return 1.0;
1400 }
1401 
1403 {
1404  idle_anim_rate_ = std::pow(2.0, -rate / 10.0);
1405 }
1406 
1408 {
1409  return *map_labels_;
1410 }
1411 
1413 {
1414  return *map_labels_;
1415 }
1416 
1417 const SDL_Rect display::get_clip_rect()
1418 {
1419  return map_area();
1420 }
1421 
1423 {
1424  return image::TOD_COLORED;
1425 }
1426 
1428 {
1430 
1432  if(animate_map_) {
1433  for(const map_location& loc : get_visible_hexes()) {
1434  if(shrouded(loc)) {
1435  continue;
1436  }
1437 
1438  builder_->update_animation(loc);
1439  }
1440  }
1441 
1442  for(const unit& u : get_units()) {
1443  u.anim_comp().refresh();
1444  }
1445 
1446  for(const unit* u : *fake_unit_man_) {
1447  u->anim_comp().refresh();
1448  }
1449 }
1450 
1452 {
1453  for(const unit& u : get_units()) {
1454  u.anim_comp().set_standing();
1455  }
1456 }
1457 
1459 {
1460  for(const map_location& loc : arrow.get_path()) {
1461  arrows_map_[loc].push_back(&arrow);
1462  }
1463 }
1464 
1466 {
1467  for(const map_location& loc : arrow.get_path()) {
1468  arrows_map_[loc].remove(&arrow);
1469  }
1470 }
1471 
1473 {
1474  for(const map_location& loc : arrow.get_previous_path()) {
1475  arrows_map_[loc].remove(&arrow);
1476  }
1477 
1478  for(const map_location& loc : arrow.get_path()) {
1479  arrows_map_[loc].push_back(&arrow);
1480  }
1481 }
1482 
1484 {
1485  const SDL_Rect& rect = map_area();
1486  return pixel_position_to_hex(xpos_ + rect.x + rect.w / 2, ypos_ + rect.y + rect.h / 2);
1487 }
1488 
1489 void display::write(config& cfg) const
1490 {
1491  cfg["view_locked"] = view_locked_;
1492  cfg["color_adjust_red"] = color_adjust_.r;
1493  cfg["color_adjust_green"] = color_adjust_.g;
1494  cfg["color_adjust_blue"] = color_adjust_.b;
1495 
1496  get_middle_location().write(cfg.add_child("location"));
1497 }
1498 
1499 void display::read(const config& cfg)
1500 {
1501  view_locked_ = cfg["view_locked"].to_bool(false);
1502  color_adjust_.r = cfg["color_adjust_red"].to_int(0);
1503  color_adjust_.g = cfg["color_adjust_green"].to_int(0);
1504  color_adjust_.b = cfg["color_adjust_blue"].to_int(0);
1505 }
1506 
1507 //
1508 // NEW RENDERING CODE =========================================================================
1509 //
1510 
1512 {
1513  // DO NOTHING
1514 }
1515 
1516 void display::draw_visible_hexes(const rect_of_hexes& visible_hexes, TERRAIN_TYPE layer)
1517 {
1518  assert(builder_);
1519 
1520  drawn_hexes_ = 0;
1521 
1522  terrain_builder::TERRAIN_TYPE builder_terrain_type = layer == FOREGROUND
1525 
1526  for(const map_location& loc : visible_hexes) {
1527  if(shrouded(loc)) {
1528  continue;
1529  }
1530 
1531  //image::TYPE image_type = get_image_type(loc);
1532  const time_of_day& tod = get_time_of_day(loc);
1533 
1534  // Get the image list for this location.
1535  const terrain_builder::imagelist* const terrains = builder_->get_terrain_at(loc, tod.id, builder_terrain_type);
1536  if(!terrains) {
1537  continue;
1538  }
1539 
1540 #if 0
1542 
1543  const time_of_day& tod = get_time_of_day(loc);
1544 
1545  //get all the light transitions
1546  map_location adjs[6];
1547  get_adjacent_tiles(loc,adjs);
1548 
1549  for(int d=0; d<6; ++d){
1550  /* concave
1551  _____
1552  / \
1553  / atod1 \_____
1554  \ !tod / \
1555  \_____/ atod2 \
1556  / \__\ !tod /
1557  / \_____/
1558  \ tod /
1559  \_____/*/
1560 
1561  const time_of_day& atod1 = get_time_of_day(adjs[d]);
1562  const time_of_day& atod2 = get_time_of_day(adjs[(d + 1) % 6]);
1563 
1564  if(atod1.color == tod.color || atod2.color == tod.color || atod1.color != atod2.color)
1565  continue;
1566 
1567  if(lt.empty()) {
1568  //color the full hex before adding transitions
1569  tod_color col = tod.color + color_adjust_;
1570  lt = image::get_light_string(0, col.r, col.g, col.b);
1571  }
1572 
1573  // add the directional transitions
1574  tod_color acol = atod1.color + color_adjust_;
1575  lt += image::get_light_string(d + 1, acol.r, acol.g, acol.b);
1576  }
1577  for(int d=0; d<6; ++d){
1578  /* convex 1
1579  _____
1580  / \
1581  / atod1 \_____
1582  \ !tod / \
1583  \_____/ atod2 \
1584  / \__\ tod /
1585  / \_____/
1586  \ tod /
1587  \_____/*/
1588 
1589  const time_of_day& atod1 = get_time_of_day(adjs[d]);
1590  const time_of_day& atod2 = get_time_of_day(adjs[(d + 1) % 6]);
1591 
1592  if(atod1.color == tod.color || atod1.color == atod2.color)
1593  continue;
1594 
1595  if(lt.empty()) {
1596  //color the full hex before adding transitions
1597  tod_color col = tod.color + color_adjust_;
1598  lt = image::get_light_string(0, col.r, col.g, col.b);
1599  }
1600 
1601  // add the directional transitions
1602  tod_color acol = atod1.color + color_adjust_;
1603  lt += image::get_light_string(d + 7, acol.r, acol.g, acol.b);
1604  }
1605  for(int d=0; d<6; ++d){
1606  /* convex 2
1607  _____
1608  / \
1609  / atod1 \_____
1610  \ tod / \
1611  \_____/ atod2 \
1612  / \__\ !tod /
1613  / \_____/
1614  \ tod /
1615  \_____/*/
1616 
1617  const time_of_day& atod1 = get_time_of_day(adjs[d]);
1618  const time_of_day& atod2 = get_time_of_day(adjs[(d + 1) % 6]);
1619 
1620  if(atod2.color == tod.color || atod1.color == atod2.color)
1621  continue;
1622 
1623  if(lt.empty()) {
1624  //color the full hex before adding transitions
1625  tod_color col = tod.color + color_adjust_;
1626  lt = image::get_light_string(0, col.r, col.g, col.b);
1627  }
1628 
1629  // add the directional transitions
1630  tod_color acol = atod2.color + color_adjust_;
1631  lt += image::get_light_string(d + 13, acol.r, acol.g, acol.b);
1632  }
1633 
1634  if(lt.empty()){
1635  tod_color col = tod.color + color_adjust_;
1636  if(!col.is_zero()){
1637  // no real lightmap needed but still color the hex
1638  lt = image::get_light_string(-1, col.r, col.g, col.b);
1639  }
1640  }
1641 #endif
1642 
1643  // Cache the offmap name.
1644  // Since it is themeable it can change, so don't make it static.
1645  //const std::string off_map_name = "terrain/" + theme_.border().tile_image;
1646 
1647  for(const auto& terrain : *terrains) {
1648  const image::locator& image = animate_map_
1649  ? terrain.get_current_frame()
1650  : terrain.get_first_frame();
1651 
1652  // We prevent ToD coloring and brightening of off-map tiles,
1653  // We need to test for the tile to be rendered and
1654  // not the location, since the transitions are rendered
1655  // over the offmap-terrain and these need a ToD coloring.
1656  texture tex = image::get_texture(image, image::HEXED); // TODO: scaled to hex?
1657 
1658  //const bool off_map = (image.get_filename() == off_map_name || image.get_modifications().find("NO_TOD_SHIFT()") != std::string::npos);
1659 #if 0
1660  if(off_map) {
1661  surf = image::get_image(image, off_map ? image::SCALED_TO_HEX : image_type);
1662  } else if(lt.empty()) {
1663  surf = image::get_image(image, image::SCALED_TO_HEX);
1664  } else {
1665  surf = image::get_lighted_image(image, lt, image::SCALED_TO_HEX);
1666  }
1667 #endif
1668  if(!tex.null()) {
1669  render_scaled_to_zoom(tex, loc);
1670  }
1671  }
1672 
1673  ++drawn_hexes_;
1674  }
1675 }
1676 
1677 void display::draw_gamemap()
1678 {
1679  // Currenty visible hexes.
1680  const rect_of_hexes& visible_hexes = get_visible_hexes();
1681 
1682  //
1683  // Background terrains
1684  //
1685  draw_visible_hexes(visible_hexes, BACKGROUND);
1686 
1687  //
1688  // On-map overlays, such as [item]s.
1689  //
1690  for(const auto& overlay_record : get_overlays()) {
1691  const map_location& o_loc = overlay_record.first;
1692 
1693  if(shrouded(o_loc)) {
1694  continue;
1695  }
1696 
1697  const overlay& item = overlay_record.second;
1698  const std::string& current_team_name = get_teams()[viewing_team()].team_name();
1699 
1700  if((item.team_name.empty() || item.team_name.find(current_team_name) != std::string::npos) &&
1701  (!fogged(o_loc) || item.visible_in_fog))
1702  {
1703  const texture tex = item.image.find("~NO_TOD_SHIFT()") == std::string::npos
1704  ? image::get_texture(item.image) // TODO
1705  : image::get_texture(item.image);
1706 
1707  // was: SCALED_TO_HEX
1708  render_scaled_to_zoom(tex, o_loc);
1709  }
1710  }
1711 
1712  //
1713  // Village flags
1714  //
1715  for(const team& t : get_teams()) {
1716  auto& flag = flags_[t.side() - 1];
1717  flag.update_last_draw_time();
1718 
1719  for(const map_location& v_loc : t.villages()) {
1720  if(!fogged(v_loc) || !dc_->get_team(viewing_side()).is_enemy(t.side())) {
1721 
1722  // TODO: move this if-animated check to a helper function.
1723  const image::locator& flag_image = animate_map_
1724  ? flag.get_current_frame()
1725  : flag.get_first_frame();
1726 
1727  render_scaled_to_zoom(image::get_texture(flag_image), v_loc);
1728  }
1729  }
1730  }
1731 
1732  //
1733  // The grid overlay, if that's been enabled
1734  //
1735  if(grid_) {
1736  for(const map_location& loc : visible_hexes) {
1737  if(shrouded(loc)) {
1738  continue;
1739  }
1740 
1741  // TODO: split into drawing layers? If not, combine into one image or texture.
1742  static const texture grid_top = image::get_texture(game_config::images::grid_top);
1743  render_scaled_to_zoom(grid_top, loc);
1744 
1745  static const texture grid_bottom = image::get_texture(game_config::images::grid_bottom);
1746  render_scaled_to_zoom(grid_bottom, loc);
1747  }
1748  }
1749 
1750  //
1751  // Real (standing) units
1752  //
1753  if(!get_teams().empty()) {
1754  unit_drawer drawer = unit_drawer(*this);
1755 
1756  for(const unit& real_unit : get_units()) {
1757  drawer.redraw_unit(real_unit);
1758  }
1759 
1760  // TODO: re-add exclusionary checks for exclusive_unit_draw_requests_ later on, if necessary.
1761 #if 0
1762  auto request = exclusive_unit_draw_requests_.find(loc);
1763  if(request == exclusive_unit_draw_requests_.end() || request->second == u_it->id()) {};
1764 #endif
1765  }
1766 
1767  //
1768  // Foreground terrains. FIXME! sometimes cut off units...
1769  //
1770  draw_visible_hexes(visible_hexes, FOREGROUND);
1771 
1772  //
1773  // Fake (moving) units
1774  //
1775  if(!get_teams().empty()) {
1776  unit_drawer drawer = unit_drawer(*this); // TODO: don't create this twice per cycle.
1777 
1778  for(const unit* temp_unit : *fake_unit_man_) {
1779  drawer.redraw_unit(*temp_unit);
1780  }
1781  }
1782 
1783  //
1784  // Draws various overlays, such as reach maps, etc.
1785  //
1786  draw_hex_overlays();
1787 
1788  //
1789  // Hex cursor (TODO: split into layers?)
1790  //
1791  draw_hex_cursor(mouseoverHex_);
1792 
1793  //
1794  // Shroud and fog
1795  //
1796  for(const map_location& loc : visible_hexes) {
1797  image::TYPE image_type = get_image_type(loc);
1798 
1799  const bool is_shrouded = shrouded(loc);
1800  const bool is_fogged = fogged(loc);
1801 
1802  // Main images.
1803  if(is_shrouded || is_fogged) {
1804 
1805  // If is_shrouded is false, is_fogged is true
1806  const std::string& weather_image = is_shrouded
1807  ? get_variant(shroud_images_, loc)
1808  : get_variant(fog_images_, loc);
1809 
1810  // TODO: image type
1811  render_scaled_to_zoom(image::get_texture(weather_image), loc);
1812  }
1813 
1814  // Transitions to main hexes.
1815  if(!is_shrouded) {
1816  draw_fog_shroud_transition_images(loc, image_type);
1817  }
1818  }
1819 
1820  // ================================================================================
1821  // TODO: RE-ADD ALL THIS!
1822  // ================================================================================
1823 
1824 #if 0
1825 
1826  //
1827  // Mouseover overlays (TODO: delegate to editor)
1828  //
1829  if(loc == mouseoverHex_ && (on_map || (in_editor() && get_map().on_board_with_border(loc)))
1830  && mouseover_hex_overlay_ != nullptr)
1831  {
1832  render_scaled_to_zoom(mouseover_hex_overlay_, xpos, ypos);
1833  }
1834 
1835  //
1836  // Arrows (whiteboard?) TODO:
1837  //
1838  auto arrows_in_hex = arrows_map_.find(loc);
1839  if(arrows_in_hex != arrows_map_.end()) {
1840  for(arrow* const a : arrows_in_hex->second) {
1841  a->draw_hex(loc);
1842  }
1843  }
1844 
1845  //
1846  // ToD Mask
1847  //
1848  // Draw the time-of-day mask on top of the terrain in the hex.
1849  // tod may differ from tod if hex is illuminated.
1850  const std::string& tod_hex_mask = tod.image_mask;
1851  if(tod_hex_mask1 != nullptr || tod_hex_mask2 != nullptr) {
1852  drawing_queue_add(drawing_queue::LAYER_TERRAIN_FG, loc, xpos, ypos, tod_hex_mask1);
1853  drawing_queue_add(drawing_queue::LAYER_TERRAIN_FG, loc, xpos, ypos, tod_hex_mask2);
1854  } else if(!tod_hex_mask.empty()) {
1855  drawing_queue_add(drawing_queue::LAYER_TERRAIN_FG, loc, xpos, ypos,
1856  image::get_image(tod_hex_mask,image::SCALED_TO_HEX));
1857  }
1858 
1859  //
1860  // Debugging output - coordinates, etc.
1861  //
1862  if(on_map) {
1863  if(draw_coordinates_) {
1864  int off_x = xpos + hex_size()/2;
1865  int off_y = ypos + hex_size()/2;
1866  surface text = font::get_rendered_text(lexical_cast<std::string>(loc), font::SIZE_SMALL, font::NORMAL_COLOR);
1867  surface bg = create_neutral_surface(text->w, text->h);
1868  SDL_Rect bg_rect {0, 0, text->w, text->h};
1869  sdl::fill_surface_rect(bg, &bg_rect, 0xaa000000);
1870  off_x -= text->w / 2;
1871  off_y -= text->h / 2;
1872  if (draw_terrain_codes_) {
1873  off_y -= text->h / 2;
1874  }
1875  if (draw_num_of_bitmaps_) {
1876  off_y -= text->h / 2;
1877  }
1878  drawing_queue_add(drawing_queue::LAYER_FOG_SHROUD, loc, off_x, off_y, bg);
1879  drawing_queue_add(drawing_queue::LAYER_FOG_SHROUD, loc, off_x, off_y, text);
1880  }
1881 
1882  if(draw_terrain_codes_ && (game_config::debug || !shrouded(loc))) {
1883  int off_x = xpos + hex_size()/2;
1884  int off_y = ypos + hex_size()/2;
1885  surface text = font::get_rendered_text(lexical_cast<std::string>(get_map().get_terrain(loc)), font::SIZE_SMALL, font::NORMAL_COLOR);
1886  surface bg = create_neutral_surface(text->w, text->h);
1887  SDL_Rect bg_rect {0, 0, text->w, text->h};
1888  sdl::fill_surface_rect(bg, &bg_rect, 0xaa000000);
1889  off_x -= text->w / 2;
1890  off_y -= text->h / 2;
1891  if (draw_coordinates_ && !draw_num_of_bitmaps_) {
1892  off_y += text->h / 2;
1893  } else if (draw_num_of_bitmaps_ && !draw_coordinates_) {
1894  off_y -= text->h / 2;
1895  }
1896  drawing_queue_add(drawing_queue::LAYER_FOG_SHROUD, loc, off_x, off_y, bg);
1897  drawing_queue_add(drawing_queue::LAYER_FOG_SHROUD, loc, off_x, off_y, text);
1898  }
1899 
1900  if(draw_num_of_bitmaps_) {
1901  int off_x = xpos + hex_size()/2;
1902  int off_y = ypos + hex_size()/2;
1903  surface text = font::get_rendered_text(lexical_cast<std::string>(num_images_bg + num_images_fg), font::SIZE_SMALL, font::NORMAL_COLOR);
1904  surface bg = create_neutral_surface(text->w, text->h);
1905  SDL_Rect bg_rect {0, 0, text->w, text->h};
1906  sdl::fill_surface_rect(bg, &bg_rect, 0xaa000000);
1907  off_x -= text->w / 2;
1908  off_y -= text->h / 2;
1909  if (draw_coordinates_) {
1910  off_y += text->h / 2;
1911  }
1912  if (draw_terrain_codes_) {
1913  off_y += text->h / 2;
1914  }
1915  drawing_queue_add(drawing_queue::LAYER_FOG_SHROUD, loc, off_x, off_y, bg);
1916  drawing_queue_add(drawing_queue::LAYER_FOG_SHROUD, loc, off_x, off_y, text);
1917  }
1918  }
1919 
1920  if(debug_foreground) {
1921  drawing_queue_add(drawing_queue::LAYER_UNIT_DEFAULT, loc, xpos, ypos,
1922  image::get_image("terrain/foreground.png", image_type));
1923  }
1924 #endif
1925 }
1926 
1927 void display::draw()
1928 {
1929  // Execute any pre-draw actions from derived classes.
1930  pre_draw();
1931 
1932  // Draw theme background.
1933  draw_background();
1934 
1935  // Progress animations.
1936  invalidate_animations();
1937 
1938  // Draw the gamemap and its contents (units, etc)
1939  {
1940  SDL_Rect map_area_rect = map_area();
1941  render_clip_rect_setter setter(&map_area_rect);
1942 
1943  draw_gamemap();
1944  }
1945 
1946  // Draw debugging aids such as the FPS counter.
1947  draw_debugging_aids();
1948 
1949  // Draw floating labels (includes map labels).
1950  font::draw_floating_labels();
1951 
1952  // TODO: what dis?
1953  // events::raise_volatile_draw_event();
1954  // events::raise_volatile_undraw_event();
1955 
1956  // Execute any post-draw actions from derived classes.
1957  post_draw();
1958 }
1959 
1960 void display::handle_window_event(const SDL_Event& event)
1961 {
1962  if(event.type == SDL_WINDOWEVENT) {
1963  switch(event.window.event) {
1964  case SDL_WINDOWEVENT_RESIZED:
1965  case SDL_WINDOWEVENT_RESTORED:
1966  case SDL_WINDOWEVENT_EXPOSED:
1967  // TODO: add additional handling here if needed.
1968  break;
1969  }
1970  }
1971 }
1972 
1973 void display::handle_event(const SDL_Event& /*event*/)
1974 {
1976  return;
1977  }
1978 }
1979 
1980 display* display::singleton_ = nullptr;
constexpr const T & clamp(const T &value, const T &min, const T &max)
Definition: general.hpp:31
TYPE
UNSCALED : image will be drawn "as is" without changing size, even in case of redraw SCALED_TO_ZOOM :...
Definition: image.hpp:181
int zoom_index_
Definition: display.hpp:865
void recalculate_shroud()
Definition: label.cpp:277
bool discard_previous
An announcement according these options should replace the previous announce (typical of fast announc...
Definition: display.hpp:629
bool is_odd(T num)
Definition: math.hpp:34
virtual void select_hex(map_location hex)
Definition: display.cpp:910
Arrows destined to be drawn on the map.
int h() const
Effective map height.
Definition: map.hpp:93
bool update_locked() const
Whether the screen has been &#39;locked&#39; or not.
Definition: video.cpp:292
void write(config &cfg) const
Definition: display.cpp:1489
virtual void draw_hex_overlays()
Draws various map overlays such as game reachmap.
Definition: display.cpp:1511
bool show_fps()
Definition: general.cpp:827
Small struct to store and manipulate ToD color adjusts.
Definition: time_of_day.hpp:28
void adjust_color_overlay(int r, int g, int b)
Add r,g,b to the colors for all images displayed on the map.
Definition: display.cpp:354
const arrow_path_t & get_path() const
Definition: arrow.cpp:116
#define DefaultZoom
Definition: display.cpp:63
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
Definition: location.cpp:517
void invalidate_animations()
Function to invalidate animated terrains and units which may have changed.
Definition: display.cpp:1427
#define ERR_DP
Definition: display.cpp:56
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
This class represents a single unit of a specific type.
Definition: unit.hpp:99
virtual void notify_observers()
tod_color color
The color modifications that should be made to the game board to reflect the time of day...
const std::string & get_variant(const std::vector< std::string > &variants, const map_location &loc) const
Definition: display.cpp:389
static void toggle_benchmark()
Toggle to continuously redraw the screen.
Definition: display.cpp:799
CKey keys_
Definition: display.hpp:902
void set_clip_rect(const SDL_Rect &r)
bool set_zoom(bool increase)
Zooms the display in (true) or out (false).
Definition: display.cpp:1013
void change_display_context(const display_context *dc)
Definition: display.cpp:405
const map_location hex_clicked_on(int x, int y) const
given x,y co-ordinates of an onscreen pixel, will return the location of the hex that this pixel corr...
Definition: display.cpp:490
boost::circular_buffer< unsigned > frametimes_
Definition: display.hpp:886
static help_manager manager
The help manager.
Definition: help.cpp:34
int ypos_
Definition: display.hpp:860
void draw_background()
Draws the background behind the gamemap.
Definition: display.cpp:858
void set_playing_team(std::size_t team)
set_playing_team sets the team whose turn it currently is
Definition: display.cpp:271
void set_default_zoom()
Sets the zoom amount to the default.
Definition: display.cpp:1079
void set_idle_anim_rate(int rate)
Definition: display.cpp:1402
const map_location pixel_position_to_hex(int x, int y) const
given x,y co-ordinates of a pixel on the map, will return the location of the hex that this pixel cor...
Definition: display.cpp:504
void scroll_floating_labels(double xmove, double ymove)
Moves all floating labels that have &#39;scroll_mode&#39; set to ANCHOR_LABEL_MAP.
const std::string & flag() const
Definition: team.hpp:298
Definition: video.hpp:36
map_location mouseoverHex_
Definition: display.hpp:901
void init_flags()
Initialize the flag list for all sides.
Definition: display.cpp:178
Manages a list of fake units for the display object.
std::string id
Definition: time_of_day.hpp:91
void lock_updates(bool value)
Stop the screen being redrawn.
Definition: video.cpp:283
const SDL_Rect & map_area() const
Returns the area used for the map.
Definition: display.cpp:449
int scroll_speed()
Definition: general.cpp:723
void remove_floating_label(int handle)
Removes the floating label given by &#39;handle&#39; from the screen.
static lg::log_domain log_display("display")
int fps_handle_
Handle for the label which displays frames per second.
Definition: display.hpp:940
bool show_everything() const
Definition: display.hpp:104
The class terrain_builder is constructed from a config object, and a gamemap object.
Definition: builder.hpp:45
map_location minimap_location_on(int x, int y)
given x,y co-ordinates of the mouse, will return the location of the hex in the minimap that the mous...
Definition: display.cpp:639
bool idle_anim()
Definition: general.cpp:457
void reset_halo_manager()
Definition: display.cpp:411
const SDL_Rect map_outside_area() const
Returns the available area for a map, this may differ from the above.
Definition: display.cpp:477
const unit_map & get_units() const
Definition: display.hpp:157
bool non_interactive() const
Definition: video.cpp:90
#define h
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
#define MaxZoom
Definition: display.cpp:66
map_location selectedHex_
Definition: display.hpp:900
void set_font_size(int font_size)
const std::vector< std::string > items
static display * singleton_
Definition: display.hpp:964
#define d
const int SIZE_PLUS
Definition: constants.cpp:26
-file sdl_utils.hpp
static unsigned int zoom_
Definition: display.hpp:864
surface create_neutral_surface(int w, int h)
Definition: utils.cpp:85
const SDL_Rect & minimap_area() const
mapx is the width of the portion of the display which shows the game area.
Definition: display.hpp:276
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.
void reset_standing_animations()
Definition: display.cpp:1451
void remove_arrow(arrow &)
Definition: display.cpp:1465
void add_frame(int duration, const T &value, bool force_change=false)
Adds a frame to an animation.
#define DBG_DP
Definition: display.cpp:58
Wrapper class to encapsulate creation and management of an SDL_Texture.
Definition: texture.hpp:26
const rect_of_hexes get_visible_hexes() const
Returns the rectangular area of visible hexes.
Definition: display.cpp:601
void draw_debugging_aids()
Definition: display.cpp:809
std::string id
Definition: overlay.hpp:40
bool team_valid() const
Definition: display.cpp:606
#define b
const int SIZE_XLARGE
Definition: constants.cpp:29
std::vector< std::string > shroud_images_
Definition: display.hpp:898
Object which defines a time of day with associated bonuses, image, sounds etc.
Definition: time_of_day.hpp:57
bool exists(const image::locator &i_locator)
returns true if the given image actually exists, without loading it.
Definition: image.cpp:1184
void blindfold(bool flag)
Definition: display.cpp:421
virtual const SDL_Rect get_clip_rect()
Get the clipping rectangle for drawing.
Definition: display.cpp:1417
const config & options()
Definition: game.cpp:569
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:44
virtual void draw() override final
Main drawing function.
Definition: display.cpp:1927
CVideo & video_
Definition: display.hpp:856
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
void set_alignment(ALIGN align)
const std::string & id() const
Gets this unit&#39;s id.
Definition: unit.hpp:305
const arrow_path_t & get_previous_path() const
Definition: arrow.cpp:121
double turbo_speed() const
Definition: display.cpp:1387
static bool zoom_at_max()
Definition: display.cpp:1003
bool null() const
Definition: texture.hpp:79
void new_animation_frame()
Definition: animated.cpp:30
static bool outside_area(const SDL_Rect &area, const int x, const int y)
Check if the bbox of the hex at x,y has pixels outside the area rectangle.
Definition: display.cpp:482
bool tile_fully_on_screen(const map_location &loc) const
Check if a tile is fully visible on screen.
Definition: display.cpp:1091
Arrows destined to be drawn on the map.
Definition: arrow.hpp:29
surface screenshot(bool map_screenshot=false)
Capture a (map-)screenshot into a surface.
Definition: display.cpp:662
std::array< int, 2 > bottom
Definition: hex_rect.hpp:48
std::string theme()
Definition: game.cpp:819
void set_lifetime(int lifetime)
Set the number of frames to display the text for, or -1 to display until removed. ...
Sets the renderer output target to the specified texture.
void recalculate_minimap()
Schedule the minimap for recalculation.
Definition: display.hpp:647
void scroll_to_xy(int screenxpos, int screenypos, SCROLL_TYPE scroll_type, bool force=true)
Definition: display.cpp:1107
bool valid() const
Definition: location.hpp:93
bool map_screenshot_
Used to indicate to drawing functions that we are doing a map screenshot.
Definition: display.hpp:919
arrows_map_t arrows_map_
Maps the list of arrows for each location.
Definition: display.hpp:959
virtual image::TYPE get_image_type(const map_location &loc)
Definition: display.cpp:1422
const std::unique_ptr< map_labels > map_labels_
Definition: display.hpp:875
int xpos_
Definition: display.hpp:860
void update_tod(const time_of_day *tod_override=nullptr)
Applies r,g,b coloring to the map.
Definition: display.cpp:343
std::string background_image
Definition: theme.hpp:86
SDL_Rect minimap_location_
Definition: display.hpp:869
double size
Definition: theme.hpp:84
void set_zoom(unsigned int amount)
sets the amount scaled images should be scaled.
Definition: image.cpp:842
TERRAIN_TYPE
Used as a parameter for the get_terrain_at function.
Definition: builder.hpp:49
tod_color color_adjust_
Definition: display.hpp:961
fake_unit_manager * fake_units
Definition: resources.cpp:30
Rectangular area of hexes.
Definition: hex_rect.hpp:33
void bounds_check_position()
Definition: display.cpp:1362
Modify, read and display user preferences.
#define MinZoom
Definition: display.cpp:65
void set_position(double xpos, double ypos)
Set the location on the screen to display the text.
void update_arrow(arrow &a)
Called by arrow objects when they change.
Definition: display.cpp:1472
map_display and display: classes which take care of displaying the map and game-data on the screen...
unsigned int fps_actual_
Definition: display.hpp:889
bool animate_map()
Definition: general.cpp:757
std::string shroud_prefix
Definition: game_config.cpp:70
std::array< map_location, 6 > adjacent_loc_array_t
Definition: location.hpp:170
const color_t YELLOW_COLOR
static const std::string & get_direction(std::size_t n)
Definition: display.cpp:711
const color_t NORMAL_COLOR
bool fogged(const map_location &loc) const
Returns true if location (x,y) is covered in fog.
Definition: display.cpp:616
bool point_in_rect(int x, int y, const SDL_Rect &rect)
Tests whether a point is inside a rectangle.
Definition: rect.cpp:22
static int hex_width()
Function which returns the width of a hex in pixels, up to where the next hex starts.
Definition: display.hpp:312
std::string flag_rgb
static unsigned int last_zoom_
Definition: display.hpp:866
void set_color_adjustment(int r, int g, int b)
will make all scaled images have these rgb values added to all their pixels.
Definition: image.cpp:828
std::unique_ptr< halo::manager > halo_man_
Definition: display.hpp:694
SDL_Rect rect
The coordinates of this image on the spritesheet.
int idle_anim_rate()
Definition: general.cpp:467
Encapsulates the map of the game.
Definition: location.hpp:42
void set_color(const color_t &color)
void set_team(const team *)
Definition: label.cpp:138
bool shrouded(const map_location &loc) const
Returns true if location (x,y) is covered in shroud.
Definition: display.cpp:611
void set_scroll_mode(LABEL_SCROLL_MODE scroll)
bool faked() const
Definition: video.hpp:65
const border_t & border() const
Definition: theme.hpp:275
void recalculate_labels()
Definition: label.cpp:244
int w() const
Effective map width.
Definition: map.hpp:90
virtual overlay_map & get_overlays()=0
std::size_t i
Definition: function.cpp:933
virtual const std::vector< team > & teams() const =0
bool is_blindfolded() const
Definition: display.cpp:430
void scroll_to_tile(const map_location &loc, SCROLL_TYPE scroll_type=ONSCREEN, bool check_fogged=true, bool force=true)
Scroll such that location loc is on-screen.
Definition: display.cpp:1197
void announce(const std::string &msg, const color_t &color=font::GOOD_COLOR, const announce_options &options=announce_options())
Announce a message prominently.
Definition: display.cpp:939
virtual void highlight_hex(map_location hex)
Definition: display.cpp:916
Holds options for calls to function &#39;announce&#39; (announce).
Definition: display.hpp:619
std::size_t activeTeam_
Definition: display.hpp:916
void set_diagnostic(const std::string &msg)
Definition: display.cpp:921
void scroll_to_tiles(map_location loc1, map_location loc2, SCROLL_TYPE scroll_type=ONSCREEN, bool check_fogged=true, double add_spacing=0.0, bool force=true)
Scroll such that location loc1 is on-screen.
Definition: display.cpp:1210
EXIT_STATUS start(const config &game_conf, const std::string &filename, bool take_screenshot, const std::string &screenshot_filename)
Main interface for launching the editor from the title screen.
Definition: editor_main.cpp:28
map_location get_middle_location() const
Definition: display.cpp:1483
static map_location::DIRECTION s
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
std::vector< std::string > names
Definition: build_info.cpp:53
virtual ~display()
Definition: display.cpp:167
double g
Definition: astarsearch.cpp:63
void read(const config &cfg)
Definition: display.cpp:1499
bool dont_show_all_
Definition: display.hpp:859
int get_location_y(const map_location &loc) const
Definition: display.cpp:626
std::basic_string< signed char > light_string
light_string store colors info of central and adjacent hexes.
Definition: image.hpp:146
void start_animation(int start_time, bool cycles=false)
Starts an animation cycle.
int add_floating_label(const floating_label &flabel)
Add a label floating on the screen above everything else.
bool tile_nearly_on_screen(const map_location &loc) const
Checks if location loc or one of the adjacent tiles is visible on screen.
Definition: display.cpp:1098
bool add_exclusive_draw(const map_location &loc, unit &unit)
Allows a unit to request to be the only one drawn in its hex.
Definition: display.cpp:315
Represents terrains which are to be drawn in front of them.
Definition: builder.hpp:54
static bool zoom_at_min()
Definition: display.cpp:1008
int w
double get_zoom_factor() const
Returns the current zoom factor.
Definition: display.hpp:327
theme theme_
Definition: display.hpp:863
const bool & debug
bool view_locked_
Definition: display.hpp:862
Definitions for the terrain builder.
Represents terrains which are to be drawn behind unit sprites.
Definition: builder.hpp:50
config & add_child(config_key_type key)
Definition: config.cpp:479
display(const display_context *dc, std::weak_ptr< wb::manager > wb, const config &theme_cfg, const config &level, bool auto_join=true)
Definition: display.cpp:86
std::vector< std::string > fog_images_
Definition: display.hpp:897
std::vector< animated< image::locator > > imagelist
A shorthand typedef for a list of animated image locators, the base data type returned by the get_ter...
Definition: builder.hpp:72
Handling of system events.
Definition: manager.hpp:41
void set_team(std::size_t team, bool observe=false)
Sets the team controlled by the player using the computer.
Definition: display.cpp:251
std::string halo
Definition: overlay.hpp:37
std::array< int, 2 > top
Definition: hex_rect.hpp:47
bool redrawMinimap_
Definition: display.hpp:870
void add_overlay(const map_location &loc, const std::string &image, const std::string &halo="", const std::string &team_name="", const std::string &item_id="", bool visible_under_fog=true)
Functions to add and remove overlays from locations.
Definition: display.cpp:277
Definition: display.hpp:44
const std::vector< team > & get_teams() const
Definition: display.hpp:114
int get_location_x(const map_location &loc) const
Functions to get the on-screen positions of hexes.
Definition: display.cpp:621
const gamemap & get_map() const
Definition: display.hpp:109
const std::string & color() const
Definition: team.hpp:254
exclusive_unit_draw_requests_t exclusive_unit_draw_requests_
map of hexes where only one unit should be drawn, the one identified by the associated id string ...
Definition: display.hpp:854
events::generic_event scroll_event_
Event raised when the map is being scrolled.
Definition: display.hpp:878
#define f
int lifetime
Lifetime measured in frames.
Definition: display.hpp:622
double t
Definition: astarsearch.cpp:63
void reload_map()
Updates internals that cache map size.
Definition: display.cpp:400
constexpr const SDL_Rect empty_rect
Definition: rect.hpp:31
unsigned int tile_size
Definition: game_config.cpp:67
const display_context * dc_
Definition: display.hpp:692
this module manages the cache of images.
Definition: image.cpp:102
double idle_anim_rate_
Definition: display.hpp:945
void fill_rectangle(const SDL_Rect &rect, const color_t &color)
Draws a filled rectangle.
Definition: rect.cpp:65
int drawn_hexes_
Count work done for the debug info displayed under fps.
Definition: display.hpp:942
Standard logging facilities (interface).
double turbo_speed_
Definition: display.hpp:873
int diagnostic_label_
Definition: display.hpp:872
void run_event_loop()
Definition: events.cpp:420
bool scroll_to_action()
Definition: general.cpp:365
map_labels & labels()
Definition: display.cpp:1407
static void fill_images_list(const std::string &prefix, std::vector< std::string > &images)
Definition: display.cpp:360
const std::unique_ptr< fake_unit_manager > fake_unit_man_
Definition: display.hpp:867
#define SmallZoom
Definition: display.cpp:64
#define final_zoom_index
Definition: display.cpp:62
std::vector< animated< image::locator > > flags_
Animated flags for each team.
Definition: display.hpp:912
void draw_visible_hexes(const rect_of_hexes &visible_hexes, TERRAIN_TYPE layer)
Draws the visible map hex terrains.
Definition: display.cpp:1516
const config & child_or_empty(config_key_type key) const
Returns the first child with the given key, or an empty config if there is none.
Definition: config.cpp:456
#define zoom_levels
Definition: display.cpp:61
int get_end_time() const
int side() const
Definition: team.hpp:187
virtual const time_of_day & get_time_of_day(const map_location &loc=map_location::null_location()) const
Definition: display.cpp:337
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
SDL_Point get_loc_drawing_origin(const map_location &loc) const
Wrapper to return the drawing origin for the specified location in screen coordinates.
Definition: display.cpp:631
void remove_single_overlay(const map_location &loc, const std::string &toDelete)
remove_single_overlay will remove a single overlay from a tile
Definition: display.cpp:299
SDL_Rect screen_area(bool as_pixels=true) const
Returns the current window renderer area, either in pixels or screen coordinates. ...
Definition: video.cpp:194
static map_location::DIRECTION n
std::shared_ptr< halo_record > handle
Definition: halo.hpp:31
SDL_Renderer * get_renderer()
Returns a pointer to the underlying window&#39;s renderer.
Definition: video.cpp:323
bool scroll(int xmov, int ymov, bool force=false)
Scrolls the display by xmov,ymov pixels.
Definition: display.cpp:955
bool turbo_
Definition: display.hpp:874
void add_arrow(arrow &)
Definition: display.cpp:1458
void remove_overlay(const map_location &loc)
remove_overlay will remove all overlays on a tile.
Definition: display.cpp:294
bool animate_map_
Local cache for preferences::animate_map, since it is constantly queried.
Definition: display.hpp:905
const SDL_Rect & max_map_area() const
Returns the maximum area used for the map regardless to resolution and view size. ...
Definition: display.cpp:435
static rng & default_instance()
Definition: random.cpp:73
#define LOG_DP
Definition: display.cpp:57
static void toggle_debug_foreground()
Toggle to debug foreground terrain.
Definition: display.cpp:804
const std::unique_ptr< terrain_builder > builder_
Definition: display.hpp:868
std::string fog_prefix
Definition: game_config.cpp:70
std::weak_ptr< wb::manager > wb_
Definition: display.hpp:696
Definition: display.hpp:49
void set_theme(config theme_cfg)
Definition: display.cpp:173
int blindfold_ctr_
Definition: display.hpp:688
TERRAIN_TYPE
Definition: display.hpp:732
texture get_texture(const image::locator &i_locator, TYPE type)
Definition: image.cpp:1483
void render_copy(const texture &txt, SDL_Rect *src_rect=nullptr, SDL_Rect *dst_rect=nullptr, const bool flip_h=false, const bool flip_v=false)
Definition: video.cpp:250
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.
std::string remove_exclusive_draw(const map_location &loc)
Cancels an exclusive draw request.
Definition: display.cpp:325
const color_t BAD_COLOR
int draw_text_in_hex(const map_location &loc, const std::string &text, std::size_t font_size, color_t color, int fl_label_id=0, double x_in_hex=0.5, double y_in_hex=0.5)
Adds a floating label with the specified text at the given location.
Definition: display.cpp:878
std::size_t currentTeam_
Definition: display.hpp:858
void rebuild_all()
Rebuild all dynamic terrain.
Definition: display.cpp:395
void write(config &cfg) const
Definition: location.cpp:210
void draw_fog_shroud_transition_images(const map_location &loc, image::TYPE image_type)
Draw the appropriate fog or shroud transition images for a specific hex.
Definition: display.cpp:717
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:557
std::string image
Definition: overlay.hpp:36