The Battle for Wesnoth  1.15.9+dev
minimap.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2018 by Mark de Wever <koraq@xs4all.nl>
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 "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 "sdl/rect.hpp"
27 #include "../../minimap.hpp" // We want the file in src/
28 
29 #include <functional>
30 
31 #include <algorithm>
32 
33 static lg::log_domain log_config("config");
34 #define ERR_CF LOG_STREAM_INDENT(err, log_config)
35 
36 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
37 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
38 
39 // Define this to enable debug output for the minimap cache.
40 //#define DEBUG_MINIMAP_CACHE
41 
42 namespace gui2
43 {
44 
45 // ------------ WIDGET -----------{
46 
47 REGISTER_WIDGET(minimap)
48 
49 minimap::minimap(const implementation::builder_minimap& builder)
50  : styled_widget(builder, type())
51  , map_data_()
52 {
53 }
54 
55 void minimap::set_active(const bool /*active*/)
56 {
57  /* DO NOTHING */
58 }
59 
60 bool minimap::get_active() const
61 {
62  return true;
63 }
64 
65 unsigned minimap::get_state() const
66 {
67  return 0;
68 }
69 
70 /** Key type for the cache. */
71 struct key_type
72 {
73  key_type(const int w, const int h, const std::string& map_data)
74  : w(w), h(h), map_data(map_data)
75  {
76  }
77 
78  /** Width of the image. */
79  const int w;
80 
81  /** Height of the image. */
82  const int h;
83 
84  /** The data used to generate the image. */
85  const std::string map_data;
86 };
87 
88 static bool operator<(const key_type& lhs, const key_type& rhs)
89 {
90  return std::tie(lhs.w, lhs.h, lhs.map_data) < std::tie(rhs.w, rhs.h, rhs.map_data);
91 }
92 
93 /** Value type for the cache. */
94 struct value_type
95 {
96  value_type(const surface& surf) : surf(surf), age(1)
97  {
98  }
99 
100  /** The cached image. */
101  const surface surf;
102 
103  /**
104  * The age of the image.
105  *
106  * Every time an image is used its age is increased by one. Once the cache
107  * is full 25% of the cache is emptied. This is done by halving the age of
108  * the items in the cache and then erase the 25% with the lowest age. If
109  * items have the same age their order is unspecified.
110  */
111  unsigned age;
112 };
113 
114 /**
115  * Maximum number of items in the cache (multiple of 4).
116  *
117  * No testing on the optimal number is done, just seems a nice number.
118  */
119 static const size_t cache_max_size = 100;
120 
121 /** The cache. */
122 typedef std::map<key_type, value_type> tcache;
123 static tcache cache;
124 
125 static bool compare(const std::pair<unsigned, tcache::iterator>& lhs,
126  const std::pair<unsigned, tcache::iterator>& rhs)
127 {
128  return lhs.first < rhs.first;
129 }
130 
131 static void shrink_cache()
132 {
133 #ifdef DEBUG_MINIMAP_CACHE
134  std::cerr << "\nShrink cache from " << cache.size();
135 #else
136  DBG_GUI_D << "Shrinking the minimap cache.\n";
137 #endif
138 
139  std::vector<std::pair<unsigned, tcache::iterator>> items;
140  for(tcache::iterator itor = cache.begin(); itor != cache.end(); ++itor) {
141 
142  itor->second.age /= 2;
143  items.emplace_back(itor->second.age, itor);
144  }
145 
146  std::partial_sort(items.begin(),
147  items.begin() + cache_max_size / 4,
148  items.end(),
149  compare);
150 
151  for(std::vector<std::pair<unsigned, tcache::iterator>>::iterator vitor
152  = items.begin();
153  vitor < items.begin() + cache_max_size / 4;
154  ++vitor) {
155 
156  cache.erase(vitor->second);
157  }
158 
159 #ifdef DEBUG_MINIMAP_CACHE
160  std::cerr << " to " << cache.size() << ".\n";
161 #endif
162 }
163 
165 {
166  return false;
167 }
168 
169 const surface minimap::get_image(const int w, const int h) const
170 {
171  const key_type key(w, h, map_data_);
172  tcache::iterator itor = cache.find(key);
173 
174  if(itor != cache.end()) {
175 #ifdef DEBUG_MINIMAP_CACHE
176  std::cerr << '+';
177 #endif
178  itor->second.age++;
179  return itor->second.surf;
180  }
181 
182  if(cache.size() >= cache_max_size) {
183  shrink_cache();
184  }
185 
186  try
187  {
188  const gamemap map(map_data_);
189  const surface surf = image::getMinimap(w, h, map, nullptr, nullptr, true);
190  cache.emplace(key, value_type(surf));
191 #ifdef DEBUG_MINIMAP_CACHE
192  std::cerr << '-';
193 #endif
194  return surf;
195  }
196  catch(const incorrect_map_format_error& e)
197  {
198  ERR_CF << "Error while loading the map: " << e.message << '\n';
199 #ifdef DEBUG_MINIMAP_CACHE
200  std::cerr << 'X';
201 #endif
202  }
203  return nullptr;
204 }
205 
207  int x_offset,
208  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  sdl_blit(surf, nullptr, frame_buffer, &rect);
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 
253 {
254  minimap* widget = new 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.
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:125
#define DBG_GUI_P
Definition: log.hpp:65
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:420
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:169
SDL_Rect calculate_blitting_rectangle(const int x_offset, const int y_offset)
Calculates the blitting rectangle of the widget.
Definition: widget.cpp:351
std::string map_data_
The map data to be used to generate the map.
Definition: minimap.hpp:83
Base class for all widgets.
Definition: widget.hpp:49
const std::string & map_data() const
Definition: minimap.hpp:76
#define h
const std::vector< std::string > items
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
Generic file dialog.
Definition: field-fwd.hpp:22
value_type(const surface &surf)
Definition: minimap.cpp:96
static void shrink_cache()
Definition: minimap.cpp:131
#define DBG_GUI_D
Definition: log.hpp:28
virtual bool get_active() const override
See styled_widget::get_active.
Definition: minimap.cpp:60
const int h
Height of the image.
Definition: minimap.cpp:82
static lg::log_domain log_config("config")
#define ERR_CF
Definition: minimap.cpp:34
std::string definition
Parameters for the styled_widget.
unsigned age
The age of the image.
Definition: minimap.cpp:111
This file contains the settings handling of the widget library.
std::map< key_type, value_type > tcache
The cache.
Definition: minimap.cpp:122
Encapsulates the map of the game.
Definition: map.hpp:33
static bool operator<(const key_type &lhs, const key_type &rhs)
Definition: minimap.cpp:88
Value type for the cache.
Definition: minimap.cpp:94
#define REGISTER_WIDGET(id)
Wrapper for REGISTER_WIDGET3.
bool disable_click_dismiss() const override
See widget::disable_click_dismiss.
Definition: minimap.cpp:164
const std::string map_data
The data used to generate the image.
Definition: minimap.cpp:85
virtual void impl_draw_background(surface &frame_buffer, int x_offset, int y_offset) override
See widget::impl_draw_background.
Definition: minimap.cpp:206
#define LOG_HEADER
Definition: minimap.cpp:37
static tcache cache
Definition: minimap.cpp:123
minimap_definition(const config &cfg)
Definition: minimap.cpp:228
int w
Base class for all visible items.
The basic minimap class.
Definition: minimap.hpp:42
static const size_t cache_max_size
Maximum number of items in the cache (multiple of 4).
Definition: minimap.cpp:119
const int w
Width of the image.
Definition: minimap.cpp:79
Contains the SDL_Rect helper code.
virtual void set_active(const bool active) override
See styled_widget::set_active.
Definition: minimap.cpp:55
key_type(const int w, const int h, const std::string &map_data)
Definition: minimap.cpp:73
std::string message
Definition: exceptions.hpp:31
#define e
virtual unsigned get_state() const override
See styled_widget::get_state.
Definition: minimap.cpp:65
void sdl_blit(const surface &src, SDL_Rect *src_rect, surface &dst, SDL_Rect *dst_rect)
Definition: utils.hpp:31
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:60
virtual widget * build() const override
Definition: minimap.cpp:252
#define DBG_GUI_G
Definition: log.hpp:40
Key type for the cache.
Definition: minimap.cpp:71
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
Contains the implementation details for lexical_cast and shouldn&#39;t be used directly.
const surface surf
The cached image.
Definition: minimap.cpp:101