The Battle for Wesnoth  1.15.2+dev
minimap.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project 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 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
17 #include "minimap.hpp"
18 
19 #include "color.hpp"
20 #include "display.hpp"
21 #include "game_board.hpp"
22 #include "gettext.hpp"
23 #include "picture.hpp"
24 #include "log.hpp"
25 #include "map/map.hpp"
26 #include "preferences/general.hpp"
27 #include "resources.hpp"
28 #include "sdl/surface.hpp"
29 #include "team.hpp"
30 #include "terrain/type_data.hpp"
31 
32 static lg::log_domain log_display("display");
33 #define DBG_DP LOG_STREAM(debug, log_display)
34 #define WRN_DP LOG_STREAM(warn, log_display)
35 
36 
37 namespace image {
38 
39 surface getMinimap(int w, int h, const gamemap &map, const team *vw, const std::map<map_location,unsigned int> *reach_map, bool ignore_terrain_disabled)
40 {
41  const terrain_type_data & tdata = *map.tdata();
42 
43 
44  const bool preferences_minimap_draw_terrain = preferences::minimap_draw_terrain() || ignore_terrain_disabled;
45  const bool preferences_minimap_terrain_coding = preferences::minimap_terrain_coding();
46  const bool preferences_minimap_draw_villages = preferences::minimap_draw_villages();
47  const bool preferences_minimap_unit_coding = preferences::minimap_movement_coding();
48 
49  const int scale = (preferences_minimap_draw_terrain && preferences_minimap_terrain_coding) ? 24 : 4;
50 
51  DBG_DP << "creating minimap " << int(map.w()*scale*0.75) << "," << map.h()*scale << "\n";
52 
53  const std::size_t map_width = map.w()*scale*3/4;
54  const std::size_t map_height = map.h()*scale;
55  if(map_width == 0 || map_height == 0) {
56  return surface(nullptr);
57  }
58 
59  if(!preferences_minimap_draw_villages && !preferences_minimap_draw_terrain)
60  {
61  //return if there is nothing to draw.
62  //(optimisation)
63  double ratio = std::min<double>( w*1.0 / map_width, h*1.0 / map_height);
64  return surface(map_width * ratio, map_height * ratio);
65  }
66 
67  surface minimap(map_width, map_height);
68  if(minimap == nullptr)
69  return surface(nullptr);
70 
71  typedef mini_terrain_cache_map cache_map;
72  cache_map *normal_cache = &mini_terrain_cache;
73  cache_map *fog_cache = &mini_fogged_terrain_cache;
74  cache_map *highlight_cache = &mini_highlighted_terrain_cache;
75 
76  for(int y = 0; y <= map.total_height(); ++y)
77  for(int x = 0; x <= map.total_width(); ++x) {
78 
79  const map_location loc(x,y);
80  if(!map.on_board_with_border(loc))
81  continue;
82 
83  const bool shrouded = (display::get_singleton() != nullptr && display::get_singleton()->is_blindfolded()) || (vw != nullptr && vw->shrouded(loc));
84  // shrouded hex are not considered fogged (no need to fog a black image)
85  const bool fogged = (vw != nullptr && !shrouded && vw->fogged(loc));
86 
87  const bool highlighted = reach_map && reach_map->count(loc) != 0 && !shrouded;
88 
89  const t_translation::terrain_code terrain = shrouded ?
90  t_translation::VOID_TERRAIN : map[loc];
91  const terrain_type& terrain_info = tdata.get_terrain_info(terrain);
92 
93  // we need a balanced shift up and down of the hexes.
94  // if not, only the bottom half-hexes are clipped
95  // and it looks asymmetrical.
96 
97  SDL_Rect maprect {
98  x * scale * 3 / 4 - (scale / 4)
99  , y * scale + scale / 4 * (is_odd(x) ? 1 : -1) - (scale / 4)
100  , 0
101  , 0
102  };
103 
104  if (preferences_minimap_draw_terrain) {
105 
106  if (preferences_minimap_terrain_coding) {
107 
108  surface surf(nullptr);
109 
110  bool need_fogging = false;
111  bool need_highlighting = false;
112 
113  cache_map* cache = fogged ? fog_cache : normal_cache;
114  if (highlighted)
115  cache = highlight_cache;
116  cache_map::iterator i = cache->find(terrain);
117 
118  if (fogged && i == cache->end()) {
119  // we don't have the fogged version in cache
120  // try the normal cache and ask fogging the image
121  cache = normal_cache;
122  i = cache->find(terrain);
123  need_fogging = true;
124  }
125 
126  if (highlighted && i == cache->end()) {
127  // we don't have the highlighted version in cache
128  // try the normal cache and ask fogging the image
129  cache = normal_cache;
130  i = cache->find(terrain);
131  need_highlighting = true;
132  }
133 
134  if(i == cache->end() && !terrain_info.minimap_image().empty()) {
135  std::string base_file =
136  "terrain/" + terrain_info.minimap_image() + ".png";
137  surface tile = get_image(base_file,image::HEXED);
138 
139  //Compose images of base and overlay if necessary
140  // NOTE we also skip overlay when base is missing (to avoid hiding the error)
141  if(tile != nullptr && tdata.get_terrain_info(terrain).is_combined() && !terrain_info.minimap_image_overlay().empty()) {
142  std::string overlay_file =
143  "terrain/" + terrain_info.minimap_image_overlay() + ".png";
144  surface overlay = get_image(overlay_file,image::HEXED);
145 
146  if(overlay != nullptr && overlay != tile) {
147  surface combined(tile->w, tile->h);
148  SDL_Rect r {0,0,0,0};
149  sdl_blit(tile, nullptr, combined, &r);
150  r.x = std::max(0, (tile->w - overlay->w)/2);
151  r.y = std::max(0, (tile->h - overlay->h)/2);
152  sdl_blit(overlay, nullptr, combined, &r);
153  tile = combined;
154  }
155  }
156 
157  surf = scale_surface_sharp(tile, scale, scale);
158 
159  i = normal_cache->emplace(terrain, surf).first;
160  }
161 
162  if (i != cache->end())
163  {
164  surf = i->second;
165 
166  if (need_fogging) {
167  surf = adjust_surface_color(surf, -50, -50, -50);
168  fog_cache->emplace(terrain, surf);
169  }
170 
171  if (need_highlighting) {
172  surf = adjust_surface_color(surf, 50, 50, 50);
173  highlight_cache->emplace(terrain, surf);
174  }
175  }
176 
177  if(surf != nullptr)
178  sdl_blit(surf, nullptr, minimap, &maprect);
179 
180  } else {
181 
182  color_t col;
183  std::map<std::string, color_range>::const_iterator it = game_config::team_rgb_range.find(terrain_info.id());
184  if (it == game_config::team_rgb_range.end()) {
185  col = color_t(0,0,0,0);
186  } else
187  col = it->second.rep();
188 
189  bool first = true;
190  const t_translation::ter_list& underlying_terrains = tdata.underlying_union_terrain(terrain);
191  for(const t_translation::terrain_code& underlying_terrain : underlying_terrains) {
192 
193  const std::string& terrain_id = tdata.get_terrain_info(underlying_terrain).id();
194  it = game_config::team_rgb_range.find(terrain_id);
195  if (it == game_config::team_rgb_range.end())
196  continue;
197 
198  color_t tmp = it->second.rep();
199 
200  if (fogged) {
201  if (tmp.b < 50) tmp.b = 0;
202  else tmp.b -= 50;
203  if (tmp.g < 50) tmp.g = 0;
204  else tmp.g -= 50;
205  if (tmp.r < 50) tmp.r = 0;
206  else tmp.r -= 50;
207  }
208 
209  if (highlighted) {
210  if (tmp.b > 205) tmp.b = 255;
211  else tmp.b += 50;
212  if (tmp.g > 205) tmp.g = 255;
213  else tmp.g += 50;
214  if (tmp.r > 205) tmp.r = 255;
215  else tmp.r += 50;
216  }
217 
218  if (first) {
219  first = false;
220  col = tmp;
221  } else {
222  col.r = col.r - (col.r - tmp.r)/2;
223  col.g = col.g - (col.g - tmp.g)/2;
224  col.b = col.b - (col.b - tmp.b)/2;
225  }
226  }
227  SDL_Rect fillrect {maprect.x, maprect.y, scale * 3/4, scale};
228  const uint32_t mapped_col = SDL_MapRGB(minimap->format,col.r,col.g,col.b);
229  sdl::fill_surface_rect(minimap, &fillrect, mapped_col);
230  }
231  }
232 
233  if (terrain_info.is_village() && preferences_minimap_draw_villages) {
234 
235  int side = (resources::gameboard ? resources::gameboard->village_owner(loc) : -1); //check needed for mp create dialog
236 
237  // TODO: Add a key to [game_config][colors] for this
238  auto iter = game_config::team_rgb_range.find("white");
239  color_t col(255,255,255);
240  if(iter != game_config::team_rgb_range.end()) {
241  col = iter->second.min();
242  }
243 
244  if (!fogged) {
245  if (side > -1) {
246 
247  if (preferences_minimap_unit_coding || !vw ) {
248  col = team::get_minimap_color(side + 1);
249  } else {
250 
251  if (vw->owns_village(loc))
253  else if (vw->is_enemy(side + 1))
255  else
257  }
258  }
259  }
260 
261  SDL_Rect fillrect {
262  maprect.x
263  , maprect.y
264  , scale * 3/4
265  , scale
266  };
267 
268  const uint32_t mapped_col = SDL_MapRGB(minimap->format,col.r,col.g,col.b);
269  sdl::fill_surface_rect(minimap, &fillrect, mapped_col);
270 
271  }
272 
273  }
274 
275  double wratio = w*1.0 / minimap->w;
276  double hratio = h*1.0 / minimap->h;
277  double ratio = std::min<double>(wratio, hratio);
278 
279  minimap = scale_surface_sharp(minimap,
280  static_cast<int>(minimap->w * ratio), static_cast<int>(minimap->h * ratio));
281 
282  DBG_DP << "done generating minimap\n";
283 
284  return minimap;
285 }
286 
287 
288 }
int village_owner(const map_location &loc) const
Given the location of a village, will return the 0-based index of the team that currently owns it...
surface get_image(const image::locator &i_locator, TYPE type)
function to get the surface corresponding to an image.
Definition: picture.cpp:833
std::string unmoved_color()
Definition: general.cpp:343
bool is_odd(T num)
Definition: math.hpp:34
int h() const
Effective map height, in hexes.
Definition: map.hpp:128
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:88
std::map< std::string, color_range > team_rgb_range
surface adjust_surface_color(const surface &surf, int red, int green, int blue)
Definition: utils.cpp:595
bool minimap_movement_coding()
Definition: general.cpp:775
mini_terrain_cache_map mini_fogged_terrain_cache
Definition: picture.cpp:220
void fill_surface_rect(surface &dst, SDL_Rect *dst_rect, const uint32_t color)
Fill a rectangle on a given surface.
Definition: rect.hpp:114
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:50
const terrain_type & get_terrain_info(const t_translation::terrain_code &terrain) const
Get the corresponding terrain_type information object for a given type of terrain.
Definition: type_data.cpp:100
#define h
std::map< t_translation::terrain_code, surface > mini_terrain_cache_map
Definition: picture.hpp:130
surface getMinimap(int w, int h, const gamemap &map, const team *vw, const std::map< map_location, unsigned int > *reach_map, bool ignore_terrain_disabled)
function to create the minimap for a given map the surface returned must be freed by the user ...
Definition: minimap.cpp:39
-file sdl_utils.hpp
#define DBG_DP
Definition: minimap.cpp:33
const terrain_code VOID_TERRAIN
VOID_TERRAIN is used for shrouded hexes.
int total_width() const
Real width of the map, including borders.
Definition: map.hpp:134
bool is_village() const
Definition: terrain.hpp:120
Contains the database of all known terrain types, both those defined explicitly by WML [terrain_type]...
Definition: type_data.hpp:37
bool minimap_draw_villages()
Definition: general.cpp:805
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:44
bool is_combined() const
Definition: terrain.hpp:135
void scale(size_t factor, const uint32_t *src, uint32_t *trg, int srcWidth, int srcHeight, const ScalerCfg &cfg=ScalerCfg(), int yFirst=0, int yLast=std::numeric_limits< int >::max())
Definition: xbrz.cpp:1190
static lg::log_domain log_display("display")
bool on_board_with_border(const map_location &loc) const
Definition: map.cpp:382
game_board * gameboard
Definition: resources.cpp:20
Encapsulates the map of the game.
Definition: map.hpp:36
uint8_t r
Red value.
Definition: color.hpp:177
bool is_enemy(int n) const
Definition: team.hpp:243
map_display and display: classes which take care of displaying the map and game-data on the screen...
static const ::config * terrain
The terrain used to create the cache.
Definition: minimap.cpp:130
Encapsulates the map of the game.
Definition: location.hpp:42
bool shrouded(const map_location &loc) const
Definition: team.cpp:652
int w() const
Effective map width, in hexes.
Definition: map.hpp:125
std::string allied_color()
Definition: general.cpp:303
std::size_t i
Definition: function.cpp:933
bool is_blindfolded() const
Definition: display.cpp:533
const ter_data_cache & tdata() const
Definition: map.hpp:69
static tcache cache
Definition: minimap.cpp:134
mini_terrain_cache_map mini_highlighted_terrain_cache
Definition: picture.cpp:221
const std::string & minimap_image() const
Definition: terrain.hpp:30
int w
const t_translation::ter_list & underlying_union_terrain(const t_translation::terrain_code &terrain) const
Unordered set of all terrains used in either underlying_mvt_terrain or underlying_def_terrain.
Definition: type_data.cpp:141
int total_height() const
Real height of the map, including borders.
Definition: map.hpp:137
mini_terrain_cache_map mini_terrain_cache
Definition: picture.cpp:219
static color_t get_minimap_color(int side)
Definition: team.cpp:953
color_t rep() const
High-contrast shade, intended for the minimap markers.
Definition: color_range.hpp:96
bool minimap_draw_terrain()
Definition: general.cpp:815
const color_range & color_info(const std::string &name)
this module manages the cache of images.
surface scale_surface_sharp(const surface &surf, int w, int h)
Scale a surface using modified nearest neighbour algorithm.
Definition: utils.cpp:462
Standard logging facilities (interface).
const std::string & id() const
Definition: terrain.hpp:37
std::vector< terrain_code > ter_list
Definition: translation.hpp:78
bool fogged(const map_location &loc) const
Definition: team.cpp:661
void sdl_blit(const surface &src, SDL_Rect *src_rect, surface &dst, SDL_Rect *dst_rect)
Definition: utils.hpp:33
bool owns_village(const map_location &loc) const
Definition: team.hpp:185
uint8_t g
Green value.
Definition: color.hpp:180
uint8_t b
Blue value.
Definition: color.hpp:183
const std::string & minimap_image_overlay() const
Definition: terrain.hpp:31
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
std::string enemy_color()
Definition: general.cpp:323
bool minimap_terrain_coding()
Definition: general.cpp:785