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