The Battle for Wesnoth  1.15.0-dev
image_modifications.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2018 by Iris Morelle <shadowm2006@gmail.com>
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 #include "image_modifications.hpp"
16 
17 #include "color.hpp"
18 #include "config.hpp"
19 #include "game_config.hpp"
20 #include "picture.hpp"
21 #include "lexical_cast.hpp"
22 #include "log.hpp"
24 
25 #include "formula/formula.hpp"
26 #include "formula/callable.hpp"
27 
28 #define GETTEXT_DOMAIN "wesnoth-lib"
29 
30 static lg::log_domain log_display("display");
31 #define ERR_DP LOG_STREAM(err, log_display)
32 
33 namespace image {
34 
35 /** Adds @a mod to the queue (unless mod is nullptr). */
37 {
38  // Null pointers do not get stored. (Shouldn't happen, but just in case.)
39  if(mod != nullptr) {
40  priorities_[mod->priority()].emplace_back(mod);
41  }
42 }
43 
44 /** Removes the top element from the queue */
46 {
47  map_type::iterator top_pair = priorities_.begin();
48  auto& top_vector = top_pair->second;
49 
50  // Erase the top element.
51  top_vector.erase(top_vector.begin());
52  if(top_vector.empty()) {
53  // We need to keep the map clean.
54  priorities_.erase(top_pair);
55  }
56 }
57 
58 /** Returns the number of elements in the queue. */
59 std::size_t modification_queue::size() const
60 {
61  std::size_t count = 0;
62  for(const map_type::value_type& pair : priorities_) {
63  count += pair.second.size();
64  }
65 
66  return count;
67 }
68 
69 /** Returns the top element in the queue . */
71 {
72  return priorities_.begin()->second.front().get();
73 }
74 
75 
76 namespace {
77 
78 /// A function used to parse modification arguments
79 using mod_parser = std::function<modification*(const std::string&)>;
80 
81 /** A map of all registered mod parsers
82  *
83  * The mapping is between the modification name and the parser function pointer
84  * An example of an entry would be "TC" -> &parse_TC_mod
85  */
86 std::map<std::string, mod_parser> mod_parsers;
87 
88 /** Decodes a single modification using an appropriate mod_parser
89  *
90  * @param encoded_mod A string representing a single modification
91  *
92  * @return A pointer to the decoded modification object
93  * @retval nullptr if the string is invalid or a parser isn't found
94  */
95 modification* decode_modification(const std::string& encoded_mod)
96 {
97  std::vector<std::string> split = utils::parenthetical_split(encoded_mod);
98 
99  if(split.size() != 2) {
100  ERR_DP << "error parsing image modifications: " << encoded_mod << "\n";
101  return nullptr;
102  }
103 
104  std::string mod_type = split[0];
105  std::string args = split[1];
106 
107  if(mod_parsers.find(mod_type) == mod_parsers.end()) {
108  ERR_DP << "unknown image function in path: " << mod_type << '\n';
109  return nullptr;
110  }
111 
112  return mod_parsers[mod_type](args);
113 }
114 
115 } // end anon namespace
116 
117 
118 modification::imod_exception::imod_exception(const std::stringstream& message_stream)
119  : message(message_stream.str())
120 {
121 }
122 
124  : message(message)
125 {
126 }
127 
128 /** Decodes the modification string
129  *
130  * Important:
131  * It creates new objects which need to be deleted after use
132  *
133  * @param encoded_mods A string representing any number of modifications
134  *
135  * @return A modification_queue filled with decoded modification pointers
136  */
137 modification_queue modification::decode(const std::string& encoded_mods)
138 {
139  modification_queue mods;
140 
141  for(const std::string& encoded_mod : utils::parenthetical_split(encoded_mods, '~')) {
142  modification* mod = decode_modification(encoded_mod);
143 
144  if(mod) {
145  mods.push(mod);
146  }
147  }
148 
149  return mods;
150 }
151 
153 {
154  // unchecked
155  return recolor_image(src, rc_map_);
156 }
157 
159 {
160  surface ret = src;
161 
162  if(horiz_ && vert_ ) {
163  // Slightly faster than doing both a flip and a flop.
164  ret = rotate_180_surface(ret);
165  } else if(horiz_) {
166  ret = flip_surface(ret);
167  } else if(vert_) {
168  ret = flop_surface(ret);
169  }
170 
171  return ret;
172 }
173 
175 {
176  // Convert the number of degrees to the interval [0,360].
177  const int normalized = degrees_ >= 0 ?
178  degrees_ - 360 * (degrees_ / 360) :
179  degrees_ + 360 * (1 + (-degrees_) / 360); // In case compilers disagree as to what -90/360 is.
180 
181  switch ( normalized )
182  {
183  case 0: return src;
184  case 90: return rotate_90_surface(src, true);
185  case 180: return rotate_180_surface(src);
186  case 270: return rotate_90_surface(src, false);
187  case 360: return src;
188  }
189 
190  return rotate_any_surface(src, normalized, zoom_, offset_);
191 }
192 
194 {
195  return greyscale_image(src);
196 }
197 
199 {
200  return monochrome_image(src, threshold_);
201 }
202 
204 {
205  return sepia_image(src);
206 }
207 
209 {
210  return negative_image(src, red_, green_, blue_);
211 }
212 
214 {
215  return alpha_to_greyscale(src);
216 }
217 
219 {
220  return wipe_alpha(src);
221 }
222 
223 // TODO: Is this useful enough to move into formula/callable_objects?
225 {
226 public:
227  pixel_callable(SDL_Point p, color_t clr, uint32_t w, uint32_t h)
228  : p(p), clr(clr), w(w), h(h)
229  {}
230 
231  void get_inputs(wfl::formula_input_vector& inputs) const override
232  {
233  add_input(inputs, "x");
234  add_input(inputs, "y");
235  add_input(inputs, "u");
236  add_input(inputs, "v");
237  add_input(inputs, "red");
238  add_input(inputs, "green");
239  add_input(inputs, "blue");
240  add_input(inputs, "alpha");
241  add_input(inputs, "height");
242  add_input(inputs, "width");
243  }
244 
245  wfl::variant get_value(const std::string& key) const override
246  {
247  using wfl::variant;
248  if(key == "x") {
249  return variant(p.x);
250  } else if(key == "y") {
251  return variant(p.y);
252  } else if(key == "red") {
253  return variant(clr.r);
254  } else if(key == "green") {
255  return variant(clr.g);
256  } else if(key == "blue") {
257  return variant(clr.b);
258  } else if(key == "alpha") {
259  return variant(clr.a);
260  } else if(key == "width") {
261  return variant(w);
262  } else if(key == "height") {
263  return variant(h);
264  } else if(key == "u") {
265  return variant(p.x / static_cast<float>(w));
266  } else if(key == "v") {
267  return variant(p.y / static_cast<float>(h));
268  }
269 
270  return variant();
271  }
272 
273 private:
274  SDL_Point p;
276  uint32_t w, h;
277 };
278 
280 {
281  if(src == nullptr) {
282  return nullptr;
283  }
284 
285  wfl::formula new_alpha(formula_);
286 
287  surface nsurf(make_neutral_surface(src));
288 
289  if(nsurf == nullptr) {
290  std::cerr << "could not make neutral surface...\n";
291  return nullptr;
292  }
293 
294  {
295  surface_lock lock(nsurf);
296  uint32_t* cur = lock.pixels();
297  uint32_t* const end = cur + nsurf->w * src->h;
298  uint32_t* const beg = cur;
299 
300  while(cur != end) {
301  color_t pixel;
302  pixel.a = (*cur) >> 24;
303  pixel.r = (*cur) >> 16;
304  pixel.g = (*cur) >> 8;
305  pixel.b = (*cur);
306 
307  int i = cur - beg;
308  SDL_Point p;
309  p.y = i / nsurf->w;
310  p.x = i % nsurf->w;
311 
312  pixel_callable px(p, pixel, nsurf->w, nsurf->h);
313  pixel.a = std::min<unsigned>(new_alpha.evaluate(px).as_int(), 255);
314  *cur = (pixel.a << 24) + (pixel.r << 16) + (pixel.g << 8) + pixel.b;
315 
316  ++cur;
317  }
318  }
319 
320  return nsurf;
321 }
322 
324 {
325  if(src == nullptr) {
326  return nullptr;
327  }
328 
329  wfl::formula new_red(formulas_[0]);
330  wfl::formula new_green(formulas_[1]);
331  wfl::formula new_blue(formulas_[2]);
332  wfl::formula new_alpha(formulas_[3]);
333 
334  surface nsurf(make_neutral_surface(src));
335 
336  if(nsurf == nullptr) {
337  std::cerr << "could not make neutral surface...\n";
338  return nullptr;
339  }
340 
341  {
342  surface_lock lock(nsurf);
343  uint32_t* cur = lock.pixels();
344  uint32_t* const end = cur + nsurf->w * src->h;
345  uint32_t* const beg = cur;
346 
347  while(cur != end) {
348  color_t pixel;
349  pixel.a = (*cur) >> 24;
350  pixel.r = (*cur) >> 16;
351  pixel.g = (*cur) >> 8;
352  pixel.b = (*cur);
353 
354  int i = cur - beg;
355  SDL_Point p;
356  p.y = i / nsurf->w;
357  p.x = i % nsurf->w;
358 
359  pixel_callable px(p, pixel, nsurf->w, nsurf->h);
360  pixel.r = std::min<unsigned>(new_red.evaluate(px).as_int(), 255);
361  pixel.g = std::min<unsigned>(new_green.evaluate(px).as_int(), 255);
362  pixel.b = std::min<unsigned>(new_blue.evaluate(px).as_int(), 255);
363  pixel.a = std::min<unsigned>(new_alpha.evaluate(px).as_int(), 255);
364  *cur = (pixel.a << 24) + (pixel.r << 16) + (pixel.g << 8) + pixel.b;
365 
366  ++cur;
367  }
368  }
369 
370  return nsurf;
371 }
372 
374 {
375  SDL_Rect area = slice_;
376  if(area.w == 0) {
377  area.w = src->w;
378  }
379 
380  if(area.h == 0) {
381  area.h = src->h;
382  }
383 
384  /*
385  * Unlike other image functions cut_surface does not convert the input
386  * surface to a neutral surface, nor does it convert its return surface
387  * to an optimised surface.
388  *
389  * Since it seems to work for most cases, rather change this caller instead
390  * of the function signature. (The issue was discovered in bug #20876).
391  */
392  surface temp = cut_surface(make_neutral_surface(src), area);
393  return temp;
394 }
395 
397 {
398  if(x_ >= src->w) {
399  std::stringstream sstr;
400  sstr << "~BLIT(): x-coordinate '"
401  << x_ << "' larger than destination image's width '"
402  << src->w << "' no blitting performed.\n";
403 
404  throw imod_exception(sstr);
405  }
406 
407  if(y_ >= src->h) {
408  std::stringstream sstr;
409  sstr << "~BLIT(): y-coordinate '"
410  << y_ << "' larger than destination image's height '"
411  << src->h << "' no blitting performed.\n";
412 
413  throw imod_exception(sstr);
414  }
415 
416  if(surf_->w + x_ < 0) {
417  std::stringstream sstr;
418  sstr << "~BLIT(): offset and width '"
419  << x_ + surf_->w << "' less than zero no blitting performed.\n";
420 
421  throw imod_exception(sstr);
422  }
423 
424  if(surf_->h + y_ < 0) {
425  std::stringstream sstr;
426  sstr << "~BLIT(): offset and height '"
427  << y_ + surf_->h << "' less than zero no blitting performed.\n";
428 
429  throw imod_exception(sstr);
430  }
431 
432  surface nsrc = make_neutral_surface(src);
433  surface nsurf = make_neutral_surface(surf_);
434  SDL_Rect r {x_, y_, 0, 0};
435  sdl_blit(nsurf, nullptr, nsrc, &r);
436  return nsrc;
437 }
438 
440 {
441  if(src->w == mask_->w && src->h == mask_->h && x_ == 0 && y_ == 0) {
442  return mask_surface(src, mask_);
443  }
444 
445  SDL_Rect r {x_, y_, 0, 0};
446  surface new_mask = create_neutral_surface(src->w, src->h);
447  sdl_blit(mask_, nullptr, new_mask, &r);
448  return mask_surface(src, new_mask);
449 }
450 
452  if(src == nullptr) { return nullptr; }
453 
454  // light_surface wants a neutral surface having same dimensions
455  surface nsurf;
456  if(surf_->w != src->w || surf_->h != src->h) {
457  nsurf = scale_surface(surf_, src->w, src->h);
458  } else {
459  nsurf = make_neutral_surface(surf_);
460  }
461 
462  return light_surface(src, nsurf);
463 }
464 
466 {
467  std::pair<int,int> sz = calculate_size(src);
468 
469  if(nn_) {
470  return scale_surface_sharp(src, sz.first, sz.second);
471  } else {
472  return scale_surface_legacy(src, sz.first, sz.second);
473  }
474 }
475 
476 std::pair<int,int> scale_exact_modification::calculate_size(const surface& src) const
477 {
478  const int old_w = src->w;
479  const int old_h = src->h;
480  int w = get_w();
481  int h = get_h();
482 
483  if(w <= 0) {
484  if(w < 0) {
485  ERR_DP << "width of " << fn_ << " is negative - resetting to original width" << std::endl;
486  }
487  w = old_w;
488  }
489 
490  if(h <= 0) {
491  if(h < 0) {
492  ERR_DP << "height of " << fn_ << " is negative - resetting to original height" << std::endl;
493  }
494  h = old_h;
495  }
496 
497  return {w, h};
498 }
499 
500 std::pair<int,int> scale_into_modification::calculate_size(const surface& src) const
501 {
502  const int old_w = src->w;
503  const int old_h = src->h;
504  long double w = get_w();
505  long double h = get_h();
506 
507  if(w <= 0) {
508  if(w < 0) {
509  ERR_DP << "width of SCALE_INTO is negative - resetting to original width" << std::endl;
510  }
511  w = old_w;
512  }
513 
514  if(h <= 0) {
515  if(h < 0) {
516  ERR_DP << "height of SCALE_INTO is negative - resetting to original height" << std::endl;
517  }
518  h = old_h;
519  }
520 
521  long double ratio = std::min(w / old_w, h / old_h);
522 
523  return {static_cast<int>(old_w * ratio), static_cast<int>(old_h * ratio)};
524 }
525 
527 {
528  if(z_ == 1) {
529  return src;
530  }
531 
532  return scale_surface_xbrz(src, z_);
533 }
534 
535 /*
536  * The Opacity IPF doesn't seem to work with surface-wide alpha and instead needs per-pixel alpha.
537  * If this is needed anywhere else it can be moved back to sdl/utils.*pp.
538  */
540 {
541  surface nsurf(make_neutral_surface(src));
542 
543  if(nsurf == nullptr) {
544  std::cerr << "could not make neutral surface...\n";
545  return nullptr;
546  }
547 
548  uint16_t amount = ftofxp(opacity_);
549 
550  {
551  surface_lock lock(nsurf);
552  uint32_t* beg = lock.pixels();
553  uint32_t* end = beg + nsurf->w * src->h;
554 
555  while(beg != end) {
556  uint8_t alpha = (*beg) >> 24;
557 
558  if(alpha) {
559  uint8_t r, g, b;
560  r = (*beg) >> 16;
561  g = (*beg) >> 8;
562  b = (*beg);
563 
564  alpha = std::min<unsigned>(static_cast<unsigned>(fxpmult(alpha,amount)), 255);
565  *beg = (alpha << 24) + (r << 16) + (g << 8) + b;
566  }
567 
568  ++beg;
569  }
570  }
571 
572  return nsurf;
573 }
574 
576 {
577  return((r_ != 0 || g_ != 0 || b_ != 0)
578  ? adjust_surface_color(src, r_, g_, b_)
579  : src
580  );
581 }
582 
584 {
585  return blend_surface(src, static_cast<double>(a_), color_t(r_, g_, b_));
586 }
587 
589 {
590  return blur_alpha_surface(src, depth_);
591 }
592 
594 {
595  surface ret = make_neutral_surface(src);
596  SDL_FillRect(ret, nullptr, SDL_MapRGBA(ret->format, color_.r, color_.g,
597  color_.b, color_.a));
598  surface temp = src;
599  sdl_blit(temp, nullptr, ret, nullptr);
600  return ret;
601 }
602 
604 {
605  return swap_channels_image(src, red_, green_, blue_, alpha_);
606 }
607 
608 namespace {
609 
610 struct parse_mod_registration
611 {
612  parse_mod_registration(const char* name, mod_parser parser)
613  {
614  mod_parsers[name] = parser;
615  }
616 };
617 
618 /** A macro for automatic modification parser registration
619  *
620  * It automatically registers the created parser in the mod_parsers map
621  * It should be used just like a function header (look at the uses below)
622  * It should only be used within an anonymous namespace
623  *
624  * @param type The modification type to be registered (unquoted)
625  * @param args_var The name for the string argument provided
626  */
627 #define REGISTER_MOD_PARSER(type, args_var) \
628  static modification* parse_##type##_mod(const std::string&); \
629  static parse_mod_registration parse_##type##_mod_registration_aux(#type, &parse_##type##_mod); \
630  static modification* parse_##type##_mod(const std::string& args_var) \
631 
632 // Color-range-based recoloring
633 REGISTER_MOD_PARSER(TC, args)
634 {
635  std::vector<std::string> params = utils::split(args,',');
636 
637  if(params.size() < 2) {
638  ERR_DP << "too few arguments passed to the ~TC() function" << std::endl;
639 
640  return nullptr;
641  }
642 
643  int side_n = lexical_cast_default<int>(params[0], -1);
644  std::string team_color;
645  if(side_n < 1) {
646  ERR_DP << "invalid team (" << side_n
647  << ") passed to the ~TC() function\n";
648  return nullptr;
649  } else if(side_n <= static_cast<int>(image::get_team_colors().size())) {
650  team_color = image::get_team_colors()[side_n - 1];
651  } else {
652  // This side is not initialized; use default "n"
653  try {
654  team_color = std::to_string(side_n);
655  } catch(const bad_lexical_cast&) {
656  ERR_DP << "bad things happen" << std::endl;
657 
658  return nullptr;
659  }
660  }
661 
662  //
663  // Pass argseters for RC functor
664  //
665  if(!game_config::tc_info(params[1]).size()){
666  ERR_DP << "could not load TC info for '" << params[1]
667  << "' palette\n"
668  << "bailing out from TC\n";
669 
670  return nullptr;
671  }
672 
673  color_range_map rc_map;
674  try {
675  const color_range& new_color = game_config::color_info(team_color);
676  const std::vector<color_t>& old_color = game_config::tc_info(params[1]);
677 
678  rc_map = recolor_range(new_color,old_color);
679  } catch(const config::error& e) {
680  ERR_DP << "caught config::error while processing TC: "
681  << e.message
682  << '\n'
683  << "bailing out from TC\n";
684 
685  return nullptr;
686  }
687 
688  return new rc_modification(rc_map);
689 }
690 
691 // Team-color-based color range selection and recoloring
692 REGISTER_MOD_PARSER(RC, args)
693 {
694  const std::vector<std::string> recolor_params = utils::split(args,'>');
695 
696  if(recolor_params.size() <= 1) {
697  return nullptr;
698  }
699 
700  //
701  // recolor source palette to color range
702  //
703  color_range_map rc_map;
704  try {
705  const color_range& new_color = game_config::color_info(recolor_params[1]);
706  const std::vector<color_t>& old_color = game_config::tc_info(recolor_params[0]);
707 
708  rc_map = recolor_range(new_color,old_color);
709  } catch (const config::error& e) {
710  ERR_DP
711  << "caught config::error while processing color-range RC: "
712  << e.message
713  << '\n';
714  ERR_DP
715  << "bailing out from RC\n";
716  rc_map.clear();
717  }
718 
719  return new rc_modification(rc_map);
720 }
721 
722 // Palette switch
723 REGISTER_MOD_PARSER(PAL, args)
724 {
725  const std::vector<std::string> remap_params = utils::split(args,'>');
726 
727  if(remap_params.size() < 2) {
728  ERR_DP << "not enough arguments passed to the ~PAL() function: " << args << "\n";
729 
730  return nullptr;
731  }
732 
733  try {
734  color_range_map rc_map;
735  const std::vector<color_t>& old_palette = game_config::tc_info(remap_params[0]);
736  const std::vector<color_t>& new_palette =game_config::tc_info(remap_params[1]);
737 
738  for(std::size_t i = 0; i < old_palette.size() && i < new_palette.size(); ++i) {
739  rc_map[old_palette[i]] = new_palette[i];
740  }
741 
742  return new rc_modification(rc_map);
743  } catch(const config::error& e) {
744  ERR_DP
745  << "caught config::error while processing PAL function: "
746  << e.message
747  << '\n';
748  ERR_DP
749  << "bailing out from PAL\n";
750 
751  return nullptr;
752  }
753 }
754 
755 // Flip/flop
756 REGISTER_MOD_PARSER(FL, args)
757 {
758  bool horiz = (args.empty() || args.find("horiz") != std::string::npos);
759  bool vert = (args.find("vert") != std::string::npos);
760 
761  return new fl_modification(horiz, vert);
762 }
763 
764 // Rotations
765 REGISTER_MOD_PARSER(ROTATE, args)
766 {
767  const std::vector<std::string>& slice_params = utils::split(args, ',', utils::STRIP_SPACES);
768  const std::size_t s = slice_params.size();
769 
770  switch(s) {
771  case 0:
772  return new rotate_modification();
773  break;
774  case 1:
775  return new rotate_modification(
776  lexical_cast_default<int>(slice_params[0]));
777  break;
778  case 2:
779  return new rotate_modification(
780  lexical_cast_default<int>(slice_params[0]),
781  lexical_cast_default<int>(slice_params[1]));
782  break;
783  case 3:
784  return new rotate_modification(
785  lexical_cast_default<int>(slice_params[0]),
786  lexical_cast_default<int>(slice_params[1]),
787  lexical_cast_default<int>(slice_params[2]));
788  break;
789  }
790  return nullptr;
791 }
792 
793 // Grayscale
795 {
796  return new gs_modification;
797 }
798 
799 // Black and white
800 REGISTER_MOD_PARSER(BW, args)
801 {
802  const std::vector<std::string>& params = utils::split(args, ',');
803 
804  if(params.size() != 1) {
805  ERR_DP << "~BW() requires exactly one argument" << std::endl;
806  return nullptr;
807  }
808 
809  try {
810  int threshold = std::stoi(params[0]);
811  if(threshold < 0 || threshold > 255) {
812  ERR_DP << "~BW() argument out of range 0 - 255" << std::endl;
813  return nullptr;
814  } else {
815  return new bw_modification(threshold);
816  }
817  } catch (const std::invalid_argument&) {
818  ERR_DP << "unsupported argument in ~BW() function" << std::endl;
819  return nullptr;
820  }
821 }
822 
823 // Sepia
824 REGISTER_MOD_PARSER(SEPIA, )
825 {
826  return new sepia_modification;
827 }
828 
829 // Negative
830 REGISTER_MOD_PARSER(NEG, args)
831 {
832  const std::vector<std::string>& params = utils::split(args, ',');
833 
834  switch (params.size()) {
835  case 0:
836  // apparently -1 may be a magic number
837  // but this is the threshold value required
838  // to fully invert a channel
839  return new negative_modification(-1,-1,-1);
840  break;
841  case 1:
842  try {
843  int threshold = std::stoi(params[0]);
844  if(threshold < -1 || threshold > 255) {
845  ERR_DP << "unsupported argument value in ~NEG() function" << std::endl;
846  return nullptr;
847  } else {
848  return new negative_modification(threshold, threshold, threshold);
849  }
850  } catch (const std::invalid_argument&) {
851  ERR_DP << "unsupported argument value in ~NEG() function" << std::endl;
852  return nullptr;
853  }
854  break;
855  case 3:
856  try {
857  int thresholdRed = std::stoi(params[0]);
858  int thresholdGreen = std::stoi(params[1]);
859  int thresholdBlue = std::stoi(params[2]);
860  if(thresholdRed < -1 || thresholdRed > 255 || thresholdGreen < -1 || thresholdGreen > 255 || thresholdBlue < -1 || thresholdBlue > 255) {
861  ERR_DP << "unsupported argument value in ~NEG() function" << std::endl;
862  return nullptr;
863  } else {
864  return new negative_modification(thresholdRed, thresholdGreen, thresholdBlue);
865  }
866  } catch (const std::invalid_argument&) {
867  ERR_DP << "unsupported argument value in ~NEG() function" << std::endl;
868  return nullptr;
869  }
870  break;
871  default:
872  ERR_DP << "~NEG() requires 0, 1 or 3 arguments" << std::endl;
873  return nullptr;
874  }
875 
876  return nullptr;
877 }
878 
879 // Plot Alpha
880 REGISTER_MOD_PARSER(PLOT_ALPHA, )
881 {
882  return new plot_alpha_modification;
883 }
884 
885 // Wipe Alpha
886 REGISTER_MOD_PARSER(WIPE_ALPHA, )
887 {
888  return new wipe_alpha_modification;
889 }
890 
891 // Adjust Alpha
892 REGISTER_MOD_PARSER(ADJUST_ALPHA, args)
893 {
894  // Formulas may contain commas, so use parenthetical split to ensure that they're properly considered a single argument.
895  // (A comma in a formula is only valid in function parameters or list/map literals, so this should always work.)
896  const std::vector<std::string>& params = utils::parenthetical_split(args, ',', "([", ")]");
897 
898  if(params.size() != 1) {
899  ERR_DP << "~ADJUST_ALPHA() requires exactly 1 arguments" << std::endl;
900  return nullptr;
901  }
902 
903  return new adjust_alpha_modification(params.at(0));
904 }
905 
906 // Adjust Channels
907 REGISTER_MOD_PARSER(CHAN, args)
908 {
909  // Formulas may contain commas, so use parenthetical split to ensure that they're properly considered a single argument.
910  // (A comma in a formula is only valid in function parameters or list/map literals, so this should always work.)
911  const std::vector<std::string>& params = utils::parenthetical_split(args, ',', "([", ")]");
912 
913  if(params.size() < 1 || params.size() > 4) {
914  ERR_DP << "~CHAN() requires 1 to 4 arguments" << std::endl;
915  return nullptr;
916  }
917 
918  return new adjust_channels_modification(params);
919 }
920 
921 // Color-shift
922 REGISTER_MOD_PARSER(CS, args)
923 {
924  std::vector<std::string> const factors = utils::split(args, ',');
925  const std::size_t s = factors.size();
926 
927  if(s == 0) {
928  ERR_DP << "no arguments passed to the ~CS() function" << std::endl;
929  return nullptr;
930  }
931 
932  int r = 0, g = 0, b = 0;
933 
934  r = lexical_cast_default<int>(factors[0]);
935 
936  if(s > 1 ) {
937  g = lexical_cast_default<int>(factors[1]);
938  }
939  if(s > 2 ) {
940  b = lexical_cast_default<int>(factors[2]);
941  }
942 
943  return new cs_modification(r, g, b);
944 }
945 
946 // Color blending
947 REGISTER_MOD_PARSER(BLEND, args)
948 {
949  const std::vector<std::string>& params = utils::split(args, ',');
950 
951  if(params.size() != 4) {
952  ERR_DP << "~BLEND() requires exactly 4 arguments" << std::endl;
953  return nullptr;
954  }
955 
956  float opacity = 0.0f;
957  const std::string& opacity_str = params[3];
958  const std::string::size_type p100_pos = opacity_str.find('%');
959 
960  if(p100_pos == std::string::npos)
961  opacity = lexical_cast_default<float>(opacity_str);
962  else {
963  // make multiplier
964  const std::string& parsed_field = opacity_str.substr(0, p100_pos);
965  opacity = lexical_cast_default<float>(parsed_field);
966  opacity /= 100.0f;
967  }
968 
969  return new blend_modification(
970  lexical_cast_default<int>(params[0]),
971  lexical_cast_default<int>(params[1]),
972  lexical_cast_default<int>(params[2]),
973  opacity);
974 }
975 
976 // Crop/slice
977 REGISTER_MOD_PARSER(CROP, args)
978 {
979  const std::vector<std::string>& slice_params = utils::split(args, ',', utils::STRIP_SPACES);
980  const std::size_t s = slice_params.size();
981 
982  if(s == 0 || (s == 1 && slice_params[0].empty())) {
983  ERR_DP << "no arguments passed to the ~CROP() function" << std::endl;
984  return nullptr;
985  }
986 
987  SDL_Rect slice_rect { 0, 0, 0, 0 };
988 
989  slice_rect.x = lexical_cast_default<int16_t, const std::string&>(slice_params[0]);
990 
991  if(s > 1) {
992  slice_rect.y = lexical_cast_default<int16_t, const std::string&>(slice_params[1]);
993  }
994  if(s > 2) {
995  slice_rect.w = lexical_cast_default<uint16_t, const std::string&>(slice_params[2]);
996  }
997  if(s > 3) {
998  slice_rect.h = lexical_cast_default<uint16_t, const std::string&>(slice_params[3]);
999  }
1000 
1001  return new crop_modification(slice_rect);
1002 }
1003 
1004 static bool check_image(const image::locator& img, std::stringstream & message)
1005 {
1006  if(img.file_exists()) return true;
1007  message << " image not found: '" << img.get_filename() << "'\n";
1008  ERR_DP << message.str();
1009  return false;
1010 }
1011 
1012 // Blit
1013 REGISTER_MOD_PARSER(BLIT, args)
1014 {
1015  std::vector<std::string> param = utils::parenthetical_split(args, ',');
1016  const std::size_t s = param.size();
1017 
1018  if(s == 0 || (s == 1 && param[0].empty())){
1019  ERR_DP << "no arguments passed to the ~BLIT() function" << std::endl;
1020  return nullptr;
1021  }
1022 
1023  if(s > 3){
1024  ERR_DP << "too many arguments passed to the ~BLIT() function" << std::endl;
1025  return nullptr;
1026  }
1027 
1028  int x = 0, y = 0;
1029 
1030  if(s == 3) {
1031  x = lexical_cast_default<int>(param[1]);
1032  y = lexical_cast_default<int>(param[2]);
1033  }
1034 
1035  const image::locator img(param[0]);
1036  std::stringstream message;
1037  message << "~BLIT():";
1038  if(!check_image(img, message))
1039  return nullptr;
1040  surface surf = get_image(img);
1041 
1042  return new blit_modification(surf, x, y);
1043 }
1044 
1045 // Mask
1046 REGISTER_MOD_PARSER(MASK, args)
1047 {
1048  std::vector<std::string> param = utils::parenthetical_split(args, ',');
1049  const std::size_t s = param.size();
1050 
1051  if(s == 0 || (s == 1 && param[0].empty())){
1052  ERR_DP << "no arguments passed to the ~MASK() function" << std::endl;
1053  return nullptr;
1054  }
1055 
1056  int x = 0, y = 0;
1057 
1058  if(s == 3) {
1059  x = lexical_cast_default<int>(param[1]);
1060  y = lexical_cast_default<int>(param[2]);
1061  }
1062 
1063  if(x < 0 || y < 0) {
1064  ERR_DP << "negative position arguments in ~MASK() function" << std::endl;
1065  return nullptr;
1066  }
1067 
1068  const image::locator img(param[0]);
1069  std::stringstream message;
1070  message << "~MASK():";
1071  if(!check_image(img, message))
1072  return nullptr;
1073  surface surf = get_image(img);
1074 
1075  return new mask_modification(surf, x, y);
1076 }
1077 
1078 // Light
1079 REGISTER_MOD_PARSER(L, args)
1080 {
1081  if(args.empty()){
1082  ERR_DP << "no arguments passed to the ~L() function" << std::endl;
1083  return nullptr;
1084  }
1085 
1086  surface surf = get_image(args);
1087 
1088  return new light_modification(surf);
1089 }
1090 
1091 // Scale
1092 REGISTER_MOD_PARSER(SCALE, args)
1093 {
1094  const std::vector<std::string>& scale_params = utils::split(args, ',', utils::STRIP_SPACES);
1095  const std::size_t s = scale_params.size();
1096 
1097  if(s == 0 || (s == 1 && scale_params[0].empty())) {
1098  ERR_DP << "no arguments passed to the ~SCALE() function" << std::endl;
1099  return nullptr;
1100  }
1101 
1102  int w = 0, h = 0;
1103 
1104  w = lexical_cast_default<int, const std::string&>(scale_params[0]);
1105 
1106  if(s > 1) {
1107  h = lexical_cast_default<int, const std::string&>(scale_params[1]);
1108  }
1109 
1110  return new scale_exact_modification(w, h, "SCALE", false);
1111 }
1112 
1113 REGISTER_MOD_PARSER(SCALE_SHARP, args)
1114 {
1115  const std::vector<std::string>& scale_params = utils::split(args, ',', utils::STRIP_SPACES);
1116  const std::size_t s = scale_params.size();
1117 
1118  if(s == 0 || (s == 1 && scale_params[0].empty())) {
1119  ERR_DP << "no arguments passed to the ~SCALE_SHARP() function" << std::endl;
1120  return nullptr;
1121  }
1122 
1123  int w = 0, h = 0;
1124 
1125  w = lexical_cast_default<int, const std::string&>(scale_params[0]);
1126 
1127  if(s > 1) {
1128  h = lexical_cast_default<int, const std::string&>(scale_params[1]);
1129  }
1130 
1131  return new scale_exact_modification(w, h, "SCALE_SHARP", true);
1132 }
1133 
1134 REGISTER_MOD_PARSER(SCALE_INTO, args)
1135 {
1136  const std::vector<std::string>& scale_params = utils::split(args, ',', utils::STRIP_SPACES);
1137  const std::size_t s = scale_params.size();
1138 
1139  if(s == 0 || (s == 1 && scale_params[0].empty())) {
1140  ERR_DP << "no arguments passed to the ~SCALE_INTO() function" << std::endl;
1141  return nullptr;
1142  }
1143 
1144  int w = 0, h = 0;
1145 
1146  w = lexical_cast_default<int, const std::string&>(scale_params[0]);
1147 
1148  if(s > 1) {
1149  h = lexical_cast_default<int, const std::string&>(scale_params[1]);
1150  }
1151 
1152  return new scale_into_modification(w, h, "SCALE_INTO", false);
1153 }
1154 
1155 REGISTER_MOD_PARSER(SCALE_INTO_SHARP, args)
1156 {
1157  const std::vector<std::string>& scale_params = utils::split(args, ',', utils::STRIP_SPACES);
1158  const std::size_t s = scale_params.size();
1159 
1160  if(s == 0 || (s == 1 && scale_params[0].empty())) {
1161  ERR_DP << "no arguments passed to the ~SCALE_INTO_SHARP() function" << std::endl;
1162  return nullptr;
1163  }
1164 
1165  int w = 0, h = 0;
1166 
1167  w = lexical_cast_default<int, const std::string&>(scale_params[0]);
1168 
1169  if(s > 1) {
1170  h = lexical_cast_default<int, const std::string&>(scale_params[1]);
1171  }
1172 
1173  return new scale_into_modification(w, h, "SCALE_INTO_SHARP", true);
1174 }
1175 
1176 // xBRZ
1177 REGISTER_MOD_PARSER(XBRZ, args)
1178 {
1179  int z = lexical_cast_default<int, const std::string &>(args);
1180  if(z < 1 || z > 5) {
1181  z = 5; //only values 2 - 5 are permitted for xbrz scaling factors.
1182  }
1183 
1184  return new xbrz_modification(z);
1185 }
1186 
1187 // scale
1188 
1189 // Gaussian-like blur
1190 REGISTER_MOD_PARSER(BL, args)
1191 {
1192  const int depth = std::max<int>(0, lexical_cast_default<int>(args));
1193 
1194  return new bl_modification(depth);
1195 }
1196 
1197 // Opacity-shift
1198 REGISTER_MOD_PARSER(O, args)
1199 {
1200  const std::string::size_type p100_pos = args.find('%');
1201  float num = 0.0f;
1202  if(p100_pos == std::string::npos) {
1203  num = lexical_cast_default<float,const std::string&>(args);
1204  } else {
1205  // make multiplier
1206  const std::string parsed_field = args.substr(0, p100_pos);
1207  num = lexical_cast_default<float,const std::string&>(parsed_field);
1208  num /= 100.0f;
1209  }
1210 
1211  return new o_modification(num);
1212 }
1213 
1214 //
1215 // ~R(), ~G() and ~B() are the children of ~CS(). Merely syntactic sugar.
1216 // Hence they are at the end of the evaluation.
1217 //
1218 // Red component color-shift
1219 REGISTER_MOD_PARSER(R, args)
1220 {
1221  const int r = lexical_cast_default<int>(args);
1222 
1223  return new cs_modification(r,0,0);
1224 }
1225 
1226 // Green component color-shift
1227 REGISTER_MOD_PARSER(G, args)
1228 {
1229  const int g = lexical_cast_default<int>(args);
1230 
1231  return new cs_modification(0,g,0);
1232 }
1233 
1234 // Blue component color-shift
1235 REGISTER_MOD_PARSER(B, args)
1236 {
1237  const int b = lexical_cast_default<int>(args);
1238 
1239  return new cs_modification(0,0,b);
1240 }
1241 
1242 REGISTER_MOD_PARSER(NOP, )
1243 {
1244  return nullptr;
1245 }
1246 
1247 // Only used to tag terrain images which should not be color-shifted by ToD
1248 REGISTER_MOD_PARSER(NO_TOD_SHIFT, )
1249 {
1250  return nullptr;
1251 }
1252 
1253 // Fake image function used by GUI2 portraits until
1254 // Mordante gets rid of it. *tsk* *tsk*
1255 REGISTER_MOD_PARSER(RIGHT, )
1256 {
1257  return nullptr;
1258 }
1259 
1260 // Add a background color.
1261 REGISTER_MOD_PARSER(BG, args)
1262 {
1263  int c[4] { 0, 0, 0, SDL_ALPHA_OPAQUE };
1264  std::vector<std::string> factors = utils::split(args, ',');
1265 
1266  for(int i = 0; i < std::min<int>(factors.size(), 4); ++i) {
1267  c[i] = lexical_cast_default<int>(factors[i]);
1268  }
1269 
1270  return new background_modification(color_t(c[0], c[1], c[2], c[3]));
1271 }
1272 
1273 // Channel swap
1274 REGISTER_MOD_PARSER(SWAP, args)
1275 {
1276  std::vector<std::string> params = utils::split(args, ',', utils::STRIP_SPACES);
1277 
1278  // accept 3 arguments (rgb) or 4 (rgba)
1279  if(params.size() != 3 && params.size() != 4) {
1280  ERR_DP << "incorrect number of arguments in ~SWAP() function, they must be 3 or 4" << std::endl;
1281  return nullptr;
1282  }
1283 
1284  channel redValue, greenValue, blueValue, alphaValue;
1285  // compare the parameter's value with the constants defined in the channels enum
1286  if(params[0] == "red") {
1287  redValue = RED;
1288  } else if(params[0] == "green") {
1289  redValue = GREEN;
1290  } else if(params[0] == "blue") {
1291  redValue = BLUE;
1292  } else if(params[0] == "alpha") {
1293  redValue = ALPHA;
1294  } else {
1295  ERR_DP << "unsupported argument value in ~SWAP() function: " << params[0] << std::endl;
1296  return nullptr;
1297  }
1298 
1299  // wash, rinse and repeat for the other three channels
1300  if(params[1] == "red") {
1301  greenValue = RED;
1302  } else if(params[1] == "green") {
1303  greenValue = GREEN;
1304  } else if(params[1] == "blue") {
1305  greenValue = BLUE;
1306  } else if(params[1] == "alpha") {
1307  greenValue = ALPHA;
1308  } else {
1309  ERR_DP << "unsupported argument value in ~SWAP() function: " << params[0] << std::endl;
1310  return nullptr;
1311  }
1312 
1313  if(params[2] == "red") {
1314  blueValue = RED;
1315  } else if(params[2] == "green") {
1316  blueValue = GREEN;
1317  } else if(params[2] == "blue") {
1318  blueValue = BLUE;
1319  } else if(params[2] == "alpha") {
1320  blueValue = ALPHA;
1321  } else {
1322  ERR_DP << "unsupported argument value in ~SWAP() function: " << params[0] << std::endl;
1323  return nullptr;
1324  }
1325 
1326  // additional check: the params vector may not have a fourth elementh
1327  // if so, default to the same channel
1328  if(params.size() == 3) {
1329  alphaValue = ALPHA;
1330  } else {
1331  if(params[3] == "red") {
1332  alphaValue = RED;
1333  } else if(params[3] == "green") {
1334  alphaValue = GREEN;
1335  } else if(params[3] == "blue") {
1336  alphaValue = BLUE;
1337  } else if(params[3] == "alpha") {
1338  alphaValue = ALPHA;
1339  } else {
1340  ERR_DP << "unsupported argument value in ~SWAP() function: " << params[3] << std::endl;
1341  return nullptr;
1342  }
1343  }
1344 
1345  return new swap_modification(redValue, greenValue, blueValue, alphaValue);
1346 }
1347 
1348 } // end anon namespace
1349 
1350 } /* end namespace image */
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
Definition: utils.hpp:161
surface get_image(const image::locator &i_locator, TYPE type)
function to get the surface corresponding to an image.
Definition: picture.cpp:1022
pixel_t * pixels() const
Definition: surface.hpp:148
surface recolor_image(surface surf, const color_range_map &map_rgb)
Recolors a surface using a map with source and converted palette values.
Definition: utils.cpp:1093
surface negative_image(const surface &surf, const int thresholdR, const int thresholdG, const int thresholdB)
Definition: utils.cpp:855
surface scale_surface_legacy(const surface &surf, int w, int h)
Scale a surface using simple bilinear filtering (discarding rgb from source pixels with 0 alpha) ...
Definition: utils.cpp:406
surface create_neutral_surface(int w, int h)
Definition: utils.cpp:84
void get_inputs(wfl::formula_input_vector &inputs) const override
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
static variant evaluate(const const_formula_ptr &f, const formula_callable &variables, formula_debugger *fdb=nullptr, variant default_res=variant(0))
Definition: formula.hpp:39
surface adjust_surface_color(const surface &surf, int red, int green, int blue)
Definition: utils.cpp:683
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
variant b_
Definition: function.cpp:722
New lexcical_cast header.
int as_int() const
Definition: variant.cpp:298
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
#define RC(i)
Definition: lvm.cpp:730
A modified priority queue used to order image modifications.
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
virtual std::pair< int, int > calculate_size(const surface &src) const
surface rotate_180_surface(const surface &surf)
Rotates a surface 180 degrees.
Definition: utils.cpp:1962
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
std::vector< formula_input > formula_input_vector
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
#define REGISTER_MOD_PARSER(type, args_var)
A macro for automatic modification parser registration.
#define G(L)
Definition: lstate.h:205
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
#define h
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:274
surface blend_surface(const surface &surf, const double amount, const color_t color)
Blends a surface with a color.
Definition: utils.cpp:1804
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
surface flip_surface(const surface &surf)
Definition: utils.cpp:2041
Definitions for the interface to Wesnoth Markup Language (WML).
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
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.
virtual int priority() const
Specifies the priority of the modification.
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
void push(modification *mod)
Adds mod to the queue (unless mod is nullptr).
#define b
static const char * name(const std::vector< SDL_Joystick *> &joysticks, const std::size_t index)
Definition: joystick.cpp:48
std::size_t size() const
Returns the number of elements in the queue.
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:1221
surface flop_surface(const surface &surf)
Definition: utils.cpp:2070
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:86
imod_exception(const std::stringstream &message_stream)
Constructor.
static lg::log_domain log_display("display")
#define fxpmult(x, y)
IN: unsigned and fixed_t - OUT: unsigned.
Definition: math.hpp:300
surface blur_alpha_surface(const surface &surf, int depth)
Cross-fades a surface with alpha channel.
Definition: utils.cpp:1599
Definition: utils.hpp:161
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
REMOVE_EMPTY: remove empty elements.
uint8_t r
Red value.
Definition: color.hpp:177
uint8_t a
Alpha value.
Definition: color.hpp:186
#define ERR_DP
surface cut_surface(const surface &surf, const SDL_Rect &r)
Cuts a rectangle from a surface.
Definition: utils.cpp:1746
Base abstract class for an image-path modification.
color_range_map recolor_range(const color_range &new_range, const std::vector< color_t > &old_rgb)
Converts a source palette using the specified color_range object.
Definition: color_range.cpp:28
surface rotate_90_surface(const surface &surf, bool clockwise)
Rotates a surface 90 degrees.
Definition: utils.cpp:2004
static modification_queue decode(const std::string &)
Decodes modifications from a modification string.
#define ftofxp(x)
IN: float or int - OUT: fixed_t.
Definition: math.hpp:297
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
std::unordered_map< color_t, color_t > color_range_map
Definition: color_range.hpp:32
Definition: utils.hpp:161
surface alpha_to_greyscale(const surface &surf)
Definition: utils.cpp:898
std::size_t i
Definition: function.cpp:933
surface monochrome_image(const surface &surf, const int threshold)
Definition: utils.cpp:773
wfl::variant get_value(const std::string &key) const override
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
mock_party p
static map_location::DIRECTION s
double g
Definition: astarsearch.cpp:64
surface scale_surface_xbrz(const surface &surf, std::size_t z)
Scale a surface using xBRZ algorithm.
Definition: utils.cpp:195
Helper class for pinning SDL surfaces into memory.
Definition: surface.hpp:128
A color range definition is made of four reference RGB colors, used for calculating conversions from ...
Definition: color_range.hpp:50
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
int w
Definition: utils.hpp:161
const std::string & get_filename() const
Definition: picture.hpp:85
surface greyscale_image(const surface &surf)
Definition: utils.cpp:728
variant a_
Definition: function.cpp:722
surface light_surface(const surface &surf, const surface &lightmap)
Light surf using lightmap.
Definition: utils.cpp:1398
surface wipe_alpha(const surface &surf)
Definition: utils.cpp:926
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
virtual std::pair< int, int > calculate_size(const surface &src) const
pixel_callable(SDL_Point p, color_t clr, uint32_t w, uint32_t h)
surface make_neutral_surface(const surface &surf)
Definition: utils.cpp:72
const color_range & color_info(const std::string &name)
this module manages the cache of images.
surface scale_surface_sharp(const surface &surf, int w, int h)
Scale a surface using modified nearest neighbour algorithm.
Definition: utils.cpp:546
Standard logging facilities (interface).
modification * top() const
Returns the top element in the queue .
std::string message
Definition: exceptions.hpp:31
map_type priorities_
Map from a mod&#39;s priority() to the mods having that priority.
const std::vector< color_t > & tc_info(const std::string &name)
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
const std::vector< std::string > & get_team_colors()
Definition: picture.cpp:870
#define e
void pop()
Removes the top element from the queue.
void sdl_blit(const surface &src, SDL_Rect *src_rect, surface &dst, SDL_Rect *dst_rect)
Definition: utils.hpp:33
surface sepia_image(const surface &surf)
Definition: utils.cpp:813
uint8_t g
Green value.
Definition: color.hpp:180
uint8_t b
Blue value.
Definition: color.hpp:183
mock_char c
Thrown when a lexical_cast fails.
surface rotate_any_surface(const surface &surf, float angle, int zoom, int offset)
Rotates a surface by any degrees.
Definition: utils.cpp:1851
bool file_exists() const
Tests whether the file the locater points at exists.
Definition: picture.cpp:780
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
surface swap_channels_image(const surface &surf, channel r, channel g, channel b, channel a)
Definition: utils.cpp:991
virtual surface operator()(const surface &src) const
Applies the image-path modification on the specified surface.
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...
channel
Definition: utils.hpp:161
const std::string message
The error message regarding the failed operation.