The Battle for Wesnoth  1.17.4+dev
minimap.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2022
3  by Mark de Wever <koraq@xs4all.nl>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #define GETTEXT_DOMAIN "wesnoth-lib"
17 
18 #include "gui/widgets/minimap.hpp"
19 
20 #include "gui/core/log.hpp"
24 #include "gui/widgets/settings.hpp"
25 #include "map/map.hpp"
26 #include "map/exception.hpp"
27 #include "sdl/rect.hpp"
28 #include "../../minimap.hpp" // We want the file in src/
29 #include "video.hpp"
30 
31 #include <functional>
32 
33 #include <algorithm>
34 
35 static lg::log_domain log_config("config");
36 #define ERR_CF LOG_STREAM_INDENT(err, log_config)
37 
38 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
39 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
40 
41 // Define this to enable debug output for the minimap cache.
42 //#define DEBUG_MINIMAP_CACHE
43 
44 namespace gui2
45 {
46 
47 // ------------ WIDGET -----------{
48 
49 REGISTER_WIDGET(minimap)
50 
51 minimap::minimap(const implementation::builder_minimap& builder)
52  : styled_widget(builder, type())
53  , map_data_()
54 {
55 }
56 
57 void minimap::set_active(const bool /*active*/)
58 {
59  /* DO NOTHING */
60 }
61 
62 bool minimap::get_active() const
63 {
64  return true;
65 }
66 
67 unsigned minimap::get_state() const
68 {
69  return 0;
70 }
71 
72 /** Key type for the cache. */
73 struct key_type
74 {
75  key_type(const int w, const int h, const std::string& map_data)
76  : w(w), h(h), map_data(map_data)
77  {
78  }
79 
80  /** Width of the image. */
81  const int w;
82 
83  /** Height of the image. */
84  const int h;
85 
86  /** The data used to generate the image. */
87  const std::string map_data;
88 };
89 
90 static bool operator<(const key_type& lhs, const key_type& rhs)
91 {
92  return std::tie(lhs.w, lhs.h, lhs.map_data) < std::tie(rhs.w, rhs.h, rhs.map_data);
93 }
94 
95 /** Value type for the cache. */
96 struct value_type
97 {
98  value_type(const surface& surf) : surf(surf), age(1)
99  {
100  }
101 
102  /** The cached image. */
103  const surface surf;
104 
105  /**
106  * The age of the image.
107  *
108  * Every time an image is used its age is increased by one. Once the cache
109  * is full 25% of the cache is emptied. This is done by halving the age of
110  * the items in the cache and then erase the 25% with the lowest age. If
111  * items have the same age their order is unspecified.
112  */
113  unsigned age;
114 };
115 
116 /**
117  * Maximum number of items in the cache (multiple of 4).
118  *
119  * No testing on the optimal number is done, just seems a nice number.
120  */
121 static const size_t cache_max_size = 100;
122 
123 /** The cache. */
124 typedef std::map<key_type, value_type> tcache;
125 static tcache cache;
126 
127 static bool compare(const std::pair<unsigned, tcache::iterator>& lhs,
128  const std::pair<unsigned, tcache::iterator>& rhs)
129 {
130  return lhs.first < rhs.first;
131 }
132 
133 static void shrink_cache()
134 {
135 #ifdef DEBUG_MINIMAP_CACHE
136  std::cerr << "\nShrink cache from " << cache.size();
137 #else
138  DBG_GUI_D << "Shrinking the minimap cache.\n";
139 #endif
140 
141  std::vector<std::pair<unsigned, tcache::iterator>> items;
142  for(tcache::iterator itor = cache.begin(); itor != cache.end(); ++itor) {
143 
144  itor->second.age /= 2;
145  items.emplace_back(itor->second.age, itor);
146  }
147 
148  std::partial_sort(items.begin(),
149  items.begin() + cache_max_size / 4,
150  items.end(),
151  compare);
152 
153  for(std::vector<std::pair<unsigned, tcache::iterator>>::iterator vitor
154  = items.begin();
155  vitor < items.begin() + cache_max_size / 4;
156  ++vitor) {
157 
158  cache.erase(vitor->second);
159  }
160 
161 #ifdef DEBUG_MINIMAP_CACHE
162  std::cerr << " to " << cache.size() << ".\n";
163 #endif
164 }
165 
167 {
168  return false;
169 }
170 
171 const surface minimap::get_image(const int w, const int h) const
172 {
173  const key_type key(w, h, map_data_);
174  tcache::iterator itor = cache.find(key);
175 
176  if(itor != cache.end()) {
177 #ifdef DEBUG_MINIMAP_CACHE
178  std::cerr << '+';
179 #endif
180  itor->second.age++;
181  return itor->second.surf;
182  }
183 
184  if(cache.size() >= cache_max_size) {
185  shrink_cache();
186  }
187 
188  try
189  {
190  const gamemap map(map_data_);
191  const surface surf = image::getMinimap(w, h, map, nullptr, nullptr, true);
192  cache.emplace(key, value_type(surf));
193 #ifdef DEBUG_MINIMAP_CACHE
194  std::cerr << '-';
195 #endif
196  return surf;
197  }
198  catch(const incorrect_map_format_error& e)
199  {
200  ERR_CF << "Error while loading the map: " << e.message << '\n';
201 #ifdef DEBUG_MINIMAP_CACHE
202  std::cerr << 'X';
203 #endif
204  }
205  return nullptr;
206 }
207 
208 void minimap::impl_draw_background(int x_offset, int y_offset)
209 {
210  DBG_GUI_D << LOG_HEADER << " size "
211  << calculate_blitting_rectangle(x_offset, y_offset) << ".\n";
212 
213  if(map_data_.empty()) {
214  return;
215  }
216 
217  SDL_Rect rect = calculate_blitting_rectangle(x_offset, y_offset);
218  assert(rect.w > 0 && rect.h > 0);
219 
220  const ::surface surf = get_image(rect.w, rect.h);
221  if(surf) {
222  CVideo::get_singleton().blit_surface(rect.x, rect.y, surf);
223  }
224 }
225 
226 // }---------- DEFINITION ---------{
227 
230 {
231  DBG_GUI_P << "Parsing minimap " << id << '\n';
232 
233  load_resolutions<resolution>(cfg);
234 }
235 
237  : resolution_definition(cfg)
238 {
239  // Note the order should be the same as the enum state_t in minimap.hpp.
240  state.emplace_back(cfg.child("state_enabled"));
241 }
242 
243 // }---------- BUILDER -----------{
244 
245 namespace implementation
246 {
247 
248 builder_minimap::builder_minimap(const config& cfg) : builder_styled_widget(cfg)
249 {
250 }
251 
252 std::unique_ptr<widget> builder_minimap::build() const
253 {
254  auto widget = std::make_unique<minimap>(*this);
255 
256  DBG_GUI_G << "Window builder: placed minimap '" << id
257  << "' with definition '" << definition << "'.\n";
258 
259  return widget;
260 }
261 
262 } // namespace implementation
263 
264 // }------------ END --------------
265 
266 } // namespace gui2
Define the common log macros for the gui toolkit.
virtual void impl_draw_background()
See draw_background.
Definition: widget.hpp:595
Base class of a resolution, contains the common keys for a resolution.
static bool compare(const std::pair< unsigned, tcache::iterator > &lhs, const std::pair< unsigned, tcache::iterator > &rhs)
Definition: minimap.cpp:127
#define DBG_GUI_P
Definition: log.hpp:66
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:402
std::vector< state_definition > state
const surface get_image(const int w, const int h) const
Gets the image for the minimap.
Definition: minimap.cpp:171
SDL_Rect calculate_blitting_rectangle(const int x_offset, const int y_offset)
Calculates the blitting rectangle of the widget.
Definition: widget.cpp:353
std::string map_data_
The map data to be used to generate the map.
Definition: minimap.hpp:84
Base class for all widgets.
Definition: widget.hpp:49
const std::string & map_data() const
Definition: minimap.hpp:77
const std::vector< std::string > items
static CVideo & get_singleton()
Definition: video.hpp:53
#define h
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:40
Generic file dialog.
Definition: field-fwd.hpp:23
value_type(const surface &surf)
Definition: minimap.cpp:98
static void shrink_cache()
Definition: minimap.cpp:133
#define DBG_GUI_D
Definition: log.hpp:29
virtual bool get_active() const override
See styled_widget::get_active.
Definition: minimap.cpp:62
const int h
Height of the image.
Definition: minimap.cpp:84
static lg::log_domain log_config("config")
#define ERR_CF
Definition: minimap.cpp:36
std::string definition
Parameters for the styled_widget.
void blit_surface(const surface &surf, SDL_Rect *dst)
Draws a surface at the given location.
Definition: video.cpp:190
unsigned age
The age of the image.
Definition: minimap.cpp:113
This file contains the settings handling of the widget library.
std::map< key_type, value_type > tcache
The cache.
Definition: minimap.cpp:124
virtual std::unique_ptr< widget > build() const override
Definition: minimap.cpp:252
Encapsulates the map of the game.
Definition: map.hpp:171
static bool operator<(const key_type &lhs, const key_type &rhs)
Definition: minimap.cpp:90
Value type for the cache.
Definition: minimap.cpp:96
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
bool disable_click_dismiss() const override
See widget::disable_click_dismiss.
Definition: minimap.cpp:166
const std::string map_data
The data used to generate the image.
Definition: minimap.cpp:87
#define LOG_HEADER
Definition: minimap.cpp:39
static tcache cache
Definition: minimap.cpp:125
minimap_definition(const config &cfg)
Definition: minimap.cpp:228
int w
Base class for all visible items.
The basic minimap class.
Definition: minimap.hpp:43
static const size_t cache_max_size
Maximum number of items in the cache (multiple of 4).
Definition: minimap.cpp:121
const int w
Width of the image.
Definition: minimap.cpp:81
Contains the SDL_Rect helper code.
virtual void set_active(const bool active) override
See styled_widget::set_active.
Definition: minimap.cpp:57
key_type(const int w, const int h, const std::string &map_data)
Definition: minimap.cpp:75
std::string message
Definition: exceptions.hpp:30
#define e
virtual unsigned get_state() const override
See styled_widget::get_state.
Definition: minimap.cpp:67
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:60
#define DBG_GUI_G
Definition: log.hpp:41
Key type for the cache.
Definition: minimap.cpp:73
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
Contains the implementation details for lexical_cast and shouldn&#39;t be used directly.
const surface surf
The cached image.
Definition: minimap.cpp:103