1 /*
2    Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
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 /**
16  * @file
17  *
18  * map_display and display: classes which take care of
19  * displaying the map and game-data on the screen.
20  *
21  * The display is divided into two main sections:
22  * - the game area, which displays the tiles of the game board, and units on them,
23  * - and the side bar, which appears on the right hand side.
24  * The side bar display is divided into three sections:
25  * - the minimap, which is displayed at the top right
26  * - the game status, which includes the day/night image,
27  *   the turn number, information about the current side,
28  *   and information about the hex currently moused over (highlighted)
29  * - the unit status, which displays an image and stats
30  *   for the current unit.
31  */
32 
33 #pragma once
34 
35 class config;
36 class fake_unit_manager;
37 class terrain_builder;
38 class map_labels;
39 class arrow;
40 class reports;
41 class team;
42 
43 namespace halo {
44 	class manager;
45 }
46 
47 namespace wb {
48 	class manager;
49 }
50 
51 #include "animated.hpp"
52 #include "display_context.hpp"
53 #include "font/standard_colors.hpp"
54 #include "picture.hpp" //only needed for enums (!)
55 #include "key.hpp"
56 #include "time_of_day.hpp"
57 #include "sdl/rect.hpp"
58 #include "sdl/surface.hpp"
59 #include "theme.hpp"
60 #include "video.hpp"
61 #include "widgets/button.hpp"
62 
63 #include "overlay.hpp"
64 
65 #include <boost/circular_buffer.hpp>
66 
67 #include "utils/functional.hpp"
68 #include <chrono>
69 #include <cstdint>
70 #include <deque>
71 #include <list>
72 #include <map>
73 #include <memory>
74 
75 class gamemap;
76 
77 class display : public video2::draw_layering
78 {
79 public:
80 	display(const display_context * dc, std::weak_ptr<wb::manager> wb,
81 			reports & reports_object,
82 			const config& theme_cfg, const config& level, bool auto_join=true);
83 	virtual ~display();
84 	/// Returns the display object if a display object exists. Otherwise it returns nullptr.
85 	/// the display object represents the game gui which handles themewml and drawing the map.
86 	/// A display object only exists during a game or while the mapeditor is running.
get_singleton()87 	static display* get_singleton() { return singleton_ ;}
88 
show_everything() const89 	bool show_everything() const { return !dont_show_all_ && !is_blindfolded(); }
90 
get_map() const91 	const gamemap& get_map() const { return dc_->map(); }
92 
get_teams() const93 	const std::vector<team>& get_teams() const {return dc_->teams();}
94 
95 	/** The playing team is the team whose turn it is. */
playing_team() const96 	size_t playing_team() const { return activeTeam_; }
97 
98 	bool team_valid() const;
99 
100 	/** The viewing team is the team currently viewing the game. */
viewing_team() const101 	size_t viewing_team() const { return currentTeam_; }
viewing_side() const102 	int viewing_side() const { return currentTeam_ + 1; }
103 
104 	/**
105 	 * Sets the team controlled by the player using the computer.
106 	 * Data from this team will be displayed in the game status.
107 	 */
108 	void set_team(size_t team, bool observe=false);
109 
110 	/**
111 	 * set_playing_team sets the team whose turn it currently is
112 	 */
113 	void set_playing_team(size_t team);
114 
115 
116 	/**
117 	 * Cancels all the exclusive draw requests.
118 	 */
clear_exclusive_draws()119 	void clear_exclusive_draws() { exclusive_unit_draw_requests_.clear(); }
get_units() const120 	const unit_map& get_units() const {return dc_->units();}
121 
122 	/**
123 	 * Allows a unit to request to be the only one drawn in its hex. Useful for situations where
124 	 * multiple units (one real, multiple temporary) can end up stacked, such as with the whiteboard.
125 	 * @param loc The location of the unit requesting exclusivity.
126 	 * @param unit The unit requesting exclusivity.
127 	 * @return false if there's already an exclusive draw request for this location.
128 	 */
129 	bool add_exclusive_draw(const map_location& loc, unit& unit);
130 	/**
131 	 * Cancels an exclusive draw request.
132 	 * @return The id of the unit whose exclusive draw request was canceled, or else
133 	 *         the empty string if there was no exclusive draw request for this location.
134 	 */
135 	std::string remove_exclusive_draw(const map_location& loc);
136 
137 	/**
138 	 * Check the overlay_map for proper team-specific overlays to be
139 	 * displayed/hidden
140 	 */
141 	void parse_team_overlays();
142 
143 	/**
144 	 * Functions to add and remove overlays from locations.
145 	 *
146 	 * An overlay is an image that is displayed on top of the tile.
147 	 * One tile may have multiple overlays.
148 	 */
149 	void add_overlay(const map_location& loc, const std::string& image,
150 		const std::string& halo="", const std::string& team_name="",const std::string& item_id="",
151 		bool visible_under_fog = true);
152 
153 	/** remove_overlay will remove all overlays on a tile. */
154 	void remove_overlay(const map_location& loc);
155 
156 	/** remove_single_overlay will remove a single overlay from a tile */
157 	void remove_single_overlay(const map_location& loc, const std::string& toDelete);
158 
159 	/**
160 	 * Updates internals that cache map size. This should be called when the map
161 	 * size has changed.
162 	 */
163 	void reload_map();
164 
165 	void change_display_context(const display_context* dc);
166 
get_disp_context() const167 	const display_context& get_disp_context() const
168 	{
169 		return *dc_;
170 	}
171 
172 	void reset_halo_manager();
173 	void reset_halo_manager(halo::manager & hm);
get_halo_manager()174 	halo::manager & get_halo_manager() { return *halo_man_; }
175 
176 	/**
177 	 * Applies r,g,b coloring to the map.
178 	 *
179 	 * The color is usually taken from @ref get_time_of_day unless @a tod_override is given, in which
180 	 * case that color is used.
181 	 *
182 	 * @param tod_override             The ToD to apply to the map instead of that of the current ToD's.
183 	 */
184 	void update_tod(const time_of_day* tod_override = nullptr);
185 
186 	/**
187 	 * Add r,g,b to the colors for all images displayed on the map.
188 	 *
189 	 * Used for special effects like flashes.
190 	 */
191 	void adjust_color_overlay(int r, int g, int b);
192 
193 
194 	/** Gets the underlying screen object. */
video()195 	CVideo& video() { return screen_; }
196 
197 	/** return the screen surface or the surface used for map_screenshot. */
get_screen_surface()198 	surface& get_screen_surface() { return map_screenshot_ ? map_screenshot_surf_ : screen_.getSurface();}
199 
in_game() const200 	virtual bool in_game() const { return false; }
in_editor() const201 	virtual bool in_editor() const { return false; }
202 
203 	/** Virtual functions shadowed in game_display. These are needed to generate reports easily, without dynamic casting. Hope to factor out eventually. */
displayed_unit_hex() const204 	virtual const map_location & displayed_unit_hex() const { return map_location::null_location(); }
playing_side() const205 	virtual int playing_side() const { return -100; } //In this case give an obviously wrong answer to fail fast, since this could actually cause a big bug. */
observers() const206 	virtual const std::set<std::string>& observers() const { static const std::set<std::string> fake_obs = std::set<std::string> (); return fake_obs; }
207 
208 	/**
209 	 * mapx is the width of the portion of the display which shows the game area.
210 	 * Between mapx and x is the sidebar region.
211 	 */
212 
minimap_area() const213 	const SDL_Rect& minimap_area() const
214 		{ return theme_.mini_map_location(screen_.screen_area()); }
palette_area() const215 	const SDL_Rect& palette_area() const
216 		{ return theme_.palette_location(screen_.screen_area()); }
unit_image_area() const217 	const SDL_Rect& unit_image_area() const
218 		{ return theme_.unit_image_location(screen_.screen_area()); }
219 
220 	/**
221 	 * Returns the maximum area used for the map
222 	 * regardless to resolution and view size
223 	 */
224 	const SDL_Rect& max_map_area() const;
225 
226 	/**
227 	 * Returns the area used for the map
228 	 */
229 	const SDL_Rect& map_area() const;
230 
231 	/**
232 	 * Returns the available area for a map, this may differ
233 	 * from the above. This area will get the background area
234 	 * applied to it.
235 	 */
map_outside_area() const236 	const SDL_Rect& map_outside_area() const { return map_screenshot_ ?
237 		max_map_area() : theme_.main_map_location(screen_.screen_area()); }
238 
239 	/** Check if the bbox of the hex at x,y has pixels outside the area rectangle. */
240 	static bool outside_area(const SDL_Rect& area, const int x,const int y);
241 
242 	/**
243 	 * Function which returns the width of a hex in pixels,
244 	 * up to where the next hex starts.
245 	 * (i.e. not entirely from tip to tip -- use hex_size()
246 	 * to get the distance from tip to tip)
247 	 */
hex_width()248 	static int hex_width() { return (zoom_*3)/4; }
249 
250 	/**
251 	 * Function which returns the size of a hex in pixels
252 	 * (from top tip to bottom tip or left edge to right edge).
253 	 */
hex_size()254 	static int hex_size(){ return zoom_; }
255 
256 	/** Returns the current zoom factor. */
get_zoom_factor()257 	static double get_zoom_factor()
258 	{
259 		return static_cast<double>(zoom_) / static_cast<double>(game_config::tile_size);
260 	}
261 
262 	/**
263 	 * given x,y co-ordinates of an onscreen pixel, will return the
264 	 * location of the hex that this pixel corresponds to.
265 	 * Returns an invalid location if the mouse isn't over any valid location.
266 	 */
267 	const map_location hex_clicked_on(int x, int y) const;
268 
269 	/**
270 	 * given x,y co-ordinates of a pixel on the map, will return the
271 	 * location of the hex that this pixel corresponds to.
272 	 * Returns an invalid location if the mouse isn't over any valid location.
273 	 */
274 	const map_location pixel_position_to_hex(int x, int y) const;
275 
276 	/**
277 	 * given x,y co-ordinates of the mouse, will return the location of the
278 	 * hex in the minimap that the mouse is currently over, or an invalid
279 	 * location if the mouse isn't over the minimap.
280 	 */
281 	map_location minimap_location_on(int x, int y);
282 
selected_hex() const283 	const map_location& selected_hex() const { return selectedHex_; }
mouseover_hex() const284 	const map_location& mouseover_hex() const { return mouseoverHex_; }
285 
286 	virtual void select_hex(map_location hex);
287 	virtual void highlight_hex(map_location hex);
288 
289 	/** Function to invalidate the game status displayed on the sidebar. */
invalidate_game_status()290 	void invalidate_game_status() { invalidateGameStatus_ = true; }
291 
292 	/** Functions to get the on-screen positions of hexes. */
293 	int get_location_x(const map_location& loc) const;
294 	int get_location_y(const map_location& loc) const;
295 
296 	/**
297 	 * Rectangular area of hexes, allowing to decide how the top and bottom
298 	 * edges handles the vertical shift for each parity of the x coordinate
299 	 */
300 	struct rect_of_hexes{
301 		int left;
302 		int right;
303 		int top[2]; // for even and odd values of x, respectively
304 		int bottom[2];
305 
306 		/**  very simple iterator to walk into the rect_of_hexes */
307 		struct iterator {
iteratordisplay::rect_of_hexes::iterator308 			iterator(const map_location &loc, const rect_of_hexes &rect)
309 				: loc_(loc), rect_(rect){}
310 
311 			/** increment y first, then when reaching bottom, increment x */
312 			iterator& operator++();
operator ==display::rect_of_hexes::iterator313 			bool operator==(const iterator &that) const { return that.loc_ == loc_; }
operator !=display::rect_of_hexes::iterator314 			bool operator!=(const iterator &that) const { return that.loc_ != loc_; }
operator *display::rect_of_hexes::iterator315 			const map_location& operator*() const {return loc_;}
316 
317 			typedef std::forward_iterator_tag iterator_category;
318 			typedef map_location value_type;
319 			typedef int difference_type;
320 			typedef const map_location *pointer;
321 			typedef const map_location &reference;
322 
323 			private:
324 				map_location loc_;
325 				const rect_of_hexes &rect_;
326 		};
327 		typedef iterator const_iterator;
328 
329 		iterator begin() const;
330 		iterator end() const;
331 	};
332 
333 	/** Return the rectangular area of hexes overlapped by r (r is in screen coordinates) */
334 	const rect_of_hexes hexes_under_rect(const SDL_Rect& r) const;
335 
336 	/** Returns the rectangular area of visible hexes */
get_visible_hexes() const337 	const rect_of_hexes get_visible_hexes() const {return hexes_under_rect(map_area());}
338 
339 	/** Returns true if location (x,y) is covered in shroud. */
340 	bool shrouded(const map_location& loc) const;
341 
342 	/** Returns true if location (x,y) is covered in fog. */
343 	bool fogged(const map_location& loc) const;
344 
345 	/**
346 	 * Determines whether a grid should be overlayed on the game board.
347 	 * (to more clearly show where hexes are)
348 	 */
set_grid(const bool grid)349 	void set_grid(const bool grid) { grid_ = grid; }
350 
351 	/** Getter for the x,y debug overlay on tiles */
get_draw_coordinates() const352 	bool get_draw_coordinates() const { return draw_coordinates_; }
353 	/** Setter for the x,y debug overlay on tiles */
set_draw_coordinates(bool value)354 	void set_draw_coordinates(bool value) { draw_coordinates_ = value; }
355 
356 	/** Getter for the terrain code debug overlay on tiles */
get_draw_terrain_codes() const357 	bool get_draw_terrain_codes() const { return draw_terrain_codes_; }
358 	/** Setter for the terrain code debug overlay on tiles */
set_draw_terrain_codes(bool value)359 	void set_draw_terrain_codes(bool value) { draw_terrain_codes_ = value; }
360 
361 	/** Getter for the number of bitmaps debug overlay on tiles */
get_draw_num_of_bitmaps() const362 	bool get_draw_num_of_bitmaps() const { return draw_num_of_bitmaps_; }
363 	/** Setter for the terrain code debug overlay on tiles */
set_draw_num_of_bitmaps(bool value)364 	void set_draw_num_of_bitmaps(bool value) { draw_num_of_bitmaps_ = value; }
365 
366 	/** Capture a (map-)screenshot into a surface. */
367 	surface screenshot(bool map_screenshot = false);
368 
369 	/** Invalidates entire screen, including all tiles and sidebar. Calls redraw observers. */
370 	void redraw_everything();
371 
372 	/** Adds a redraw observer, a function object to be called when redraw_everything is used */
373 	void add_redraw_observer(std::function<void(display&)> f);
374 
375 	/** Clear the redraw observers */
376 	void clear_redraw_observers();
377 
get_theme()378 	theme& get_theme() { return theme_; }
379 	void set_theme(config theme_cfg);
380 
381 	/**
382 	 * Retrieves a pointer to a theme UI button.
383 	 *
384 	 * @note The returned pointer may either be nullptr, meaning the button
385 	 *       isn't defined by the current theme, or point to a valid
386 	 *       gui::button object. However, the objects retrieved will be
387 	 *       destroyed and recreated by draw() method calls. Do *NOT* store
388 	 *       these pointers for longer than strictly necessary to
389 	 *       accomplish a specific task before the next screen refresh.
390 	 */
391 	std::shared_ptr<gui::button> find_action_button(const std::string& id);
392 	std::shared_ptr<gui::button> find_menu_button(const std::string& id);
393 
394 	static gui::button::TYPE string_to_button_type(std::string type);
395 	void create_buttons();
396 
397 	void layout_buttons();
398 
399 	void render_buttons();
400 
invalidate_theme()401 	void invalidate_theme() { panelsDrawn_ = false; }
402 
403 	void refresh_report(const std::string& report_name, const config * new_cfg=nullptr);
404 
405 	void draw_minimap_units();
406 
407 	/** Function to invalidate all tiles. */
408 	void invalidate_all();
409 
410 	/** Function to invalidate a specific tile for redrawing. */
411 	bool invalidate(const map_location& loc);
412 
413 	bool invalidate(const std::set<map_location>& locs);
414 
415 	/**
416 	 * If this set is partially invalidated, invalidate all its hexes.
417 	 * Returns if any new invalidation was needed
418 	 */
419 	bool propagate_invalidation(const std::set<map_location>& locs);
420 
421 	/** invalidate all hexes under the rectangle rect (in screen coordinates) */
422 	bool invalidate_locations_in_rect(const SDL_Rect& rect);
423 	bool invalidate_visible_locations_in_rect(const SDL_Rect& rect);
424 
425 	/**
426 	 * Function to invalidate animated terrains and units which may have changed.
427 	 */
428 	void invalidate_animations();
429 
430 	/**
431 	 * Per-location invalidation called by invalidate_animations()
432 	 * Extra game per-location invalidation (village ownership)
433 	 */
434 	void invalidate_animations_location(const map_location& loc);
435 
436 	void reset_standing_animations();
437 
438 	/**
439 	 * mouseover_hex_overlay_ require a prerendered surface
440 	 * and is drawn underneath the mouse's location
441 	 */
set_mouseover_hex_overlay(const surface & image)442 	void set_mouseover_hex_overlay(const surface& image)
443 		{ mouseover_hex_overlay_ = image; }
444 
clear_mouseover_hex_overlay()445 	void clear_mouseover_hex_overlay()
446 		{ mouseover_hex_overlay_ = nullptr; }
447 
448 	/** Toggle to continuously redraw the screen. */
449 	static void toggle_benchmark();
450 
451 	/**
452 	 * Toggle to debug foreground terrain.
453 	 * Separate background and foreground layer
454 	 * to better spot any error there.
455 	 */
456 	static void toggle_debug_foreground();
457 
get_builder()458 	terrain_builder& get_builder() {return *builder_;}
459 
460 	void flip();
461 
462 	/** Copy the backbuffer to the framebuffer. */
463 	void update_display();
464 
465 	/** Rebuild all dynamic terrain. */
466 	void rebuild_all();
467 
468 	const theme::action* action_pressed();
469 	const theme::menu*   menu_pressed();
470 
471 	/**
472 	 * Finds the menu which has a given item in it,
473 	 * and enables or disables it.
474 	 */
475 	void enable_menu(const std::string& item, bool enable);
476 
477 	void set_diagnostic(const std::string& msg);
478 
479 	/**
480 	 * Set/Get whether 'turbo' mode is on.
481 	 * When turbo mode is on, everything moves much faster.
482 	 */
set_turbo(const bool turbo)483 	void set_turbo(const bool turbo) { turbo_ = turbo; }
484 
485 	double turbo_speed() const;
486 
set_turbo_speed(const double speed)487 	void set_turbo_speed(const double speed) { turbo_speed_ = speed; }
488 
489 	/** control unit idle animations and their frequency */
set_idle_anim(bool ison)490 	void set_idle_anim(bool ison) { idle_anim_ = ison; }
idle_anim() const491 	bool idle_anim() const { return idle_anim_; }
492 	void set_idle_anim_rate(int rate);
idle_anim_rate() const493 	double idle_anim_rate() const { return idle_anim_rate_; }
494 
495 	void bounds_check_position();
496 	void bounds_check_position(int& xpos, int& ypos) const;
497 
498 	/**
499 	 * Scrolls the display by xmov,ymov pixels.
500 	 * Invalidation and redrawing will be scheduled.
501 	 * @return true if the map actually moved.
502 	 */
503 	bool scroll(int xmov, int ymov, bool force = false);
504 
505 	/** Zooms the display in (true) or out (false). */
506 	bool set_zoom(bool increase);
507 
508 	/** Sets the display zoom to the specified amount. */
509 	bool set_zoom(unsigned int amount, const bool validate_value_and_set_index = true);
510 
511 	static bool zoom_at_max();
512 	static bool zoom_at_min();
513 
514 	/** Sets the zoom amount to the default. */
515 	void set_default_zoom();
516 
view_locked() const517 	bool view_locked() const { return view_locked_; }
518 
519 	/** Sets whether the map view is locked (e.g. so the user can't scroll away) */
set_view_locked(bool value)520 	void set_view_locked(bool value) { view_locked_ = value; }
521 
522 	enum SCROLL_TYPE { SCROLL, WARP, ONSCREEN, ONSCREEN_WARP };
523 
524 	/**
525 	 * Scroll such that location loc is on-screen.
526 	 * WARP jumps to loc; SCROLL uses scroll speed;
527 	 * ONSCREEN only scrolls if x,y is offscreen
528 	 * force : scroll even if preferences tell us not to,
529 	 * or the view is locked.
530 	 */
531 	void scroll_to_tile(const map_location& loc, SCROLL_TYPE scroll_type=ONSCREEN, bool check_fogged=true,bool force = true);
532 
533 	/**
534 	 * Scroll such that location loc1 is on-screen.
535 	 * It will also try to make it such that loc2 is on-screen,
536 	 * but this is not guaranteed. For ONSCREEN scrolls add_spacing
537 	 * sets the desired minimum distance from the border in hexes.
538 	 */
539 	void scroll_to_tiles(map_location loc1, map_location loc2,
540 	                     SCROLL_TYPE scroll_type=ONSCREEN, bool check_fogged=true,
541 	                     double add_spacing=0.0, bool force=true);
542 
543 	/** Scroll to fit as many locations on-screen as possible, starting with the first. */
544 	void scroll_to_tiles(const std::vector<map_location>::const_iterator & begin,
545 	                     const std::vector<map_location>::const_iterator & end,
546 	                     SCROLL_TYPE scroll_type=ONSCREEN, bool check_fogged=true,
547 	                     bool only_if_possible=false, double add_spacing=0.0,
548 	                     bool force=true);
549 	/** Scroll to fit as many locations on-screen as possible, starting with the first. */
scroll_to_tiles(const std::vector<map_location> & locs,SCROLL_TYPE scroll_type=ONSCREEN,bool check_fogged=true,bool only_if_possible=false,double add_spacing=0.0,bool force=true)550 	void scroll_to_tiles(const std::vector<map_location>& locs,
551 	                     SCROLL_TYPE scroll_type=ONSCREEN, bool check_fogged=true,
552 	                     bool only_if_possible=false,
553 	                     double add_spacing=0.0, bool force=true)
554 	{
555 		scroll_to_tiles(locs.begin(), locs.end(), scroll_type, check_fogged,
556 		                only_if_possible, add_spacing, force);
557 	}
558 
559 	/** Expose the event, so observers can be notified about map scrolling. */
scroll_event() const560 	events::generic_event &scroll_event() const { return scroll_event_; }
561 
complete_redraw_event()562 	events::generic_event& complete_redraw_event() { return complete_redraw_event_; }
563 
564 	/** Check if a tile is fully visible on screen. */
565 	bool tile_fully_on_screen(const map_location& loc) const;
566 
567 	/** Checks if location @a loc or one of the adjacent tiles is visible on screen. */
568 	bool tile_nearly_on_screen(const map_location &loc) const;
569 
570 	/**
571 	 * Draws invalidated items.
572 	 * If update is true, will also copy the display to the frame buffer.
573 	 * If force is true, will not skip frames, even if running behind.
574 	 * Not virtual, since it gathers common actions. Calls various protected
575 	 * virtuals (further below) to allow specialized behavior in derived classes.
576 	 */
577 	virtual void draw();
578 
579 	void draw(bool update);
580 
581 	void draw(bool update, bool force);
582 
583 	map_labels& labels();
584 	const map_labels& labels() const;
585 
586 	/** Holds options for calls to function 'announce' (@ref announce). */
587 	struct announce_options
588 	{
589 		/** Lifetime measured in frames. */
590 		int lifetime;
591 
592 		/**
593 		 * An announcement according these options should replace the
594 		 * previous announce (typical of fast announcing) or not
595 		 * (typical of movement feedback).
596 		 */
597 		bool discard_previous;
598 
announce_optionsdisplay::announce_options599 		announce_options()
600 			: lifetime(100)
601 			, discard_previous(false)
602 		{
603 		}
604 	};
605 
606 	/** Announce a message prominently. */
607 	void announce(const std::string& msg,
608 	              const color_t& color = font::GOOD_COLOR,
609 	              const announce_options& options = announce_options());
610 
611 	/**
612 	 * Schedule the minimap for recalculation.
613 	 * Useful if any terrain in the map has changed.
614 	 */
recalculate_minimap()615 	void recalculate_minimap() {minimap_ = nullptr; redrawMinimap_ = true; }
616 
617 	/**
618 	 * Schedule the minimap to be redrawn.
619 	 * Useful if units have moved about on the map.
620 	 */
redraw_minimap()621 	void redraw_minimap() { redrawMinimap_ = true; }
622 
623 	virtual const time_of_day& get_time_of_day(const map_location& loc = map_location::null_location()) const;
624 
has_time_area() const625 	virtual bool has_time_area() const {return false;}
626 
627 	void blindfold(bool flag);
628 	bool is_blindfolded() const;
629 
630 	void write(config& cfg) const;
631 
632 	virtual void handle_event(const SDL_Event& );
633 	virtual void handle_window_event(const SDL_Event& event);
634 
635 private:
636 	void read(const config& cfg);
637 
638 public:
639 	/** Init the flag list and the team colors used by ~TC */
640 	void init_flags();
641 
642 	/** Rebuild the flag list (not team colors) for a single side. */
643 	void reinit_flags_for_side(size_t side);
reset_reports(reports & reports_object)644 	void reset_reports(reports& reports_object)
645 	{
646 		reports_object_ = &reports_object;
647 	}
648 private:
649 	void init_flags_for_side_internal(size_t side, const std::string& side_color);
650 
651 	int blindfold_ctr_;
652 
653 protected:
654 	//TODO sort
655 	const display_context * dc_;
656 	std::unique_ptr<halo::manager> halo_man_;
657 	std::weak_ptr<wb::manager> wb_;
658 
659 	typedef std::map<map_location, std::string> exclusive_unit_draw_requests_t;
660 	/// map of hexes where only one unit should be drawn, the one identified by the associated id string
661 	exclusive_unit_draw_requests_t exclusive_unit_draw_requests_;
662 
663 	map_location get_middle_location() const;
664 	/**
665 	 * Called near the beginning of each draw() call.
666 	 * Derived classes can use this to add extra actions before redrawing
667 	 * invalidated hexes takes place. No action here by default.
668 	 */
pre_draw()669 	virtual void pre_draw() {}
670 
671 	/**
672 	 * Called at the very end of each draw() call.
673 	 * Derived classes can use this to add extra actions after redrawing
674 	 * invalidated hexes takes place. No action here by default.
675 	 */
post_draw()676 	virtual void post_draw() {}
677 
678 	/**
679 	 * Get the clipping rectangle for drawing.
680 	 * Virtual since the editor might use a slightly different approach.
681 	 */
682 	virtual const SDL_Rect& get_clip_rect();
683 
684 	/**
685 	 * Only called when there's actual redrawing to do. Loops through
686 	 * invalidated locations and redraws them. Derived classes can override
687 	 * this, possibly to insert pre- or post-processing around a call to the
688 	 * base class's function.
689 	 */
690 	virtual void draw_invalidated();
691 
692 	/**
693 	 * Hook for actions to take right after draw() calls drawing_buffer_commit
694 	 * No action here by default.
695 	 */
post_commit()696 	virtual void post_commit() {}
697 
698 	/**
699 	 * Redraws a single gamemap location.
700 	 */
701 	virtual void draw_hex(const map_location& loc);
702 
703 	/**
704 	 * @returns the image type to be used for the passed hex
705 	 */
706 	virtual image::TYPE get_image_type(const map_location& loc);
707 
708 	/**
709 	 * Called near the end of a draw operation, derived classes can use this
710 	 * to render a specific sidebar. Very similar to post_commit.
711 	 */
draw_sidebar()712 	virtual void draw_sidebar() {}
713 
714 	void draw_minimap();
715 
716 	enum TERRAIN_TYPE { BACKGROUND, FOREGROUND};
717 
718 	void get_terrain_images(const map_location &loc,
719 					const std::string& timeid,
720 					TERRAIN_TYPE terrain_type);
721 
722 	std::vector<surface> get_fog_shroud_images(const map_location& loc, image::TYPE image_type);
723 
724 	void draw_image_for_report(surface& img, SDL_Rect& rect);
725 
726 	void scroll_to_xy(int screenxpos, int screenypos, SCROLL_TYPE scroll_type,bool force = true);
727 
728 	static void fill_images_list(const std::string& prefix, std::vector<std::string>& images);
729 
730 	static const std::string& get_variant(const std::vector<std::string>& variants, const map_location &loc);
731 
732 	CVideo& screen_;
733 	size_t currentTeam_;
734 	bool dont_show_all_; //const team *viewpoint_;
735 	/// Position of the top-left corner of the viewport, in pixels.
736 	///
737 	/// Dependent on zoom_.. For example, ypos_==72 only means we're one
738 	/// hex below the top of the map when zoom_ == 72 (the default value).
739 	int xpos_, ypos_;
740 	bool view_locked_;
741 	theme theme_;
742 	/// The current zoom, in pixels (on screen) per 72 pixels (in the
743 	/// graphic assets), i.e., 72 means 100%.
744 	static unsigned int zoom_;
745 	int zoom_index_;
746 	/// The previous value of zoom_.
747 	static unsigned int last_zoom_;
748 	const std::unique_ptr<fake_unit_manager> fake_unit_man_;
749 	const std::unique_ptr<terrain_builder> builder_;
750 	surface minimap_;
751 	SDL_Rect minimap_location_;
752 	bool redrawMinimap_;
753 	bool redraw_background_;
754 	bool invalidateAll_;
755 	bool grid_;
756 	int diagnostic_label_;
757 	bool panelsDrawn_;
758 	double turbo_speed_;
759 	bool turbo_;
760 	bool invalidateGameStatus_;
761 	const std::unique_ptr<map_labels> map_labels_;
762 	reports * reports_object_;
763 
764 	/** Event raised when the map is being scrolled */
765 	mutable events::generic_event scroll_event_;
766 
767 	/**
768 	 * notify observers that the screen has been redrawn completely
769 	 * atm this is used for replay_controller to add replay controls to the standard theme
770 	 */
771 	events::generic_event complete_redraw_event_;
772 
773 	boost::circular_buffer<unsigned> frametimes_; // in milliseconds
774 	unsigned int fps_counter_;
775 	std::chrono::seconds fps_start_;
776 	unsigned int fps_actual_;
777 	uint32_t last_frame_finished_ = 0u;
778 
779 	// Not set by the initializer:
780 	std::map<std::string, SDL_Rect> reportRects_;
781 	std::map<std::string, surface> reportSurfaces_;
782 	std::map<std::string, config> reports_;
783 	std::vector<std::shared_ptr<gui::button>> menu_buttons_, action_buttons_;
784 	std::set<map_location> invalidated_;
785 	surface mouseover_hex_overlay_;
786 	// If we're transitioning from one time of day to the next,
787 	// then we will use these two masks on top of all hexes when we blit.
788 	surface tod_hex_mask1, tod_hex_mask2;
789 	std::vector<std::string> fog_images_;
790 	std::vector<std::string> shroud_images_;
791 
792 	map_location selectedHex_;
793 	map_location mouseoverHex_;
794 	CKey keys_;
795 
796 	/** Local cache for preferences::animate_map, since it is constantly queried. */
797 	bool animate_map_;
798 
799 	/** Local version of preferences::animate_water, used to detect when it's changed. */
800 	bool animate_water_;
801 
802 private:
803 
804 	// This surface must be freed by the caller
805 	surface get_flag(const map_location& loc);
806 
807 	/** Animated flags for each team */
808 	std::vector<animated<image::locator>> flags_;
809 
810 	// This vector is a class member to avoid repeated memory allocations in get_terrain_images(),
811 	// which turned out to be a significant bottleneck while profiling.
812 	std::vector<surface> terrain_image_vector_;
813 
814 public:
815 	/**
816 	 * The layers to render something on. This value should never be stored
817 	 * it's the internal drawing order and adding removing and reordering
818 	 * the layers should be safe.
819 	 * If needed in WML use the name and map that to the enum value.
820 	 */
821 	enum drawing_layer {
822 		LAYER_TERRAIN_BG,          /**<
823 		                            * Layer for the terrain drawn behind the
824 		                            * unit.
825 		                            */
826 		LAYER_GRID_TOP,            /**< Top half part of grid image */
827 		LAYER_MOUSEOVER_OVERLAY,   /**< Mouseover overlay used by editor*/
828 		LAYER_FOOTSTEPS,           /**< Footsteps showing path from unit to mouse */
829 		LAYER_MOUSEOVER_TOP,       /**< Top half of image following the mouse */
830 		LAYER_UNIT_FIRST,          /**< Reserve layers to be selected for WML. */
831 		LAYER_UNIT_BG = LAYER_UNIT_FIRST+10,             /**< Used for the ellipse behind the unit. */
832 		LAYER_UNIT_DEFAULT=LAYER_UNIT_FIRST+40,/**<default layer for drawing units */
833 		LAYER_TERRAIN_FG = LAYER_UNIT_FIRST+50, /**<
834 		                            * Layer for the terrain drawn in front of
835 		                            * the unit.
836 		                            */
837 		LAYER_GRID_BOTTOM,         /**<
838 		                            * Used for the bottom half part of grid image.
839 		                            * Should be under moving units, to avoid masking south move.
840 		                            */
841 		LAYER_UNIT_MOVE_DEFAULT=LAYER_UNIT_FIRST+60/**<default layer for drawing moving units */,
842 		LAYER_UNIT_FG =  LAYER_UNIT_FIRST+80, /**<
843 		                            * Used for the ellipse in front of the
844 		                            * unit.
845 		                            */
846 		LAYER_UNIT_MISSILE_DEFAULT = LAYER_UNIT_FIRST+90, /**< default layer for missile frames*/
847 		LAYER_UNIT_LAST=LAYER_UNIT_FIRST+100,
848 		LAYER_REACHMAP,            /**< "black stripes" on unreachable hexes. */
849 		LAYER_MOUSEOVER_BOTTOM,    /**< Bottom half of image following the mouse */
850 		LAYER_FOG_SHROUD,          /**< Fog and shroud. */
851 		LAYER_ARROWS,              /**< Arrows from the arrows framework. Used for planned moves display. */
852 		LAYER_ACTIONS_NUMBERING,   /**< Move numbering for the whiteboard. */
853 		LAYER_SELECTED_HEX,        /**< Image on the selected unit */
854 		LAYER_ATTACK_INDICATOR,    /**< Layer which holds the attack indicator. */
855 		LAYER_UNIT_BAR,            /**<
856 		                            * Unit bars and overlays are drawn on this
857 		                            * layer (for testing here).
858 		                            */
859 		LAYER_MOVE_INFO,           /**< Movement info (defense%, etc...). */
860 		LAYER_LINGER_OVERLAY,      /**< The overlay used for the linger mode. */
861 		LAYER_BORDER,              /**< The border of the map. */
862 	};
863 
864 	/**
865 	 * Draw an image at a certain location.
866 	 * x,y: pixel location on screen to draw the image
867 	 * image: the image to draw
868 	 * reverse: if the image should be flipped across the x axis
869 	 * greyscale: used for instance to give the petrified appearance to a unit image
870 	 * alpha: the merging to use with the background
871 	 * blendto: blend to this color using blend_ratio
872 	 * submerged: the amount of the unit out of 1.0 that is submerged
873 	 *            (presumably under water) and thus shouldn't be drawn
874 	 */
875 	void render_image(int x, int y, const display::drawing_layer drawing_layer,
876 			const map_location& loc, surface image,
877 			bool hreverse=false, bool greyscale=false,
878 			fixed_t alpha=ftofxp(1.0), color_t blendto = {0,0,0},
879 			double blend_ratio=0, double submerged=0.0,bool vreverse =false);
880 
881 	/**
882 	 * Draw text on a hex. (0.5, 0.5) is the center.
883 	 * The font size is adjusted to the zoom factor.
884 	 */
885 	void draw_text_in_hex(const map_location& loc,
886 		const drawing_layer layer, const std::string& text, size_t font_size,
887 		color_t color, double x_in_hex=0.5, double y_in_hex=0.5);
888 
889 protected:
890 
891 	//TODO sort
892 	size_t activeTeam_;
893 
894 	/**
895 	 * In order to render a hex properly it needs to be rendered per row. On
896 	 * this row several layers need to be drawn at the same time. Mainly the
897 	 * unit and the background terrain. This is needed since both can spill
898 	 * in the next hex. The foreground terrain needs to be drawn before to
899 	 * avoid decapitation a unit.
900 	 *
901 	 * In other words:
902 	 * for every layer
903 	 *   for every row (starting from the top)
904 	 *     for every hex in the row
905 	 *       ...
906 	 *
907 	 * this is modified to:
908 	 * for every layer group
909 	 *   for every row (starting from the top)
910 	 *     for every layer in the group
911 	 *       for every hex in the row
912 	 *         ...
913 	 *
914 	 * * Surfaces are rendered per level in a map.
915 	 * * Per level the items are rendered per location these locations are
916 	 *   stored in the drawing order required for units.
917 	 * * every location has a vector with surfaces, each with its own screen
918 	 *   coordinate to render at.
919 	 * * every vector element has a vector with surfaces to render.
920 	 */
921 	class drawing_buffer_key
922 	{
923 	private:
924 		unsigned int key_;
925 
926 		static const std::array<drawing_layer, 4> layer_groups;
927 
928 	public:
929 		drawing_buffer_key(const map_location &loc, drawing_layer layer);
930 
operator <(const drawing_buffer_key & rhs) const931 		bool operator<(const drawing_buffer_key &rhs) const { return key_ < rhs.key_; }
932 	};
933 
934 	/** Helper structure for rendering the terrains. */
935 	class blit_helper
936 	{
937 	public:
938 		// We don't want to copy this.
939 		// It's expensive when done frequently due to the surface vector.
940 		blit_helper(const blit_helper&) = delete;
941 
blit_helper(const drawing_layer layer,const map_location & loc,const int x,const int y,const surface & surf,const SDL_Rect & clip)942 		blit_helper(const drawing_layer layer, const map_location& loc,
943 				const int x, const int y, const surface& surf,
944 				const SDL_Rect& clip)
945 			: x_(x), y_(y), surf_(1, surf), clip_(clip),
946 			key_(loc, layer)
947 		{}
948 
blit_helper(const drawing_layer layer,const map_location & loc,const int x,const int y,const std::vector<surface> & surf,const SDL_Rect & clip)949 		blit_helper(const drawing_layer layer, const map_location& loc,
950 				const int x, const int y, const std::vector<surface>& surf,
951 				const SDL_Rect& clip)
952 			: x_(x), y_(y), surf_(surf), clip_(clip),
953 			key_(loc, layer)
954 		{}
955 
x() const956 		int x() const { return x_; }
y() const957 		int y() const { return y_; }
surf() const958 		const std::vector<surface> &surf() const { return surf_; }
clip() const959 		const SDL_Rect &clip() const { return clip_; }
960 
operator <(const blit_helper & rhs) const961 		bool operator<(const blit_helper &rhs) const { return key_ < rhs.key_; }
962 
963 	private:
964 		int x_;                      /**< x screen coordinate to render at. */
965 		int y_;                      /**< y screen coordinate to render at. */
966 		std::vector<surface> surf_;  /**< surface(s) to render. */
967 		SDL_Rect clip_;              /**<
968 									  * The clipping area of the source if
969 									  * omitted the entire source is used.
970 									  */
971 		drawing_buffer_key key_;
972 	};
973 
974 	typedef std::list<blit_helper> drawing_buffer;
975 	drawing_buffer drawing_buffer_;
976 
977 public:
978 	/**
979 	 * Add an item to the drawing buffer. You need to update screen on affected area
980 	 *
981 	 * @param layer              The layer to draw on.
982 	 * @param loc                The hex the image belongs to, needed for the
983 	 *                           drawing order.
984 	 */
985 	void drawing_buffer_add(const drawing_layer layer,
986 			const map_location& loc, int x, int y, const surface& surf,
987 			const SDL_Rect &clip = SDL_Rect());
988 
989 	void drawing_buffer_add(const drawing_layer layer,
990 			const map_location& loc, int x, int y,
991 			const std::vector<surface> &surf,
992 			const SDL_Rect &clip = SDL_Rect());
993 
994 protected:
995 
996 	/** Draws the drawing_buffer_ and clears it. */
997 	void drawing_buffer_commit();
998 
999 	/** Clears the drawing buffer. */
1000 	void drawing_buffer_clear();
1001 
1002 	/** redraw all panels associated with the map display */
1003 	void draw_all_panels();
1004 
1005 
1006 	/**
1007 	 * Initiate a redraw.
1008 	 *
1009 	 * Invalidate controls and panels when changed after they have been drawn
1010 	 * initially. Useful for dynamic theme modification.
1011 	 */
1012 	void draw_init();
1013 	void draw_wrap(bool update,bool force);
1014 
1015 	/** Used to indicate to drawing functions that we are doing a map screenshot */
1016 	bool map_screenshot_;
1017 
1018 public: //operations for the arrow framework
1019 
1020 	void add_arrow(arrow&);
1021 
1022 	void remove_arrow(arrow&);
1023 
1024 	/** Called by arrow objects when they change. You should not need to call this directly. */
1025 	void update_arrow(arrow & a);
1026 
1027 protected:
1028 
1029 	// Tiles lit for showing where unit(s) can reach
1030 	typedef std::map<map_location,unsigned int> reach_map;
1031 	reach_map reach_map_;
1032 	reach_map reach_map_old_;
1033 	bool reach_map_changed_;
1034 	void process_reachmap_changes();
1035 
1036 	typedef std::multimap<map_location, overlay> overlay_map;
1037 
1038 private:
1039 
1040 
1041 	overlay_map* overlays_;
1042 
1043 	/** Handle for the label which displays frames per second. */
1044 	int fps_handle_;
1045 	/** Count work done for the debug info displayed under fps */
1046 	int invalidated_hexes_;
1047 	int drawn_hexes_;
1048 
1049 	bool idle_anim_;
1050 	double idle_anim_rate_;
1051 
1052 	surface map_screenshot_surf_;
1053 
1054 	std::vector<std::function<void(display&)>> redraw_observers_;
1055 
1056 	/** Debug flag - overlay x,y coords on tiles */
1057 	bool draw_coordinates_;
1058 	/** Debug flag - overlay terrain codes on tiles */
1059 	bool draw_terrain_codes_;
1060 	/** Debug flag - overlay number of bitmaps on tiles */
1061 	bool draw_num_of_bitmaps_;
1062 
1063 	typedef std::list<arrow*> arrows_list_t;
1064 	typedef std::map<map_location, arrows_list_t > arrows_map_t;
1065 	/** Maps the list of arrows for each location */
1066 	arrows_map_t arrows_map_;
1067 
1068 	tod_color color_adjust_;
1069 
1070 	bool dirty_;
1071 
1072 public:
replace_overlay_map(overlay_map * overlays)1073 	void replace_overlay_map(overlay_map* overlays) { overlays_ = overlays; }
1074 
1075 protected:
1076 	static display * singleton_;
1077 };
1078 
1079 struct blindfold
1080 {
blindfoldblindfold1081 	blindfold(display& d, bool lock=true) : display_(d), blind(lock) {
1082 		if(blind) {
1083 			display_.blindfold(true);
1084 		}
1085 	}
1086 
~blindfoldblindfold1087 	~blindfold() {
1088 		unblind();
1089 	}
1090 
unblindblindfold1091 	void unblind() {
1092 		if(blind) {
1093 			display_.blindfold(false);
1094 			blind = false;
1095 		}
1096 	}
1097 
1098 private:
1099 	display& display_;
1100 	bool blind;
1101 };
1102