35 #include <SDL2/SDL_image.h> 39 #include <boost/algorithm/string.hpp> 40 #include <boost/functional/hash_fwd.hpp> 46 #define ERR_IMG LOG_STREAM(err, log_image) 47 #define WRN_IMG LOG_STREAM(warn, log_image) 48 #define LOG_IMG LOG_STREAM(info, log_image) 49 #define DBG_IMG LOG_STREAM(debug, log_image) 52 #define ERR_CFG LOG_STREAM(err, log_config) 78 struct hash<
image::locator::value>
82 std::size_t hash = std::hash<unsigned>{}(val.
type_);
89 boost::hash_combine(hash, val.
loc_.
x);
90 boost::hash_combine(hash, val.
loc_.
y);
114 if(static_cast<unsigned>(index) >= content_.size())
115 content_.resize(index + 1);
116 return content_[
index];
131 return index_ < 0 ? false : cache.
get_element(index_).loaded;
138 return index_ < 0 ? dummy : cache.
get_element(index_).item;
145 return index_ < 0 ? dummy : cache.
get_element(index_).item;
161 std::array<surface_cache, NUM_TYPES> surfaces_;
167 using texture_cache_map = std::map<image::scale_quality, image::texture_cache>;
169 texture_cache_map textures_;
170 texture_cache_map textures_hexed_;
171 texture_cache_map texture_tod_colored_;
187 std::array<bool_cache, NUM_TYPES> skipped_cache_;
188 int duplicate_loads_ = 0;
189 int total_loads_ = 0;
193 std::map<std::string, bool> image_existence_map;
196 std::set<std::string> precached_dirs;
198 int red_adjust = 0, green_adjust = 0, blue_adjust = 0;
200 const std::string data_uri_prefix =
"data:";
201 struct parsed_data_URI{
202 explicit parsed_data_URI(std::string_view data_URI);
209 parsed_data_URI::parsed_data_URI(std::string_view data_URI)
211 const std::size_t colon = data_URI.find(
':');
212 const std::string_view after_scheme = data_URI.substr(colon + 1);
214 const std::size_t comma = after_scheme.find(
',');
215 const std::string_view type_info = after_scheme.substr(0, comma);
217 const std::size_t semicolon = type_info.find(
';');
219 scheme = data_URI.substr(0, colon);
220 base64 = type_info.substr(semicolon + 1);
221 mime = type_info.substr(0, semicolon);
222 data = after_scheme.substr(comma + 1);
239 lit_surfaces_.flush();
240 lit_textures_.flush();
241 surface_lightmaps_.clear();
242 texture_lightmaps_.clear();
243 in_hex_info_.flush();
244 is_empty_hex_.flush();
246 textures_hexed_.clear();
247 texture_tod_colored_.clear();
248 mini_terrain_cache.clear();
249 mini_fogged_terrain_cache.clear();
250 mini_highlighted_terrain_cache.clear();
251 image_existence_map.clear();
252 precached_dirs.clear();
259 void locator::init_index()
261 auto i = locator_finder.find(val_);
263 if(
i == locator_finder.end()) {
264 index_ = last_index_++;
265 locator_finder.emplace(val_, index_);
271 void locator::parse_arguments()
273 std::string& fn = val_.filename_;
278 if(boost::algorithm::starts_with(fn, data_uri_prefix)) {
279 parsed_data_URI parsed{fn};
282 std::string_view view{ fn };
283 std::string_view stripped = view.substr(0, view.find(
","));
284 ERR_IMG <<
"Invalid data URI: " << stripped;
287 val_.is_data_uri_ =
true;
290 std::size_t markup_field = fn.find(
'~');
292 if(markup_field != std::string::npos) {
293 val_.type_ = SUB_FILE;
294 val_.modifications_ = fn.substr(markup_field, fn.size() - markup_field);
295 fn = fn.substr(0, markup_field);
336 ,
val_(filename, modifications)
343 ,
val_(filename, modifications)
354 ,
val_(filename, loc, center_x, center_y, modifications)
381 , is_data_uri_(false)
488 surface ovr_surf = IMG_Load_RW(rwops.release(),
true);
493 SDL_Rect area {0, 0, ovr_surf->w, ovr_surf->h};
495 sdl_blit(ovr_surf, 0, orig_surf, &area);
509 std::string webp_name = name.substr(0, name.size() - 4) +
".webp";
511 if(!location.empty()) {
512 WRN_IMG <<
"Replaced missing '" << name <<
"' with found '" 513 << webp_name <<
"'.";
518 if(!location.empty()) {
521 if(!loc_location.empty()) {
522 location = loc_location;
526 res = IMG_Load_RW(rwops.release(),
true);
529 if(res && loc_location.empty()) {
531 if(!ovr_location.empty()) {
538 if(!res && !name.empty()) {
539 ERR_IMG <<
"could not open image '" << name <<
"'";
552 if(surf ==
nullptr) {
558 while(!mods.
empty()) {
564 std::ostringstream ss;
568 ss <<
"\t" << mod_name <<
"\n";
571 ERR_CFG <<
"Failed to apply a modification to an image:\n" 573 <<
"Modifications: " << ss.str() <<
"\n" 596 bool is_empty =
false;
621 std::string_view stripped = fn.substr(0, fn.find(
","));
622 ERR_IMG <<
"Invalid data URI: " << stripped;
623 }
else if(parsed.mime.substr(0, 5) !=
"image") {
624 ERR_IMG <<
"Data URI not of image MIME type: " << parsed.mime;
626 const std::vector<uint8_t> image_data =
base64::decode(parsed.data);
629 if(image_data.empty()) {
630 ERR_IMG <<
"Invalid encoding in data URI";
631 }
else if(parsed.mime ==
"image/png") {
632 surf = IMG_LoadTyped_RW(rwops.release(),
true,
"PNG");
633 }
else if(parsed.mime ==
"image/jpeg") {
634 surf = IMG_LoadTyped_RW(rwops.release(),
true,
"JPG");
636 ERR_IMG <<
"Invalid image MIME type: " << parsed.mime;
646 return static_cast<signed char>(std::min<int>(127, std::max<int>(-128, i / 2)));
667 int m = ls[0] == -1 ? 2 : 1;
673 auto i = surface_lightmaps_.find(ls);
674 if(
i != surface_lightmaps_.end()) {
675 lightmap =
i->second;
678 static const std::string
p =
"terrain/light/light";
679 static const std::string lm_img[19] {
681 p +
"-concave-2-tr.png", p +
"-concave-2-r.png", p +
"-concave-2-br.png",
682 p +
"-concave-2-bl.png", p +
"-concave-2-l.png", p +
"-concave-2-tl.png",
683 p +
"-convex-br-bl.png", p +
"-convex-bl-l.png", p +
"-convex-l-tl.png",
684 p +
"-convex-tl-tr.png", p +
"-convex-tr-r.png", p +
"-convex-r-br.png",
685 p +
"-convex-l-bl.png", p +
"-convex-tl-l.png", p +
"-convex-tr-tl.png",
686 p +
"-convex-r-tr.png", p +
"-convex-br-r.png", p +
"-convex-bl-br.png" 690 for(std::size_t
c = 0;
c + 3 < ls.size();
c += 4) {
699 if(lightmap ==
nullptr) {
701 lightmap = lts.
clone();
703 sdl_blit(lts,
nullptr, lightmap,
nullptr);
708 surface_lightmaps_[ls] = lightmap;
749 if(r != red_adjust || g != green_adjust || b != blue_adjust) {
754 lit_surfaces_.flush();
755 lit_textures_.flush();
756 texture_tod_colored_.clear();
766 if(image && (image->w != mask->w || image->h != mask->h)) {
767 DBG_IMG <<
"adjusting [" << image->w <<
',' << image->h <<
']' 768 <<
" image to hex mask: " << i_locator;
772 if(image->w > mask->w || image->h >= mask->h) {
775 SDL_MapRGBA(fit->format, 0, 0, 0, 0)
778 int cutx = std::max(0, image->w - mask->w) / 2;
779 int cuty = std::max(0, image->h - mask->h) / 2;
780 int cutw = std::min(image->w, mask->w);
781 int cuth = std::min(image->h, mask->h);
782 image =
cut_surface(image, {cutx, cuty, cutw, cuth});
786 int placex = (mask->w - image->w) / 2;
787 int placey = (mask->h - image->h) / 2;
788 rect dst = {placex, placey, image->w, image->h};
789 sdl_blit(image,
nullptr, fit, &dst);
793 bool is_empty =
false;
809 if(red_adjust == 0 && green_adjust == 0 && blue_adjust == 0) {
839 WRN_IMG <<
"get_surface called with unknown image type";
849 DBG_IMG <<
"surface cache [" << type <<
"] miss: " << i_locator;
864 throw game::error(
"get_surface somehow lost image type?");
868 if(i_locator.in_cache(skip) && i_locator.locate_in_cache(skip))
870 DBG_IMG <<
"duplicate load: " << i_locator
871 <<
" [" << type <<
"]" 872 <<
" (" << duplicate_loads_ <<
"/" << total_loads_ <<
" total)";
878 DBG_IMG <<
"surface cache [" << type <<
"] skip: " << i_locator;
879 i_locator.add_to_cache(skip,
true);
881 i_locator.add_to_cache(imap, res);
905 auto lvi = lvar.find(ls);
906 if(lvi != lvar.end()) {
911 DBG_IMG <<
"lit surface cache miss: " << i_locator;
918 i_locator.access_in_cache(*imap)[ls] = res;
942 auto lvi = lvar.find(ls);
943 if(lvi != lvar.end()) {
948 DBG_IMG <<
"lit texture cache miss: " << i_locator;
954 i_locator.access_in_cache(*imap)[ls] = tex;
979 if(i_locator.
in_cache(in_hex_info_)) {
1000 if(!i_locator.
in_cache(is_empty_hex_)) {
1004 if(!i_locator.
in_cache(is_empty_hex_)) {
1008 bool is_empty =
false;
1021 if(type != loc::FILE && type != loc::SUB_FILE) {
1029 bool& cache = iter->second;
1032 cache = parsed_data_URI{i_locator.
get_filename()}.good;
1043 const std::string checked_dir = dir +
"/" + subdir;
1044 if(precached_dirs.find(checked_dir) != precached_dirs.end()) {
1048 precached_dirs.insert(checked_dir);
1054 std::vector<std::string> files_found;
1055 std::vector<std::string> dirs_found;
1059 for(
const auto&
f : files_found) {
1060 image_existence_map[subdir +
f] =
true;
1063 for(
const auto&
d : dirs_found) {
1072 for(
const auto&
p : paths) {
1079 const auto b = image_existence_map.find(file);
1080 if(
b != image_existence_map.end()) {
1099 LOG_IMG <<
"Writing a JPG image to " << filename;
1106 LOG_IMG <<
"Writing a PNG image to " << filename;
1147 cache = &textures_hexed_[quality];
1150 cache = &texture_tod_colored_[quality];
1153 cache = &textures_[quality];
1166 DBG_IMG <<
"texture cache [" << type <<
"] miss: " << i_locator;
1176 if(i_locator.get_modifications().empty()) {
1185 DBG_IMG <<
"texture cache [" << type <<
"] skip: " << i_locator;
1187 i_locator.add_to_cache(*cache, res);
TYPE
Used to specify the rendering format of images.
static surface load_image_file(const image::locator &loc)
const std::string & get_modifications() const
void sdl_blit(const surface &src, const SDL_Rect *src_rect, surface &dst, SDL_Rect *dst_rect)
static surface get_hexed(const locator &i_locator, bool skip_cache=false)
void precache_file_existence(const std::string &subdir)
Precache the existence of files in a binary path subdirectory (e.g.
void add_to_cache(cache_type< T > &cache, const T &data) const
surface adjust_surface_color(const surface &surf, int red, int green, int blue)
bool precached_file_exists(const std::string &file)
static surface load_from_disk(const locator &loc)
A modified priority queue used to order image modifications.
bool ends_with(const std::string &str, const std::string &suffix)
surface get_surface(const image::locator &i_locator, TYPE type, bool skip_cache)
Returns an image surface suitable for software manipulation.
mini_terrain_cache_map mini_fogged_terrain_cache
static surface load_image_data_uri(const image::locator &loc)
cache_item< T > & get_element(int index)
rwops_ptr make_read_RWops(const std::string &path)
static signed char col_to_uchar(int i)
void fill_surface_rect(surface &dst, SDL_Rect *dst_rect, const uint32_t color)
Fill a rectangle on a given surface.
std::map< light_string, surface > lit_surface_variants
Type used to pair light possibilities with the corresponding lit surface.
save_result save_image(const locator &i_locator, const std::string &filename)
bool in_mask_surface(const surface &surf, const surface &mask)
Check if a surface fit into a mask.
std::map< t_translation::terrain_code, surface > mini_terrain_cache_map
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't prese...
Standard hexagonal tile mask applied, removing portions that don't fit.
point get_size(const locator &i_locator, bool skip_cache)
Returns the width and height of an image.
Definitions for the interface to Wesnoth Markup Language (WML).
Same as HEXED, but with Time of Day color tint applied.
surface clone() const
Makes a copy of this surface.
Wrapper class to encapsulate creation and management of an SDL_Texture.
void flush_cache()
Purges all image caches.
static TYPE simplify_type(const image::locator &i_locator, TYPE type)
translate type to a simpler one when possible
bool exists(const image::locator &i_locator)
Returns true if the given image actually exists, without loading it.
surface mask_surface(const surface &surf, const surface &mask, bool *empty_result, const std::string &filename)
Applies a mask on a surface.
const T & locate_in_cache(cache_type< T > &cache) const
static surface load_image_sub_file(const image::locator &loc)
rwops_ptr make_write_RWops(const std::string &path)
light_string get_light_string(int op, int r, int g, int b)
Returns the light_string for one light operation.
std::string modifications_
std::ostream & operator<<(std::ostream &s, const locator &l)
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs, name_mode mode, filter_mode filter, reorder_mode reorder, file_tree_checksum *checksum)
Get a list of all files and/or directories in a given directory.
std::unordered_map< value, int > locator_finder_t
std::map< light_string, texture > lit_texture_variants
bool is_directory(const std::string &fname)
Returns true if the given file is a directory.
std::vector< cache_item< T > > content_
surface cut_surface(const surface &surf, const SDL_Rect &r)
Cuts a rectangle from a surface.
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.
static void precache_file_existence_internal(const std::string &dir, const std::string &subdir)
Generic locator abstracting the location of an image.
static modification_queue decode(const std::string &)
Decodes modifications from a modification string.
void set_color_adjustment(int r, int g, int b)
Changes Time of Day color tint for all applicable image types.
std::size_t operator()(const image::locator::value &val) const
Encapsulates the map of the game.
surface get_lighted_image(const image::locator &i_locator, const light_string &ls)
Caches and returns an image with a lightmap applied to it.
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.
std::vector< uint8_t > decode(std::string_view in)
static map_location::DIRECTION s
static lg::log_domain log_config("config")
locator & operator=(const locator &a)
surface get_hexmask()
Retrieves the standard hexagonal tile mask.
std::basic_string< signed char > light_string
Type used to store color information of central and adjacent hexes.
An abstract description of a rectangle with integer coordinates.
mini_terrain_cache_map mini_highlighted_terrain_cache
Declarations for File-IO.
std::unique_ptr< SDL_RWops, void(*)(SDL_RWops *)> rwops_ptr
std::string get_localized_path(const std::string &file, const std::string &suff)
Returns the localized version of the given filename, if it exists.
const std::string & get_filename() const
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.
static lg::log_domain log_image("image")
bool is_in_hex(const locator &i_locator)
Checks if an image fits into a single hex.
bool operator<(const value &a) const
surface light_surface(const surface &surf, const surface &lightmap)
Light surf using lightmap.
mini_terrain_cache_map mini_terrain_cache
cache_item(const T &item)
const std::vector< std::string > & modifications(bool mp)
Contains the SDL_Rect helper code.
texture get_lighted_texture(const image::locator &i_locator, const light_string &ls)
const map_location & get_loc() const
Base class for all the errors encountered by the engine.
bool is_empty_hex(const locator &i_locator)
Checks if an image is empty after hex masking.
static void add_localized_overlay(const std::string &ovr_file, surface &orig_surf)
Functions to load and save images from/to disk.
Standard logging facilities (interface).
modification * top() const
Returns the top element in the queue .
static surface get_tod_colored(const locator &i_locator, bool skip_cache=false)
bool operator==(const value &a) const
void pop()
Removes the top element from the queue.
bool is_void() const
Returns true if the locator does not correspond to an actual image.
texture get_texture(const image::locator &i_locator, TYPE type, bool skip_cache)
Returns an image texture suitable for hardware-accelerated rendering.
bool in_cache(cache_type< T > &cache) const
Unmodified original-size image.
Exception thrown by the operator() when an error occurs.
bool file_exists() const
Tests whether the file the locator points at exists.
static surface apply_light(surface surf, const light_string &ls)
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.