gui/widgets/minimap.cpp

Go to the documentation of this file.
00001 /* $Id: minimap.cpp 54007 2012-04-28 19:16:10Z mordante $ */
00002 /*
00003    Copyright (C) 2008 - 2012 by Mark de Wever <koraq@xs4all.nl>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 #define GETTEXT_DOMAIN "wesnoth-lib"
00017 
00018 #include "gui/widgets/minimap.hpp"
00019 
00020 #include "gui/auxiliary/log.hpp"
00021 #include "gui/auxiliary/widget_definition/minimap.hpp"
00022 #include "gui/auxiliary/window_builder/minimap.hpp"
00023 #include "gui/widgets/settings.hpp"
00024 #include "map.hpp"
00025 #include "map_exception.hpp"
00026 #include "../../minimap.hpp"
00027 
00028 #include <boost/bind.hpp>
00029 
00030 #include <algorithm>
00031 
00032 static lg::log_domain log_config("config");
00033 #define ERR_CF LOG_STREAM_INDENT(err, log_config)
00034 
00035 #define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
00036 #define LOG_HEADER LOG_SCOPE_HEADER + ':'
00037 
00038 // Define this to enable debug output for the minimap cache.
00039 //#define DEBUG_MINIMAP_CACHE
00040 
00041 namespace gui2 {
00042 
00043 REGISTER_WIDGET(minimap)
00044 
00045 /** Key type for the cache. */
00046 struct tkey
00047 {
00048     tkey(const int w, const int h, const std::string& map_data)
00049         : w(w)
00050         , h(h)
00051         , map_data(map_data)
00052     {
00053     }
00054 
00055     /** Width of the image. */
00056     const int w;
00057 
00058     /** Height of the image. */
00059     const int h;
00060 
00061     /** The data used to generate the image. */
00062     const std::string map_data;
00063 };
00064 
00065 static bool operator<(const tkey& lhs, const tkey& rhs)
00066 {
00067     return lhs.w < rhs.w || (lhs.w == rhs.w
00068             && (lhs.h < rhs.h || (lhs.h == rhs.h
00069                 && lhs.map_data < rhs.map_data)));
00070 }
00071 
00072 /** Value type for the cache. */
00073 struct tvalue
00074 {
00075     tvalue(const surface& surf)
00076         : surf(surf)
00077         , age(1)
00078     {
00079     }
00080 
00081     /** The cached image. */
00082     const surface surf;
00083 
00084     /**
00085      * The age of the image.
00086      *
00087      * Every time an image is used its age is increased by one. Once the cache
00088      * is full 25% of the cache is emptied. This is done by halving the age of
00089      * the items in the cache and then erase the 25% with the lowest age. If
00090      * items have the same age their order is unspecified.
00091      */
00092     unsigned age;
00093 };
00094 
00095 #ifdef LOW_MEM
00096     /**
00097      * Maximum number of items in the cache (multiple of 4).
00098      *
00099      * As small as possible for low mem.
00100      */
00101     static const size_t cache_max_size = 4;
00102 #else
00103     /**
00104      * Maximum number of items in the cache (multiple of 4).
00105      *
00106      * No testing on the optimal number is done, just seems a nice number.
00107      */
00108     static const size_t cache_max_size = 100;
00109 #endif
00110 
00111     /**
00112      * The terrain used to create the cache.
00113      *
00114      * If another terrain config is used the cache needs to be cleared, this
00115      * normally doesn't happen a lot so the clearing of the cache is rather
00116      * unusual.
00117      */
00118     static const ::config* terrain = NULL;
00119 
00120     /** The cache. */
00121     typedef std::map<tkey, tvalue> tcache;
00122     static tcache cache;
00123 
00124 static bool compare(const std::pair<unsigned, tcache::iterator>& lhs
00125         , const std::pair<unsigned, tcache::iterator>& rhs)
00126 {
00127     return lhs.first < rhs.first;
00128 }
00129 
00130 static void shrink_cache()
00131 {
00132 #ifdef DEBUG_MINIMAP_CACHE
00133     std::cerr << "\nShrink cache from " << cache.size();
00134 #else
00135     DBG_GUI_D << "Shrinking the minimap cache.\n";
00136 #endif
00137 
00138     std::vector<std::pair<unsigned, tcache::iterator> > items;
00139     for(tcache::iterator itor = cache.begin(); itor != cache.end(); ++itor) {
00140 
00141         itor->second.age /= 2;
00142         items.push_back(std::make_pair(itor->second.age, itor));
00143     }
00144 
00145     std::partial_sort(items.begin()
00146             , items.begin() + cache_max_size / 4
00147             , items.end()
00148             , compare);
00149 
00150     for(std::vector<std::pair<unsigned, tcache::iterator> >::iterator
00151               vitor = items.begin()
00152             ; vitor < items.begin() + cache_max_size / 4
00153             ; ++vitor) {
00154 
00155         cache.erase(vitor->second);
00156     }
00157 
00158 #ifdef DEBUG_MINIMAP_CACHE
00159     std::cerr << " to " << cache.size() << ".\n";
00160 #endif
00161 }
00162 
00163 const surface tminimap::get_image(const int w, const int h) const
00164 {
00165     if(!terrain_) {
00166         return NULL;
00167     }
00168 
00169     if(terrain_ != terrain) {
00170 #ifdef DEBUG_MINIMAP_CACHE
00171         std::cerr << "\nFlush cache.\n";
00172 #else
00173         DBG_GUI_D << "Flushing the minimap cache.\n";
00174 #endif
00175         terrain = terrain_;
00176         cache.clear();
00177 
00178     }
00179 
00180     const tkey key(w, h, map_data_);
00181     tcache::iterator itor = cache.find(key);
00182 
00183     if(itor != cache.end()) {
00184 #ifdef DEBUG_MINIMAP_CACHE
00185         std::cerr << '+';
00186 #endif
00187         itor->second.age++;
00188         return itor->second.surf;
00189     }
00190 
00191     if(cache.size() >= cache_max_size) {
00192         shrink_cache();
00193     }
00194 
00195     try {
00196         const gamemap map(*terrain_, map_data_);
00197         const surface surf = image::getMinimap(w, h, map, NULL);
00198         cache.insert(std::make_pair(key, tvalue(surf)));
00199 #ifdef DEBUG_MINIMAP_CACHE
00200         std::cerr << '-';
00201 #endif
00202         return surf;
00203 
00204     } catch (incorrect_map_format_error& e) {
00205         ERR_CF << "Error while loading the map: " << e.message << '\n';
00206 #ifdef DEBUG_MINIMAP_CACHE
00207         std::cerr << 'X';
00208 #endif
00209     }
00210     return NULL;
00211 }
00212 
00213 void tminimap::impl_draw_background(surface& frame_buffer)
00214 {
00215     if (!terrain_) return;
00216     assert(terrain_);
00217 
00218     DBG_GUI_D << LOG_HEADER
00219             << " size " << get_rect()
00220             << ".\n";
00221 
00222     if(map_data_.empty()) {
00223         return;
00224     }
00225 
00226     SDL_Rect rect = get_rect();
00227     assert(rect.w > 0 && rect.h > 0);
00228 
00229     const ::surface surf = get_image(rect.w, rect.h);
00230     if(surf) {
00231         sdl_blit(surf, NULL, frame_buffer, &rect);
00232     }
00233 }
00234 
00235 void tminimap::impl_draw_background(
00236           surface& frame_buffer
00237         , int x_offset
00238         , int y_offset)
00239 {
00240     if (!terrain_) return;
00241     assert(terrain_);
00242 
00243     DBG_GUI_D << LOG_HEADER
00244             << " size " << calculate_blitting_rectangle(x_offset, y_offset)
00245             << ".\n";
00246 
00247     if(map_data_.empty()) {
00248         return;
00249     }
00250 
00251     SDL_Rect rect = calculate_blitting_rectangle(x_offset, y_offset);
00252     assert(rect.w > 0 && rect.h > 0);
00253 
00254     const ::surface surf = get_image(rect.w, rect.h);
00255     if(surf) {
00256         sdl_blit(surf, NULL, frame_buffer, &rect);
00257     }
00258 }
00259 
00260 const std::string& tminimap::get_control_type() const
00261 {
00262     static const std::string type = "minimap";
00263     return type;
00264 }
00265 
00266 } // namespace gui2
00267 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:02:55 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs