The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
minimap.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2016 by Mark de Wever <[email protected]>
3  Part of the Battle for Wesnoth Project http://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 "gui/widgets/minimap.hpp"
18 
19 #include "gui/core/log.hpp"
23 #include "gui/widgets/settings.hpp"
24 #include "map/map.hpp"
25 #include "map/exception.hpp"
26 #include "terrain/type_data.hpp"
27 #include "../../minimap.hpp" // We want the file in src/
28 
29 #include "utils/functional.hpp"
30 #include <boost/make_shared.hpp>
31 
32 #include <algorithm>
33 
34 static lg::log_domain log_config("config");
35 #define ERR_CF LOG_STREAM_INDENT(err, log_config)
36 
37 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
38 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
39 
40 // Define this to enable debug output for the minimap cache.
41 //#define DEBUG_MINIMAP_CACHE
42 
43 namespace gui2
44 {
45 
46 // ------------ WIDGET -----------{
47 
48 REGISTER_WIDGET(minimap)
49 
50 void tminimap::set_active(const bool /*active*/)
51 {
52  /* DO NOTHING */
53 }
54 
56 {
57  return true;
58 }
59 
60 unsigned tminimap::get_state() const
61 {
62  return 0;
63 }
64 
65 /** Key type for the cache. */
66 struct tkey
67 {
68  tkey(const int w, const int h, const std::string& map_data)
69  : w(w), h(h), map_data(map_data)
70  {
71  }
72 
73  /** Width of the image. */
74  const int w;
75 
76  /** Height of the image. */
77  const int h;
78 
79  /** The data used to generate the image. */
81 };
82 
83 static bool operator<(const tkey& lhs, const tkey& rhs)
84 {
85  return lhs.w < rhs.w
86  || (lhs.w == rhs.w
87  && (lhs.h < rhs.h
88  || (lhs.h == rhs.h && lhs.map_data < rhs.map_data)));
89 }
90 
91 /** Value type for the cache. */
92 struct tvalue
93 {
94  tvalue(const surface& surf) : surf(surf), age(1)
95  {
96  }
97 
98  /** The cached image. */
99  const surface surf;
100 
101  /**
102  * The age of the image.
103  *
104  * Every time an image is used its age is increased by one. Once the cache
105  * is full 25% of the cache is emptied. This is done by halving the age of
106  * the items in the cache and then erase the 25% with the lowest age. If
107  * items have the same age their order is unspecified.
108  */
109  unsigned age;
110 };
111 
112 #ifdef LOW_MEM
113 /**
114  * Maximum number of items in the cache (multiple of 4).
115  *
116  * As small as possible for low mem.
117  */
118 static const size_t cache_max_size = 4;
119 #else
120 /**
121  * Maximum number of items in the cache (multiple of 4).
122  *
123  * No testing on the optimal number is done, just seems a nice number.
124  */
125 static const size_t cache_max_size = 100;
126 #endif
127 
128 /**
129  * The terrain used to create the cache.
130  *
131  * If another terrain config is used the cache needs to be cleared, this
132  * normally doesn't happen a lot so the clearing of the cache is rather
133  * unusual.
134  */
135 static const ::config* terrain = nullptr;
136 
137 /** The cache. */
138 typedef std::map<tkey, tvalue> tcache;
139 static tcache cache;
140 
141 static bool compare(const std::pair<unsigned, tcache::iterator>& lhs,
142  const std::pair<unsigned, tcache::iterator>& rhs)
143 {
144  return lhs.first < rhs.first;
145 }
146 
147 static void shrink_cache()
148 {
149 #ifdef DEBUG_MINIMAP_CACHE
150  std::cerr << "\nShrink cache from " << cache.size();
151 #else
152  DBG_GUI_D << "Shrinking the minimap cache.\n";
153 #endif
154 
155  std::vector<std::pair<unsigned, tcache::iterator> > items;
156  for(tcache::iterator itor = cache.begin(); itor != cache.end(); ++itor) {
157 
158  itor->second.age /= 2;
159  items.push_back(std::make_pair(itor->second.age, itor));
160  }
161 
162  std::partial_sort(items.begin(),
163  items.begin() + cache_max_size / 4,
164  items.end(),
165  compare);
166 
167  for(std::vector<std::pair<unsigned, tcache::iterator> >::iterator vitor
168  = items.begin();
169  vitor < items.begin() + cache_max_size / 4;
170  ++vitor) {
171 
172  cache.erase(vitor->second);
173  }
174 
175 #ifdef DEBUG_MINIMAP_CACHE
176  std::cerr << " to " << cache.size() << ".\n";
177 #endif
178 }
179 
181 {
182  return false;
183 }
184 
185 const surface tminimap::get_image(const int w, const int h) const
186 {
187  if(!terrain_) {
188  return nullptr;
189  }
190 
191  if(terrain_ != terrain) {
192 #ifdef DEBUG_MINIMAP_CACHE
193  std::cerr << "\nFlush cache.\n";
194 #else
195  DBG_GUI_D << "Flushing the minimap cache.\n";
196 #endif
197  terrain = terrain_;
198  cache.clear();
199  }
200 
201  const tkey key(w, h, map_data_);
202  tcache::iterator itor = cache.find(key);
203 
204  if(itor != cache.end()) {
205 #ifdef DEBUG_MINIMAP_CACHE
206  std::cerr << '+';
207 #endif
208  itor->second.age++;
209  return itor->second.surf;
210  }
211 
212  if(cache.size() >= cache_max_size) {
213  shrink_cache();
214  }
215 
216  try
217  {
218  const gamemap map(boost::make_shared<terrain_type_data>(*terrain_), map_data_);
219  const surface surf = image::getMinimap(w, h, map, nullptr);
220  cache.insert(std::make_pair(key, tvalue(surf)));
221 #ifdef DEBUG_MINIMAP_CACHE
222  std::cerr << '-';
223 #endif
224  return surf;
225  }
227  {
228  ERR_CF << "Error while loading the map: " << e.message << '\n';
229 #ifdef DEBUG_MINIMAP_CACHE
230  std::cerr << 'X';
231 #endif
232  }
233  return nullptr;
234 }
235 
237  int x_offset,
238  int y_offset)
239 {
240  if(!terrain_)
241  return;
242  assert(terrain_);
243 
244  DBG_GUI_D << LOG_HEADER << " size "
245  << calculate_blitting_rectangle(x_offset, y_offset) << ".\n";
246 
247  if(map_data_.empty()) {
248  return;
249  }
250 
251  SDL_Rect rect = calculate_blitting_rectangle(x_offset, y_offset);
252  assert(rect.w > 0 && rect.h > 0);
253 
254  const ::surface surf = get_image(rect.w, rect.h);
255  if(surf) {
256  sdl_blit(surf, nullptr, frame_buffer, &rect);
257  }
258 }
259 
261 {
262  static const std::string type = "minimap";
263  return type;
264 }
265 
266 // }---------- DEFINITION ---------{
267 
269  : tcontrol_definition(cfg)
270 {
271  DBG_GUI_P << "Parsing minimap " << id << '\n';
272 
273  load_resolutions<tresolution>(cfg);
274 }
275 
276 /*WIKI
277  * @page = GUIWidgetDefinitionWML
278  * @order = 1_minimap
279  *
280  * == Minimap ==
281  *
282  * @macro = minimap_description
283  *
284  * The following states exist:
285  * * state_enabled, the minimap is enabled.
286  * @begin{parent}{name="gui/"}
287  * @begin{tag}{name="minimap_definition"}{min=0}{max=-1}{super="generic/widget_definition"}
288  * @begin{tag}{name="resolution"}{min=0}{max=-1}{super="generic/widget_definition/resolution"}
289  * @begin{tag}{name="state_enabled"}{min=0}{max=1}{super="generic/state"}
290  * @end{tag}{name="state_enabled"}
291  * @end{tag}{name="resolution"}
292  * @end{tag}{name="minimap_definition"}
293  * @end{parent}{name="gui/"}
294  */
297 {
298  // Note the order should be the same as the enum tstate in minimap.hpp.
299  state.push_back(tstate_definition(cfg.child("state_enabled")));
300 }
301 
302 // }---------- BUILDER -----------{
303 
304 /*WIKI_MACRO
305  * @begin{macro}{minimap_description}
306  *
307  * A minimap to show the gamemap, this only shows the map and has no
308  * interaction options. This version is used for map previews, there
309  * will be a another version which allows interaction.
310  * @end{macro}
311  */
312 
313 /*WIKI
314  * @page = GUIWidgetInstanceWML
315  * @order = 2_minimap
316  *
317  * == Minimap ==
318  *
319  * @macro = minimap_description
320  *
321  * A minimap has no extra fields.
322  * @begin{parent}{name="gui/window/resolution/grid/row/column/"}
323  * @begin{tag}{name="minimap"}{min=0}{max=-1}{super="generic/widget_instance"}
324  * @end{tag}{name="minimap"}
325  * @end{parent}{name="gui/window/resolution/grid/row/column/"}
326  */
327 
328 namespace implementation
329 {
330 
331 tbuilder_minimap::tbuilder_minimap(const config& cfg) : tbuilder_control(cfg)
332 {
333 }
334 
336 {
337  tminimap* widget = new tminimap();
338 
339  init_control(widget);
340 
341  DBG_GUI_G << "Window builder: placed minimap '" << id
342  << "' with definition '" << definition << "'.\n";
343 
344  return widget;
345 }
346 
347 } // namespace implementation
348 
349 // }------------ END --------------
350 
351 } // namespace gui2
Define the common log macros for the gui toolkit.
static bool compare(const std::pair< unsigned, tcache::iterator > &lhs, const std::pair< unsigned, tcache::iterator > &rhs)
Definition: minimap.cpp:141
#define DBG_GUI_P
Definition: log.hpp:69
tkey(const int w, const int h, const std::string &map_data)
Definition: minimap.cpp:68
surface getMinimap(int w, int h, const gamemap &map, const team *vw, const std::map< map_location, unsigned int > *reach_map)
function to create the minimap for a given map the surface returned must be freed by the user ...
Definition: minimap.cpp:43
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
Definition: glew.h:1806
The basic minimap class.
Definition: minimap.hpp:36
Value type for the cache.
Definition: minimap.cpp:92
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1221
const int h
Height of the image.
Definition: minimap.cpp:77
bool disable_click_dismiss() const override
See twidget::disable_click_dismiss.
Definition: minimap.cpp:180
virtual unsigned get_state() const override
See tcontrol::get_state.
Definition: minimap.cpp:60
const std::vector< std::string > items
std::map< tkey, tvalue > tcache
The cache.
Definition: minimap.cpp:138
Base class of a resolution, contains the common keys for a resolution.
A class inherited from ttext_box that displays its input as stars.
Definition: field-fwd.hpp:23
void init_control(tcontrol *control) const
Definition: control.cpp:675
std::string definition
Parameters for the control.
Definition: control.hpp:530
const surface surf
The cached image.
Definition: minimap.cpp:99
static void shrink_cache()
Definition: minimap.cpp:147
#define DBG_GUI_D
Definition: log.hpp:29
static lg::log_domain log_config("config")
#define ERR_CF
Definition: minimap.cpp:35
This file contains the settings handling of the widget library.
std::string map_data_
The map data to be used to generate the map.
Definition: minimap.hpp:84
static bool operator<(const tkey &lhs, const tkey &rhs)
Definition: minimap.cpp:83
GLubyte GLubyte GLubyte GLubyte w
Definition: glew.h:1858
unsigned age
The age of the image.
Definition: minimap.cpp:109
Encapsulates the map of the game.
Definition: map.hpp:37
virtual void impl_draw_background(surface &frame_buffer, int x_offset, int y_offset) override
See twidget::impl_draw_background.
Definition: minimap.cpp:236
static const ::config * terrain
The terrain used to create the cache.
Definition: minimap.cpp:135
surf
Definition: filter.cpp:143
Contains the state info for a resolution.
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
virtual const std::string & get_control_type() const override
See tcontrol::get_control_type.
Definition: minimap.cpp:260
virtual bool get_active() const override
See tcontrol::get_active.
Definition: minimap.cpp:55
std::map< std::string, tfilter >::iterator itor
Definition: filter.cpp:199
#define LOG_HEADER
Definition: minimap.cpp:38
static tcache cache
Definition: minimap.cpp:139
const std::string map_data
The data used to generate the image.
Definition: minimap.cpp:80
GLfloat GLfloat GLfloat GLfloat h
Definition: glew.h:5910
SDL_Rect calculate_blitting_rectangle(const int x_offset, const int y_offset)
Calculates the blitting rectangle of the widget.
Definition: widget.cpp:321
tvalue(const surface &surf)
Definition: minimap.cpp:94
static const size_t cache_max_size
Maximum number of items in the cache (multiple of 4).
Definition: minimap.cpp:125
const surface get_image(const int w, const int h) const
Gets the image for the minimap.
Definition: minimap.cpp:185
std::vector< tstate_definition > state
const int w
Width of the image.
Definition: minimap.cpp:74
tminimap_definition(const config &cfg)
Definition: minimap.cpp:268
config & child(const std::string &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:658
const ::config * terrain_
The config object with the terrain data.
Definition: minimap.hpp:91
Base class for all widgets.
Definition: widget.hpp:49
std::string message
Definition: exceptions.hpp:29
#define e
void sdl_blit(const surface &src, SDL_Rect *src_rect, surface &dst, SDL_Rect *dst_rect)
Definition: utils.hpp:112
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
#define DBG_GUI_G
Definition: log.hpp:41
GLsizei const GLcharARB ** string
Definition: glew.h:4503
Key type for the cache.
Definition: minimap.cpp:66
Contains the implementation details for lexical_cast and shouldn't be used directly.