apply patch 2633 by automagic : refactoring of the imagepath code

This commit is contained in:
Jérémy Rosen 2011-04-15 14:44:23 +00:00
parent a1c5abdfca
commit c68a158f37
10 changed files with 1410 additions and 813 deletions

View file

@ -1028,6 +1028,9 @@
name = "Karl Miller (karlm)"
email = "karl_DOT_miller_DOT_km_AT_gmail_DOT_com"
[/entry]
[entry]
name = "Karol Kozub (automagic)"
[/entry]
[entry]
name = "Laurent Birtz"
[/entry]

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
@ -448,7 +448,7 @@
>
</File>
<File
RelativePath="..\..\src\image_function.cpp"
RelativePath="..\..\src\image_modifications.cpp"
>
</File>
<File
@ -7131,7 +7131,7 @@
>
</File>
<File
RelativePath="..\..\src\image_function.hpp"
RelativePath="..\..\src\image_modifications.hpp"
>
</File>
<File

View file

@ -585,7 +585,7 @@ set(libwesnoth-game_STAT_SRC
font.cpp
hotkeys.cpp
image.cpp
image_function.cpp
image_modifications.cpp
key.cpp
language.cpp
loadscreen.cpp

View file

@ -83,7 +83,7 @@ libwesnoth_sources = Split("""
generic_event.cpp
hotkeys.cpp
image.cpp
image_function.cpp
image_modifications.cpp
key.cpp
language.cpp
loadscreen.cpp

View file

@ -28,7 +28,7 @@
#include "foreach.hpp"
#include "game_config.hpp"
#include "image.hpp"
#include "image_function.hpp"
#include "image_modifications.hpp"
#include "log.hpp"
#include "gettext.hpp"
#include "serialization/string_utils.hpp"
@ -488,375 +488,13 @@ surface locator::load_image_sub_file() const
surf = mask_surface(cut, get_hexmask());
}
if(val_.modifications_.size()){
// The RC functor is very special; it must be applied
// before anything else, and it is not accumulative.
rc_function rc;
// The FL functor is delayed until the end of the sequence.
// This allows us to ignore things like ~FL(horiz)~FL(horiz)
fl_function fl;
// Regular functors
std::vector< image::function_base* > functor_queue;
modification_queue mods = modification::decode(val_.modifications_);
const std::vector<std::string> modlist = utils::parenthetical_split(val_.modifications_,'~');
for(; !mods.empty(); mods.pop()) {
modification* mod = mods.top();
foreach(const std::string& s, modlist) {
const std::vector<std::string> tmpmod = utils::parenthetical_split(s);
std::vector<std::string>::const_iterator j = tmpmod.begin();
while(j!= tmpmod.end()){
const std::string function = *j++;
if(j == tmpmod.end()){
if(function.size()){
ERR_DP << "error parsing image modifications: "
<< val_.modifications_<< "\n";
}
break;
}
const std::string field = *j++;
typedef std::pair<Uint32,Uint32> rc_entry_type;
// Team color (TC), a subset of RC's functionality
if("TC" == function) {
std::vector<std::string> param = utils::split(field,',');
if(param.size() < 2) {
ERR_DP << "too few arguments passed to the ~TC() function\n";
break;
}
int side_n = lexical_cast_default<int>(param[0], -1);
std::string team_color;
if (side_n < 1) {
ERR_DP << "invalid team (" << side_n << ") passed to the ~TC() function\n";
break;
}
else if (side_n < static_cast<int>(team_colors.size())) {
team_color = team_colors[side_n - 1];
}
else {
// This side is not initialized; use default "n"
try {
team_color = lexical_cast<std::string>(side_n);
} catch(bad_lexical_cast const&) {
ERR_DP << "bad things happen\n";
}
}
//
// Pass parameters for RC functor
//
if(game_config::tc_info(param[1]).size()){
std::map<Uint32, Uint32> tmp_map;
try {
color_range const& new_color =
game_config::color_info(team_color);
std::vector<Uint32> const& old_color =
game_config::tc_info(param[1]);
tmp_map = recolor_range(new_color,old_color);
}
catch(config::error const& e) {
ERR_DP
<< "caught config::error while processing TC: "
<< e.message
<< '\n';
ERR_DP
<< "bailing out from TC\n";
tmp_map.clear();
}
foreach(const rc_entry_type& rc_entry, tmp_map) {
rc.map()[rc_entry.first] = rc_entry.second;
}
}
else {
ERR_DP
<< "could not load TC info for '" << param[1] << "' palette\n";
ERR_DP
<< "bailing out from TC\n";
}
}
// Palette recolor (RC)
else if("RC" == function) {
const std::vector<std::string> recolor_params = utils::split(field,'>');
if(recolor_params.size()>1){
//
// recolor source palette to color range
//
std::map<Uint32, Uint32> tmp_map;
try {
color_range const& new_color =
game_config::color_info(recolor_params[1]);
std::vector<Uint32> const& old_color =
game_config::tc_info(recolor_params[0]);
tmp_map = recolor_range(new_color,old_color);
}
catch (config::error& e) {
ERR_DP
<< "caught config::error while processing color-range RC: "
<< e.message
<< '\n';
ERR_DP
<< "bailing out from RC\n";
tmp_map.clear();
}
foreach(const rc_entry_type& rc_entry, tmp_map) {
rc.map()[rc_entry.first] = rc_entry.second;
}
}
else {
///@Deprecated 1.6 palette switch syntax
if(field.find('=') != std::string::npos) {
lg::wml_error << "the ~RC() image function cannot be used for palette switch (A=B) in 1.7.x; use ~PAL(A>B) instead\n";
}
}
}
// Palette switch (PAL)
else if("PAL" == function) {
const std::vector<std::string> remap_params = utils::split(field,'>');
if(remap_params.size() > 1) {
std::map<Uint32, Uint32> tmp_map;
try {
std::vector<Uint32> const& old_palette =
game_config::tc_info(remap_params[0]);
std::vector<Uint32> const& new_palette =
game_config::tc_info(remap_params[1]);
for(size_t i = 0; i < old_palette.size() && i < new_palette.size(); ++i) {
tmp_map[old_palette[i]] = new_palette[i];
}
}
catch(config::error& e) {
ERR_DP
<< "caught config::error while processing PAL function: "
<< e.message
<< '\n';
ERR_DP
<< "bailing out from PAL\n";
tmp_map.clear();
}
foreach(const rc_entry_type& rc_entry, tmp_map) {
rc.map()[rc_entry.first] = rc_entry.second;
}
}
}
// Flip-flop (FL)
else if("FL" == function) {
if(field.empty() || field.find("horiz") != std::string::npos) {
fl.toggle_horiz();
}
if(field.find("vert") != std::string::npos) {
fl.toggle_vert();
}
}
// Grayscale (GS)
else if("GS" == function) {
functor_queue.push_back(new gs_function());
}
// Color-shift (CS)
else if("CS" == function) {
std::vector<std::string> const factors = utils::split(field, ',');
const size_t s = factors.size();
if(s) {
int r = 0, g = 0, b = 0;
r = lexical_cast_default<int>(factors[0]);
if( s > 1 ) {
g = lexical_cast_default<int>(factors[1]);
}
if( s > 2 ) {
b = lexical_cast_default<int>(factors[2]);
}
functor_queue.push_back(new cs_function(r,g,b));
}
else {
LOG_DP << "no arguments passed to the ~CS() function\n";
}
}
// Crop/slice (CROP)
else if("CROP" == function) {
std::vector<std::string> const& slice_params = utils::split(field, ',', utils::STRIP_SPACES);
const size_t s = slice_params.size();
if(s) {
SDL_Rect slice_rect = { 0, 0, 0, 0 };
slice_rect.x = lexical_cast_default<Sint16, const std::string&>(slice_params[0]);
if(s > 1) {
slice_rect.y = lexical_cast_default<Sint16, const std::string&>(slice_params[1]);
}
if(s > 2) {
slice_rect.w = lexical_cast_default<Uint16, const std::string&>(slice_params[2]);
}
if(s > 3) {
slice_rect.h = lexical_cast_default<Uint16, const std::string&>(slice_params[3]);
}
functor_queue.push_back(new crop_function(slice_rect));
}
else {
ERR_DP << "no arguments passed to the ~CROP() function\n";
}
}
// LOC function
else if("LOC" == function) {
//FIXME: WIP, don't use it yet
std::vector<std::string> const& params = utils::split(field);
int x = lexical_cast<int>(params[0]);
int y = lexical_cast<int>(params[1]);
int cx = lexical_cast<int>(params[2]);
int cy = lexical_cast<int>(params[3]);
image::locator new_loc(val_.filename_, map_location(x,y), cx, cy, "");//TODO remove only ~LOC
surf = get_image(new_loc, TOD_COLORED);
}
// BLIT function
else if("BLIT" == function) {
std::vector<std::string> param = utils::parenthetical_split(field, ',');
const size_t s = param.size();
if(s > 0){
int x = 0, y = 0;
if(s == 3) {
x = lexical_cast_default<int>(param[1]);
y = lexical_cast_default<int>(param[2]);
}
if(x >= 0 && y >= 0) { //required by blit_surface
surface surf = get_image(param[0]);
functor_queue.push_back(new blit_function(surf, x, y));
} else {
ERR_DP << "negative position arguments in ~BLIT() function\n";
}
} else {
ERR_DP << "no arguments passed to the ~BLIT() function\n";
}
}
else if("MASK" == function) {
std::vector<std::string> param = utils::parenthetical_split(field, ',');
const size_t s = param.size();
if(s > 0){
int x = 0, y = 0;
if(s == 3) {
x = lexical_cast_default<int>(param[1]);
y = lexical_cast_default<int>(param[2]);
}
if(x >= 0 && y >= 0) { //required by blit_surface
surface surf = get_image(param[0]);
functor_queue.push_back(new mask_function(surf, x, y));
} else {
ERR_DP << "negative position arguments in ~MASK() function\n";
}
} else {
ERR_DP << "no arguments passed to the ~MASK() function\n";
}
}
else if("L" == function) {
if(!field.empty()){
surface surf = get_image(field);
functor_queue.push_back(new light_function(surf));
} else {
ERR_DP << "no arguments passed to the ~L() function\n";
}
}
// Scale (SCALE)
else if("SCALE" == function) {
std::vector<std::string> const& scale_params = utils::split(field, ',', utils::STRIP_SPACES);
const size_t s = scale_params.size();
if(s) {
int w = 0, h = 0;
w = lexical_cast_default<int, const std::string&>(scale_params[0]);
if(s > 1) {
h = lexical_cast_default<int, const std::string&>(scale_params[1]);
}
functor_queue.push_back(new scale_function(w, h));
}
else {
ERR_DP << "no arguments passed to the ~SCALE() function\n";
}
}
// Gaussian-like blur (BL)
else if("BL" == function) {
const int depth = std::max<int>(0, lexical_cast_default<int>(field));
functor_queue.push_back(new bl_function(depth));
}
// Opacity-shift (O)
else if("O" == function) {
const std::string::size_type p100_pos = field.find('%');
float num = 0.0f;
if(p100_pos == std::string::npos)
num = lexical_cast_default<float,const std::string&>(field);
else {
// make multiplier
const std::string parsed_field = field.substr(0, p100_pos);
num = lexical_cast_default<float,const std::string&>(parsed_field);
num /= 100.0f;
}
functor_queue.push_back(new o_function(num));
}
//
// ~R(), ~G() and ~B() are the children of ~CS(). Merely syntatic sugar.
// Hence they are at the end of the evaluation.
//
// Red component color-shift (R)
else if("R" == function) {
const int r = lexical_cast_default<int>(field);
functor_queue.push_back(new cs_function(r,0,0));
}
// Green component color-shift (G)
else if("G" == function) {
const int g = lexical_cast_default<int>(field);
functor_queue.push_back(new cs_function(0,g,0));
}
// Blue component color-shift (B)
else if("B" == function) {
const int b = lexical_cast_default<int>(field);
functor_queue.push_back(new cs_function(0,0,b));
}
else if("NOP" == function) {
}
// Fake image function used by GUI2 portraits until
// Mordante gets rid of it. *tsk* *tsk*
else if("RIGHT" == function) {
}
// Add a bright overlay.
else if (function == "BRIGHTEN") {
functor_queue.push_back(new brighten_function());
}
// Add a dark overlay.
else if (function == "DARKEN") {
functor_queue.push_back(new darken_function());
}
// Add a background color.
else if (function == "BG")
{
int c[4] = { 0, 0, 0, 255 };
std::vector<std::string> factors = utils::split(field, ',');
for (int i = 0; i < std::min<int>(factors.size(), 4); ++i) {
c[i] = lexical_cast_default<int>(factors[i]);
}
functor_queue.push_back(new background_function(create_color(c[0], c[1], c[2], c[3])));
}
else {
ERR_DP << "unknown image function in path: " << function << '\n';
}
}
}
if(!rc.no_op()) {
surf = rc(surf);
}
if(!fl.no_op()) {
surf = fl(surf);
}
foreach(function_base* f, functor_queue) {
surf = (*f)(surf);
delete f;
}
surf = (*mod)(surf);
delete mod;
}
return surf;
@ -943,6 +581,11 @@ void set_team_colors(const std::vector<std::string>* colors)
}
}
const std::vector<std::string>& get_team_colors()
{
return team_colors;
}
void set_zoom(int amount)
{
if(amount != zoom) {

View file

@ -168,6 +168,8 @@ namespace image {
///using NULL will reset to default TC
void set_team_colors(const std::vector<std::string>* colors = NULL);
const std::vector<std::string>& get_team_colors();
///sets the pixel format used by the images. Is called every time the
///video mode changes. Invalidates all images.
void set_pixel_format(SDL_PixelFormat* format);

View file

@ -1,169 +0,0 @@
/* $Id$ */
/*
Copyright (C) 2009 - 2011 by Ignacio R. Morelle <shadowm2006@gmail.com>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "image_function.hpp"
#include "game_config.hpp"
#include "image.hpp"
#include "log.hpp"
#define GETTEXT_DOMAIN "wesnoth-lib"
static lg::log_domain log_display("display");
#define ERR_DP LOG_STREAM(err, log_display)
namespace image {
surface rc_function::operator()(const surface& src) const
{
// unchecked
return recolor_image(src, rc_map_);
}
surface fl_function::operator()(const surface& src) const
{
surface ret = src;
if(horiz_) {
ret = flip_surface(ret);
}
if(vert_) {
ret = flop_surface(ret);
}
return ret;
}
surface gs_function::operator()(const surface& src) const
{
return greyscale_image(src);
}
surface crop_function::operator()(const surface& src) const
{
SDL_Rect area = slice_;
if(area.w == 0) {
area.w = src->w;
}
if(area.h == 0) {
area.h = src->h;
}
if(area.x < 0) {
ERR_DP << "start X coordinate of SECTION function is negative - truncating to zero\n";
area.x = 0;
}
if(area.y < 0) {
ERR_DP << "start Y coordinate of SECTION function is negative - truncating to zero\n";
area.y = 0;
}
return cut_surface(src, area);
}
surface blit_function::operator()(const surface& src) const
{
//blit_surface want neutral surfaces
surface nsrc = make_neutral_surface(src);
surface nsurf = make_neutral_surface(surf_);
SDL_Rect r = create_rect(x_, y_, 0, 0);
blit_surface(nsurf, NULL, nsrc, &r);
return nsrc;
}
surface mask_function::operator()(const surface& src) const
{
if(src->w == mask_->w && src->h == mask_->h && x_ == 0 && y_ == 0)
return mask_surface(src, mask_);
SDL_Rect r = create_rect(x_, y_, 0, 0);
surface new_mask = create_neutral_surface(src->w, src->h);
blit_surface(mask_, NULL, new_mask, &r);
return mask_surface(src, new_mask);
}
surface light_function::operator()(const surface& src) const
{
return light_surface(src, surf_);;
}
surface scale_function::operator()(const surface& src) const
{
const int old_w = src->w;
const int old_h = src->h;
int w = w_;
int h = h_;
if(w <= 0) {
if(w < 0) {
ERR_DP << "width of SCALE is negative - resetting to original width\n";
}
w = old_w;
}
if(h <= 0) {
if(h < 0) {
ERR_DP << "height of SCALE is negative - resetting to original height\n";
}
h = old_h;
}
return scale_surface(src, w, h);
}
surface o_function::operator()(const surface& src) const
{
return adjust_surface_alpha(src, ftofxp(opacity_));
}
surface cs_function::operator()(const surface& src) const
{
return(
(r_ != 0 || g_ != 0 || b_ != 0) ?
adjust_surface_color(src, r_, g_, b_) :
src
);
}
surface bl_function::operator()(const surface& src) const
{
return blur_alpha_surface(src, depth_);
}
surface brighten_function::operator()(const surface &src) const
{
surface ret = make_neutral_surface(src);
surface tod_bright(image::get_image(game_config::images:: tod_bright));
if (tod_bright)
blit_surface(tod_bright, NULL, ret, NULL);
return ret;
}
surface darken_function::operator()(const surface &src) const
{
surface ret = make_neutral_surface(src);
surface tod_dark(image::get_image(game_config::images::tod_dark));
if (tod_dark)
blit_surface(tod_dark, NULL, ret, NULL);
return ret;
}
surface background_function::operator()(const surface &src) const
{
surface ret = make_neutral_surface(src);
SDL_FillRect(ret, NULL, SDL_MapRGBA(ret->format, color_.r, color_.g, color_.b, color_.unused));
SDL_SetAlpha(src, SDL_SRCALPHA, SDL_ALPHA_OPAQUE);
SDL_BlitSurface(src, NULL, ret, NULL);
return ret;
}
} /* end namespace image */

View file

@ -1,271 +0,0 @@
/* $Id$ */
/*
Copyright (C) 2009 - 2011 by Ignacio R. Morelle <shadowm2006@gmail.com>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/** @file */
#ifndef IMAGE_FUNCTION_HPP_INCLUDED
#define IMAGE_FUNCTION_HPP_INCLUDED
#include "sdl_utils.hpp"
namespace image {
/**
* Base abstract class for an image-path function.
* It actually just enforces the operator()() protocol.
*/
class function_base
{
public:
virtual ~function_base() {}
/**
* Applies the image-path function on the specified surface.
*/
virtual surface operator()(const surface& src) const = 0;
};
/**
* Recolor (RC/TC/PAL) function.
* It is used not only for color-range-based recoloring ("~RC(magenta>teal)")
* but also for team-color-based color range selection and recoloring
* ("~TC(3,magenta)") and palette switches ("~PAL(000000,005000 > FFFFFF,FF00FF)").
*/
class rc_function : public function_base
{
public:
/**
* Default constructor.
*/
rc_function()
: rc_map_()
{}
/**
* RC-map based constructor.
* @param recolor_map The palette switch map.
*/
rc_function(const std::map<Uint32, Uint32>& recolor_map)
: rc_map_(recolor_map)
{}
virtual surface operator()(const surface& src) const;
bool no_op() const { return rc_map_.empty(); }
const std::map<Uint32, Uint32>& map() const { return rc_map_;}
std::map<Uint32, Uint32>& map() { return rc_map_;}
private:
std::map<Uint32, Uint32> rc_map_;
};
/**
* Mirror (FL) function.
*/
class fl_function : public function_base
{
public:
/**
* Constructor.
* @param horiz Horizontal mirror flag.
* @param vert Vertical mirror flag.
*/
fl_function(bool horiz = false, bool vert = false)
: horiz_(horiz)
, vert_(vert)
{}
virtual surface operator()(const surface& src) const;
void set_horiz(bool val) { horiz_ = val; }
void set_vert(bool val) { vert_ = val; }
bool get_horiz() const { return horiz_; }
bool get_vert() const { return vert_; }
/** Toggle horizontal mirror flag.
* @return The new flag state after toggling. */
bool toggle_horiz() { return((horiz_ = !horiz_)); }
/** Toggle vertical mirror flag.
* @return The new flag state after toggling. */
bool toggle_vert() { return((vert_ = !vert_)); }
bool no_op() const { return ((!horiz_) && (!vert_)); }
private:
bool horiz_;
bool vert_;
};
/**
* Grayscale (GS) function.
*/
class gs_function : public function_base
{
public:
gs_function() {}
virtual surface operator()(const surface& src) const;
};
/**
* Crop (CROP) function.
*/
class crop_function : public function_base
{
public:
crop_function(const SDL_Rect& slice)
: slice_(slice)
{}
virtual surface operator()(const surface& src) const;
private:
SDL_Rect slice_;
};
/**
* Scale (BLIT) function.
*/
class blit_function : public function_base
{
public:
blit_function(const surface& surf, int x, int y)
: surf_(surf), x_(x), y_(y)
{}
virtual surface operator()(const surface& src) const;
private:
surface surf_;
int x_;
int y_;
};
/**
* Mask (MASK) function.
*/
class mask_function : public function_base
{
public:
mask_function(const surface& mask, int x, int y)
: mask_(mask), x_(x), y_(y)
{}
virtual surface operator()(const surface& src) const;
private:
surface mask_;
int x_;
int y_;
};
/**
* LIGHT (L) function.
*/
class light_function : public function_base
{
public:
light_function(const surface& surf)
: surf_(surf)
{}
virtual surface operator()(const surface& src) const;
private:
surface surf_;
};
/**
* Scale (SCALE) function.
*/
class scale_function : public function_base
{
public:
scale_function(int width, int height)
: w_(width), h_(height)
{}
virtual surface operator()(const surface& src) const;
private:
int w_, h_;
};
/**
* Opacity (O) function
*/
class o_function : public function_base
{
public:
o_function(float opacity)
: opacity_(opacity)
{}
virtual surface operator()(const surface& src) const;
private:
float opacity_;
};
/**
* Color-shift (CS, R, G, B) function.
*/
class cs_function : public function_base
{
public:
cs_function(int r, int g, int b)
: r_(r), g_(g), b_(b)
{}
virtual surface operator()(const surface& src) const;
private:
int r_, g_, b_;
};
/**
* Gaussian-like blur (BL) function.
*/
class bl_function : public function_base
{
public:
bl_function(int depth)
: depth_(depth)
{}
virtual surface operator()(const surface& src) const;
private:
int depth_;
};
/**
* Overlay with ToD brightening (BRIGHTEN).
*/
struct brighten_function : function_base
{
virtual surface operator()(const surface &src) const;
};
/**
* Overlay with ToD darkening (DARKEN).
*/
struct darken_function : function_base
{
virtual surface operator()(const surface &src) const;
};
/**
* Fill background with a color (BG).
*/
struct background_function : function_base
{
background_function(SDL_Color const &c): color_(c) {}
virtual surface operator()(const surface &src) const;
SDL_Color color_;
};
} /* end namespace image */
#endif /* !defined(IMAGE_FUNCTION_HPP_INCLUDED) */

763
src/image_modifications.cpp Normal file
View file

@ -0,0 +1,763 @@
/* $Id$ */
/*
Copyright (C) 2009 - 2011 by Ignacio R. Morelle <shadowm2006@gmail.com>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "color_range.hpp"
#include "config.hpp"
#include "foreach.hpp"
#include "game_config.hpp"
#include "image.hpp"
#include "image_modifications.hpp"
#include "log.hpp"
#include "serialization/string_utils.hpp"
#include <map>
#define GETTEXT_DOMAIN "wesnoth-lib"
static lg::log_domain log_display("display");
#define ERR_DP LOG_STREAM(err, log_display)
#define LOG_DP LOG_STREAM(info, log_display)
namespace image {
namespace {
/// A function used to parse modification arguments
typedef modification* (*mod_parser)(const std::string&);
/** A map of all registered mod parsers
*
* The mapping is between the modification name and the parser function pointer
* An example of an entry would be "TC" -> &parse_TC_mod
*/
std::map<std::string, mod_parser> mod_parsers;
/** Decodes a single modification using an appropriate mod_parser
*
* @param encoded_mod A string representing a single modification
*
* @return A pointer to the decoded modification object
* @retval NULL if the string is invalid or a parser isn't found
*/
modification* decode_modification(const std::string& encoded_mod)
{
std::vector<std::string> split = utils::parenthetical_split(encoded_mod);
if(split.size() != 2) {
ERR_DP << "error parsing image modifications: "
<< encoded_mod << "\n";
return NULL;
}
std::string mod_type = split[0];
std::string args = split[1];
if(mod_parsers.find(mod_type) == mod_parsers.end()) {
ERR_DP << "unknown image function in path: "
<< mod_type << '\n';
return NULL;
}
return (*mod_parsers[mod_type])(args);
}
} // end anon namespace
/** Decodes the modification string
*
* Important:
* It creates new objects which need to be deleted after use
*
* @param encoded_mods A string representing any number of modifications
*
* @return A modification_queue filled with decoded modification pointers
*/
modification_queue modification::decode(const std::string& encoded_mods)
{
modification_queue mods;
foreach(const std::string& encoded_mod,
utils::parenthetical_split(encoded_mods, '~')) {
modification* mod = decode_modification(encoded_mod);
if(mod) {
mods.push(mod);
}
}
return mods;
}
/// Compares two modification pointers, providing descending priority order
bool mod_ptr_comparator_::operator()(const modification* a,
const modification* b) const
{
return a->priority() < b->priority();
}
surface rc_modification::operator()(const surface& src) const
{
// unchecked
return recolor_image(src, rc_map_);
}
surface fl_modification::operator()(const surface& src) const
{
surface ret = src;
if(horiz_) {
ret = flip_surface(ret);
}
if(vert_) {
ret = flop_surface(ret);
}
return ret;
}
surface gs_modification::operator()(const surface& src) const
{
return greyscale_image(src);
}
surface crop_modification::operator()(const surface& src) const
{
SDL_Rect area = slice_;
if(area.w == 0) {
area.w = src->w;
}
if(area.h == 0) {
area.h = src->h;
}
if(area.x < 0) {
ERR_DP << "start X coordinate of SECTION modification is negative - truncating to zero\n";
area.x = 0;
}
if(area.y < 0) {
ERR_DP << "start Y coordinate of SECTION modification is negative - truncating to zero\n";
area.y = 0;
}
return cut_surface(src, area);
}
const SDL_Rect& crop_modification::get_slice() const
{
return slice_;
}
surface blit_modification::operator()(const surface& src) const
{
//blit_surface want neutral surfaces
surface nsrc = make_neutral_surface(src);
surface nsurf = make_neutral_surface(surf_);
SDL_Rect r = create_rect(x_, y_, 0, 0);
blit_surface(nsurf, NULL, nsrc, &r);
return nsrc;
}
const surface& blit_modification::get_surface() const
{
return surf_;
}
int blit_modification::get_x() const
{
return x_;
}
int blit_modification::get_y() const
{
return y_;
}
surface mask_modification::operator()(const surface& src) const
{
if(src->w == mask_->w && src->h == mask_->h && x_ == 0 && y_ == 0)
return mask_surface(src, mask_);
SDL_Rect r = create_rect(x_, y_, 0, 0);
surface new_mask = create_neutral_surface(src->w, src->h);
blit_surface(mask_, NULL, new_mask, &r);
return mask_surface(src, new_mask);
}
const surface& mask_modification::get_mask() const
{
return mask_;
}
int mask_modification::get_x() const
{
return x_;
}
int mask_modification::get_y() const
{
return y_;
}
surface light_modification::operator()(const surface& src) const
{
return light_surface(src, surf_);;
}
const surface& light_modification::get_surface() const
{
return surf_;
}
surface scale_modification::operator()(const surface& src) const
{
const int old_w = src->w;
const int old_h = src->h;
int w = w_;
int h = h_;
if(w <= 0) {
if(w < 0) {
ERR_DP << "width of SCALE is negative - resetting to original width\n";
}
w = old_w;
}
if(h <= 0) {
if(h < 0) {
ERR_DP << "height of SCALE is negative - resetting to original height\n";
}
h = old_h;
}
return scale_surface(src, w, h);
}
int scale_modification::get_w() const
{
return w_;
}
int scale_modification::get_h() const
{
return h_;
}
surface o_modification::operator()(const surface& src) const
{
return adjust_surface_alpha(src, ftofxp(opacity_));
}
float o_modification::get_opacity() const
{
return opacity_;
}
surface cs_modification::operator()(const surface& src) const
{
return(
(r_ != 0 || g_ != 0 || b_ != 0) ?
adjust_surface_color(src, r_, g_, b_) :
src
);
}
int cs_modification::get_r() const
{
return r_;
}
int cs_modification::get_g() const
{
return g_;
}
int cs_modification::get_b() const
{
return b_;
}
surface bl_modification::operator()(const surface& src) const
{
return blur_alpha_surface(src, depth_);
}
int bl_modification::get_depth() const
{
return depth_;
}
surface brighten_modification::operator()(const surface &src) const
{
surface ret = make_neutral_surface(src);
surface tod_bright(image::get_image(game_config::images:: tod_bright));
if (tod_bright)
blit_surface(tod_bright, NULL, ret, NULL);
return ret;
}
surface darken_modification::operator()(const surface &src) const
{
surface ret = make_neutral_surface(src);
surface tod_dark(image::get_image(game_config::images::tod_dark));
if (tod_dark)
blit_surface(tod_dark, NULL, ret, NULL);
return ret;
}
surface background_modification::operator()(const surface &src) const
{
surface ret = make_neutral_surface(src);
SDL_FillRect(ret, NULL, SDL_MapRGBA(ret->format, color_.r, color_.g,
color_.b, color_.unused));
SDL_SetAlpha(src, SDL_SRCALPHA, SDL_ALPHA_OPAQUE);
SDL_BlitSurface(src, NULL, ret, NULL);
return ret;
}
const SDL_Color& background_modification::get_color() const
{
return color_;
}
namespace {
/** A macro for automatic modification parser registration
*
* It automatically registers the created parser in the mod_parsers map
* It should be used just like a function header (look at the uses below)
* It should only be used within an anonymous namespace
*
* @param type The modification type to be registered (unquoted)
* @args_var The name for the string argument provided
*/
#define REGISTER_MOD_PARSER(type, args_var) \
modification* parse_##type##_mod(const std::string&); \
struct parse_##type##_mod_registration \
{ \
parse_##type##_mod_registration() \
{ \
mod_parsers[#type] = &parse_##type##_mod; \
} \
} parse_##type##_mod_registration_aux; \
modification* parse_##type##_mod(const std::string& args_var)
// Color-range-based recoloring
REGISTER_MOD_PARSER(TC, args)
{
std::vector<std::string> params = utils::split(args,',');
if(params.size() < 2) {
ERR_DP << "too few arguments passed to the ~TC() function\n";
return NULL;
}
int side_n = lexical_cast_default<int>(params[0], -1);
std::string team_color;
if (side_n < 1) {
ERR_DP << "invalid team (" << side_n
<< ") passed to the ~TC() function\n";
return NULL;
}
else if (side_n < static_cast<int>(image::get_team_colors().size())) {
team_color = image::get_team_colors()[side_n - 1];
}
else {
// This side is not initialized; use default "n"
try {
team_color = lexical_cast<std::string>(side_n);
} catch(bad_lexical_cast const&) {
ERR_DP << "bad things happen\n";
return NULL;
}
}
//
// Pass argseters for RC functor
//
if(!game_config::tc_info(params[1]).size()){
ERR_DP << "could not load TC info for '" << params[1]
<< "' palette\n"
<< "bailing out from TC\n";
return NULL;
}
std::map<Uint32, Uint32> rc_map;
try {
color_range const& new_color =
game_config::color_info(team_color);
std::vector<Uint32> const& old_color =
game_config::tc_info(params[1]);
rc_map = recolor_range(new_color,old_color);
}
catch(config::error const& e) {
ERR_DP << "caught config::error while processing TC: "
<< e.message
<< '\n'
<< "bailing out from TC\n";
return NULL;
}
return new rc_modification(rc_map);
}
// Team-color-based color range selection and recoloring
REGISTER_MOD_PARSER(RC, args)
{
const std::vector<std::string> recolor_params = utils::split(args,'>');
if(recolor_params.size()>1){
//
// recolor source palette to color range
//
std::map<Uint32, Uint32> rc_map;
try {
color_range const& new_color =
game_config::color_info(recolor_params[1]);
std::vector<Uint32> const& old_color =
game_config::tc_info(recolor_params[0]);
rc_map = recolor_range(new_color,old_color);
}
catch (config::error& e) {
ERR_DP
<< "caught config::error while processing color-range RC: "
<< e.message
<< '\n';
ERR_DP
<< "bailing out from RC\n";
rc_map.clear();
}
return new rc_modification(rc_map);
}
else {
///@Deprecated 1.6 palette switch syntax
if(args.find('=') != std::string::npos) {
lg::wml_error << "the ~RC() image function cannot be used for palette switch (A=B) in 1.7.x; use ~PAL(A>B) instead\n";
}
}
return NULL;
}
// Palette switch
REGISTER_MOD_PARSER(PAL, args)
{
const std::vector<std::string> remap_params = utils::split(args,'>');
if(remap_params.size() < 2) {
ERR_DP << "not enough arguments passed to the ~PAL() function: "
<< args << "\n";
return NULL;
}
try {
std::map<Uint32, Uint32> rc_map;
std::vector<Uint32> const& old_palette =
game_config::tc_info(remap_params[0]);
std::vector<Uint32> const& new_palette =
game_config::tc_info(remap_params[1]);
for(size_t i = 0; i < old_palette.size() && i < new_palette.size(); ++i) {
rc_map[old_palette[i]] = new_palette[i];
}
return new rc_modification(rc_map);
}
catch(config::error& e) {
ERR_DP
<< "caught config::error while processing PAL function: "
<< e.message
<< '\n';
ERR_DP
<< "bailing out from PAL\n";
return NULL;
}
}
// Flip/flop
REGISTER_MOD_PARSER(FL, args)
{
bool horiz = (args.empty() || args.find("horiz") != std::string::npos);
bool vert = (args.find("vert") != std::string::npos);
return new fl_modification(horiz, vert);
}
// Grayscale
REGISTER_MOD_PARSER(GS, )
{
return new gs_modification;
}
// Color-shift
REGISTER_MOD_PARSER(CS, args)
{
std::vector<std::string> const factors = utils::split(args, ',');
const size_t s = factors.size();
if(s == 0) {
ERR_DP << "no arguments passed to the ~CS() function\n";
return NULL;
}
int r = 0, g = 0, b = 0;
r = lexical_cast_default<int>(factors[0]);
if( s > 1 ) {
g = lexical_cast_default<int>(factors[1]);
}
if( s > 2 ) {
b = lexical_cast_default<int>(factors[2]);
}
return new cs_modification(r, g, b);
}
// Crop/slice
REGISTER_MOD_PARSER(CROP, args)
{
std::vector<std::string> const& slice_params = utils::split(args, ',', utils::STRIP_SPACES);
const size_t s = slice_params.size();
if(s == 0) {
ERR_DP << "no arguments passed to the ~CROP() function\n";
return NULL;
}
SDL_Rect slice_rect = { 0, 0, 0, 0 };
slice_rect.x = lexical_cast_default<Sint16, const std::string&>(slice_params[0]);
if(s > 1) {
slice_rect.y = lexical_cast_default<Sint16, const std::string&>(slice_params[1]);
}
if(s > 2) {
slice_rect.w = lexical_cast_default<Uint16, const std::string&>(slice_params[2]);
}
if(s > 3) {
slice_rect.h = lexical_cast_default<Uint16, const std::string&>(slice_params[3]);
}
return new crop_modification(slice_rect);
}
// LOC function (unsupported)
REGISTER_MOD_PARSER(LOC, )
{
/*
//FIXME: WIP, don't use it yet
std::vector<std::string> const& params = utils::split(args);
int x = lexical_cast<int>(params[0]);
int y = lexical_cast<int>(params[1]);
int cx = lexical_cast<int>(params[2]);
int cy = lexical_cast<int>(params[3]);
image::locator new_loc(val_.filename_, map_location(x,y), cx, cy, "");//TODO remove only ~LOC
surf = get_image(new_loc, TOD_COLORED);
*/
return NULL;
}
// Blit
REGISTER_MOD_PARSER(BLIT, args)
{
std::vector<std::string> param = utils::parenthetical_split(args, ',');
const size_t s = param.size();
if(s == 0){
ERR_DP << "no arguments passed to the ~BLIT() function\n";
return NULL;
}
int x = 0, y = 0;
if(s == 3) {
x = lexical_cast_default<int>(param[1]);
y = lexical_cast_default<int>(param[2]);
}
if(x < 0 || y < 0) { //required by blit_surface
ERR_DP << "negative position arguments in ~BLIT() function\n";
return NULL;
}
surface surf = get_image(param[0]);
return new blit_modification(surf, x, y);
}
// Mask
REGISTER_MOD_PARSER(MASK, args)
{
std::vector<std::string> param = utils::parenthetical_split(args, ',');
const size_t s = param.size();
if(s == 0){
ERR_DP << "no arguments passed to the ~MASK() function\n";
return NULL;
}
int x = 0, y = 0;
if(s == 3) {
x = lexical_cast_default<int>(param[1]);
y = lexical_cast_default<int>(param[2]);
}
if(x < 0 || y < 0) { //required by blit_surface
ERR_DP << "negative position arguments in ~MASK() function\n";
return NULL;
}
surface surf = get_image(param[0]);
return new mask_modification(surf, x, y);
}
// Light
REGISTER_MOD_PARSER(L, args)
{
if(args.empty()){
ERR_DP << "no arguments passed to the ~L() function\n";
return NULL;
}
surface surf = get_image(args);
return new light_modification(surf);
}
// Scale
REGISTER_MOD_PARSER(SCALE, args)
{
std::vector<std::string> const& scale_params = utils::split(args, ',', utils::STRIP_SPACES);
const size_t s = scale_params.size();
if(s == 0) {
ERR_DP << "no arguments passed to the ~SCALE() function\n";
return NULL;
}
int w = 0, h = 0;
w = lexical_cast_default<int, const std::string&>(scale_params[0]);
if(s > 1) {
h = lexical_cast_default<int, const std::string&>(scale_params[1]);
}
return new scale_modification(w, h);
}
// Gaussian-like blur
REGISTER_MOD_PARSER(BL, args)
{
const int depth = std::max<int>(0, lexical_cast_default<int>(args));
return new bl_modification(depth);
}
// Opacity-shift
REGISTER_MOD_PARSER(O, args)
{
const std::string::size_type p100_pos = args.find('%');
float num = 0.0f;
if(p100_pos == std::string::npos)
num = lexical_cast_default<float,const std::string&>(args);
else {
// make multiplier
const std::string parsed_field = args.substr(0, p100_pos);
num = lexical_cast_default<float,const std::string&>(parsed_field);
num /= 100.0f;
}
return new o_modification(num);
}
//
// ~R(), ~G() and ~B() are the children of ~CS(). Merely syntatic sugar.
// Hence they are at the end of the evaluation.
//
// Red component color-shift
REGISTER_MOD_PARSER(R, args)
{
const int r = lexical_cast_default<int>(args);
return new cs_modification(r,0,0);
}
// Green component color-shift
REGISTER_MOD_PARSER(G, args)
{
const int g = lexical_cast_default<int>(args);
return new cs_modification(0,g,0);
}
// Blue component color-shift
REGISTER_MOD_PARSER(B, args)
{
const int b = lexical_cast_default<int>(args);
return new cs_modification(0,0,b);
}
REGISTER_MOD_PARSER(NOP, )
{
return NULL;
}
// Fake image function used by GUI2 portraits until
// Mordante gets rid of it. *tsk* *tsk*
REGISTER_MOD_PARSER(RIGHT, )
{
return NULL;
}
// Add a bright overlay.
REGISTER_MOD_PARSER(BRIGHTEN, )
{
return new brighten_modification;
}
// Add a dark overlay.
REGISTER_MOD_PARSER(DARKEN, )
{
return new darken_modification;
}
// Add a background color.
REGISTER_MOD_PARSER(BG, args)
{
int c[4] = { 0, 0, 0, 255 };
std::vector<std::string> factors = utils::split(args, ',');
for (int i = 0; i < std::min<int>(factors.size(), 4); ++i) {
c[i] = lexical_cast_default<int>(factors[i]);
}
return new background_modification(create_color(c[0], c[1], c[2], c[3]));
}
} // end anon namespace
} /* end namespace image */

626
src/image_modifications.hpp Normal file
View file

@ -0,0 +1,626 @@
/* $Id$ */
/*
Copyright (C) 2009 - 2011 by Ignacio R. Morelle <shadowm2006@gmail.com>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/** @file */
#ifndef IMAGE_MODIFICATIONS_HPP_INCLUDED
#define IMAGE_MODIFICATIONS_HPP_INCLUDED
#include "sdl_utils.hpp"
#include <queue>
namespace image {
class modification;
struct mod_ptr_comparator_;
/// A priority queue used to enforce using the rc modifications first
typedef std::priority_queue<modification*,
std::vector<modification*>,
mod_ptr_comparator_> modification_queue;
/// Base abstract class for an image-path modification
class modification
{
public:
/// Decodes modifications from a modification string
static modification_queue decode(const std::string&);
virtual ~modification() {}
///Applies the image-path modification on the specified surface
virtual surface operator()(const surface& src) const = 0;
/// Specifies the priority of the modification
virtual int priority() const { return 0; }
};
/// A functor for comparing modification pointers
struct mod_ptr_comparator_
{
/// Provides a descending priority ordering
bool operator()(const modification* a, const modification* b) const;
};
/**
* Recolor (RC/TC/PAL) modification.
* It is used not only for color-range-based recoloring ("~RC(magenta>teal)")
* but also for team-color-based color range selection and recoloring
* ("~TC(3,magenta)") and palette switches ("~PAL(000000,005000 > FFFFFF,FF00FF)").
*/
class rc_modification : public modification
{
public:
/**
* Default constructor.
*/
rc_modification()
: rc_map_()
{}
/**
* RC-map based constructor.
* @param recolor_map The palette switch map.
*/
rc_modification(const std::map<Uint32, Uint32>& recolor_map)
: rc_map_(recolor_map)
{}
virtual surface operator()(const surface& src) const;
// The rc modification has a higher priority
virtual int priority() const { return 1; }
bool no_op() const { return rc_map_.empty(); }
const std::map<Uint32, Uint32>& map() const { return rc_map_;}
std::map<Uint32, Uint32>& map() { return rc_map_;}
private:
std::map<Uint32, Uint32> rc_map_;
};
/**
* Mirror (FL) modification.
*/
class fl_modification : public modification
{
public:
/**
* Constructor.
* @param horiz Horizontal mirror flag.
* @param vert Vertical mirror flag.
*/
fl_modification(bool horiz = false, bool vert = false)
: horiz_(horiz)
, vert_(vert)
{}
virtual surface operator()(const surface& src) const;
void set_horiz(bool val) { horiz_ = val; }
void set_vert(bool val) { vert_ = val; }
bool get_horiz() const { return horiz_; }
bool get_vert() const { return vert_; }
/** Toggle horizontal mirror flag.
* @return The new flag state after toggling. */
bool toggle_horiz() { return((horiz_ = !horiz_)); }
/** Toggle vertical mirror flag.
* @return The new flag state after toggling. */
bool toggle_vert() { return((vert_ = !vert_)); }
bool no_op() const { return ((!horiz_) && (!vert_)); }
private:
bool horiz_;
bool vert_;
};
/**
* Grayscale (GS) modification.
*/
class gs_modification : public modification
{
public:
virtual surface operator()(const surface& src) const;
};
/**
* Crop (CROP) modification.
*/
class crop_modification : public modification
{
public:
crop_modification(const SDL_Rect& slice)
: slice_(slice)
{}
virtual surface operator()(const surface& src) const;
const SDL_Rect& get_slice() const;
private:
SDL_Rect slice_;
};
/**
* Scale (BLIT) modification.
*/
class blit_modification : public modification
{
public:
blit_modification(const surface& surf, int x, int y)
: surf_(surf), x_(x), y_(y)
{}
virtual surface operator()(const surface& src) const;
const surface& get_surface() const;
int get_x() const;
int get_y() const;
private:
surface surf_;
int x_;
int y_;
};
/**
* Mask (MASK) modification.
*/
class mask_modification : public modification
{
public:
mask_modification(const surface& mask, int x, int y)
: mask_(mask), x_(x), y_(y)
{}
virtual surface operator()(const surface& src) const;
const surface& get_mask() const;
int get_x() const;
int get_y() const;
private:
surface mask_;
int x_;
int y_;
};
/**
* LIGHT (L) modification.
*/
class light_modification : public modification
{
public:
light_modification(const surface& surf)
: surf_(surf)
{}
virtual surface operator()(const surface& src) const;
const surface& get_surface() const;
private:
surface surf_;
};
/**
* Scale (SCALE) modification.
*/
class scale_modification : public modification
{
public:
scale_modification(int width, int height)
: w_(width), h_(height)
{}
virtual surface operator()(const surface& src) const;
int get_w() const;
int get_h() const;
private:
int w_, h_;
};
/**
* Opacity (O) modification
*/
class o_modification : public modification
{
public:
o_modification(float opacity)
: opacity_(opacity)
{}
virtual surface operator()(const surface& src) const;
float get_opacity() const;
private:
float opacity_;
};
/**
* Color-shift (CS, R, G, B) modification.
*/
class cs_modification : public modification
{
public:
cs_modification(int r, int g, int b)
: r_(r), g_(g), b_(b)
{}
virtual surface operator()(const surface& src) const;
int get_r() const;
int get_g() const;
int get_b() const;
private:
int r_, g_, b_;
};
/**
* Gaussian-like blur (BL) modification.
*/
class bl_modification : public modification
{
public:
bl_modification(int depth)
: depth_(depth)
{}
virtual surface operator()(const surface& src) const;
int get_depth() const;
private:
int depth_;
};
/**
* Overlay with ToD brightening (BRIGHTEN).
*/
struct brighten_modification : modification
{
virtual surface operator()(const surface &src) const;
};
/**
* Overlay with ToD darkening (DARKEN).
*/
struct darken_modification : modification
{
virtual surface operator()(const surface &src) const;
};
/**
* Fill background with a color (BG).
*/
struct background_modification : modification
{
background_modification(SDL_Color const &c): color_(c) {}
virtual surface operator()(const surface &src) const;
const SDL_Color& get_color() const;
private:
SDL_Color color_;
};
} /* end namespace image */
#endif /* !defined(IMAGE_MODIFICATIONS_HPP_INCLUDED) */
/* $Id$ */
/*
Copyright (C) 2009 - 2011 by Ignacio R. Morelle <shadowm2006@gmail.com>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/** @file */
#ifndef IMAGE_MODIFICATIONS_HPP_INCLUDED
#define IMAGE_MODIFICATIONS_HPP_INCLUDED
#include "sdl_utils.hpp"
#include <queue>
namespace image {
class modification;
struct mod_ptr_comparator_;
/// A priority queue used to enforce using the rc modifications first
typedef std::priority_queue<modification*,
std::vector<modification*>,
mod_ptr_comparator_> modification_queue;
/// Base abstract class for an image-path modification
class modification
{
public:
/// Decodes modifications from a modification string
static modification_queue decode(const std::string&);
virtual ~modification() {}
///Applies the image-path modification on the specified surface
virtual surface operator()(const surface& src) const = 0;
/// Specifies the priority of the modification
virtual int priority() const { return 0; }
};
/// A functor for comparing modification pointers
struct mod_ptr_comparator_
{
/// Provides a descending priority ordering
bool operator()(const modification* a, const modification* b) const;
};
/**
* Recolor (RC/TC/PAL) modification.
* It is used not only for color-range-based recoloring ("~RC(magenta>teal)")
* but also for team-color-based color range selection and recoloring
* ("~TC(3,magenta)") and palette switches ("~PAL(000000,005000 > FFFFFF,FF00FF)").
*/
class rc_modification : public modification
{
public:
/**
* Default constructor.
*/
rc_modification()
: rc_map_()
{}
/**
* RC-map based constructor.
* @param recolor_map The palette switch map.
*/
rc_modification(const std::map<Uint32, Uint32>& recolor_map)
: rc_map_(recolor_map)
{}
virtual surface operator()(const surface& src) const;
// The rc modification has a higher priority
virtual int priority() const { return 1; }
bool no_op() const { return rc_map_.empty(); }
const std::map<Uint32, Uint32>& map() const { return rc_map_;}
std::map<Uint32, Uint32>& map() { return rc_map_;}
private:
std::map<Uint32, Uint32> rc_map_;
};
/**
* Mirror (FL) modification.
*/
class fl_modification : public modification
{
public:
/**
* Constructor.
* @param horiz Horizontal mirror flag.
* @param vert Vertical mirror flag.
*/
fl_modification(bool horiz = false, bool vert = false)
: horiz_(horiz)
, vert_(vert)
{}
virtual surface operator()(const surface& src) const;
void set_horiz(bool val) { horiz_ = val; }
void set_vert(bool val) { vert_ = val; }
bool get_horiz() const { return horiz_; }
bool get_vert() const { return vert_; }
/** Toggle horizontal mirror flag.
* @return The new flag state after toggling. */
bool toggle_horiz() { return((horiz_ = !horiz_)); }
/** Toggle vertical mirror flag.
* @return The new flag state after toggling. */
bool toggle_vert() { return((vert_ = !vert_)); }
bool no_op() const { return ((!horiz_) && (!vert_)); }
private:
bool horiz_;
bool vert_;
};
/**
* Grayscale (GS) modification.
*/
class gs_modification : public modification
{
public:
virtual surface operator()(const surface& src) const;
};
/**
* Crop (CROP) modification.
*/
class crop_modification : public modification
{
public:
crop_modification(const SDL_Rect& slice)
: slice_(slice)
{}
virtual surface operator()(const surface& src) const;
const SDL_Rect& get_slice() const;
private:
SDL_Rect slice_;
};
/**
* Scale (BLIT) modification.
*/
class blit_modification : public modification
{
public:
blit_modification(const surface& surf, int x, int y)
: surf_(surf), x_(x), y_(y)
{}
virtual surface operator()(const surface& src) const;
const surface& get_surface() const;
int get_x() const;
int get_y() const;
private:
surface surf_;
int x_;
int y_;
};
/**
* Mask (MASK) modification.
*/
class mask_modification : public modification
{
public:
mask_modification(const surface& mask, int x, int y)
: mask_(mask), x_(x), y_(y)
{}
virtual surface operator()(const surface& src) const;
const surface& get_mask() const;
int get_x() const;
int get_y() const;
private:
surface mask_;
int x_;
int y_;
};
/**
* LIGHT (L) modification.
*/
class light_modification : public modification
{
public:
light_modification(const surface& surf)
: surf_(surf)
{}
virtual surface operator()(const surface& src) const;
const surface& get_surface() const;
private:
surface surf_;
};
/**
* Scale (SCALE) modification.
*/
class scale_modification : public modification
{
public:
scale_modification(int width, int height)
: w_(width), h_(height)
{}
virtual surface operator()(const surface& src) const;
int get_w() const;
int get_h() const;
private:
int w_, h_;
};
/**
* Opacity (O) modification
*/
class o_modification : public modification
{
public:
o_modification(float opacity)
: opacity_(opacity)
{}
virtual surface operator()(const surface& src) const;
float get_opacity() const;
private:
float opacity_;
};
/**
* Color-shift (CS, R, G, B) modification.
*/
class cs_modification : public modification
{
public:
cs_modification(int r, int g, int b)
: r_(r), g_(g), b_(b)
{}
virtual surface operator()(const surface& src) const;
int get_r() const;
int get_g() const;
int get_b() const;
private:
int r_, g_, b_;
};
/**
* Gaussian-like blur (BL) modification.
*/
class bl_modification : public modification
{
public:
bl_modification(int depth)
: depth_(depth)
{}
virtual surface operator()(const surface& src) const;
int get_depth() const;
private:
int depth_;
};
/**
* Overlay with ToD brightening (BRIGHTEN).
*/
struct brighten_modification : modification
{
virtual surface operator()(const surface &src) const;
};
/**
* Overlay with ToD darkening (DARKEN).
*/
struct darken_modification : modification
{
virtual surface operator()(const surface &src) const;
};
/**
* Fill background with a color (BG).
*/
struct background_modification : modification
{
background_modification(SDL_Color const &c): color_(c) {}
virtual surface operator()(const surface &src) const;
const SDL_Color& get_color() const;
private:
SDL_Color color_;
};
} /* end namespace image */
#endif /* !defined(IMAGE_MODIFICATIONS_HPP_INCLUDED) */