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