wesnoth/src/display.hpp

1090 lines
36 KiB
C++

/*
Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file
*
* map_display and display: classes which take care of
* displaying the map and game-data on the screen.
*
* The display is divided into two main sections:
* - the game area, which displays the tiles of the game board, and units on them,
* - and the side bar, which appears on the right hand side.
* The side bar display is divided into three sections:
* - the minimap, which is displayed at the top right
* - the game status, which includes the day/night image,
* the turn number, information about the current side,
* and information about the hex currently moused over (highlighted)
* - the unit status, which displays an image and stats
* for the current unit.
*/
#pragma once
class config;
class fake_unit_manager;
class terrain_builder;
class map_labels;
class arrow;
class reports;
class team;
struct overlay;
namespace halo {
class manager;
}
namespace wb {
class manager;
}
#include "animated.hpp"
#include "display_context.hpp"
#include "font/standard_colors.hpp"
#include "game_config.hpp"
#include "picture.hpp" //only needed for enums (!)
#include "key.hpp"
#include "time_of_day.hpp"
#include "sdl/rect.hpp"
#include "sdl/surface.hpp"
#include "theme.hpp"
#include "video.hpp"
#include "widgets/button.hpp"
#include <boost/circular_buffer.hpp>
#include "utils/functional.hpp"
#include <chrono>
#include <cstdint>
#include <deque>
#include <list>
#include <map>
#include <memory>
#include <vector>
class gamemap;
class display : public video2::draw_layering
{
public:
display(const display_context * dc, std::weak_ptr<wb::manager> wb,
reports & reports_object,
const config& theme_cfg, const config& level, bool auto_join=true);
virtual ~display();
/// Returns the display object if a display object exists. Otherwise it returns nullptr.
/// the display object represents the game gui which handles themewml and drawing the map.
/// A display object only exists during a game or while the mapeditor is running.
static display* get_singleton() { return singleton_ ;}
bool show_everything() const { return !dont_show_all_ && !is_blindfolded(); }
const gamemap& get_map() const { return dc_->map(); }
const std::vector<team>& get_teams() const {return dc_->teams();}
/** The playing team is the team whose turn it is. */
std::size_t playing_team() const { return activeTeam_; }
bool team_valid() const;
/** The viewing team is the team currently viewing the game. */
std::size_t viewing_team() const { return currentTeam_; }
int viewing_side() const { return currentTeam_ + 1; }
/**
* Sets the team controlled by the player using the computer.
* Data from this team will be displayed in the game status.
*/
void set_team(std::size_t team, bool observe=false);
/**
* set_playing_team sets the team whose turn it currently is
*/
void set_playing_team(std::size_t team);
/**
* Cancels all the exclusive draw requests.
*/
void clear_exclusive_draws() { exclusive_unit_draw_requests_.clear(); }
const unit_map& get_units() const {return dc_->units();}
/**
* Allows a unit to request to be the only one drawn in its hex. Useful for situations where
* multiple units (one real, multiple temporary) can end up stacked, such as with the whiteboard.
* @param loc The location of the unit requesting exclusivity.
* @param unit The unit requesting exclusivity.
* @return false if there's already an exclusive draw request for this location.
*/
bool add_exclusive_draw(const map_location& loc, unit& unit);
/**
* Cancels an exclusive draw request.
* @return The id of the unit whose exclusive draw request was canceled, or else
* the empty string if there was no exclusive draw request for this location.
*/
std::string remove_exclusive_draw(const map_location& loc);
/**
* Check the overlay_map for proper team-specific overlays to be
* displayed/hidden
*/
void parse_team_overlays();
/**
* Functions to add and remove overlays from locations.
*
* An overlay is an image that is displayed on top of the tile.
* One tile may have multiple overlays.
*/
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, float z_order = 0);
/** remove_overlay will remove all overlays on a tile. */
void remove_overlay(const map_location& loc);
/** remove_single_overlay will remove a single overlay from a tile */
void remove_single_overlay(const map_location& loc, const std::string& toDelete);
/**
* Updates internals that cache map size. This should be called when the map
* size has changed.
*/
void reload_map();
void change_display_context(const display_context* dc);
const display_context& get_disp_context() const
{
return *dc_;
}
void reset_halo_manager();
void reset_halo_manager(halo::manager & hm);
halo::manager & get_halo_manager() { return *halo_man_; }
/**
* Applies r,g,b coloring to the map.
*
* The color is usually taken from @ref get_time_of_day unless @a tod_override is given, in which
* case that color is used.
*
* @param tod_override The ToD to apply to the map instead of that of the current ToD's.
*/
void update_tod(const time_of_day* tod_override = nullptr);
/**
* Add r,g,b to the colors for all images displayed on the map.
*
* Used for special effects like flashes.
*/
void adjust_color_overlay(int r, int g, int b);
/** Gets the underlying screen object. */
CVideo& video() { return screen_; }
/** return the screen surface or the surface used for map_screenshot. */
surface& get_screen_surface() { return map_screenshot_ ? map_screenshot_surf_ : screen_.getSurface();}
virtual bool in_game() const { return false; }
virtual bool in_editor() const { return false; }
/** Virtual functions shadowed in game_display. These are needed to generate reports easily, without dynamic casting. Hope to factor out eventually. */
virtual const map_location & displayed_unit_hex() const { return map_location::null_location(); }
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. */
virtual const std::set<std::string>& observers() const { static const std::set<std::string> fake_obs = std::set<std::string> (); return fake_obs; }
/**
* mapx is the width of the portion of the display which shows the game area.
* Between mapx and x is the sidebar region.
*/
const SDL_Rect& minimap_area() const
{ return theme_.mini_map_location(screen_.screen_area()); }
const SDL_Rect& palette_area() const
{ return theme_.palette_location(screen_.screen_area()); }
const SDL_Rect& unit_image_area() const
{ return theme_.unit_image_location(screen_.screen_area()); }
/**
* Returns the maximum area used for the map
* regardless to resolution and view size
*/
const SDL_Rect& max_map_area() const;
/**
* Returns the area used for the map
*/
const SDL_Rect& map_area() const;
/**
* Returns the available area for a map, this may differ
* from the above. This area will get the background area
* applied to it.
*/
const SDL_Rect& map_outside_area() const { return map_screenshot_ ?
max_map_area() : theme_.main_map_location(screen_.screen_area()); }
/** Check if the bbox of the hex at x,y has pixels outside the area rectangle. */
static bool outside_area(const SDL_Rect& area, const int x,const int y);
/**
* Function which returns the width of a hex in pixels,
* up to where the next hex starts.
* (i.e. not entirely from tip to tip -- use hex_size()
* to get the distance from tip to tip)
*/
static int hex_width() { return (zoom_*3)/4; }
/**
* Function which returns the size of a hex in pixels
* (from top tip to bottom tip or left edge to right edge).
*/
static int hex_size(){ return zoom_; }
/** Returns the current zoom factor. */
static double get_zoom_factor()
{
return static_cast<double>(zoom_) / static_cast<double>(game_config::tile_size);
}
/**
* given x,y co-ordinates of an onscreen pixel, will return the
* location of the hex that this pixel corresponds to.
* Returns an invalid location if the mouse isn't over any valid location.
*/
const map_location hex_clicked_on(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 corresponds to.
* Returns an invalid location if the mouse isn't over any valid location.
*/
const map_location pixel_position_to_hex(int x, int y) const;
/**
* given x,y co-ordinates of the mouse, will return the location of the
* hex in the minimap that the mouse is currently over, or an invalid
* location if the mouse isn't over the minimap.
*/
map_location minimap_location_on(int x, int y);
const map_location& selected_hex() const { return selectedHex_; }
const map_location& mouseover_hex() const { return mouseoverHex_; }
virtual void select_hex(map_location hex);
virtual void highlight_hex(map_location hex);
/** Function to invalidate the game status displayed on the sidebar. */
void invalidate_game_status() { invalidateGameStatus_ = true; }
/** Functions to get the on-screen positions of hexes. */
int get_location_x(const map_location& loc) const;
int get_location_y(const map_location& loc) const;
/**
* Rectangular area of hexes, allowing to decide how the top and bottom
* edges handles the vertical shift for each parity of the x coordinate
*/
struct rect_of_hexes{
int left;
int right;
int top[2]; // for even and odd values of x, respectively
int bottom[2];
/** very simple iterator to walk into the rect_of_hexes */
struct iterator {
iterator(const map_location &loc, const rect_of_hexes &rect)
: loc_(loc), rect_(rect){}
/** increment y first, then when reaching bottom, increment x */
iterator& operator++();
bool operator==(const iterator &that) const { return that.loc_ == loc_; }
bool operator!=(const iterator &that) const { return that.loc_ != loc_; }
const map_location& operator*() const {return loc_;}
typedef std::forward_iterator_tag iterator_category;
typedef map_location value_type;
typedef int difference_type;
typedef const map_location *pointer;
typedef const map_location &reference;
private:
map_location loc_;
const rect_of_hexes &rect_;
};
typedef iterator const_iterator;
iterator begin() const;
iterator end() const;
};
/** Return the rectangular area of hexes overlapped by r (r is in screen coordinates) */
const rect_of_hexes hexes_under_rect(const SDL_Rect& r) const;
/** Returns the rectangular area of visible hexes */
const rect_of_hexes get_visible_hexes() const {return hexes_under_rect(map_area());}
/** Returns true if location (x,y) is covered in shroud. */
bool shrouded(const map_location& loc) const;
/** Returns true if location (x,y) is covered in fog. */
bool fogged(const map_location& loc) const;
/**
* Determines whether a grid should be overlayed on the game board.
* (to more clearly show where hexes are)
*/
void set_grid(const bool grid) { grid_ = grid; }
/** Getter for the x,y debug overlay on tiles */
bool get_draw_coordinates() const { return draw_coordinates_; }
/** Setter for the x,y debug overlay on tiles */
void set_draw_coordinates(bool value) { draw_coordinates_ = value; }
/** Getter for the terrain code debug overlay on tiles */
bool get_draw_terrain_codes() const { return draw_terrain_codes_; }
/** Setter for the terrain code debug overlay on tiles */
void set_draw_terrain_codes(bool value) { draw_terrain_codes_ = value; }
/** Getter for the number of bitmaps debug overlay on tiles */
bool get_draw_num_of_bitmaps() const { return draw_num_of_bitmaps_; }
/** Setter for the terrain code debug overlay on tiles */
void set_draw_num_of_bitmaps(bool value) { draw_num_of_bitmaps_ = value; }
/** Capture a (map-)screenshot into a surface. */
surface screenshot(bool map_screenshot = false);
/** Invalidates entire screen, including all tiles and sidebar. Calls redraw observers. */
void redraw_everything();
/** Adds a redraw observer, a function object to be called when redraw_everything is used */
void add_redraw_observer(std::function<void(display&)> f);
/** Clear the redraw observers */
void clear_redraw_observers();
theme& get_theme() { return theme_; }
void set_theme(config theme_cfg);
/**
* Retrieves a pointer to a theme UI button.
*
* @note The returned pointer may either be nullptr, meaning the button
* isn't defined by the current theme, or point to a valid
* gui::button object. However, the objects retrieved will be
* destroyed and recreated by draw() method calls. Do *NOT* store
* these pointers for longer than strictly necessary to
* accomplish a specific task before the next screen refresh.
*/
std::shared_ptr<gui::button> find_action_button(const std::string& id);
std::shared_ptr<gui::button> find_menu_button(const std::string& id);
static gui::button::TYPE string_to_button_type(const std::string& type);
void create_buttons();
void layout_buttons();
void render_buttons();
void invalidate_theme() { panelsDrawn_ = false; }
void refresh_report(const std::string& report_name, const config * new_cfg=nullptr);
void draw_minimap_units();
/** Function to invalidate all tiles. */
void invalidate_all();
/** Function to invalidate a specific tile for redrawing. */
bool invalidate(const map_location& loc);
bool invalidate(const std::set<map_location>& locs);
/**
* If this set is partially invalidated, invalidate all its hexes.
* Returns if any new invalidation was needed
*/
bool propagate_invalidation(const std::set<map_location>& locs);
/** invalidate all hexes under the rectangle rect (in screen coordinates) */
bool invalidate_locations_in_rect(const SDL_Rect& rect);
bool invalidate_visible_locations_in_rect(const SDL_Rect& rect);
/**
* Function to invalidate animated terrains and units which may have changed.
*/
void invalidate_animations();
/**
* Per-location invalidation called by invalidate_animations()
* Extra game per-location invalidation (village ownership)
*/
void invalidate_animations_location(const map_location& loc);
void reset_standing_animations();
/**
* mouseover_hex_overlay_ require a prerendered surface
* and is drawn underneath the mouse's location
*/
void set_mouseover_hex_overlay(const surface& image)
{ mouseover_hex_overlay_ = image; }
void clear_mouseover_hex_overlay()
{ mouseover_hex_overlay_ = nullptr; }
/** Toggle to continuously redraw the screen. */
static void toggle_benchmark();
/**
* Toggle to debug foreground terrain.
* Separate background and foreground layer
* to better spot any error there.
*/
static void toggle_debug_foreground();
terrain_builder& get_builder() {return *builder_;}
void flip();
/** Copy the backbuffer to the framebuffer. */
void update_display();
/** Rebuild all dynamic terrain. */
void rebuild_all();
const theme::action* action_pressed();
const theme::menu* menu_pressed();
/**
* Finds the menu which has a given item in it,
* and enables or disables it.
*/
void enable_menu(const std::string& item, bool enable);
void set_diagnostic(const std::string& msg);
/**
* Set/Get whether 'turbo' mode is on.
* When turbo mode is on, everything moves much faster.
*/
void set_turbo(const bool turbo) { turbo_ = turbo; }
double turbo_speed() const;
void set_turbo_speed(const double speed) { turbo_speed_ = speed; }
/** control unit idle animations and their frequency */
void set_idle_anim(bool ison) { idle_anim_ = ison; }
bool idle_anim() const { return idle_anim_; }
void set_idle_anim_rate(int rate);
double idle_anim_rate() const { return idle_anim_rate_; }
void bounds_check_position();
void bounds_check_position(int& xpos, int& ypos) const;
/**
* Scrolls the display by xmov,ymov pixels.
* Invalidation and redrawing will be scheduled.
* @return true if the map actually moved.
*/
bool scroll(int xmov, int ymov, bool force = false);
/** Zooms the display in (true) or out (false). */
bool set_zoom(bool increase);
/** Sets the display zoom to the specified amount. */
bool set_zoom(unsigned int amount, const bool validate_value_and_set_index = true);
static bool zoom_at_max();
static bool zoom_at_min();
/** Sets the zoom amount to the default. */
void set_default_zoom();
bool view_locked() const { return view_locked_; }
/** Sets whether the map view is locked (e.g. so the user can't scroll away) */
void set_view_locked(bool value) { view_locked_ = value; }
enum SCROLL_TYPE { SCROLL, WARP, ONSCREEN, ONSCREEN_WARP };
/**
* Scroll such that location loc is on-screen.
* WARP jumps to loc; SCROLL uses scroll speed;
* ONSCREEN only scrolls if x,y is offscreen
* force : scroll even if preferences tell us not to,
* or the view is locked.
*/
void scroll_to_tile(const map_location& loc, SCROLL_TYPE scroll_type=ONSCREEN, bool check_fogged=true,bool force = true);
/**
* Scroll such that location loc1 is on-screen.
* It will also try to make it such that loc2 is on-screen,
* but this is not guaranteed. For ONSCREEN scrolls add_spacing
* sets the desired minimum distance from the border in hexes.
*/
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 to fit as many locations on-screen as possible, starting with the first. */
void scroll_to_tiles(const std::vector<map_location>::const_iterator & begin,
const std::vector<map_location>::const_iterator & end,
SCROLL_TYPE scroll_type=ONSCREEN, bool check_fogged=true,
bool only_if_possible=false, double add_spacing=0.0,
bool force=true);
/** Scroll to fit as many locations on-screen as possible, starting with the first. */
void 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)
{
scroll_to_tiles(locs.begin(), locs.end(), scroll_type, check_fogged,
only_if_possible, add_spacing, force);
}
/** Expose the event, so observers can be notified about map scrolling. */
events::generic_event &scroll_event() const { return scroll_event_; }
events::generic_event& complete_redraw_event() { return complete_redraw_event_; }
/** Check if a tile is fully visible on screen. */
bool tile_fully_on_screen(const map_location& loc) const;
/** Checks if location @a loc or one of the adjacent tiles is visible on screen. */
bool tile_nearly_on_screen(const map_location &loc) const;
/**
* Draws invalidated items.
* If update is true, will also copy the display to the frame buffer.
* If force is true, will not skip frames, even if running behind.
* Not virtual, since it gathers common actions. Calls various protected
* virtuals (further below) to allow specialized behavior in derived classes.
*/
virtual void draw();
void draw(bool update);
void draw(bool update, bool force);
map_labels& labels();
const map_labels& labels() const;
/** Holds options for calls to function 'announce' (@ref announce). */
struct announce_options
{
/** Lifetime measured in frames. */
int lifetime;
/**
* An announcement according these options should replace the
* previous announce (typical of fast announcing) or not
* (typical of movement feedback).
*/
bool discard_previous;
announce_options()
: lifetime(100)
, discard_previous(false)
{
}
};
/** Announce a message prominently. */
void announce(const std::string& msg,
const color_t& color = font::GOOD_COLOR,
const announce_options& options = announce_options());
/**
* Schedule the minimap for recalculation.
* Useful if any terrain in the map has changed.
*/
void recalculate_minimap() {minimap_ = nullptr; redrawMinimap_ = true; }
/**
* Schedule the minimap to be redrawn.
* Useful if units have moved about on the map.
*/
void redraw_minimap() { redrawMinimap_ = true; }
virtual const time_of_day& get_time_of_day(const map_location& loc = map_location::null_location()) const;
virtual bool has_time_area() const {return false;}
void blindfold(bool flag);
bool is_blindfolded() const;
void write(config& cfg) const;
virtual void handle_event(const SDL_Event& );
virtual void handle_window_event(const SDL_Event& event);
private:
void read(const config& cfg);
public:
/** Init the flag list and the team colors used by ~TC */
void init_flags();
/** Rebuild the flag list (not team colors) for a single side. */
void reinit_flags_for_side(std::size_t side);
void reset_reports(reports& reports_object)
{
reports_object_ = &reports_object;
}
private:
void init_flags_for_side_internal(std::size_t side, const std::string& side_color);
int blindfold_ctr_;
protected:
//TODO sort
const display_context * dc_;
std::unique_ptr<halo::manager> halo_man_;
std::weak_ptr<wb::manager> wb_;
typedef std::map<map_location, std::string> exclusive_unit_draw_requests_t;
/// map of hexes where only one unit should be drawn, the one identified by the associated id string
exclusive_unit_draw_requests_t exclusive_unit_draw_requests_;
map_location get_middle_location() const;
/**
* Called near the beginning of each draw() call.
* Derived classes can use this to add extra actions before redrawing
* invalidated hexes takes place. No action here by default.
*/
virtual void pre_draw() {}
/**
* Called at the very end of each draw() call.
* Derived classes can use this to add extra actions after redrawing
* invalidated hexes takes place. No action here by default.
*/
virtual void post_draw() {}
/**
* Get the clipping rectangle for drawing.
* Virtual since the editor might use a slightly different approach.
*/
virtual const SDL_Rect& get_clip_rect();
/**
* Only called when there's actual redrawing to do. Loops through
* invalidated locations and redraws them. Derived classes can override
* this, possibly to insert pre- or post-processing around a call to the
* base class's function.
*/
virtual void draw_invalidated();
/**
* Hook for actions to take right after draw() calls drawing_buffer_commit
* No action here by default.
*/
virtual void post_commit() {}
/**
* Redraws a single gamemap location.
*/
virtual void draw_hex(const map_location& loc);
/**
* @returns the image type to be used for the passed hex
*/
virtual image::TYPE get_image_type(const map_location& loc);
/**
* Called near the end of a draw operation, derived classes can use this
* to render a specific sidebar. Very similar to post_commit.
*/
virtual void draw_sidebar() {}
void draw_minimap();
enum TERRAIN_TYPE { BACKGROUND, FOREGROUND};
void get_terrain_images(const map_location &loc,
const std::string& timeid,
TERRAIN_TYPE terrain_type);
std::vector<surface> get_fog_shroud_images(const map_location& loc, image::TYPE image_type);
void draw_image_for_report(surface& img, SDL_Rect& rect);
void scroll_to_xy(int screenxpos, int screenypos, SCROLL_TYPE scroll_type,bool force = true);
static void fill_images_list(const std::string& prefix, std::vector<std::string>& images);
static const std::string& get_variant(const std::vector<std::string>& variants, const map_location &loc);
CVideo& screen_;
std::size_t currentTeam_;
bool dont_show_all_; //const team *viewpoint_;
int xpos_, ypos_;
bool view_locked_;
theme theme_;
static unsigned int zoom_;
int zoom_index_;
static unsigned int last_zoom_;
const std::unique_ptr<fake_unit_manager> fake_unit_man_;
const std::unique_ptr<terrain_builder> builder_;
surface minimap_;
SDL_Rect minimap_location_;
bool redrawMinimap_;
bool redraw_background_;
bool invalidateAll_;
bool grid_;
int diagnostic_label_;
bool panelsDrawn_;
double turbo_speed_;
bool turbo_;
bool invalidateGameStatus_;
const std::unique_ptr<map_labels> map_labels_;
reports * reports_object_;
/** Event raised when the map is being scrolled */
mutable events::generic_event scroll_event_;
/**
* notify observers that the screen has been redrawn completely
* atm this is used for replay_controller to add replay controls to the standard theme
*/
events::generic_event complete_redraw_event_;
boost::circular_buffer<unsigned> frametimes_; // in milliseconds
unsigned int fps_counter_;
std::chrono::seconds fps_start_;
unsigned int fps_actual_;
uint32_t last_frame_finished_ = 0u;
// Not set by the initializer:
std::map<std::string, SDL_Rect> reportRects_;
std::map<std::string, surface> reportSurfaces_;
std::map<std::string, config> reports_;
std::vector<std::shared_ptr<gui::button>> menu_buttons_, action_buttons_;
std::set<map_location> invalidated_;
surface mouseover_hex_overlay_;
// If we're transitioning from one time of day to the next,
// then we will use these two masks on top of all hexes when we blit.
surface tod_hex_mask1, tod_hex_mask2;
std::vector<std::string> fog_images_;
std::vector<std::string> shroud_images_;
map_location selectedHex_;
map_location mouseoverHex_;
CKey keys_;
/** Local cache for preferences::animate_map, since it is constantly queried. */
bool animate_map_;
/** Local version of preferences::animate_water, used to detect when it's changed. */
bool animate_water_;
private:
// This surface must be freed by the caller
surface get_flag(const map_location& loc);
/** Animated flags for each team */
std::vector<animated<image::locator>> flags_;
// This vector is a class member to avoid repeated memory allocations in get_terrain_images(),
// which turned out to be a significant bottleneck while profiling.
std::vector<surface> terrain_image_vector_;
public:
/**
* The layers to render something on. This value should never be stored
* it's the internal drawing order and adding removing and reordering
* the layers should be safe.
* If needed in WML use the name and map that to the enum value.
*/
enum drawing_layer {
LAYER_TERRAIN_BG, /**<
* Layer for the terrain drawn behind the
* unit.
*/
LAYER_GRID_TOP, /**< Top half part of grid image */
LAYER_MOUSEOVER_OVERLAY, /**< Mouseover overlay used by editor*/
LAYER_FOOTSTEPS, /**< Footsteps showing path from unit to mouse */
LAYER_MOUSEOVER_TOP, /**< Top half of image following the mouse */
LAYER_UNIT_FIRST, /**< Reserve layers to be selected for WML. */
LAYER_UNIT_BG = LAYER_UNIT_FIRST+10, /**< Used for the ellipse behind the unit. */
LAYER_UNIT_DEFAULT=LAYER_UNIT_FIRST+40,/**<default layer for drawing units */
LAYER_TERRAIN_FG = LAYER_UNIT_FIRST+50, /**<
* Layer for the terrain drawn in front of
* the unit.
*/
LAYER_GRID_BOTTOM, /**<
* Used for the bottom half part of grid image.
* Should be under moving units, to avoid masking south move.
*/
LAYER_UNIT_MOVE_DEFAULT=LAYER_UNIT_FIRST+60/**<default layer for drawing moving units */,
LAYER_UNIT_FG = LAYER_UNIT_FIRST+80, /**<
* Used for the ellipse in front of the
* unit.
*/
LAYER_UNIT_MISSILE_DEFAULT = LAYER_UNIT_FIRST+90, /**< default layer for missile frames*/
LAYER_UNIT_LAST=LAYER_UNIT_FIRST+100,
LAYER_REACHMAP, /**< "black stripes" on unreachable hexes. */
LAYER_MOUSEOVER_BOTTOM, /**< Bottom half of image following the mouse */
LAYER_FOG_SHROUD, /**< Fog and shroud. */
LAYER_ARROWS, /**< Arrows from the arrows framework. Used for planned moves display. */
LAYER_ACTIONS_NUMBERING, /**< Move numbering for the whiteboard. */
LAYER_SELECTED_HEX, /**< Image on the selected unit */
LAYER_ATTACK_INDICATOR, /**< Layer which holds the attack indicator. */
LAYER_UNIT_BAR, /**<
* Unit bars and overlays are drawn on this
* layer (for testing here).
*/
LAYER_MOVE_INFO, /**< Movement info (defense%, etc...). */
LAYER_LINGER_OVERLAY, /**< The overlay used for the linger mode. */
LAYER_BORDER, /**< The border of the map. */
};
/**
* Draw an image at a certain location.
* x,y: pixel location on screen to draw the image
* image: the image to draw
* reverse: if the image should be flipped across the x axis
* greyscale: used for instance to give the petrified appearance to a unit image
* alpha: the merging to use with the background
* blendto: blend to this color using blend_ratio
* submerged: the amount of the unit out of 1.0 that is submerged
* (presumably under water) and thus shouldn't be drawn
*/
void render_image(int x, int y, const display::drawing_layer drawing_layer,
const map_location& loc, surface image,
bool hreverse=false, bool greyscale=false,
fixed_t alpha=ftofxp(1.0), color_t blendto = {0,0,0},
double blend_ratio=0, double submerged=0.0,bool vreverse =false);
/**
* Draw text on a hex. (0.5, 0.5) is the center.
* The font size is adjusted to the zoom factor.
*/
void draw_text_in_hex(const map_location& loc,
const drawing_layer layer, const std::string& text, std::size_t font_size,
color_t color, double x_in_hex=0.5, double y_in_hex=0.5);
protected:
//TODO sort
std::size_t activeTeam_;
/**
* In order to render a hex properly it needs to be rendered per row. On
* this row several layers need to be drawn at the same time. Mainly the
* unit and the background terrain. This is needed since both can spill
* in the next hex. The foreground terrain needs to be drawn before to
* avoid decapitation a unit.
*
* In other words:
* for every layer
* for every row (starting from the top)
* for every hex in the row
* ...
*
* this is modified to:
* for every layer group
* for every row (starting from the top)
* for every layer in the group
* for every hex in the row
* ...
*
* * Surfaces are rendered per level in a map.
* * Per level the items are rendered per location these locations are
* stored in the drawing order required for units.
* * every location has a vector with surfaces, each with its own screen
* coordinate to render at.
* * every vector element has a vector with surfaces to render.
*/
class drawing_buffer_key
{
private:
unsigned int key_;
static const std::array<drawing_layer, 4> layer_groups;
public:
drawing_buffer_key(const map_location &loc, drawing_layer layer);
bool operator<(const drawing_buffer_key &rhs) const { return key_ < rhs.key_; }
};
/** Helper structure for rendering the terrains. */
class blit_helper
{
public:
// We don't want to copy this.
// It's expensive when done frequently due to the surface vector.
blit_helper(const blit_helper&) = delete;
blit_helper(const drawing_layer layer, const map_location& loc,
const int x, const int y, const surface& surf,
const SDL_Rect& clip)
: x_(x), y_(y), surf_(1, surf), clip_(clip),
key_(loc, layer)
{}
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)
: x_(x), y_(y), surf_(surf), clip_(clip),
key_(loc, layer)
{}
int x() const { return x_; }
int y() const { return y_; }
const std::vector<surface> &surf() const { return surf_; }
const SDL_Rect &clip() const { return clip_; }
bool operator<(const blit_helper &rhs) const { return key_ < rhs.key_; }
private:
int x_; /**< x screen coordinate to render at. */
int y_; /**< y screen coordinate to render at. */
std::vector<surface> surf_; /**< surface(s) to render. */
SDL_Rect clip_; /**<
* The clipping area of the source if
* omitted the entire source is used.
*/
drawing_buffer_key key_;
};
typedef std::list<blit_helper> drawing_buffer;
drawing_buffer drawing_buffer_;
public:
/**
* Add an item to the drawing buffer. You need to update screen on affected area
*
* @param layer The layer to draw on.
* @param loc The hex the image belongs to, needed for the
* drawing order.
*/
void drawing_buffer_add(const drawing_layer layer,
const map_location& loc, int x, int y, const surface& surf,
const SDL_Rect &clip = SDL_Rect());
void drawing_buffer_add(const drawing_layer layer,
const map_location& loc, int x, int y,
const std::vector<surface> &surf,
const SDL_Rect &clip = SDL_Rect());
protected:
/** Draws the drawing_buffer_ and clears it. */
void drawing_buffer_commit();
/** Clears the drawing buffer. */
void drawing_buffer_clear();
/** redraw all panels associated with the map display */
void draw_all_panels();
/**
* Initiate a redraw.
*
* Invalidate controls and panels when changed after they have been drawn
* initially. Useful for dynamic theme modification.
*/
void draw_init();
void draw_wrap(bool update,bool force);
/** Used to indicate to drawing functions that we are doing a map screenshot */
bool map_screenshot_;
public: //operations for the arrow framework
void add_arrow(arrow&);
void remove_arrow(arrow&);
/** Called by arrow objects when they change. You should not need to call this directly. */
void update_arrow(arrow & a);
protected:
// Tiles lit for showing where unit(s) can reach
typedef std::map<map_location,unsigned int> reach_map;
reach_map reach_map_;
reach_map reach_map_old_;
bool reach_map_changed_;
void process_reachmap_changes();
typedef std::map<map_location, std::vector<overlay>> overlay_map;
virtual overlay_map& get_overlays() = 0;
private:
/** Handle for the label which displays frames per second. */
int fps_handle_;
/** Count work done for the debug info displayed under fps */
int invalidated_hexes_;
int drawn_hexes_;
bool idle_anim_;
double idle_anim_rate_;
surface map_screenshot_surf_;
std::vector<std::function<void(display&)>> redraw_observers_;
/** Debug flag - overlay x,y coords on tiles */
bool draw_coordinates_;
/** Debug flag - overlay terrain codes on tiles */
bool draw_terrain_codes_;
/** Debug flag - overlay number of bitmaps on tiles */
bool draw_num_of_bitmaps_;
typedef std::list<arrow*> arrows_list_t;
typedef std::map<map_location, arrows_list_t > arrows_map_t;
/** Maps the list of arrows for each location */
arrows_map_t arrows_map_;
tod_color color_adjust_;
bool dirty_;
protected:
static display * singleton_;
};
struct blindfold
{
blindfold(display& d, bool lock=true) : display_(d), blind(lock) {
if(blind) {
display_.blindfold(true);
}
}
~blindfold() {
unblind();
}
void unblind() {
if(blind) {
display_.blindfold(false);
blind = false;
}
}
private:
display& display_;
bool blind;
};