The Battle for Wesnoth  1.15.0-dev
image.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 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 /**
16  * @file
17  * Routines for images: load, scale, re-color, etc.
18  */
19 
20 #define GETTEXT_DOMAIN "wesnoth-lib"
21 
22 #include "image.hpp"
23 
24 #include "config.hpp"
25 #include "display.hpp"
26 #include "filesystem.hpp"
27 #include "game_config.hpp"
28 #include "gettext.hpp"
29 #include "image_modifications.hpp"
30 #include "log.hpp"
31 #include "preferences/general.hpp"
32 #include "serialization/base64.hpp"
34 #include "sdl/rect.hpp"
35 #include "sdl/render_utils.hpp"
36 #include "sdl/texture.hpp"
37 #include "utils/general.hpp"
38 
39 #include <SDL_image.h>
40 
41 #include "utils/functional.hpp"
42 
43 #include <boost/algorithm/string.hpp>
44 #include <boost/functional/hash_fwd.hpp>
45 
46 #include <set>
47 
48 static lg::log_domain log_display("display");
49 #define ERR_DP LOG_STREAM(err, log_display)
50 #define LOG_DP LOG_STREAM(info, log_display)
51 
52 static lg::log_domain log_config("config");
53 #define ERR_CFG LOG_STREAM(err, log_config)
54 
56 
57 template<typename T>
58 struct cache_item
59 {
61  : item()
62  , loaded(false)
63  {
64  }
65 
66  cache_item(const T& item)
67  : item(item)
68  , loaded(true)
69  {
70  }
71 
72  T item;
73  bool loaded;
74 };
75 
76 namespace std
77 {
78 template<>
79 struct hash<image::locator::value>
80 {
81  std::size_t operator()(const image::locator::value& val) const
82  {
83  std::size_t hash = std::hash<unsigned>{}(val.type_);
84 
86  boost::hash_combine(hash, val.filename_);
87  }
88 
89  if(val.type_ == image::locator::SUB_FILE) {
90  boost::hash_combine(hash, val.loc_.x);
91  boost::hash_combine(hash, val.loc_.y);
92  boost::hash_combine(hash, val.center_x_);
93  boost::hash_combine(hash, val.center_y_);
94  boost::hash_combine(hash, val.modifications_);
95  }
96 
97  return hash;
98  }
99 };
100 }
101 
102 namespace image
103 {
104 template<typename T>
106 {
107 public:
109  : content_()
110  {
111  }
112 
114  {
115  if(static_cast<unsigned>(index) >= content_.size())
116  content_.resize(index + 1);
117  return content_[index];
118  }
119 
120  void flush()
121  {
122  content_.clear();
123  }
124 
125 private:
126  std::vector<cache_item<T>> content_;
127 };
128 
129 template<typename T>
130 bool locator::in_cache(cache_type<T>& cache) const
131 {
132  return index_ < 0 ? false : cache.get_element(index_).loaded;
133 }
134 
135 template<typename T>
136 const T& locator::locate_in_cache(cache_type<T>& cache) const
137 {
138  static T dummy;
139  return index_ < 0 ? dummy : cache.get_element(index_).item;
140 }
141 
142 template<typename T>
143 T& locator::access_in_cache(cache_type<T>& cache) const
144 {
145  static T dummy;
146  return index_ < 0 ? dummy : cache.get_element(index_).item;
147 }
148 
149 template<typename T>
150 void locator::add_to_cache(cache_type<T>& cache, const T& data) const
151 {
152  if(index_ >= 0) {
153  cache.get_element(index_) = cache_item<T>(data);
154  }
155 }
156 }
157 
158 namespace
159 {
160 image::locator::locator_finder_t locator_finder;
161 
162 /** Definition of all image maps */
164  images_,
165  scaled_to_zoom_,
166  hexed_images_,
167  scaled_to_hex_images_,
168  tod_colored_images_,
169  brightened_images_;
170 
171 /**
172  * Texture caches.
173  * Note that the latter two are temporary and should be removed once we have OGL and shader support.
174  */
175 using texture_cache_map = std::map<image::SCALE_QUALITY, image::texture_cache>;
176 
177 texture_cache_map
178  textures_,
179  textures_hexed_,
180  texture_tod_colored_;
181 
182 // cache storing if each image fit in a hex
183 image::bool_cache in_hex_info_;
184 
185 // cache storing if this is an empty hex
186 image::bool_cache is_empty_hex_;
187 
188 // caches storing the different lighted cases for each image
189 image::lit_cache lit_images_, lit_scaled_images_;
190 
191 // caches storing each lightmap generated
192 image::lit_variants lightmaps_;
193 
194 // const int cache_version_ = 0;
195 
196 std::map<std::string, bool> image_existence_map;
197 
198 // directories where we already cached file existence
199 std::set<std::string> precached_dirs;
200 
201 std::map<surface, surface> reversed_images_;
202 
203 int red_adjust = 0, green_adjust = 0, blue_adjust = 0;
204 
205 unsigned int zoom = tile_size;
206 unsigned int cached_zoom = 0;
207 
208 /** Algorithm choices */
209 // typedef std::function<surface(const surface &, int, int)> scaling_function;
210 typedef surface (*scaling_function)(const surface&, int, int);
211 scaling_function scale_to_zoom_func;
212 scaling_function scale_to_hex_func;
213 
214 const std::string data_uri_prefix = "data:";
215 struct parsed_data_URI{
216  explicit parsed_data_URI(utils::string_view data_URI);
217  utils::string_view scheme;
218  utils::string_view mime;
220  utils::string_view data;
221  bool good;
222 };
223 parsed_data_URI::parsed_data_URI(utils::string_view data_URI)
224 {
225  const std::size_t colon = data_URI.find(':');
226  const utils::string_view after_scheme = data_URI.substr(colon + 1);
227 
228  const std::size_t comma = after_scheme.find(',');
229  const utils::string_view type_info = after_scheme.substr(0, comma);
230 
231  const std::size_t semicolon = type_info.find(';');
232 
233  scheme = data_URI.substr(0, colon);
234  base64 = type_info.substr(semicolon + 1);
235  mime = type_info.substr(0, semicolon);
236  data = after_scheme.substr(comma + 1);
237  good = (scheme == "data" && base64 == "base64" && mime.length() > 0 && data.length() > 0);
238 }
239 
240 } // end anon namespace
241 
242 namespace image
243 {
247 
248 static int last_index_ = 0;
249 
251 {
252  {
253  images_.flush();
254  hexed_images_.flush();
255  tod_colored_images_.flush();
256  scaled_to_zoom_.flush();
257  scaled_to_hex_images_.flush();
258  brightened_images_.flush();
259  lit_images_.flush();
260  lit_scaled_images_.flush();
261  in_hex_info_.flush();
262  is_empty_hex_.flush();
263  mini_terrain_cache.clear();
264  mini_fogged_terrain_cache.clear();
265  mini_highlighted_terrain_cache.clear();
266  reversed_images_.clear();
267  image_existence_map.clear();
268  precached_dirs.clear();
269  }
270  /* We can't reset last_index_, since some locators are still alive
271  when using :refresh. That would cause them to point to the wrong
272  images. Not resetting the variable causes a memory leak, though. */
273  // last_index_ = 0;
274 }
275 
276 void locator::init_index()
277 {
278  auto i = locator_finder.find(val_);
279 
280  if(i == locator_finder.end()) {
281  index_ = last_index_++;
282  locator_finder.emplace(val_, index_);
283  } else {
284  index_ = i->second;
285  }
286 }
287 
288 void locator::parse_arguments()
289 {
290  std::string& fn = val_.filename_;
291  if(fn.empty()) {
292  return;
293  }
294 
295  if(boost::algorithm::starts_with(fn, data_uri_prefix)) {
296  parsed_data_URI parsed{fn};
297 
298  if(!parsed.good) {
299  utils::string_view view{ fn };
300  utils::string_view stripped = view.substr(0, view.find(","));
301  ERR_DP << "Invalid data URI: " << stripped << std::endl;
302  }
303 
304  val_.is_data_uri_ = true;
305  }
306 
307  std::size_t markup_field = fn.find('~');
308 
309  if(markup_field != std::string::npos) {
310  val_.type_ = SUB_FILE;
311  val_.modifications_ = fn.substr(markup_field, fn.size() - markup_field);
312  fn = fn.substr(0, markup_field);
313  }
314 }
315 
316 locator::locator()
317  : index_(-1)
318  , val_()
319 {
320 }
321 
322 locator::locator(const locator& a, const std::string& mods)
323  : index_(-1)
324  , val_(a.val_)
325 {
326  if(!mods.empty()) {
327  val_.modifications_ += mods;
328  val_.type_ = SUB_FILE;
329  init_index();
330  } else {
331  index_ = a.index_;
332  }
333 }
334 
335 locator::locator(const char* filename)
336  : index_(-1)
337  , val_(filename)
338 {
339  parse_arguments();
340  init_index();
341 }
342 
343 locator::locator(const std::string& filename)
344  : index_(-1)
345  , val_(filename)
346 {
347  parse_arguments();
348  init_index();
349 }
350 
351 locator::locator(const std::string& filename, const std::string& modifications)
352  : index_(-1)
353  , val_(filename, modifications)
354 {
355  init_index();
356 }
357 
358 locator::locator(const std::string& filename,
359  const map_location& loc,
360  int center_x,
361  int center_y,
362  const std::string& modifications)
363  : index_(-1)
364  , val_(filename, loc, center_x, center_y, modifications)
365 {
366  init_index();
367 }
368 
370 {
371  index_ = a.index_;
372  val_ = a.val_;
373 
374  return *this;
375 }
376 
378  : type_(a.type_)
379  , is_data_uri_(a.is_data_uri_)
380  , filename_(a.filename_)
381  , loc_(a.loc_)
382  , modifications_(a.modifications_)
383  , center_x_(a.center_x_)
384  , center_y_(a.center_y_)
385 {
386 }
387 
389  : type_(NONE)
390  , is_data_uri_(false)
391  , filename_()
392  , loc_()
393  , modifications_()
394  , center_x_(0)
395  , center_y_(0)
396 {
397 }
398 
399 locator::value::value(const char* filename)
400  : type_(FILE)
401  , is_data_uri_(false)
402  , filename_(filename)
403  , loc_()
404  , modifications_()
405  , center_x_(0)
406  , center_y_(0)
407 {
408 }
409 
410 locator::value::value(const std::string& filename)
411  : type_(FILE)
412  , is_data_uri_(false)
413  , filename_(filename)
414  , loc_()
415  , modifications_()
416  , center_x_(0)
417  , center_y_(0)
418 {
419 }
420 
421 locator::value::value(const std::string& filename, const std::string& modifications)
422  : type_(SUB_FILE)
423  , is_data_uri_(false)
424  , filename_(filename)
425  , loc_()
426  , modifications_(modifications)
427  , center_x_(0)
428  , center_y_(0)
429 {
430 }
431 
432 locator::value::value(const std::string& filename,
433  const map_location& loc,
434  int center_x,
435  int center_y,
436  const std::string& modifications)
437  : type_(SUB_FILE)
438  , is_data_uri_(false)
439  , filename_(filename)
440  , loc_(loc)
441  , modifications_(modifications)
442  , center_x_(center_x)
443  , center_y_(center_y)
444 {
445 }
446 
448 {
449  if(a.type_ != type_) {
450  return false;
451  } else if(type_ == FILE) {
452  return filename_ == a.filename_;
453  } else if(type_ == SUB_FILE) {
454  return filename_ == a.filename_ && loc_ == a.loc_ && modifications_ == a.modifications_
455  && center_x_ == a.center_x_ && center_y_ == a.center_y_;
456  }
457 
458  return false;
459 }
460 
462 {
463  if(type_ != a.type_) {
464  return type_ < a.type_;
465  } else if(type_ == FILE) {
466  return filename_ < a.filename_;
467  } else if(type_ == SUB_FILE) {
468  if(filename_ != a.filename_)
469  return filename_ < a.filename_;
470  if(loc_ != a.loc_)
471  return loc_ < a.loc_;
472  if(center_x_ != a.center_x_)
473  return center_x_ < a.center_x_;
474  if(center_y_ != a.center_y_)
475  return center_y_ < a.center_y_;
476  return (modifications_ < a.modifications_);
477  }
478 
479  return false;
480 }
481 
482 // Check if localized file is up-to-date according to l10n track index.
483 // Make sure only that the image is not explicitly recorded as fuzzy,
484 // in order to be able to use non-tracked images (e.g. from UMC).
485 static std::set<std::string> fuzzy_localized_files;
486 static bool localized_file_uptodate(const std::string& loc_file)
487 {
488  if(fuzzy_localized_files.empty()) {
489  // First call, parse track index to collect fuzzy files by path.
490  std::string fsep = "\xC2\xA6"; // UTF-8 for "broken bar"
491  std::string trackpath = filesystem::get_binary_file_location("", "l10n-track");
492 
493  // l10n-track file not present. Assume image is up-to-date.
494  if(trackpath.empty()) {
495  return true;
496  }
497 
498  std::string contents = filesystem::read_file(trackpath);
499 
500  for(const std::string& line : utils::split(contents, '\n')) {
501  std::size_t p1 = line.find(fsep);
502  if(p1 == std::string::npos) {
503  continue;
504  }
505 
506  std::string state = line.substr(0, p1);
507  boost::trim(state);
508  if(state == "fuzzy") {
509  std::size_t p2 = line.find(fsep, p1 + fsep.length());
510  if(p2 == std::string::npos) {
511  continue;
512  }
513 
514  std::string relpath = line.substr(p1 + fsep.length(), p2 - p1 - fsep.length());
515  fuzzy_localized_files.insert(game_config::path + '/' + relpath);
516  }
517  }
518 
519  fuzzy_localized_files.insert(""); // make sure not empty any more
520  }
521 
522  return fuzzy_localized_files.count(loc_file) == 0;
523 }
524 
525 // Return path to localized counterpart of the given file, if any, or empty string.
526 // Localized counterpart may also be requested to have a suffix to base name.
527 static std::string get_localized_path(const std::string& file, const std::string& suff = "")
528 {
529  std::string dir = filesystem::directory_name(file);
530  std::string base = filesystem::base_name(file);
531 
532  const std::size_t pos_ext = base.rfind(".");
533 
534  std::string loc_base;
535  if(pos_ext != std::string::npos) {
536  loc_base = base.substr(0, pos_ext) + suff + base.substr(pos_ext);
537  } else {
538  loc_base = base + suff;
539  }
540 
541  // TRANSLATORS: This is the language code which will be used
542  // to store and fetch localized non-textual resources, such as images,
543  // when they exist. Normally it is just the code of the PO file itself,
544  // e.g. "de" of de.po for German. But it can also be a comma-separated
545  // list of language codes by priority, when the localized resource
546  // found for first of those languages will be used. This is useful when
547  // two languages share sufficient commonality, that they can use each
548  // other's resources rather than duplicating them. For example,
549  // Swedish (sv) and Danish (da) are such, so Swedish translator could
550  // translate this message as "sv,da", while Danish as "da,sv".
551  std::vector<std::string> langs = utils::split(_("language code for localized resources^en_US"));
552 
553  // In case even the original image is split into base and overlay,
554  // add en_US with lowest priority, since the message above will
555  // not have it when translated.
556  langs.push_back("en_US");
557  for(const std::string& lang : langs) {
558  std::string loc_file = dir + "/" + "l10n" + "/" + lang + "/" + loc_base;
559  if(filesystem::file_exists(loc_file) && localized_file_uptodate(loc_file)) {
560  return loc_file;
561  }
562  }
563 
564  return "";
565 }
566 
567 // Ensure PNG images with an indexed palette are converted to 32-bit RGBA.
569 {
570  if(!surf.null() && !is_neutral(surf)) {
571  surf = make_neutral_surface(surf);
572  assert(is_neutral(surf));
573  }
574 }
575 
576 // Load overlay image and compose it with the original surface.
577 static void add_localized_overlay(const std::string& ovr_file, surface& orig_surf)
578 {
580  surface ovr_surf = IMG_Load_RW(rwops.release(), true); // SDL takes ownership of rwops
581  if(ovr_surf.null()) {
582  return;
583  }
584 
585  standardize_surface_format(ovr_surf);
586 
587  SDL_Rect area {0, 0, ovr_surf->w, ovr_surf->h};
588 
589  sdl_blit(ovr_surf, 0, orig_surf, &area);
590 }
591 
593 {
594  surface res;
595 
596  std::string location = filesystem::get_binary_file_location("images", loc.get_filename());
597 
598  {
599  if(!location.empty()) {
600  // Check if there is a localized image.
601  const std::string loc_location = get_localized_path(location);
602  if(!loc_location.empty()) {
603  location = loc_location;
604  }
605 
607  res = IMG_Load_RW(rwops.release(), true); // SDL takes ownership of rwops
608 
610 
611  // If there was no standalone localized image, check if there is an overlay.
612  if(!res.null() && loc_location.empty()) {
613  const std::string ovr_location = get_localized_path(location, "--overlay");
614  if(!ovr_location.empty()) {
615  add_localized_overlay(ovr_location, res);
616  }
617  }
618  }
619  }
620 
621  if(res.null() && !loc.get_filename().empty()) {
622  ERR_DP << "could not open image '" << loc.get_filename() << "'" << std::endl;
625  }
626 
627  return res;
628 }
629 
631 {
633  if(surf == nullptr) {
634  return nullptr;
635  }
636 
638 
639  while(!mods.empty()) {
640  modification* mod = mods.top();
641 
642  try {
643  surf = (*mod)(surf);
644  } catch(const image::modification::imod_exception& e) {
645  std::ostringstream ss;
646  ss << "\n";
647 
648  for(const std::string& mod2 : utils::parenthetical_split(loc.get_modifications(), '~')) {
649  ss << "\t" << mod2 << "\n";
650  }
651 
652  ERR_CFG << "Failed to apply a modification to an image:\n"
653  << "Image: " << loc.get_filename() << "\n"
654  << "Modifications: " << ss.str() << "\n"
655  << "Error: " << e.message << "\n";
656  }
657 
658  // NOTE: do this *after* applying the mod or you'll get crashes!
659  mods.pop();
660  }
661 
662  if(loc.get_loc().valid()) {
663  SDL_Rect srcrect = sdl::create_rect(
664  ((tile_size * 3) / 4) * loc.get_loc().x,
665  tile_size * loc.get_loc().y + (tile_size / 2) * (loc.get_loc().x % 2),
666  tile_size,
667  tile_size
668  );
669 
670  if(loc.get_center_x() >= 0 && loc.get_center_y() >= 0) {
671  srcrect.x += surf->w / 2 - loc.get_center_x();
672  srcrect.y += surf->h / 2 - loc.get_center_y();
673  }
674 
675  // cut and hex mask, but also check and cache if empty result
676  surface cut(cut_surface(surf, srcrect));
677  bool is_empty = false;
678  surf = mask_surface(cut, get_hexmask(), &is_empty);
679 
680  // discard empty images to free memory
681  if(is_empty) {
682  // Safe because those images are only used by terrain rendering
683  // and it filters them out.
684  // A safer and more general way would be to keep only one copy of it
685  surf = nullptr;
686  }
687 
688  loc.add_to_cache(is_empty_hex_, is_empty);
689  }
690 
691  return surf;
692 }
693 
695 {
696  surface surf;
697 
698  parsed_data_URI parsed{loc.get_filename()};
699 
700  if(!parsed.good) {
701  utils::string_view fn = loc.get_filename();
702  utils::string_view stripped = fn.substr(0, fn.find(","));
703  ERR_DP << "Invalid data URI: " << stripped << std::endl;
704  } else if(parsed.mime.substr(0, 5) != "image") {
705  ERR_DP << "Data URI not of image MIME type: " << parsed.mime << std::endl;
706  } else {
707  const std::vector<uint8_t> image_data = base64::decode(parsed.data);
708  filesystem::rwops_ptr rwops{SDL_RWFromConstMem(image_data.data(), image_data.size()), &SDL_FreeRW};
709 
710  if(image_data.empty()) {
711  ERR_DP << "Invalid encoding in data URI" << std::endl;
712  } else if(parsed.mime == "image/png") {
713  surf = IMG_LoadTyped_RW(rwops.release(), true, "PNG");
714  } else if(parsed.mime == "image/jpeg") {
715  surf = IMG_LoadTyped_RW(rwops.release(), true, "JPG");
716  } else {
717  ERR_DP << "Invalid image MIME type: " << parsed.mime << std::endl;
718  }
719  }
720 
721  return surf;
722 }
723 
724 // small utility function to store an int from (-256,254) to an signed char
725 static signed char col_to_uchar(int i)
726 {
727  return static_cast<signed char>(std::min<int>(127, std::max<int>(-128, i / 2)));
728 }
729 
730 light_string get_light_string(int op, int r, int g, int b)
731 {
732  light_string ls;
733  ls.reserve(4);
734  ls.push_back(op);
735  ls.push_back(col_to_uchar(r));
736  ls.push_back(col_to_uchar(g));
737  ls.push_back(col_to_uchar(b));
738 
739  return ls;
740 }
741 
743 {
744  // atomic lightmap operation are handled directly (important to end recursion)
745  if(ls.size() == 4) {
746  // if no lightmap (first char = -1) then we need the initial value
747  //(before the halving done for lightmap)
748  int m = ls[0] == -1 ? 2 : 1;
749  return adjust_surface_color(surf, ls[1] * m, ls[2] * m, ls[3] * m);
750  }
751 
752  // check if the lightmap is already cached or need to be generated
753  surface lightmap = nullptr;
754  auto i = lightmaps_.find(ls);
755  if(i != lightmaps_.end()) {
756  lightmap = i->second;
757  } else {
758  // build all the paths for lightmap sources
759  static const std::string p = "terrain/light/light";
760  static const std::string lm_img[19] {
761  p + ".png",
762  p + "-concave-2-tr.png", p + "-concave-2-r.png", p + "-concave-2-br.png",
763  p + "-concave-2-bl.png", p + "-concave-2-l.png", p + "-concave-2-tl.png",
764  p + "-convex-br-bl.png", p + "-convex-bl-l.png", p + "-convex-l-tl.png",
765  p + "-convex-tl-tr.png", p + "-convex-tr-r.png", p + "-convex-r-br.png",
766  p + "-convex-l-bl.png", p + "-convex-tl-l.png", p + "-convex-tr-tl.png",
767  p + "-convex-r-tr.png", p + "-convex-br-r.png", p + "-convex-bl-br.png"
768  };
769 
770  // decompose into atomic lightmap operations (4 chars)
771  for(std::size_t c = 0; c + 3 < ls.size(); c += 4) {
772  light_string sls = ls.substr(c, 4);
773 
774  // get the corresponding image and apply the lightmap operation to it
775  // This allows to also cache lightmap parts.
776  // note that we avoid infinite recursion by using only atomic operation
777  surface lts = image::get_lighted_image(lm_img[sls[0]], sls, HEXED);
778 
779  // first image will be the base where we blit the others
780  if(lightmap == nullptr) {
781  // copy the cached image to avoid modifying the cache
782  lightmap = make_neutral_surface(lts);
783  } else {
784  sdl_blit(lts, nullptr, lightmap, nullptr);
785  }
786  }
787 
788  // cache the result
789  lightmaps_[ls] = lightmap;
790  }
791 
792  // apply the final lightmap
793  return light_surface(surf, lightmap);
794 }
795 
797 {
798  return val_.is_data_uri_
799  ? parsed_data_URI{val_.filename_}.good
801 }
802 
804 {
805  switch(loc.get_type()) {
806  case locator::FILE:
807  if(loc.is_data_uri()){
808  return load_image_data_uri(loc);
809  } else {
810  return load_image_file(loc);
811  }
812  case locator::SUB_FILE:
813  return load_image_sub_file(loc);
814  default:
815  return surface(nullptr);
816  }
817 }
818 
820 {
821 }
822 
824 {
825  flush_cache();
826 }
827 
828 void set_color_adjustment(int r, int g, int b)
829 {
830  if(r != red_adjust || g != green_adjust || b != blue_adjust) {
831  red_adjust = r;
832  green_adjust = g;
833  blue_adjust = b;
834  tod_colored_images_.flush();
835  brightened_images_.flush();
836  lit_images_.flush();
837  lit_scaled_images_.flush();
838  reversed_images_.clear();
839  }
840 }
841 
842 void set_zoom(unsigned int amount)
843 {
844  if(amount != zoom) {
845  zoom = amount;
846  tod_colored_images_.flush();
847  brightened_images_.flush();
848  reversed_images_.clear();
849 
850  // We keep these caches if:
851  // we use default zoom (it doesn't need those)
852  // or if they are already at the wanted zoom.
853  if(zoom != tile_size && zoom != cached_zoom) {
854  scaled_to_zoom_.flush();
855  scaled_to_hex_images_.flush();
856  lit_scaled_images_.flush();
857  cached_zoom = zoom;
858  }
859  }
860 }
861 
862 // F should be a scaling algorithm without "integral" zoom limitations
863 template<scaling_function F>
864 static surface scale_xbrz_helper(const surface& res, int w, int h)
865 {
866  int best_integer_zoom = std::min(w / res->w, h / res->h);
867  int legal_zoom = utils::clamp(best_integer_zoom, 1, 5);
868  return F(scale_surface_xbrz(res, legal_zoom), w, h);
869 }
870 
872 
873 static scaling_function select_algorithm(SCALING_ALGORITHM algo)
874 {
875  switch(algo.v) {
877  scaling_function result = &scale_surface;
878  return result;
879  }
880  case SCALING_ALGORITHM::NEAREST_NEIGHBOR: {
881  scaling_function result = &scale_surface_nn;
882  return result;
883  }
884  case SCALING_ALGORITHM::XBRZ_LIN: {
885  scaling_function result = &scale_xbrz_helper<scale_surface>;
886  return result;
887  }
888  case SCALING_ALGORITHM::XBRZ_NN: {
889  scaling_function result = &scale_xbrz_helper<scale_surface_nn>;
890  return result;
891  }
892  default:
893  assert(false && "I don't know how to implement this scaling algorithm");
894  throw 42;
895  }
896 }
897 
898 static surface get_hexed(const locator& i_locator)
899 {
900  surface image(get_image(i_locator, UNSCALED));
901  // hex cut tiles, also check and cache if empty result
902  bool is_empty = false;
903  surface res = mask_surface(image, get_hexmask(), &is_empty, i_locator.get_filename());
904  i_locator.add_to_cache(is_empty_hex_, is_empty);
905  return res;
906 }
907 
908 static surface get_scaled_to_hex(const locator& i_locator)
909 {
910  surface img = get_image(i_locator, HEXED);
911  // return scale_surface(img, zoom, zoom);
912 
913  if(!img.null()) {
914  return scale_to_hex_func(img, zoom, zoom);
915  }
916 
917  return surface(nullptr);
918 
919 }
920 
921 static surface get_tod_colored(const locator& i_locator)
922 {
923  surface img = get_image(i_locator, SCALED_TO_HEX);
924  return adjust_surface_color(img, red_adjust, green_adjust, blue_adjust);
925 }
926 
927 static surface get_scaled_to_zoom(const locator& i_locator)
928 {
929  assert(zoom != tile_size);
930  assert(tile_size != 0);
931 
932  surface res(get_image(i_locator, UNSCALED));
933  // For some reason haloes seems to have invalid images, protect against crashing
934  if(!res.null()) {
935  return scale_to_zoom_func(res, ((res->w * zoom) / tile_size), ((res->h * zoom) / tile_size));
936  }
937 
938  return surface(nullptr);
939 }
940 
941 static surface get_brightened(const locator& i_locator)
942 {
943  surface image(get_image(i_locator, TOD_COLORED));
945 }
946 
947 /// translate type to a simpler one when possible
948 static TYPE simplify_type(const image::locator& i_locator, TYPE type)
949 {
950  switch(type) {
951  case SCALED_TO_ZOOM:
952  if(zoom == tile_size) {
953  type = UNSCALED;
954  }
955 
956  break;
957  case BRIGHTENED:
959  type = TOD_COLORED;
960  }
961 
962  break;
963  default:
964  break;
965  }
966 
967  if(type == TOD_COLORED) {
968  if(red_adjust == 0 && green_adjust == 0 && blue_adjust == 0) {
969  type = SCALED_TO_HEX;
970  }
971  }
972 
973  if(type == SCALED_TO_HEX) {
974  if(zoom == tile_size) {
975  type = HEXED;
976  }
977  }
978 
979  if(type == HEXED) {
980  // check if the image is already hex-cut by the location system
981  if(i_locator.get_loc().valid()) {
982  type = UNSCALED;
983  }
984  }
985 
986  return type;
987 }
988 
990 {
991  surface res;
992 
993  if(i_locator.is_void()) {
994  return res;
995  }
996 
997  type = simplify_type(i_locator, type);
998 
999  image_cache* imap;
1000  // select associated cache
1001  switch(type) {
1002  case UNSCALED:
1003  imap = &images_;
1004  break;
1005  case TOD_COLORED:
1006  imap = &tod_colored_images_;
1007  break;
1008  case SCALED_TO_ZOOM:
1009  imap = &scaled_to_zoom_;
1010  break;
1011  case HEXED:
1012  imap = &hexed_images_;
1013  break;
1014  case SCALED_TO_HEX:
1015  imap = &scaled_to_hex_images_;
1016  break;
1017  case BRIGHTENED:
1018  imap = &brightened_images_;
1019  break;
1020  default:
1021  return res;
1022  }
1023 
1024  // return the image if already cached
1025  bool tmp = i_locator.in_cache(*imap);
1026 
1027  if(tmp) {
1028  surface result = i_locator.locate_in_cache(*imap);
1029  return result;
1030  }
1031 
1032  // not cached, generate it
1033  switch(type) {
1034  case UNSCALED:
1035  // If type is unscaled, directly load the image from the disk.
1036  res = load_from_disk(i_locator);
1037  break;
1038  case TOD_COLORED:
1039  res = get_tod_colored(i_locator);
1040  break;
1041  case SCALED_TO_ZOOM:
1042  res = get_scaled_to_zoom(i_locator);
1043  break;
1044  case HEXED:
1045  res = get_hexed(i_locator);
1046  break;
1047  case SCALED_TO_HEX:
1048  res = get_scaled_to_hex(i_locator);
1049  break;
1050  case BRIGHTENED:
1051  res = get_brightened(i_locator);
1052  break;
1053  default:
1054  return res;
1055  }
1056 
1057  i_locator.add_to_cache(*imap, res);
1058 
1059  return res;
1060 }
1061 
1063 {
1064  surface res;
1065  if(i_locator.is_void()) {
1066  return res;
1067  }
1068 
1069  if(type == SCALED_TO_HEX && zoom == tile_size) {
1070  type = HEXED;
1071  }
1072 
1073  // select associated cache
1074  lit_cache* imap = &lit_images_;
1075  if(type == SCALED_TO_HEX) {
1076  imap = &lit_scaled_images_;
1077  }
1078 
1079  // if no light variants yet, need to add an empty map
1080  if(!i_locator.in_cache(*imap)) {
1081  i_locator.add_to_cache(*imap, lit_variants());
1082  }
1083 
1084  // need access to add it if not found
1085  { // enclose reference pointing to data stored in a changing vector
1086  const lit_variants& lvar = i_locator.locate_in_cache(*imap);
1087  auto lvi = lvar.find(ls);
1088  if(lvi != lvar.end()) {
1089  return lvi->second;
1090  }
1091  }
1092 
1093  // not cached yet, generate it
1094  switch(type) {
1095  case HEXED:
1096  res = get_image(i_locator, HEXED);
1097  res = apply_light(res, ls);
1098  break;
1099  case SCALED_TO_HEX:
1100  // we light before scaling to reuse the unscaled cache
1101  res = get_lighted_image(i_locator, ls, HEXED);
1102  res = scale_surface(res, zoom, zoom);
1103  break;
1104  default:
1105  break;
1106  }
1107 
1108  // record the lighted surface in the corresponding variants cache
1109  i_locator.access_in_cache(*imap)[ls] = res;
1110 
1111  return res;
1112 }
1113 
1115 {
1117  return get_image(terrain_mask, UNSCALED);
1118 }
1119 
1120 bool is_in_hex(const locator& i_locator)
1121 {
1122  bool result;
1123  {
1124  if(i_locator.in_cache(in_hex_info_)) {
1125  result = i_locator.locate_in_cache(in_hex_info_);
1126  } else {
1127  const surface image(get_image(i_locator, UNSCALED));
1128 
1129  bool res = in_mask_surface(image, get_hexmask());
1130 
1131  i_locator.add_to_cache(in_hex_info_, res);
1132 
1133  // std::cout << "in_hex : " << i_locator.get_filename()
1134  // << " " << (res ? "yes" : "no") << "\n";
1135 
1136  result = res;
1137  }
1138  }
1139 
1140  return result;
1141 }
1142 
1143 bool is_empty_hex(const locator& i_locator)
1144 {
1145  if(!i_locator.in_cache(is_empty_hex_)) {
1146  const surface surf = get_image(i_locator, HEXED);
1147  // emptiness of terrain image is checked during hex cut
1148  // so, maybe in cache now, let's recheck
1149  if(!i_locator.in_cache(is_empty_hex_)) {
1150  // should never reach here
1151  // but do it manually if it happens
1152  // assert(false);
1153  bool is_empty = false;
1154  mask_surface(surf, get_hexmask(), &is_empty);
1155  i_locator.add_to_cache(is_empty_hex_, is_empty);
1156  }
1157  }
1158 
1159  return i_locator.locate_in_cache(is_empty_hex_);
1160 }
1161 
1163 {
1164  if(surf == nullptr) {
1165  return surface(nullptr);
1166  }
1167 
1168  const auto itor = reversed_images_.find(surf);
1169  if(itor != reversed_images_.end()) {
1170  // sdl_add_ref(itor->second);
1171  return itor->second;
1172  }
1173 
1174  const surface rev(flip_surface(surf));
1175  if(rev == nullptr) {
1176  return surface(nullptr);
1177  }
1178 
1179  reversed_images_.emplace(surf, rev);
1180  // sdl_add_ref(rev);
1181  return rev;
1182 }
1183 
1184 bool exists(const image::locator& i_locator)
1185 {
1186  typedef image::locator loc;
1187  loc::type type = i_locator.get_type();
1188  if(type != loc::FILE && type != loc::SUB_FILE) {
1189  return false;
1190  }
1191 
1192  // The insertion will fail if there is already an element in the cache
1193  // and this will point to the existing element.
1194  auto iter = image_existence_map.begin();
1195  bool success;
1196 
1197  std::tie(iter, success) = image_existence_map.emplace(i_locator.get_filename(), false);
1198 
1199  bool& cache = iter->second;
1200  if(success) {
1201  if(i_locator.is_data_uri()) {
1202  cache = parsed_data_URI{i_locator.get_filename()}.good;
1203  } else {
1204  cache = !filesystem::get_binary_file_location("images", i_locator.get_filename()).empty();
1205  }
1206  }
1207 
1208  return cache;
1209 }
1210 
1211 static void precache_file_existence_internal(const std::string& dir, const std::string& subdir)
1212 {
1213  const std::string checked_dir = dir + "/" + subdir;
1214  if(precached_dirs.find(checked_dir) != precached_dirs.end()) {
1215  return;
1216  }
1217 
1218  precached_dirs.insert(checked_dir);
1219 
1220  if(!filesystem::is_directory(checked_dir)) {
1221  return;
1222  }
1223 
1224  std::vector<std::string> files_found;
1225  std::vector<std::string> dirs_found;
1226  filesystem::get_files_in_dir(checked_dir, &files_found, &dirs_found, filesystem::FILE_NAME_ONLY,
1228 
1229  for(const auto& f : files_found) {
1230  image_existence_map[subdir + f] = true;
1231  }
1232 
1233  for(const auto& d : dirs_found) {
1234  precache_file_existence_internal(dir, subdir + d + "/");
1235  }
1236 }
1237 
1238 void precache_file_existence(const std::string& subdir)
1239 {
1240  const std::vector<std::string>& paths = filesystem::get_binary_paths("images");
1241 
1242  for(const auto& p : paths) {
1244  }
1245 }
1246 
1247 bool precached_file_exists(const std::string& file)
1248 {
1249  const auto b = image_existence_map.find(file);
1250  if(b != image_existence_map.end()) {
1251  return b->second;
1252  }
1253 
1254  return false;
1255 }
1256 
1257 save_result save_image(const locator& i_locator, const std::string& filename)
1258 {
1259  return save_image(get_image(i_locator), filename);
1260 }
1261 
1262 save_result save_image(const surface& surf, const std::string& filename)
1263 {
1264  if(surf.null()) {
1265  return save_result::no_image;
1266  }
1267 
1268 #ifdef SDL_IMAGE_VERSION_ATLEAST
1269 #if SDL_IMAGE_VERSION_ATLEAST(2, 0, 2)
1270  if(filesystem::ends_with(filename, ".jpeg") || filesystem::ends_with(filename, ".jpg") || filesystem::ends_with(filename, ".jpe")) {
1271  LOG_DP << "Writing a JPG image to " << filename << std::endl;
1272 
1273  const int err = IMG_SaveJPG_RW(surf, filesystem::make_write_RWops(filename).release(), true, 75); // SDL takes ownership of the RWops
1274  return err == 0 ? save_result::success : save_result::save_failed;
1275  }
1276 #endif
1277 #endif
1278 
1279  if(filesystem::ends_with(filename, ".png")) {
1280  LOG_DP << "Writing a PNG image to " << filename << std::endl;
1281 
1282  const int err = IMG_SavePNG_RW(surf, filesystem::make_write_RWops(filename).release(), true); // SDL takes ownership of the RWops
1283  return err == 0 ? save_result::success : save_result::save_failed;
1284  }
1285 
1286  if(filesystem::ends_with(filename, ".bmp")) {
1287  LOG_DP << "Writing a BMP image to " << filename << std::endl;
1288  const int err = SDL_SaveBMP(surf, filename.c_str()) == 0;
1289  return err == 0 ? save_result::success : save_result::save_failed;
1290  }
1291 
1293 }
1294 
1296 {
1298  try {
1299  algo = SCALING_ALGORITHM::string_to_enum(preferences::get("scale_hex"));
1300  } catch(const bad_enum_cast&) {
1301  }
1302 
1303  scale_to_hex_func = select_algorithm(algo);
1304 
1306  try {
1307  algo = SCALING_ALGORITHM::string_to_enum(preferences::get("scale_zoom"));
1308  } catch(const bad_enum_cast&) {
1309  }
1310 
1311  scale_to_zoom_func = select_algorithm(algo);
1312 
1313  return true;
1314 }
1315 
1316 /*
1317  * TEXTURE INTERFACE ======================================================================
1318  *
1319  * I'm keeping this seperate from the surface-based handling above since the two approaches
1320  * are so different. Might move this to a file of its own in the future.
1321  */
1322 
1323 /** Sets the texture scale quality hint. Must be called *before* creating textures! */
1325 {
1326  static const std::string n_scale_str = "nearest";
1327  static const std::string l_scale_str = "linear";
1328 
1329  set_texture_scale_quality(quality == NEAREST ? n_scale_str : l_scale_str);
1330 }
1331 
1332 /** Loads a new texture directly from disk. */
1334 {
1335  texture res;
1336 
1337  // We need the window renderer to load the texture.
1338  SDL_Renderer* renderer = CVideo::get_singleton().get_renderer();
1339  if(!renderer) {
1340  return res;
1341  }
1342 
1343  std::string location = filesystem::get_binary_file_location("images", loc.get_filename());
1344 
1345  if(!location.empty()) {
1346 #if 0
1347  // Check if there is a localized image.
1348  const std::string loc_location = get_localized_path(location);
1349  if(!loc_location.empty()) {
1350  location = loc_location;
1351  }
1352 #endif
1353 
1354  // TODO: if we need to use SDL_RWops we should use IMG_LoadTexture_RW here instead.
1355  {
1356  res.assign(IMG_LoadTexture(renderer, location.c_str()));
1357  }
1358 
1359  // TODO: decide what to do about this.
1360 #if 0
1361  // If there was no standalone localized image, check if there is an overlay.
1362  if(!res.null() && loc_location.empty()) {
1363  const std::string ovr_location = get_localized_path(location, "--overlay");
1364  if(!ovr_location.empty()) {
1365  add_localized_overlay(ovr_location, res);
1366  }
1367  }
1368 #endif
1369  }
1370 
1371  if(res.null() && !loc.get_filename().empty()) {
1372  ERR_DP << "Could not load texture for image '" << loc.get_filename() << "'" << std::endl;
1373 
1374  // Also decide what to do here.
1375 #if 0
1378  }
1379 #endif
1380  }
1381 
1382  return res;
1383 }
1384 
1385 /**
1386  * Handle IPF manipulation. Since we don't have shaders yet, we need to use the surface
1387  * modification code for now. It appears each result is saved in the relevant cache,
1388  * so this should hopefully only result in a small slowdown when first processing the
1389  * results.
1390  */
1392 {
1394  if(surf == nullptr) {
1395  return texture();
1396  }
1397 
1399 
1400  while(!mods.empty()) {
1401  modification* mod = mods.top();
1402 
1403  try {
1404  surf = (*mod)(surf);
1405  } catch(const image::modification::imod_exception& e) {
1406  std::ostringstream ss;
1407  ss << "\n";
1408 
1409  for(const std::string& mod2 : utils::parenthetical_split(loc.get_modifications(), '~')) {
1410  ss << "\t" << mod2 << "\n";
1411  }
1412 
1413  ERR_CFG << "Failed to apply a modification to an image:\n"
1414  << "Image: " << loc.get_filename() << "\n"
1415  << "Modifications: " << ss.str() << "\n"
1416  << "Error: " << e.message << "\n";
1417  }
1418 
1419  // NOTE: do this *after* applying the mod or you'll get crashes!
1420  mods.pop();
1421  }
1422 
1423 #if 0
1424  if(loc.get_loc().valid()) {
1425  SDL_Rect srcrect = sdl::create_rect(
1426  ((tile_size * 3) / 4) * loc.get_loc().x,
1427  tile_size * loc.get_loc().y + (tile_size / 2) * (loc.get_loc().x % 2),
1428  tile_size,
1429  tile_size
1430  );
1431 
1432  if(loc.get_center_x() >= 0 && loc.get_center_y() >= 0) {
1433  srcrect.x += surf->w / 2 - loc.get_center_x();
1434  srcrect.y += surf->h / 2 - loc.get_center_y();
1435  }
1436 
1437  // cut and hex mask, but also check and cache if empty result
1438  surface cut(cut_surface(surf, srcrect));
1439  bool is_empty = false;
1440  surf = mask_surface(cut, get_hexmask(), &is_empty);
1441 
1442  // discard empty images to free memory
1443  if(is_empty) {
1444  // Safe because those images are only used by terrain rendering
1445  // and it filters them out.
1446  // A safer and more general way would be to keep only one copy of it
1447  surf = nullptr;
1448  }
1449 
1450  loc.add_to_cache(is_empty_hex_, is_empty);
1451  }
1452 #endif
1453 
1454  return texture(surf);
1455 }
1456 
1458 {
1459  switch(loc.get_type()) {
1460  case locator::FILE:
1461  return create_texture_from_file(loc);
1462  case locator::SUB_FILE:
1463  return create_texture_from_sub_file(loc);
1464  default:
1465  return texture();
1466  }
1467 }
1468 
1469 /**
1470  * Small wrapper for creating a texture after applying a specific type of surface op.
1471  * Won't be necessary once we get shader support.
1472  */
1474 {
1475  surface surf = get_image(i_locator, type);
1476  if(!surf) {
1477  return texture();
1478  }
1479 
1480  return texture(surf);
1481 }
1482 
1484 {
1485  return get_texture(i_locator, NEAREST, type);
1486 }
1487 
1488 /** Returns a texture for the corresponding image. */
1490 {
1491  texture res;
1492 
1493  if(i_locator.is_void()) {
1494  return res;
1495  }
1496 
1497  // FIXME
1498  //type = simplify_type(i_locator, type);
1499 
1500  //
1501  // Select the appropriate cache. We don't need caches for every single image types,
1502  // since some types can be handled by render-time operations.
1503  //
1504  texture_cache* cache = nullptr;
1505 
1506  switch(type) {
1507  case HEXED:
1508  cache = &textures_hexed_[quality];
1509  break;
1510  case TOD_COLORED:
1511  cache = &texture_tod_colored_[quality];
1512  break;
1513  default:
1514  cache = &textures_[quality];
1515  }
1516 
1517  //
1518  // Now attempt to find a cached texture. If found, return it.
1519  //
1520  bool in_cache = i_locator.in_cache(*cache);
1521 
1522  if(in_cache) {
1523  res = i_locator.locate_in_cache(*cache);
1524  return res;
1525  }
1526 
1527  //
1528  // No texture was cached. In that case, create a new one. The explicit cases require special
1529  // handling with surfaces in order to generate the desired effect. This shouldn't be the case
1530  // once we get OGL and shader support.
1531  //
1533 
1534  switch(type) {
1535  case TOD_COLORED:
1536  case HEXED:
1537  res = create_texture_post_surface_op(i_locator, type);
1538  break;
1539  default:
1540  res = create_texture_from_disk(i_locator);
1541  }
1542 
1543  // If the texture is null at this point, return without any further action (like caching).
1544  if(!res) {
1545  return res;
1546  }
1547 
1548  //
1549  // Apply the appropriate render flags. (TODO)
1550  //
1551 #if 0
1552  switch(type) {
1553  case SCALED_TO_ZOOM:
1554 
1555  break;
1556  case SCALED_TO_HEX:
1557 
1558  break;
1559  case BRIGHTENED:
1560 
1561  break;
1562  default:
1563  // Ignore other types.
1564  break;
1565  }
1566 #endif
1567 
1568  //
1569  // And finally add the texture to the cache.
1570  //
1571  i_locator.add_to_cache(*cache, res);
1572 
1573  return res;
1574 }
1575 
1576 } // end namespace image
constexpr const T & clamp(const T &value, const T &min, const T &max)
Definition: general.hpp:31
TYPE
UNSCALED : image will be drawn "as is" without changing size, even in case of redraw SCALED_TO_ZOOM :...
Definition: image.hpp:181
static surface load_image_file(const image::locator &loc)
Definition: image.cpp:592
surface get_image(const image::locator &i_locator, TYPE type)
function to get the surface corresponding to an image.
Definition: image.cpp:989
const std::string & get_modifications() const
Definition: image.hpp:91
preferences::SCALING_ALGORITHM SCALING_ALGORITHM
Definition: image.cpp:871
surface mask_surface(const surface &surf, const surface &mask, bool *empty_result, const std::string &filename)
Applies a mask on a surface.
Definition: utils.cpp:1222
int get_center_y() const
Definition: image.hpp:90
BOOST_CXX14_CONSTEXPR size_type find(basic_string_view s, size_type pos=0) const BOOST_NOEXCEPT
bool is_neutral(const surface &surf)
Check that the surface is neutral bpp 32.
Definition: utils.cpp:41
void precache_file_existence(const std::string &subdir)
precache the existence of files in the subdir (ex: "terrain/")
Definition: image.cpp:1238
static surface scale_xbrz_helper(const surface &res, int w, int h)
Definition: image.cpp:864
map_location loc_
Definition: image.hpp:57
void add_to_cache(cache_type< T > &cache, const T &data) const
Definition: image.cpp:150
std::string filename_
Definition: image.hpp:56
surface flip_surface(const surface &surf)
Definition: utils.cpp:2042
value val_
Definition: image.hpp:123
void init_index()
Definition: image.cpp:276
int dummy
Definition: lstrlib.cpp:1125
const SCALING_ALGORITHM default_scaling_algorithm
Definition: general.cpp:76
surface scale_surface(const surface &surf, int w, int h)
Scale a surface using alpha-weighted modified bilinear filtering Note: causes artifacts with alpha gr...
Definition: utils.cpp:275
bool in_mask_surface(const surface &surf, const surface &mask)
Check if a surface fit into a mask.
Definition: utils.cpp:1291
static surface get_scaled_to_hex(const locator &i_locator)
Definition: image.cpp:908
static surface get_hexed(const locator &i_locator)
Definition: image.cpp:898
static bool file_exists(const fs::path &fpath)
Definition: filesystem.cpp:300
bool precached_file_exists(const std::string &file)
Definition: image.cpp:1247
save_result
Definition: image.hpp:221
surface reverse_image(const surface &surf)
function to reverse an image.
Definition: image.cpp:1162
static std::string get_localized_path(const std::string &file, const std::string &suff="")
Definition: image.cpp:527
SCALE_QUALITY
Definition: image.hpp:183
#define a
static texture create_texture_from_file(const image::locator &loc)
Loads a new texture directly from disk.
Definition: image.cpp:1333
A modified priority queue used to order image modifications.
bool ends_with(const std::string &str, const std::string &suffix)
mini_terrain_cache_map mini_fogged_terrain_cache
Definition: image.cpp:245
static surface load_image_data_uri(const image::locator &loc)
Definition: image.cpp:694
cache_item< T > & get_element(int index)
Definition: image.cpp:113
rwops_ptr make_read_RWops(const std::string &path)
#define val_(o)
Definition: lobject.h:123
surface surf
Image.
static signed char col_to_uchar(int i)
Definition: image.cpp:725
static void standardize_surface_format(surface &surf)
Definition: image.cpp:568
BOOST_CXX14_CONSTEXPR basic_string_view substr(size_type pos, size_type n=npos) const
texture create_texture_from_disk(const locator &loc)
Definition: image.cpp:1457
#define LOG_DP
Definition: image.cpp:50
save_result save_image(const locator &i_locator, const std::string &filename)
Definition: image.cpp:1257
#define ERR_CFG
Definition: image.cpp:53
T & access_in_cache(cache_type< T > &cache) const
Definition: image.cpp:143
static CVideo & get_singleton()
Definition: video.hpp:48
STL namespace.
#define h
void parse_arguments()
Definition: image.cpp:288
static surface get_scaled_to_zoom(const locator &i_locator)
Definition: image.cpp:927
std::map< t_translation::terrain_code, surface > mini_terrain_cache_map
Definition: image.hpp:133
std::string get_binary_file_location(const std::string &type, const std::string &filename)
Returns a complete path to the actual file of a given type or an empty string if the file isn&#39;t prese...
type get_type() const
Definition: image.hpp:92
#define d
Definitions for the interface to Wesnoth Markup Language (WML).
std::vector< std::string > split(const std::string &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
surface cut_surface(const surface &surf, const SDL_Rect &r)
Cuts a rectangle from a surface.
Definition: utils.cpp:1747
Wrapper class to encapsulate creation and management of an SDL_Texture.
Definition: texture.hpp:26
std::string terrain_mask
bool null() const
Definition: surface.hpp:79
void flush_cache()
Definition: image.cpp:250
static std::set< std::string > fuzzy_localized_files
Definition: image.cpp:485
std::string filename_
Definition: action_wml.cpp:555
map_location loc_
#define b
static TYPE simplify_type(const image::locator &i_locator, TYPE type)
translate type to a simpler one when possible
Definition: image.cpp:948
bool exists(const image::locator &i_locator)
returns true if the given image actually exists, without loading it.
Definition: image.cpp:1184
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:89
const T & locate_in_cache(cache_type< T > &cache) const
Definition: image.cpp:136
surface adjust_surface_color(const surface &surf, int red, int green, int blue)
Definition: utils.cpp:684
std::string get(const std::string &key)
Definition: general.cpp:230
static void set_scale_quality_pre_texture_creation(SCALE_QUALITY quality)
Sets the texture scale quality hint.
Definition: image.cpp:1324
static surface get_brightened(const locator &i_locator)
Definition: image.cpp:941
static surface load_image_sub_file(const image::locator &loc)
Definition: image.cpp:630
rwops_ptr make_write_RWops(const std::string &path)
bool null() const
Definition: texture.hpp:79
static surface get_tod_colored(const locator &i_locator)
Definition: image.cpp:921
light_string get_light_string(int op, int r, int g, int b)
return light_string of one light operation(see above)
Definition: image.cpp:730
std::string modifications_
Definition: image.hpp:58
static int last_index_
Definition: image.cpp:248
bool valid() const
Definition: location.hpp:93
std::unordered_map< value, int > locator_finder_t
Definition: image.hpp:67
static texture create_texture_post_surface_op(const image::locator &i_locator, TYPE type)
Small wrapper for creating a texture after applying a specific type of surface op.
Definition: image.cpp:1473
static texture create_texture_from_sub_file(const image::locator &loc)
Handle IPF manipulation.
Definition: image.cpp:1391
bool is_directory(const std::string &fname)
Returns true if the given file is a directory.
Definition: filesystem.cpp:984
void set_zoom(unsigned int amount)
sets the amount scaled images should be scaled.
Definition: image.cpp:842
std::map< light_string, surface > lit_variants
Definition: image.hpp:151
void set_texture_scale_quality(const std::string &value)
Sets the texture scale quality.
std::string path
Definition: game_config.cpp:39
std::vector< cache_item< T > > content_
Definition: image.cpp:126
map_display and display: classes which take care of displaying the map and game-data on the screen...
Base abstract class for an image-path modification.
std::string read_file(const std::string &fname)
Basic disk I/O - read file.
Definition: filesystem.cpp:886
static void precache_file_existence_internal(const std::string &dir, const std::string &subdir)
Definition: image.cpp:1211
static modification_queue decode(const std::string &)
Decodes modifications from a modification string.
surface light_surface(const surface &surf, const surface &lightmap)
Light surf using lightmap.
Definition: utils.cpp:1399
void set_color_adjustment(int r, int g, int b)
will make all scaled images have these rgb values added to all their pixels.
Definition: image.cpp:828
std::size_t operator()(const image::locator::value &val) const
Definition: image.cpp:81
#define ftofxp(x)
IN: float or int - OUT: fixed_t.
Definition: math.hpp:297
Encapsulates the map of the game.
Definition: location.hpp:42
std::vector< uint8_t > decode(utils::string_view in)
Definition: base64.cpp:215
surface load_from_disk(const locator &loc)
Definition: image.cpp:803
surface brighten_image(const surface &surf, fixed_t amount)
Definition: utils.cpp:1133
const std::vector< std::string > & get_binary_paths(const std::string &type)
Returns a vector with all possible paths to a given type of binary, e.g.
surface make_neutral_surface(const surface &surf)
Definition: utils.cpp:73
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs, file_name_option mode, file_filter_option filter, file_reorder_option reorder, file_tree_checksum *checksum)
Populates &#39;files&#39; with all the files and &#39;dirs&#39; with all the directories in dir.
Definition: filesystem.cpp:386
std::size_t i
Definition: function.cpp:933
logger & err()
Definition: log.cpp:78
cache_item()
Definition: image.cpp:60
#define ERR_DP
Definition: image.cpp:49
mock_party p
locator & operator=(const locator &a)
Definition: image.cpp:369
double g
Definition: astarsearch.cpp:63
surface get_hexmask()
function to get the standard hex mask
Definition: image.cpp:1114
std::basic_string< signed char > light_string
light_string store colors info of central and adjacent hexes.
Definition: image.hpp:146
void sdl_blit(const surface &src, SDL_Rect *src_rect, surface &dst, SDL_Rect *dst_rect)
Definition: utils.hpp:33
mini_terrain_cache_map mini_highlighted_terrain_cache
Definition: image.cpp:246
int get_center_x() const
Definition: image.hpp:89
Declarations for File-IO.
int w
std::unique_ptr< SDL_RWops, void(*)(SDL_RWops *)> rwops_ptr
Definition: filesystem.hpp:42
const bool & debug
const std::string & get_filename() const
Definition: image.hpp:86
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:71
bool is_in_hex(const locator &i_locator)
function to check if an image fit into an hex return false if the image has not the standard size...
Definition: image.cpp:1120
bool is_data_uri() const
Definition: image.hpp:87
bool operator<(const value &a) const
Definition: image.cpp:461
static bool localized_file_uptodate(const std::string &loc_file)
Definition: image.cpp:486
mini_terrain_cache_map mini_terrain_cache
Definition: image.cpp:244
cache_item(const T &item)
Definition: image.cpp:66
std::string base_name(const std::string &file, const bool remove_extension)
Returns the base filename of a file, with directory name stripped.
surface get_lighted_image(const image::locator &i_locator, const light_string &ls, TYPE type)
function to get the surface corresponding to an image.
Definition: image.cpp:1062
SDL_Rect create_rect(const int x, const int y, const int w, const int h)
Creates an SDL_Rect with the given dimensions.
Definition: rect.hpp:39
surface scale_surface_nn(const surface &surf, int w, int h)
Scale a surface using the nearest neighbor algorithm (provided by xBRZ lib)
Definition: utils.cpp:235
const std::vector< std::string > & modifications(bool mp)
Definition: game.cpp:729
Contains the SDL_Rect helper code.
#define f
const map_location & get_loc() const
Definition: image.hpp:88
unsigned int tile_size
Definition: game_config.cpp:67
bool is_empty_hex(const locator &i_locator)
function to check if an image is empty after hex cut should be only used on terrain image (cache the ...
Definition: image.cpp:1143
static void add_localized_overlay(const std::string &ovr_file, surface &orig_surf)
Definition: image.cpp:577
static scaling_function select_algorithm(SCALING_ALGORITHM algo)
Definition: image.cpp:873
void assign(SDL_Texture *t)
Replaces ownership of the managed texture with the given one.
Definition: texture.cpp:99
this module manages the cache of images.
Definition: image.cpp:102
Standard logging facilities (interface).
double hex_brightening
Definition: game_config.cpp:79
modification * top() const
Returns the top element in the queue .
static lg::log_domain log_config("config")
bool operator==(const value &a) const
Definition: image.cpp:447
#define e
void pop()
Removes the top element from the queue.
bool update_from_preferences()
initialize any private data, e.g. algorithm choices from preferences
Definition: image.cpp:1295
bool is_void() const
Definition: image.hpp:97
mock_char c
bool in_cache(cache_type< T > &cache) const
Definition: image.cpp:130
surface scale_surface_xbrz(const surface &surf, std::size_t z)
Scale a surface using xBRZ algorithm.
Definition: utils.cpp:196
SDL_Renderer * get_renderer()
Returns a pointer to the underlying window&#39;s renderer.
Definition: video.cpp:323
Exception thrown by the operator() when an error occurs.
bool file_exists() const
Tests whether the file the locater points at exists.
Definition: image.cpp:796
static lg::log_domain log_display("display")
static surface apply_light(surface surf, const light_string &ls)
Definition: image.cpp:742
std::string directory_name(const std::string &file)
Returns the directory name of a file, with filename stripped.
texture get_texture(const image::locator &i_locator, TYPE type)
Definition: image.cpp:1483
std::vector< std::string > parenthetical_split(const std::string &val, const char separator, const std::string &left, const std::string &right, const int flags)
Splits a string based either on a separator, except then the text appears within specified parenthesi...
const std::string message
The error message regarding the failed operation.
bool loaded
Definition: image.cpp:73